Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Blocks Advanced: Difference between revisions

From MoodleDocs
m (Text replacement - "<code php> " to "<syntaxhighlight lang="php">")
m (Text replacement - "<code php>" to "<syntaxhighlight lang="php">")
Line 10: Line 10:


Create a new file in the blocks/simplehtml directory called simplehtml_form.php. Add the following code:
Create a new file in the blocks/simplehtml directory called simplehtml_form.php. Add the following code:
<code php>
<syntaxhighlight lang="php">
require_once("{$CFG->libdir}/formslib.php");
require_once("{$CFG->libdir}/formslib.php");


Line 26: Line 26:
Create a new file in the blocks/simplehtml directory called view.php. In this file add the following code:
Create a new file in the blocks/simplehtml directory called view.php. In this file add the following code:


<code php>
<syntaxhighlight lang="php">
<?php
<?php


Line 52: Line 52:


In the get_content() method of our block_simplehtml class replace
In the get_content() method of our block_simplehtml class replace
<code php>
<syntaxhighlight lang="php">
$this->content->footer = 'Footer here...';
$this->content->footer = 'Footer here...';
</syntaxhighlight>
</syntaxhighlight>
with
with
<code php>
<syntaxhighlight lang="php">
global $COURSE;
global $COURSE;


Line 70: Line 70:


In the global declaration:
In the global declaration:
<code php>
<syntaxhighlight lang="php">
global $DB, $OUTPUT, $PAGE;
global $DB, $OUTPUT, $PAGE;
</syntaxhighlight>
</syntaxhighlight>
After require_login($course);
After require_login($course);
<code php>
<syntaxhighlight lang="php">
$PAGE->set_url('/blocks/simplehtml/view.php', array('id' => $courseid));
$PAGE->set_url('/blocks/simplehtml/view.php', array('id' => $courseid));
$PAGE->set_pagelayout('standard');
$PAGE->set_pagelayout('standard');
Line 80: Line 80:
</syntaxhighlight>
</syntaxhighlight>
One last lot of code to add. The following lines should be added after $simplehtml = new simplehtml_form();
One last lot of code to add. The following lines should be added after $simplehtml = new simplehtml_form();
<code php>
<syntaxhighlight lang="php">
echo $OUTPUT->header();
echo $OUTPUT->header();
$simplehtml->display();
$simplehtml->display();
Line 90: Line 90:


In view.php, add the following after $courseid = required_param('courseid', PARAM_INT);
In view.php, add the following after $courseid = required_param('courseid', PARAM_INT);
<code php>
<syntaxhighlight lang="php">
$blockid = required_param('blockid', PARAM_INT);
$blockid = required_param('blockid', PARAM_INT);


Line 97: Line 97:
</syntaxhighlight>
</syntaxhighlight>
Then add the following after the header code
Then add the following after the header code
<code php>
<syntaxhighlight lang="php">
$settingsnode = $PAGE->settingsnav->add(get_string('simplehtmlsettings', 'block_simplehtml'));
$settingsnode = $PAGE->settingsnav->add(get_string('simplehtmlsettings', 'block_simplehtml'));
$editurl = new moodle_url('/blocks/simplehtml/view.php', array('id' => $id, 'courseid' => $courseid, 'blockid' => $blockid));
$editurl = new moodle_url('/blocks/simplehtml/view.php', array('id' => $id, 'courseid' => $courseid, 'blockid' => $blockid));
Line 113: Line 113:


To implement these three scenarios adjust the code a bit. The existing form display and header code will be used as the first time display code, and an if statement added after instantiating the simplehtml_form object will handle the logic behind the application flow:
To implement these three scenarios adjust the code a bit. The existing form display and header code will be used as the first time display code, and an if statement added after instantiating the simplehtml_form object will handle the logic behind the application flow:
<code php>
<syntaxhighlight lang="php">
if($simplehtml->is_cancelled()) {
if($simplehtml->is_cancelled()) {
     // Cancelled forms redirect to the course main page.
     // Cancelled forms redirect to the course main page.
Line 148: Line 148:


To add the link title text field and the displaytext HTML area to the form, paste the following text in the function definition of the simplehtml_form.php file:  
To add the link title text field and the displaytext HTML area to the form, paste the following text in the function definition of the simplehtml_form.php file:  
<code php>
<syntaxhighlight lang="php">
          
          
// add page title element.
// add page title element.
Line 165: Line 165:
====File Upload====
====File Upload====
Add the file field to the form after the existing elements:  
Add the file field to the form after the existing elements:  
<code php>
<syntaxhighlight lang="php">
// add filename selection.
// add filename selection.
$mform->addElement('filepicker', 'filename', get_string('file'), null, array('accepted_types' => '*'));
$mform->addElement('filepicker', 'filename', get_string('file'), null, array('accepted_types' => '*'));
Line 172: Line 172:


====Fieldset Header====
====Fieldset Header====
<code php>
<syntaxhighlight lang="php">
// add picture fields grouping
// add picture fields grouping
$mform->addElement('header', 'picfield', get_string('picturefields', 'block_simplehtml'), null, false);
$mform->addElement('header', 'picfield', get_string('picturefields', 'block_simplehtml'), null, false);
</syntaxhighlight>
</syntaxhighlight>
====Yes/No Select====
====Yes/No Select====
<code php>
<syntaxhighlight lang="php">
// add display picture yes / no option
// add display picture yes / no option
$mform->addElement('selectyesno', 'displaypicture', get_string('displaypicture', 'block_simplehtml'));
$mform->addElement('selectyesno', 'displaypicture', get_string('displaypicture', 'block_simplehtml'));
Line 190: Line 190:


Create a file lib.php and place the following code into it which will define the image options via radio select.
Create a file lib.php and place the following code into it which will define the image options via radio select.
<code php>  
<syntaxhighlight lang="php">  
function block_simplehtml_images() {
function block_simplehtml_images() {
     return array(html_writer::tag('img', '', array('alt' => get_string('red', 'block_simplehtml'), 'src' => "pix/picture0.gif")),
     return array(html_writer::tag('img', '', array('alt' => get_string('red', 'block_simplehtml'), 'src' => "pix/picture0.gif")),
Line 198: Line 198:
</syntaxhighlight>
</syntaxhighlight>
Now include the above file in any files that need to use the function, for now this is just simplehtml_form.php. Add the following after require_once("$CFG->libdir/formslib.php"); in simplehtml_form.php  
Now include the above file in any files that need to use the function, for now this is just simplehtml_form.php. Add the following after require_once("$CFG->libdir/formslib.php"); in simplehtml_form.php  
<code php>
<syntaxhighlight lang="php">
require_once($CFG->dirroot.'/blocks/simplehtml/lib.php');
require_once($CFG->dirroot.'/blocks/simplehtml/lib.php');
</syntaxhighlight>
</syntaxhighlight>
You now need to add some pictures to the pix directory. In this example I have three gif images each a different colour, but you could use any image (small is better). Create a directory called pix in your simplehtml block directory. Now add the radio select to the form definition (simplethml_form.php)
You now need to add some pictures to the pix directory. In this example I have three gif images each a different colour, but you could use any image (small is better). Create a directory called pix in your simplehtml block directory. Now add the radio select to the form definition (simplethml_form.php)
<code php>
<syntaxhighlight lang="php">
// add image selector radio buttons
// add image selector radio buttons
$images = block_simplehtml_images();
$images = block_simplehtml_images();
Line 214: Line 214:
====Alt Text Input====
====Alt Text Input====
Finally, to wrap-up the image display selection, allow the user to choose the alternate text that will be displayed with the selected image.  
Finally, to wrap-up the image display selection, allow the user to choose the alternate text that will be displayed with the selected image.  
<code php>
<syntaxhighlight lang="php">
// add description field
// add description field
$attributes = array('size' => '50', 'maxlength' => '100');
$attributes = array('size' => '50', 'maxlength' => '100');
Line 226: Line 226:


Now add the date field as an optional element:
Now add the date field as an optional element:
<code php>
<syntaxhighlight lang="php">
  // add optional grouping
  // add optional grouping
$mform->addElement('header', 'optional', get_string('optional', 'form'), null, false);
$mform->addElement('header', 'optional', get_string('optional', 'form'), null, false);
</syntaxhighlight><br>
</syntaxhighlight><br>
<code php>
<syntaxhighlight lang="php">
  // add date_time selector in optional area
  // add date_time selector in optional area
$mform->addElement('date_time_selector', 'displaydate', get_string('displaydate', 'block_simplehtml'), array('optional' => true));
$mform->addElement('date_time_selector', 'displaydate', get_string('displaydate', 'block_simplehtml'), array('optional' => true));
Line 240: Line 240:
====Adding Form Buttons====
====Adding Form Buttons====
Most moodle forms have a basic set of buttons. "Submit" and "Cancel" are added by calling the moodleform member function add_action_buttons(). Add the following at the end of simplehtml_form.php
Most moodle forms have a basic set of buttons. "Submit" and "Cancel" are added by calling the moodleform member function add_action_buttons(). Add the following at the end of simplehtml_form.php
<code php>
<syntaxhighlight lang="php">
$this->add_action_buttons();
$this->add_action_buttons();
</syntaxhighlight>
</syntaxhighlight>
Line 246: Line 246:
====Add State Variables====
====Add State Variables====
Sometimes forms need to keep track of additional data that is not intended to be visible to users. These fields should be placed in hidden elements. For this form blockid and the courseid are needed. Before the call to add_action_buttons() add:  
Sometimes forms need to keep track of additional data that is not intended to be visible to users. These fields should be placed in hidden elements. For this form blockid and the courseid are needed. Before the call to add_action_buttons() add:  
<code php>
<syntaxhighlight lang="php">
// hidden elements
// hidden elements
$mform->addElement('hidden', 'blockid');
$mform->addElement('hidden', 'blockid');
Line 252: Line 252:
</syntaxhighlight>
</syntaxhighlight>
These elements will need to be populated by displaying code because these will be passed in via the URL initially. after $simplehtml = new simplehtml_form(); in view.php add:
These elements will need to be populated by displaying code because these will be passed in via the URL initially. after $simplehtml = new simplehtml_form(); in view.php add:
<code php>
<syntaxhighlight lang="php">
$toform['blockid'] = $blockid;
$toform['blockid'] = $blockid;
$toform['courseid'] = $courseid;
$toform['courseid'] = $courseid;
Line 259: Line 259:
===Process Form Data===
===Process Form Data===
After creating the form, appropriate code must be added to process the submitted form data. Accomplish this by adding code to view.php. Typically when processing form data it is helpful to remove some of the final processing steps so that your script essentially terminates execution and does not redirect you to the course page or wherever makes sense. This is tremendously helpful while debugging. The processing code will be added to this block of code in view.php :
After creating the form, appropriate code must be added to process the submitted form data. Accomplish this by adding code to view.php. Typically when processing form data it is helpful to remove some of the final processing steps so that your script essentially terminates execution and does not redirect you to the course page or wherever makes sense. This is tremendously helpful while debugging. The processing code will be added to this block of code in view.php :
<code php>
<syntaxhighlight lang="php">
} else if ($fromform = $simplehtml->get_data()) {
} else if ($fromform = $simplehtml->get_data()) {
     // We need to add code to appropriately act on and store the submitted data
     // We need to add code to appropriately act on and store the submitted data
Line 269: Line 269:


For now comment out the redirect and add the following above it.
For now comment out the redirect and add the following above it.
<code php>
<syntaxhighlight lang="php">
print_object($fromform);
print_object($fromform);
</syntaxhighlight>
</syntaxhighlight>
print_object() is a useful moodle function which prints out data from mixed data types showing the keys and data for arrays and objects. Now visit the "Add Page" link for the block and submit some form data. You should see something similar to:  
print_object() is a useful moodle function which prints out data from mixed data types showing the keys and data for arrays and objects. Now visit the "Add Page" link for the block and submit some form data. You should see something similar to:  
<code php>
<syntaxhighlight lang="php">
stdClass Object
stdClass Object
(
(
Line 290: Line 290:
</syntaxhighlight>
</syntaxhighlight>
The values in brackets are the keys and the portion after => is the data for that particular key. Since the form submission is verified as working as expected, save the submitted form data. The most direct way to save is with a call to insert_record(). This function takes the name of the table, 'block_simplehtml' in our case, and the object to be inserted. The object must have keys that map one-to-one with table column names. Choosing form element names that map directly to the database columns saves a bit of code. Save the submitted form data with the following code pasted above the commented out redirect:  
The values in brackets are the keys and the portion after => is the data for that particular key. Since the form submission is verified as working as expected, save the submitted form data. The most direct way to save is with a call to insert_record(). This function takes the name of the table, 'block_simplehtml' in our case, and the object to be inserted. The object must have keys that map one-to-one with table column names. Choosing form element names that map directly to the database columns saves a bit of code. Save the submitted form data with the following code pasted above the commented out redirect:  
<code php>
<syntaxhighlight lang="php">
// We need to add code to appropriately act on and store the submitted data
// We need to add code to appropriately act on and store the submitted data
if (!$DB->insert_record('block_simplehtml', $fromform)) {
if (!$DB->insert_record('block_simplehtml', $fromform)) {
Line 440: Line 440:


Add the following code:
Add the following code:
<code php>
<syntaxhighlight lang="php">
global $COURSE, $DB; //$COURSE should already be present
global $COURSE, $DB; //$COURSE should already be present


Line 467: Line 467:
To avoid any code duplication and make it easy to reuse this functionality create a function in '''lib.php''' to handle the page display. A preloaded simplehtml page is passed in as a single parameter, and an optional parameter will control whether the data is returned or directly printed out. Most Moodle functions that print information can be passed a true value as the last parameter. This is the function's return value, which tells the function to return the HTML and not print or echo it to the user. For development, set the return value to false so that the data is printed out.
To avoid any code duplication and make it easy to reuse this functionality create a function in '''lib.php''' to handle the page display. A preloaded simplehtml page is passed in as a single parameter, and an optional parameter will control whether the data is returned or directly printed out. Most Moodle functions that print information can be passed a true value as the last parameter. This is the function's return value, which tells the function to return the HTML and not print or echo it to the user. For development, set the return value to false so that the data is printed out.


<code php>
<syntaxhighlight lang="php">
function block_simplehtml_print_page($simplehtml, $return = false) {}
function block_simplehtml_print_page($simplehtml, $return = false) {}
</syntaxhighlight>
</syntaxhighlight>
Line 484: Line 484:
===Add Page Title===
===Add Page Title===
To display the page title use the $OUTPUT class. Add the following to block_simplehtml_print_page() in lib.php
To display the page title use the $OUTPUT class. Add the following to block_simplehtml_print_page() in lib.php
<code php>
<syntaxhighlight lang="php">
global $OUTPUT, $COURSE;
global $OUTPUT, $COURSE;
$display = $OUTPUT->heading($simplehtml->pagetitle);
$display = $OUTPUT->heading($simplehtml->pagetitle);
</syntaxhighlight>
</syntaxhighlight>
After we have displayed the title, let's add a box to put around the rest of the elements that we will display.
After we have displayed the title, let's add a box to put around the rest of the elements that we will display.
<code php>
<syntaxhighlight lang="php">
  $display .= $OUTPUT->box_start();
  $display .= $OUTPUT->box_start();
</syntaxhighlight>
</syntaxhighlight>
Line 495: Line 495:
===Display the Date===
===Display the Date===
The requirements for date display call for displaying the date in a smaller font under the page title. Moodle has a userdate() function that has several advantages over PHP's date() function. It displays the date in the user's preferred format and adjusts the date for any timezone difference.
The requirements for date display call for displaying the date in a smaller font under the page title. Moodle has a userdate() function that has several advantages over PHP's date() function. It displays the date in the user's preferred format and adjusts the date for any timezone difference.
<code php>
<syntaxhighlight lang="php">
if($simplehtml->displaydate) {
if($simplehtml->displaydate) {
     $display .= userdate($simplehtml->displaydate);
     $display .= userdate($simplehtml->displaydate);
Line 501: Line 501:
</syntaxhighlight>
</syntaxhighlight>
Notice that since the user had an option of choosing a date or not that you must check to ensure that it was set before trying to output it. Take a look at the displayed page: click on one of your page links from the block. There's no output. Add some additional code that handles the value of $return. Add the following at the end of the function definition:  
Notice that since the user had an option of choosing a date or not that you must check to ensure that it was set before trying to output it. Take a look at the displayed page: click on one of your page links from the block. There's no output. Add some additional code that handles the value of $return. Add the following at the end of the function definition:  
<code php>
<syntaxhighlight lang="php">
if($return) {
if($return) {
     return $display;
     return $display;
Line 511: Line 511:


First, put a div tag around the date, and give it a class to target with CSS later. Change the date output lines:
First, put a div tag around the date, and give it a class to target with CSS later. Change the date output lines:
<code php>
<syntaxhighlight lang="php">
$display .= html_writer::start_tag('div', array('class' => 'simplehtml displaydate'));
$display .= html_writer::start_tag('div', array('class' => 'simplehtml displaydate'));
$display .= userdate($simplehtml->displaydate);
$display .= userdate($simplehtml->displaydate);
Line 524: Line 524:
Choosing the second option, adding a styles.css file, allows more flexibility and avoids needing to create multiple entries if the site is using more than one theme. Create styles.css and add this CSS:
Choosing the second option, adding a styles.css file, allows more flexibility and avoids needing to create multiple entries if the site is using more than one theme. Create styles.css and add this CSS:


<code php>
<syntaxhighlight lang="php">
.simplehtml .displaydate {
.simplehtml .displaydate {
     font-size: .8em;
     font-size: .8em;
Line 532: Line 532:
===Display Text===
===Display Text===
Now the display text needs to be added.  
Now the display text needs to be added.  
<code php>
<syntaxhighlight lang="php">
$display .= clean_text($simplehtml->displaytext);
$display .= clean_text($simplehtml->displaytext);


Line 541: Line 541:
===Display the Picture===
===Display the Picture===
To selectively display the picture with its description text located underneath it:
To selectively display the picture with its description text located underneath it:
<code php>
<syntaxhighlight lang="php">
if ($simplehtml->displaypicture) {
if ($simplehtml->displaypicture) {
     $display .= $OUTPUT->box_start();
     $display .= $OUTPUT->box_start();
Line 555: Line 555:
To have this all come together and work we need to make a few alterations to view.php
To have this all come together and work we need to make a few alterations to view.php
First we will add another optional parameter:
First we will add another optional parameter:
<code php>
<syntaxhighlight lang="php">
$id = optional_param('id', 0, PARAM_INT);
$id = optional_param('id', 0, PARAM_INT);
$viewpage = optional_param('viewpage', false, PARAM_BOOL);
$viewpage = optional_param('viewpage', false, PARAM_BOOL);
Line 579: Line 579:


Edit the '''block_simplehtml.php''' file as follows:
Edit the '''block_simplehtml.php''' file as follows:
<code php>
<syntaxhighlight lang="php">
global $COURSE, $DB, $PAGE; //We are adding $PAGE here
global $COURSE, $DB, $PAGE; //We are adding $PAGE here


Line 613: Line 613:


First, modify the form to have a new hidden field called id to store the id of the record in the database to know which page to update. Add the following to '''simplehtml_form.php''' :
First, modify the form to have a new hidden field called id to store the id of the record in the database to know which page to update. Add the following to '''simplehtml_form.php''' :
<code php>
<syntaxhighlight lang="php">
$mform->addElement('hidden','id','0');
$mform->addElement('hidden','id','0');
</syntaxhighlight>
</syntaxhighlight>
Line 685: Line 685:
==Create delete.php==
==Create delete.php==
Refresh the course page and you should now see a black X icon next to each page after the edit icon (when editing is turned on). The purpose of delete.php is to print out a notice to the user with a verification that the user wants to delete the simplehtml page. The notice will either return the user to the course if they say No, or delete the page and return the user to the course if they say Yes. Moodle has a predefined core function in weblib.php that will create the Yes-No form for you and send the user on to the correct locations based on the answer to the question. The function is called notice_yesno(). Before using this, setup the basic file structure for delete.php (it's similar to what has been used for most of the other files like view.php and simplehtml.php).
Refresh the course page and you should now see a black X icon next to each page after the edit icon (when editing is turned on). The purpose of delete.php is to print out a notice to the user with a verification that the user wants to delete the simplehtml page. The notice will either return the user to the course if they say No, or delete the page and return the user to the course if they say Yes. Moodle has a predefined core function in weblib.php that will create the Yes-No form for you and send the user on to the correct locations based on the answer to the question. The function is called notice_yesno(). Before using this, setup the basic file structure for delete.php (it's similar to what has been used for most of the other files like view.php and simplehtml.php).
<code php>
<syntaxhighlight lang="php">
require_once('../../config.php');
require_once('../../config.php');
   
   
Line 719: Line 719:


This variable will be set when the user clicks the Yes or No button on the form. This means that a test needs to be added to test for the return value; if it is set then the database record containing the simple page id should be deleted. Add the following code after the all to the $PAGE->set_heading($heading); function:
This variable will be set when the user clicks the Yes or No button on the form. This means that a test needs to be added to test for the return value; if it is set then the database record containing the simple page id should be deleted. Add the following code after the all to the $PAGE->set_heading($heading); function:
<code php>
<syntaxhighlight lang="php">
if (!$confirm) {
if (!$confirm) {
     $optionsno = new moodle_url('/course/view.php', array('id' => $courseid));
     $optionsno = new moodle_url('/course/view.php', array('id' => $courseid));
Line 740: Line 740:
==Final Clean up==
==Final Clean up==
The block is almost finished! The one thing that has not been done is the cleanup of all data associated with the block on deletion. This is accomplished by adding a function named instance_delete() to '''block_simplehtml.php'''. In this function call delete records uses the blockid to pass in the $this->instance->id variable. The function looks like this:  
The block is almost finished! The one thing that has not been done is the cleanup of all data associated with the block on deletion. This is accomplished by adding a function named instance_delete() to '''block_simplehtml.php'''. In this function call delete records uses the blockid to pass in the $this->instance->id variable. The function looks like this:  
<code php>
<syntaxhighlight lang="php">
public function instance_delete() {
public function instance_delete() {
     global $DB;
     global $DB;
Line 751: Line 751:
#Modify/add simplehtml page(s) which will be block/simplehtml:managepages
#Modify/add simplehtml page(s) which will be block/simplehtml:managepages
We need to create an '''access.php''' file in the '''blocks/simplehtml/db directory'''. In that file add the simplehtml capability code:
We need to create an '''access.php''' file in the '''blocks/simplehtml/db directory'''. In that file add the simplehtml capability code:
<code php>
<syntaxhighlight lang="php">
defined('MOODLE_INTERNAL') || die();
defined('MOODLE_INTERNAL') || die();


Line 790: Line 790:


What does the simplehtml:viewpages mean? The presence of a string surrounded by double square brackets implies that there is a string referenced in code that has not been defined in an appropriate language file. Add the following to '''lang/en/block_simplehtml.php''':
What does the simplehtml:viewpages mean? The presence of a string surrounded by double square brackets implies that there is a string referenced in code that has not been defined in an appropriate language file. Add the following to '''lang/en/block_simplehtml.php''':
<code php>
<syntaxhighlight lang="php">
$string['simplehtml:viewpages'] = 'View Simple HTML Pages';
$string['simplehtml:viewpages'] = 'View Simple HTML Pages';
$string['simplehtml:managepages'] = 'Manage Simple HTML Pages';  
$string['simplehtml:managepages'] = 'Manage Simple HTML Pages';  
Line 796: Line 796:
==Add check to the block for the capability==
==Add check to the block for the capability==
With the two new capabilities created, it's time to use them and add a link to the form in the block. The link to the creation page is in the footer, so it's critical that the person viewing this link has the capability to manage a simplehtml page. Modify the get_content() function in blocks/simplehtml/block_simplehtml.php to check for the correct capabilities.To check for the capabilities, use the has_capability() function found in lib/access.php. Alter '''block_simplehtml.php''' to include checks for these capabilities.
With the two new capabilities created, it's time to use them and add a link to the form in the block. The link to the creation page is in the footer, so it's critical that the person viewing this link has the capability to manage a simplehtml page. Modify the get_content() function in blocks/simplehtml/block_simplehtml.php to check for the correct capabilities.To check for the capabilities, use the has_capability() function found in lib/access.php. Alter '''block_simplehtml.php''' to include checks for these capabilities.
<code php>
<syntaxhighlight lang="php">
$context = context_course::instance($COURSE->id);
$context = context_course::instance($COURSE->id);


Line 822: Line 822:
==Add Role to the simplehtml Form==
==Add Role to the simplehtml Form==
Currently any logged-in user can use the simplehtml form. In development this is not as big of a concern, but before moving into production always ensure that users have access to only those portions of the application that they should. Add the following line in '''view.php''' after <tt>require_login($course);</tt>.
Currently any logged-in user can use the simplehtml form. In development this is not as big of a concern, but before moving into production always ensure that users have access to only those portions of the application that they should. Add the following line in '''view.php''' after <tt>require_login($course);</tt>.
<code php>
<syntaxhighlight lang="php">
require_capability('block/simplehtml:managepages', context_course::instance($courseid));
require_capability('block/simplehtml:managepages', context_course::instance($courseid));
</syntaxhighlight>
</syntaxhighlight>
Line 829: Line 829:
==Add Role to Delete==
==Add Role to Delete==
To restrict deletion to those who have the managepages capability, add the following line to delete.php after require_login($course);
To restrict deletion to those who have the managepages capability, add the following line to delete.php after require_login($course);
<code php>
<syntaxhighlight lang="php">
require_capability('block/simplehtml:managepages', context_course::instance($courseid));
require_capability('block/simplehtml:managepages', context_course::instance($courseid));
</syntaxhighlight>
</syntaxhighlight>

Revision as of 13:37, 14 July 2021

Moodle 2.0


Introduction

This is a continuation of the simpleHTML block example.

Adding forms

The next thing that we want to do is add a form to create a simpleHTML page.

We are going to create two pages - view.php and simplehtml_form.php All of our logic will be contained in view.php and simplehtml_form.php will just display the form elements.

Create a new file in the blocks/simplehtml directory called simplehtml_form.php. Add the following code:

require_once("{$CFG->libdir}/formslib.php");

class simplehtml_form extends moodleform {
    
    function definition() {
        
        $mform =& $this->_form;
        $mform->addElement('header','displayinfo', get_string('textfields', 'block_simplehtml'));
    }
}

Now let's create view.php.

Create a new file in the blocks/simplehtml directory called view.php. In this file add the following code:

<?php

require_once('../../config.php');
require_once('simplehtml_form.php');

global $DB;

// Check for all required variables.
$courseid = required_param('courseid', PARAM_INT);


if (!$course = $DB->get_record('course', array('id' => $courseid))) {
    print_error('invalidcourse', 'block_simplehtml', $courseid);
}

require_login($course);

$simplehtml = new simplehtml_form();

$simplehtml->display();
?>

Next we will add a link from our block to this page so that we can see what we have created.

In the get_content() method of our block_simplehtml class replace

$this->content->footer = 'Footer here...';

with

global $COURSE;

// The other code.

$url = new moodle_url('/blocks/simplehtml/view.php', array('blockid' => $this->instance->id, 'courseid' => $COURSE->id));
$this->content->footer = html_writer::link($url, get_string('addpage', 'block_simplehtml'));

Add a Header

If you visit the page now you will see a very basic non-themed form without any of the necessary navigational structure. Note that this happens because the form processing page, in this case view.php, is being accessed directly via the URL and not by being included in another page. This means that the necessary infrastructure must be added directly to the script. Add this by using the print_header function, but a few pieces of data are needed to build appropriate navigation. Make the following adjustments to view.php:


In the global declaration:

global $DB, $OUTPUT, $PAGE;

After require_login($course);

$PAGE->set_url('/blocks/simplehtml/view.php', array('id' => $courseid));
$PAGE->set_pagelayout('standard');
$PAGE->set_heading(get_string('edithtml', 'block_simplehtml'));

One last lot of code to add. The following lines should be added after $simplehtml = new simplehtml_form();

echo $OUTPUT->header();
$simplehtml->display();
echo $OUTPUT->footer();

Navigation breadcrumbs

To really make this look like it's a part of moodle we will add the navigation breadcrumbs to the header of our page.

In view.php, add the following after $courseid = required_param('courseid', PARAM_INT);

$blockid = required_param('blockid', PARAM_INT);

// Next look for optional variables.
$id = optional_param('id', 0, PARAM_INT);

Then add the following after the header code

$settingsnode = $PAGE->settingsnav->add(get_string('simplehtmlsettings', 'block_simplehtml'));
$editurl = new moodle_url('/blocks/simplehtml/view.php', array('id' => $id, 'courseid' => $courseid, 'blockid' => $blockid));
$editnode = $settingsnode->add(get_string('editpage', 'block_simplehtml'), $editurl);
$editnode->make_active();

Don't forget to include definitions for the new strings that you are creating, into block_simplehtml.php

Form State Control

Now to add some basic form state control: The first step is to setup the appropriate actions based on the form state, accounting for three scenarios:

  1. user has cancelled
  2. form submitted and passes validation protocol. Process form data accordingly.
  3. form either doesn't pass validation protocol or it is being displayed for the first time

To implement these three scenarios adjust the code a bit. The existing form display and header code will be used as the first time display code, and an if statement added after instantiating the simplehtml_form object will handle the logic behind the application flow:

if($simplehtml->is_cancelled()) {
    // Cancelled forms redirect to the course main page.
    $courseurl = new moodle_url('/course/view.php', array('id' => $id));
    redirect($courseurl);
} else if ($simplehtml->get_data()) {
    // We need to add code to appropriately act on and store the submitted data
    // but for now we will just redirect back to the course main page.
    $courseurl = new moodle_url('/course/view.php', array('id' => $courseid));
    redirect($courseurl);
} else {
    // form didn't validate or this is the first display
    $site = get_site();
    echo $OUTPUT->header();
    $simplehtml->display();
    echo $OUTPUT->footer();
}

Notice that the existing header and form display code have been moved into the third branch of the conditional. Also, there isn't any code to handle form processing. That code will be added shortly.

Final Steps

Reviewing the progress so far:

  1. simplehtml_form.php is created which defines the class used later to display our form.
  2. view.php is created which:
    • loads base moodle API and any necessary third party modules or non-base API files.
    • loads the necessary course object and globals.
    • performs necessary access control.
    • loads our form and branches execution appropriately based on our form state.

So the form class is defined and the form is displayed in a separate file. Adding elements to the form and finishing the processing of our form will wrap it up!

Add Form Elements

Currently there are no form elements which can submit data. Editing the form class definition in simplehtml_form.php will change that by adding a wide set of form elements to the form for demonstrative purposes only. This will give an example of how to add and process various form elements.

To add the link title text field and the displaytext HTML area to the form, paste the following text in the function definition of the simplehtml_form.php file:

        
// add page title element.
$mform->addElement('text', 'pagetitle', get_string('pagetitle', 'block_simplehtml'));
$mform->setType('pagetitle', PARAM_RAW);
$mform->addRule('pagetitle', null, 'required', null, 'client');
        
// add display text field
$mform->addElement('htmleditor', 'displaytext', get_string('displayedhtml', 'block_simplehtml'));
$mform->setType('displaytext', PARAM_RAW);
$mform->addRule('displaytext', null, 'required', null, 'client');

For full details on addElement() review the moodle documentation on addElement. Also review addRule() in moodle's documentation and the PEAR web site. PEAR is an included form processing library that moodle uses for form processing.

Now add additional form elements to simplehtml_form.php:

File Upload

Add the file field to the form after the existing elements:

// add filename selection.
$mform->addElement('filepicker', 'filename', get_string('file'), null, array('accepted_types' => '*'));

This field allows the user to choose a file in the course file directory. Notice that the name of the element in the form is the same name as the field in the database. This will make it easy to insert and update the database records later.

Fieldset Header

// add picture fields grouping
$mform->addElement('header', 'picfield', get_string('picturefields', 'block_simplehtml'), null, false);

Yes/No Select

// add display picture yes / no option
$mform->addElement('selectyesno', 'displaypicture', get_string('displaypicture', 'block_simplehtml'));
$mform->setDefault('displaypicture', 1);

Radio Select

To control the available options, create a function that will return the list of available options as an array keyed by an integer. This is preferred for several reasons:

  • It keeps the database free from enum field types by providing data key by integers. This is database engine independent.
  • It makes it easy to add additional options at a later date by changing our function
  • It avoids the use of global variables.

Create a file lib.php and place the following code into it which will define the image options via radio select.

 
function block_simplehtml_images() {
    return array(html_writer::tag('img', '', array('alt' => get_string('red', 'block_simplehtml'), 'src' => "pix/picture0.gif")),
                html_writer::tag('img', '', array('alt' => get_string('blue', 'block_simplehtml'), 'src' => "pix/picture1.gif")),
                html_writer::tag('img', '', array('alt' => get_string('green', 'block_simplehtml'), 'src' => "pix/picture2.gif")));
}

Now include the above file in any files that need to use the function, for now this is just simplehtml_form.php. Add the following after require_once("$CFG->libdir/formslib.php"); in simplehtml_form.php

require_once($CFG->dirroot.'/blocks/simplehtml/lib.php');

You now need to add some pictures to the pix directory. In this example I have three gif images each a different colour, but you could use any image (small is better). Create a directory called pix in your simplehtml block directory. Now add the radio select to the form definition (simplethml_form.php)

// add image selector radio buttons
$images = block_simplehtml_images();
$radioarray = array();
for ($i = 0; $i < count($images); $i++) {
    $radioarray[] =& $mform->createElement('radio', 'picture', '', $images[$i], $i);
}
$mform->addGroup($radioarray, 'radioar', get_string('pictureselect', 'block_simplehtml'), array(' '), FALSE);

A group is also added to capture multiple form elements on one line. Another approach would be to just display each radio element on its own line.

Alt Text Input

Finally, to wrap-up the image display selection, allow the user to choose the alternate text that will be displayed with the selected image.

// add description field
$attributes = array('size' => '50', 'maxlength' => '100');
$mform->addElement('text', 'description', get_string('picturedesc', 'block_simplehtml'), $attributes);
$mform->setType('description', PARAM_TEXT);

Note that there is an attributes variable added to the text field to limit its size and length.

Date Time Selector

The setAdvanced() function adds advanced options to a form. To use this function pass in the name of the form element, group of elements, or header. The "Advanced Options" button appears in the upper right corner of the fieldset. In this example, there is a single element, but later you'll see an element within a header. Learn more about setAdvanced. The"Show/Hide Advanced" button won't be displayed until adding action buttons to the form during the next step of this tutorial.

Now add the date field as an optional element:

 // add optional grouping
$mform->addElement('header', 'optional', get_string('optional', 'form'), null, false);


 // add date_time selector in optional area
$mform->addElement('date_time_selector', 'displaydate', get_string('displaydate', 'block_simplehtml'), array('optional' => true));
$mform->setAdvanced('optional');

The above code adds a form header and sets it to hide the date/time selector within the optional (advanced) form controls.

Add State Variables and Finalize the Form

Adding Form Buttons

Most moodle forms have a basic set of buttons. "Submit" and "Cancel" are added by calling the moodleform member function add_action_buttons(). Add the following at the end of simplehtml_form.php

$this->add_action_buttons();

Notice when calling add_action_buttons(), $this is used rather than $mform because add_action_buttons() is defined in the base class moodleform and would be outside scope for $mform.

Add State Variables

Sometimes forms need to keep track of additional data that is not intended to be visible to users. These fields should be placed in hidden elements. For this form blockid and the courseid are needed. Before the call to add_action_buttons() add:

// hidden elements
$mform->addElement('hidden', 'blockid');
$mform->addElement('hidden', 'courseid');

These elements will need to be populated by displaying code because these will be passed in via the URL initially. after $simplehtml = new simplehtml_form(); in view.php add:

$toform['blockid'] = $blockid;
$toform['courseid'] = $courseid;
$simplehtml->set_data($toform);

Process Form Data

After creating the form, appropriate code must be added to process the submitted form data. Accomplish this by adding code to view.php. Typically when processing form data it is helpful to remove some of the final processing steps so that your script essentially terminates execution and does not redirect you to the course page or wherever makes sense. This is tremendously helpful while debugging. The processing code will be added to this block of code in view.php :

} else if ($fromform = $simplehtml->get_data()) {
    // We need to add code to appropriately act on and store the submitted data
    // but for now we will just redirect back to the course main page.
    $courseurl = new moodle_url('/course/view.php', array('id' => $courseid));
    redirect($courseurl);

Notice that the else if statement has been modified to create the variable $fromform.

For now comment out the redirect and add the following above it.

print_object($fromform);

print_object() is a useful moodle function which prints out data from mixed data types showing the keys and data for arrays and objects. Now visit the "Add Page" link for the block and submit some form data. You should see something similar to:

stdClass Object
(
    [pagetitle] => fish
    [displaytext] => <p>fish</p>
    [filename] => 687195712
    [displaypicture] => 1
    [picture] => 1
    [description] => ocean blue
    [displaydate] => 1333609200
    [mform_showadvanced_last] => 1
    [blockid] => 114
    [courseid] => 1
    [submitbutton] => Save changes
)

The values in brackets are the keys and the portion after => is the data for that particular key. Since the form submission is verified as working as expected, save the submitted form data. The most direct way to save is with a call to insert_record(). This function takes the name of the table, 'block_simplehtml' in our case, and the object to be inserted. The object must have keys that map one-to-one with table column names. Choosing form element names that map directly to the database columns saves a bit of code. Save the submitted form data with the following code pasted above the commented out redirect:

// We need to add code to appropriately act on and store the submitted data
if (!$DB->insert_record('block_simplehtml', $fromform)) {
    print_error('inserterror', 'block_simplehtml');
}

This code checks to see if we are updating or inserting into the database. We have not created the database yet, so this code won't work. Continue on to the next section and create the database before testing this code.

Creating a Database

We will be using the XMLDB Editor to design and create the database table that will hold the data from the form that we have just created. We have eight pieces of information to store from the simplehtml form. First create a folder named db under you main block directory. Next login to Moodle and navigate to the XMLDB editor, located in the 'Site administration->Development->XMLDB editor'. The XMLDB editor is a graphical interface to help generate the xml files that Moodle uses to create and maintain database tables. When you get to the XMLDB editor you will see all the blocks, modules and other areas that have db directories. Those that show a link already have tables defined that can be loaded and modified. Find the blocks/simplehtml/db and click on Create.


The db directory has an install.xml file with some basic information about your block and one table called simplehtml. In Moodle you will now see the block/simplehtml/db highlighted in green and the Load and Delete commands will be linked. Click on Load. Now you will see the Edit and Unload text linked. Click on Edit.


The simplehtml table must be modified to include the information entered from the form: click on the Edit link next to the simplehtml table to display the definition that is created by default for the table. Id field will be there and a primary key that links to the id field. Rename the table to block_simplehtml (if necessary). Alter the comments for this table here as well. Any changes to the comments field requires a click on the Change button for the changes to be recorded.


Now add the following fields:

  1. blockid
  2. pagetitle
  3. displaytext
  4. format
  5. filename
  6. picture
  7. description
  8. displaypicture
  9. displaydate

blockid

The blockid is a foreign key that references the block table. This will be used to join our data rows to the block table. The block table houses generic block information for installed block instances. To add the blockid field:

  1. Click the "New Field" link
  2. Change the Name to blockid
  3. Enter a Comment about the field
  4. Set the Type to int
  5. Enter a Length of 10
  6. Set Not Null to not null
  7. Set Sequence to No
  8. Enter 0 for the Default
  9. Click the Change button.

pagetitle

The pagetitle is simply text that will be used for links to this simplehtml page. Using default Moodle Themes, Moodle blocks cannot handle more than 25 characters without wrapping. To add the pagetitle field:

  1. Click the "New Field" link
  2. Change the Name to pagetitle
  3. Enter a Comment about the field
  4. Set the Type to char
  5. Enter a Length of 25
  6. Set Not Null to not null
  7. Click the Change button.

display text

The displaytext field will be displayed as text on the simplehtml page, potentially as HTML. To add the dispaytext field:

  1. Click the "New Field" link
  2. Change the Name to displaytext
  3. Enter a Comment about the field
  4. Set the Type to text
  5. Set Not Null to not null
  6. Click the Change button.

format

The format field will contain the integer value that represents the format the text was entered in. To add the format field:

  1. Click the "New Field" link
  2. Change the Name to format
  3. Enter a Comment about the field
  4. Set the Type to int
  5. Enter a Length of 3
  6. Set Not Null to not null
  7. Set Sequence to No
  8. Enter 0 for the Default
  9. Click the Change button.

filename

The filename field stores the name of a file the instructor posts on the simplehtml page, which students can then download or view. To add the filename field:

  1. Click the "New Field" link
  2. Change the Name to filename
  3. Enter a Comment about the field
  4. Set the Type to char
  5. Enter a Length of 255
  6. Set Not Null to not null
  7. Click the Change button.

picture

The URL for the user's chosen picture is in a predefined static variable that associates a number to a picture. This will allow the addition of more pictures later if necessary, or for changing the current pictures' URLs without updating the database. Because only the number is stored the database field should be created as an int rather than a char. To add the picture field:

  1. Click the "New Field" link
  2. Change the Name to picture
  3. Enter a Comment about the field
  4. Set the Type to int
  5. Enter a Length of 2
  6. Set Not Null to not null
  7. Set Sequence to No
  8. Enter 0 for the Default
  9. Click the Change button.

description

Add the description field that will be displayed on the page. To add the description field:

  1. Click the "New Field" link
  2. Change the Name to description
  3. Enter a Comment about the field
  4. Set the Type to text
  5. Set Not Null to not null
  6. Click the Change button.

displaypicture

The displaypicture field will be the "yes" or "no" question on the form. This is best represented as an 'int'. To add the displaypicture field:

  1. Click the "New Field" link
  2. Change the Name to displaypicture
  3. Enter a Comment about the field
  4. Set the Type to int
  5. Enter a Length of 1
  6. Set Not Null to not null
  7. Set Sequence to No
  8. Enter 0 for the Default
  9. Click the Change button.

displaydate

The final field to add to the table is the displaydate. It is a UNIX timestamp which is an integer value. To add the displaydate field:

  1. Click the "New Field" link
  2. Change the Name to displaydate
  3. Enter a Comment about the field
  4. Set the Type to int
  5. Enter a Length of 10
  6. Set Not Null to not null
  7. Set Sequence to No
  8. Enter 0 for the Default
  9. Click the Change button.

Now that the fields have been added to the table the install.xml needs to be saved. Click the "Back" link and the "Back to Main". Once on the main page click the "Save" link to save the changes to the install.xml. Remember update code wasn't added to install the database table after the block has already been installed. When developing within a localized environment load the database by uninstalling the module and then reinstalling it. In normal circumstances where the block or module has been in production use you would need to do this with proper update code. Now you should be able to test your code. You can view the data was stored in the proper table by viewing the table block_simplehtml via phpadmin.

Refining the User Interface

After successfully submitting data to the database via the form it is now time to begin displaying that data so that users can interact with the data and view what has been submitted. Both steps will be contained within simplehtml/block_simplehtml.php.

Add Links to Each Page of the Block

To retrieve the relevant rows we will call $DB->get_records(), which accepts two parameters::

  1. The table name
  2. An array with the name of the column or field to be queried and the value of the queried field we want to match.

Add the following code:

global $COURSE, $DB; //$COURSE should already be present

...

if (!empty($this->config->text)) {
    $this->content->text = $this->config->text;
}

// This is the new code.
if ($simplehtmlpages = $DB->get_records('block_simplehtml', array('blockid' => $this->instance->id))) {
    $this->content->text .= html_writer::start_tag('ul');
    foreach ($simplehtmlpages as $simplehtmlpage) {
        $pageurl = new moodle_url('/blocks/simplehtml/view.php', array('blockid' => $this->instance->id, 'courseid' => $COURSE->id, 'id' => $simplehtmlpage->id, 'viewpage' => '1'));
        $this->content->text .= html_writer::start_tag('li');
        $this->content->text .= html_writer::link($pageurl, $simplehtmlpage->pagetitle);
        $this->content->text .= html_writer::end_tag('li');
    }
    $this->content->text .= html_writer::end_tag('ul');
}

It is important to remember that the property $this->content->text is ignored by list blocks. Therefore, for this example ensure that the block_simplehtml class extends block_base and not block_list.

Refactor Display Method

To avoid any code duplication and make it easy to reuse this functionality create a function in lib.php to handle the page display. A preloaded simplehtml page is passed in as a single parameter, and an optional parameter will control whether the data is returned or directly printed out. Most Moodle functions that print information can be passed a true value as the last parameter. This is the function's return value, which tells the function to return the HTML and not print or echo it to the user. For development, set the return value to false so that the data is printed out.

function block_simplehtml_print_page($simplehtml, $return = false) {}

Now consider what the function needs to do in order to display all of the necessary information from our page.

Page Title
Print this out as a centered header for the HTML PAGE
Display Text
Print this out in whatever format the user specified, centered in a box on the page
Filename
Display a link to the file in the course file directory so the user has the option to download it. This will be centered in the same box as the display text.
Display Picture
Display the picture with the description on the right of the picture in a box if the user has chosen for the picture to display
Display date
Display the date under the page title in a smaller font

Add Page Title

To display the page title use the $OUTPUT class. Add the following to block_simplehtml_print_page() in lib.php

global $OUTPUT, $COURSE;
$display = $OUTPUT->heading($simplehtml->pagetitle);

After we have displayed the title, let's add a box to put around the rest of the elements that we will display.

 $display .= $OUTPUT->box_start();

This is the opening tag for the box, we will have to enter similar code later, to encapsulate the elements.

Display the Date

The requirements for date display call for displaying the date in a smaller font under the page title. Moodle has a userdate() function that has several advantages over PHP's date() function. It displays the date in the user's preferred format and adjusts the date for any timezone difference.

if($simplehtml->displaydate) {
    $display .= userdate($simplehtml->displaydate);
}

Notice that since the user had an option of choosing a date or not that you must check to ensure that it was set before trying to output it. Take a look at the displayed page: click on one of your page links from the block. There's no output. Add some additional code that handles the value of $return. Add the following at the end of the function definition:

if($return) {
    return $display;
} else {
    echo $display;
}

As mentioned earlier, the requirements for the date field were to be centered under the page title and smaller. This can be controlled with a stylesheet.

First, put a div tag around the date, and give it a class to target with CSS later. Change the date output lines:

$display .= html_writer::start_tag('div', array('class' => 'simplehtml displaydate'));
$display .= userdate($simplehtml->displaydate);
$display .= html_writer::end_tag('div');

There are two options for adding the stylesheet:

  1. Add the CSS to the theme's CSS files in the theme directory
  2. Create a styles.css file in the block and add the CSS there


Choosing the second option, adding a styles.css file, allows more flexibility and avoids needing to create multiple entries if the site is using more than one theme. Create styles.css and add this CSS:

.simplehtml .displaydate {
    font-size: .8em;
    text-align: center;
}

Display Text

Now the display text needs to be added.

$display .= clean_text($simplehtml->displaytext);

//close the box
$display .= $OUTPUT->box_end();

Display the Picture

To selectively display the picture with its description text located underneath it:

if ($simplehtml->displaypicture) {
    $display .= $OUTPUT->box_start();
    $images = block_simplehtml_images();
    $display .= $images[$simplehtml->picture];
    $display .= html_writer::start_tag('p');
    $display .= clean_text($simplehtml->description);
    $display .= html_writer::end_tag('p');
    $display .= $OUTPUT->box_end();
}

Final Alterations

To have this all come together and work we need to make a few alterations to view.php First we will add another optional parameter:

$id = optional_param('id', 0, PARAM_INT);
$viewpage = optional_param('viewpage', false, PARAM_BOOL);

And then we check to see which page to display depending on which link was selected.

...

echo $OUTPUT->header();
if ($viewpage) {
    $simplehtmlpage = $DB->get_record('block_simplehtml', array('id' => $id));
    block_simplehtml_print_page($simplehtmlpage);
} else {
    $simplehtml->display();
}
echo $OUTPUT->footer();

Try the simpleHTML block out and view the different pages that you have created.

Add editing capability

At the moment we have no way to edit the pages that we have created. Our block really does need a way to edit the existing data. The edit feature will use an image to link to the view.php instead of text. This image will only appear when the instructor turns editing on.

Moodle stores pictures and icons in the pix directory under the base moodle directory. You can also use pictures that are custom to a theme. These are stored within the theme's pix directory. For this example, use the icons in the pix directory for moodle. The image should be encapsulated in an HTML link to simplehtml.php. The url should pass the block instance id, block id, and course id to simplehtml.php.

Edit the block_simplehtml.php file as follows:

global $COURSE, $DB, $PAGE; //We are adding $PAGE here

...

// Check to see if we are in editing mode
$canmanage = $PAGE->user_is_editing($this->instance->id);

if ($simplehtmlpages = $DB->get_records('block_simplehtml', array('blockid' => $this->instance->id))) {
    $this->content->text .= html_writer::start_tag('ul');
    foreach ($simplehtmlpages as $simplehtmlpage) {
        if ($canmanage) {
            $pageparam = array('blockid' => $this->instance->id, 
                  'courseid' => $COURSE->id, 
                  'id' => $simplehtmlpage->id);
            $editurl = new moodle_url('/blocks/simplehtml/view.php', $pageparam);
            $editpicurl = new moodle_url('/pix/t/edit.gif');
            $edit = html_writer::link($editurl, html_writer::tag('img', '', array('src' => $editpicurl, 'alt' => get_string('edit'))));
        } else {
            $edit = '';
        }
        $pageurl = new moodle_url('/blocks/simplehtml/view.php', array('blockid' => $this->instance->id, 'courseid' => $COURSE->id, 'id' => $simplehtmlpage->id, 'viewpage' => true));
        $this->content->text .= html_writer::start_tag('li');
        $this->content->text .= html_writer::link($pageurl, $simplehtmlpage->pagetitle);
        $this->content->text .= $edit;
        $this->content->text .= html_writer::end_tag('li');
    }

...

Notice that there's a link to the same file view.php that handled the page adding. Make a few adjustments to view.php so that pages can also be updated.

First, modify the form to have a new hidden field called id to store the id of the record in the database to know which page to update. Add the following to simplehtml_form.php :

$mform->addElement('hidden','id','0');

Second, we alter the way the submit is handled in view.php

...

$toform['blockid'] = $blockid;
$toform['courseid'] = $courseid;
$toform['id'] = $id;

...

// We need to add code to appropriately act on and store the submitted data
if ($fromform->id != 0) {
    if (!$DB->update_record('block_simplehtml', $fromform)) {
        print_error('updateerror', 'block_simplehtml');
    }
} else {
    if (!$DB->insert_record('block_simplehtml', $fromform)) {
        print_error('inserterror', 'block_simplehtml');
    }
}

...

// form didn't validate or this is the first display
$site = get_site();
echo $OUTPUT->header();
if ($id) {
    $simplehtmlpage = $DB->get_record('block_simplehtml', array('id' => $id));
    if($viewpage) {
        block_simplehtml_print_page($simplehtmlpage);
    } else {
        $simplehtml->set_data($simplehtmlpage);
        $simplehtml->display();
    }
} else {
    $simplehtml->display();
}

...

Page Deletion

After being able to add a page and edit a page, what else would someone need to do with our html pages? Delete! Deleting is a simple operation; requiring a few simple steps::

  1. Add a link to a new delete.php file
  2. Create the delete.php file
  3. Print a verification form to the screen in case the user made a mistake
  4. Use delete_record() to delete a record from the simplehtml table given an id and a confirmation.

Add a link to delete a simpleHTML page

Begin by editing block_simplehtml.php and creating a link just after the edit link.

...

    //delete
    $deleteparam = array('id' => $simplehtmlpage->id, 'courseid' => $COURSE->id);
    $deleteurl = new moodle_url('/blocks/simplehtml/delete.php', $deleteparam);
    $deletepicurl = new moodle_url('/pix/t/delete.gif');
    $delete = html_writer::link($deleteurl, html_writer::tag('img', '', array('src' => $deletepicurl, 'alt' => get_string('delete'))));
} else {
    $edit = '';
    $delete = '';
}
$pageurl = new moodle_url('/blocks/simplehtml/view.php', array('blockid' => $this->instance->id, 'courseid' => $COURSE->id, 'id' => $simplehtmlpage->id, 'viewpage' => true));
$this->content->text .= html_writer::start_tag('li');
$this->content->text .= html_writer::link($pageurl, $simplehtmlpage->pagetitle);
$this->content->text .= $edit;
$this->content->text .= $delete;

...

Create delete.php

Refresh the course page and you should now see a black X icon next to each page after the edit icon (when editing is turned on). The purpose of delete.php is to print out a notice to the user with a verification that the user wants to delete the simplehtml page. The notice will either return the user to the course if they say No, or delete the page and return the user to the course if they say Yes. Moodle has a predefined core function in weblib.php that will create the Yes-No form for you and send the user on to the correct locations based on the answer to the question. The function is called notice_yesno(). Before using this, setup the basic file structure for delete.php (it's similar to what has been used for most of the other files like view.php and simplehtml.php).

require_once('../../config.php');
 
$courseid = required_param('courseid', PARAM_INT);
$id = optional_param('id', 0, PARAM_INT);
$confirm = optional_param('confirm', 0, PARAM_INT);
 
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
    print_error('invalidcourse', 'block_simplehtml', $courseid);
}
 
require_login($course);
 
if(! $simplehtmlpage = $DB->get_record('block_simplehtml', array('id' => $id))) {
    print_error('nopage', 'block_simplehtml', '', $id);
}
 
$site = get_site();
$PAGE->set_url('/blocks/simplehtml/view.php', array('id' => $id, 'courseid' => $courseid));
$heading = $site->fullname . ' :: ' . $course->shortname . ' :: ' . $simplehtmlpage->pagetitle;
$PAGE->set_heading($heading);
echo $OUTPUT->header();
echo $OUTPUT->footer();

This common code:

  • Checks the courseid corresponds to a valid course
  • Checks that the user is logged in
  • Checks that the simplehtml page id corresponds to an existing page id
  • Prints out the header and footer for the page

Notice that this is similar to what has been used so far, but there another optional parameter 'confirm' has been added.

This variable will be set when the user clicks the Yes or No button on the form. This means that a test needs to be added to test for the return value; if it is set then the database record containing the simple page id should be deleted. Add the following code after the all to the $PAGE->set_heading($heading); function:

if (!$confirm) {
    $optionsno = new moodle_url('/course/view.php', array('id' => $courseid));
    $optionsyes = new moodle_url('/blocks/simplehtml/delete.php', array('id' => $id, 'courseid' => $courseid, 'confirm' => 1, 'sesskey' => sesskey()));
    echo $OUTPUT->confirm(get_string('deletepage', 'block_simplehtml', $simplehtmlpage->pagetitle), $optionsyes, $optionsno);
} else {
    if (confirm_sesskey()) {
        if (!$DB->delete_records('block_simplehtml', array('id' => $id))) {
            print_error('deleteerror', 'block_simplehtml');
        }
    } else {
        print_error('sessionerror', 'block_simplehtml');
    }
    $url = new moodle_url('/course/view.php', array('id' => $courseid));
    redirect($url);
}

In the if statement above, the two variables optionsno and optionsyes are set. These are used to pass variables from the form to get or post when the user selects "yes" or "no." They are passed to the $OUTPUT->confirm() function as the third and fourth parameters. If the user clicks "no" they are sent to the course page, which means the courseid needs to be added to the form. If the user clicks "yes" the database record containing the simplehtml page id is deleted and the user is forwarded to the course. The page id, courseid, confirm, and the session key need to be passed to the form. The session key is passed to prevent the possibility of a cross-site scripting attach or users submitting valid form data without using Moodle.

Final Clean up

The block is almost finished! The one thing that has not been done is the cleanup of all data associated with the block on deletion. This is accomplished by adding a function named instance_delete() to block_simplehtml.php. In this function call delete records uses the blockid to pass in the $this->instance->id variable. The function looks like this:

public function instance_delete() {
    global $DB;
    $DB->delete_records('block_simplehtml', array('blockid' => $this->instance->id));
}

Defining Roles for our Block

We are going to create two capabilities for this block:

  1. View simplehtml page(s) which will be block/simplehtml:viewpages
  2. Modify/add simplehtml page(s) which will be block/simplehtml:managepages

We need to create an access.php file in the blocks/simplehtml/db directory. In that file add the simplehtml capability code:

defined('MOODLE_INTERNAL') || die();

$capabilities = array(
    
    'block/simplehtml:viewpages' => array(
        
        'captype' => 'read',
        'contextlevel' => CONTEXT_COURSE,
        'legacy' => array(
            'guest' => CAP_PREVENT,
            'student' => CAP_ALLOW,
            'teacher' => CAP_ALLOW,
            'editingteacher' => CAP_ALLOW,
            'coursecreator' => CAP_ALLOW,
            'manager' => CAP_ALLOW
        )
    ),
    
    'block/simplehtml:managepages' => array(
        
        'captype' => 'read',
        'contextlevel' => CONTEXT_COURSE,
        'legacy' => array(
            'guest' => CAP_PREVENT,
            'student' => CAP_PREVENT,
            'teacher' => CAP_PREVENT,
            'editingteacher' => CAP_ALLOW,
            'coursecreator' => CAP_ALLOW,
            'manager' => CAP_ALLOW
        )
    )
);

Now bump the version number up in blocks/simplehtml/version.php. Increment the last digit of $plugin->version.

Next go to the notifications link in the Site Administration block. This should update the simplehtml block. Verify that capabilities have been added by going to Users > Permissions > Define roles and selecting Manager. Search for simplehtml.

What does the simplehtml:viewpages mean? The presence of a string surrounded by double square brackets implies that there is a string referenced in code that has not been defined in an appropriate language file. Add the following to lang/en/block_simplehtml.php:

$string['simplehtml:viewpages'] = 'View Simple HTML Pages';
$string['simplehtml:managepages'] = 'Manage Simple HTML Pages';

Add check to the block for the capability

With the two new capabilities created, it's time to use them and add a link to the form in the block. The link to the creation page is in the footer, so it's critical that the person viewing this link has the capability to manage a simplehtml page. Modify the get_content() function in blocks/simplehtml/block_simplehtml.php to check for the correct capabilities.To check for the capabilities, use the has_capability() function found in lib/access.php. Alter block_simplehtml.php to include checks for these capabilities.

$context = context_course::instance($COURSE->id);

if (has_capability('block/simplehtml:managepages', $context)) {
    $url = new moodle_url('/blocks/simplehtml/view.php', array('blockid' => $this->instance->id, 'courseid' => $COURSE->id));
    $this->content->footer = html_writer::link($url, get_string('addpage', 'block_simplehtml'));
} else {
    $this->content->footer = '';
}
        
// Check to see if we are in editing mode and that we can manage pages.
$canmanage = has_capability('block/simplehtml:managepages', $context) && $PAGE->user_is_editing($this->instance->id);
$canview = has_capability('block/simplehtml:viewpages', $context);

...

if ($canview) {
    $this->content->text .= html_writer::link($pageurl, $simplehtmlpage->pagetitle);
} else {
    $this->content->text .= html_writer::tag('div', $simplehtmlpage->pagetitle);
}

Refresh the Moodle course to which you have added the simplehtml block. As an administrator or teacher you should see the 'addpage' link; as a student you should not see the link. If you login as a guest you should also not that you can no longer view the pages.

Add Role to the simplehtml Form

Currently any logged-in user can use the simplehtml form. In development this is not as big of a concern, but before moving into production always ensure that users have access to only those portions of the application that they should. Add the following line in view.php after require_login($course);.

require_capability('block/simplehtml:managepages', context_course::instance($courseid));

This ensures the user cannot access this page without having the capability 'block/simplehtml:managepages'.

Add Role to Delete

To restrict deletion to those who have the managepages capability, add the following line to delete.php after require_login($course);

require_capability('block/simplehtml:managepages', context_course::instance($courseid));