MDL-85405 modinfo: Don't show modules without FEATURE_CAN_DISPLAY

Question banks were displaying in places they shouldn't, because
FEATURE_CAN_DISPLAY wasn't fully implemented. This broadens its
usage in the following areas:

- Availability info - Not relevant to qbank. However you could feasibly
have some module which isn't shown to students, but the teacher can
use
  it to track completion, so dont display the link.
- Activities block - links to each activity's index page. We already
have
the Question banks page in the secondary nav. No need to have it here
too.
- Overview report - It doesn't make sense to display question banks
here,
  as they're not an activity students can participate in, they wont have
  dates etc.
- Externallib - Return with candisplay = false. The app needs to handle
  this correctly.
- Visibility options, moodleform_mod, modvisible and visibility
selector.
Not relevant for qbank since it doesn't include the standard
coursemodule
  options, but if an activity with without CAN_DISPLAY did display a
  visibility setting, "Hidden" should be the only option.
- Activity names filter - we dont want automatic links to question
banks.
This commit is contained in:
Luca Bösch
2025-11-27 15:14:06 +00:00
committed by Mark Johnson
parent d0f3a5723b
commit f99e1652fd
13 changed files with 69 additions and 11 deletions
@@ -0,0 +1,9 @@
issueNumber: MDL-85405
notes:
core_course:
- message: >-
The external function `core_course_get_course_contents` now includes the
`candisplay` property for each returned module. If this is false, the
module should not be displayed on the course page (for example, for
question banks).
type: improved
+5 -1
View File
@@ -746,7 +746,11 @@ abstract class info {
$modulename = format_string($cm->get_name(), true, ['context' => $context]);
// We make sure that we add a data attribute to the name so we can change it later if the
// original module name changes.
if ($cm->has_view() && $cm->get_user_visible()) {
if (
\course_modinfo::is_mod_type_visible_on_course($cm->modname)
&& $cm->has_view()
&& $cm->get_user_visible()
) {
// Help student by providing a link to the module which is preventing availability.
return \html_writer::link($cm->get_url(), $modulename, ['data-cm-name-for' => $cm->id]);
} else {
@@ -53,7 +53,11 @@ class block_activity_modules extends block_list {
foreach($modinfo->cms as $cm) {
// Exclude activities that aren't visible or have no view link (e.g. label). Account for folder being displayed inline.
if (!$cm->uservisible || (!$cm->has_view() && strcmp($cm->modname, 'folder') !== 0)) {
if (
!\course_modinfo::is_mod_type_visible_on_course($cm->modname)
|| !$cm->uservisible
|| (!$cm->has_view() && strcmp($cm->modname, 'folder') !== 0)
) {
continue;
}
if (array_key_exists($cm->modname, $modfullnames)) {
@@ -26,6 +26,7 @@ Feature: Block activity modules
| url | Frontpage url name | Frontpage url description | Acceptance test site | url0 |
| wiki | Frontpage wiki name | Frontpage wiki description | Acceptance test site | wiki0 |
| workshop | Frontpage workshop name | Frontpage workshop description | Acceptance test site | workshop0 |
| qbank | Frontpage qbank name | Frontpage qbank description | Acceptance test site | qbank0 |
When I log in as "admin"
And I am on site homepage
@@ -74,6 +75,8 @@ Feature: Block activity modules
And I should see "Frontpage imscp name"
And I should see "Frontpage folder name"
And I should see "Frontpage url name"
And I am on site homepage
And "Question banks" "link" should not exist in the "Activities" "block"
Scenario: Add activities block in a course
Given the following "courses" exist:
@@ -100,6 +103,7 @@ Feature: Block activity modules
| url | Test url name | Test url description | C1 | url1 |
| wiki | Test wiki name | Test wiki description | C1 | wiki1 |
| workshop | Test workshop name | Test workshop description | C1 | workshop1 |
| qbank | Test qbank name | Test qbank description | C1 | qbank1 |
When I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
@@ -147,3 +151,5 @@ Feature: Block activity modules
And I should see "Test imscp name"
And I should see "Test folder name"
And I should see "Test url name"
And I am on "Course 1" course homepage
And "Question banks" "link" should not exist in the "Activities" "block"
+5
View File
@@ -287,6 +287,7 @@ class core_course_external extends external_api {
$module['completion'] = $cm->completion;
$module['downloadcontent'] = $cm->downloadcontent;
$module['noviewlink'] = plugin_supports('mod', $cm->modname, FEATURE_NO_VIEW_LINK, false);
$module['candisplay'] = plugin_supports('mod', $cm->modname, FEATURE_CAN_DISPLAY, true);
$module['dates'] = $activitydates;
$module['groupmode'] = $cm->groupmode;
@@ -488,6 +489,10 @@ class core_course_external extends external_api {
'customdata' => new external_value(PARAM_RAW, 'Custom data (JSON encoded).', VALUE_OPTIONAL),
'noviewlink' => new external_value(PARAM_BOOL, 'Whether the module has no view page',
VALUE_OPTIONAL),
'candisplay' => new external_value(
PARAM_BOOL,
'Whether the module should be displayed on the course page',
VALUE_OPTIONAL),
'completion' => new external_value(PARAM_INT, 'Type of completion tracking:
0 means none, 1 manual, 2 automatic.', VALUE_OPTIONAL),
'completiondata' => $completiondefinition,
@@ -92,9 +92,14 @@ class overviewpage implements renderable, named_templatable {
$archetypes = [];
foreach ($modinfo->cms as $cm) {
// Exclude activities that aren't visible or have no view link (e.g. label).
// Exclude activities that are not displayed on the course page,
// aren't visible or have no view link (e.g. label).
// Account for folder being displayed inline.
if (!$cm->uservisible || (!$cm->has_view() && strcmp($cm->modname, 'folder') !== 0)) {
if (
!\course_modinfo::is_mod_type_visible_on_course($cm->modname)
|| !$cm->uservisible
|| (!$cm->has_view() && strcmp($cm->modname, 'folder') !== 0)
) {
continue;
}
if (array_key_exists($cm->modname, $modfullnames)) {
@@ -221,7 +221,9 @@ class overviewtable implements externable, named_templatable, renderable {
private function is_cm_displayable(cm_info $cm): bool {
// Folder is an exception because it has settings to be displayed in the course
// page without having a view link.
return $cm->uservisible && ($cm->has_view() || strcmp($cm->modname, 'folder') === 0);
return $cm->uservisible
&& ($cm->has_view() || strcmp($cm->modname, 'folder') === 0)
&& \course_modinfo::is_mod_type_visible_on_course($cm->modname);
}
/**
+5 -4
View File
@@ -225,10 +225,11 @@ class format_singleactivity extends core_courseformat\base implements core_cours
public static function get_supported_activities() {
$availabletypes = get_module_types_names();
foreach ($availabletypes as $module => $name) {
if (plugin_supports('mod', $module, FEATURE_NO_VIEW_LINK, false)) {
unset($availabletypes[$module]);
}
if (sectiondelegate::has_delegate_class('mod_' . $module)) {
if (
plugin_supports('mod', $module, FEATURE_NO_VIEW_LINK, false)
|| sectiondelegate::has_delegate_class('mod_' . $module)
|| !course_modinfo::is_mod_type_visible_on_course($module)
) {
unset($availabletypes[$module]);
}
}
@@ -34,6 +34,7 @@ Feature: Courses can be created in Single Activity mode
# Check that not all the activity types are in the dropdown.
And I should not see "Text and media" in the "Type of activity" "field"
And I should not see "Subsection" in the "Type of activity" "field"
And I should not see "Question bank" in the "Type of activity" "field"
And I set the field "Type of activity" to "Assignment"
And I press "Save and display"
And I should see "New Assignment"
@@ -109,6 +109,7 @@ Feature: Users can access the course activities overview page
| url | C1 | Activity 18 |
| wiki | C1 | Activity 19 |
| workshop | C1 | Activity 20 |
| qbank | C1 | Activity 21 |
Given I am on the "Course 1" "course > activities" page logged in as "teacher1"
And I should see "Assignments" in the "assign_overview_collapsible" "region"
And I should see "Choices" in the "choice_overview_collapsible" "region"
@@ -124,6 +125,9 @@ Feature: Users can access the course activities overview page
And I should see "Workshops" in the "workshop_overview_collapsible" "region"
# All resources are grouped.
And I should see "Resources" in the "resource_overview_collapsible" "region"
# Qbanks and labels are not shown.
And I should not see "Labels" in the "course-overview-page" "region"
And I should not see "Question banks" in the "course-overview-page" "region"
@javascript
Scenario: The resources overview is loaded at the moment the section is expanded via Ajax
@@ -20,6 +20,7 @@ use cache;
use cache_store;
use core\output\html_writer;
use core_collator;
use course_modinfo;
use filterobject;
/**
@@ -124,7 +125,12 @@ class text_filter extends \core_filters\text_filter {
$sortedactivities = [];
foreach ($modinfo->cms as $cm) {
// Use normal access control and visibility, but exclude labels and hidden activities.
if ($cm->visible && $cm->has_view() && $cm->uservisible) {
if (
$cm->visible
&& $cm->has_view()
&& $cm->uservisible
&& course_modinfo::is_mod_type_visible_on_course($cm->modname)
) {
$sortedactivities[] = (object)[
'name' => $cm->name,
'url' => $cm->url,
@@ -41,9 +41,18 @@ final class text_filter_test extends \advanced_testcase {
'page',
['course' => $course->id, 'name' => 'Test (2)']
);
// Create a label and question bank that should not be linked to.
$this->getDataGenerator()->create_module(
'label',
['course' => $course->id, 'name' => 'Label 1', 'intro' => 'Label 1']
);
$this->getDataGenerator()->create_module(
'qbank',
['course' => $course->id, 'name' => 'Question bank 1']
);
// Format text with all three entries in HTML.
$html = '<p>Please read the two pages Test 1 and <i>Test (2)</i>.</p>';
$html = '<p>Please read the two pages Test 1 and <i>Test (2)</i>, but not Label 1 or Question bank 1.</p>';
$filtered = format_text($html, FORMAT_HTML, ['context' => $context]);
// Find all the glossary links in the result.
+2
View File
@@ -1369,6 +1369,8 @@ $string['missingteacher'] = 'Must choose something';
$string['missingurl'] = 'Missing URL';
$string['missingusername'] = 'Missing username';
$string['moddoesnotsupporttype'] = 'Module {$a->modname} does not support uploads of type {$a->type}';
$string['modhidden'] = 'Availability';
$string['modhidden_help'] = '* Hide on course page: Not available to students. This module cannot be shown to students.';
$string['modhide'] = 'Hide';
$string['modshow'] = 'Show';
$string['modvisible'] = 'Availability';