Skip to content

Commit 0e575f1

Browse files
Raza403mdjnelson
authored andcommitted
Added customisable filename options for certificates (#684)
1 parent 45e7acd commit 0e575f1

File tree

5 files changed

+116
-6
lines changed

5 files changed

+116
-6
lines changed

classes/template.php

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,24 +314,83 @@ public function generate_pdf(bool $preview = false, ?int $userid = null, bool $r
314314
$deliveryoption = $customcert->deliveryoption;
315315
}
316316

317-
// Remove full-stop at the end, if it exists, to avoid "..pdf" being created and being filtered by clean_filename.
318-
$filename = rtrim(format_string($this->name, true, ['context' => $this->get_context()]), '.');
319-
317+
// Set up PDF document properties — no header/footer, auto page break.
320318
$pdf->setPrintHeader(false);
321319
$pdf->setPrintFooter(false);
322-
$pdf->SetTitle($filename);
323320
$pdf->SetAutoPageBreak(true, 0);
324321

322+
// Get filename pattern from global settings.
323+
if (!empty($customcert->usecustomfilename) && !empty($customcert->customfilenamepattern)) {
324+
$filenamepattern = $customcert->customfilenamepattern;
325+
} else {
326+
$filenamepattern = '{DEFAULT}';
327+
}
328+
329+
if (empty($filenamepattern) || $filenamepattern === '{DEFAULT}') {
330+
// Use the custom cert name as the base filename (strip any trailing dot).
331+
$filename = rtrim(format_string($this->name, true, ['context' => $this->get_context()]), '.');
332+
} else {
333+
// Build filename from pattern substitutions.
334+
335+
// Get issue record for date (if issued); fallback to current date if not found.
336+
$issue = $DB->get_record('customcert_issues', [
337+
'userid' => $user->id,
338+
'customcertid' => $customcert->id,
339+
], '*', IGNORE_MISSING);
340+
341+
if ($issue && !empty($issue->timecreated)) {
342+
$issuedate = date('Y-m-d', $issue->timecreated);
343+
} else {
344+
$issuedate = date('Y-m-d');
345+
}
346+
347+
$course = $DB->get_record('course', ['id' => $customcert->course], '*', IGNORE_MISSING);
348+
349+
$values = [
350+
'{FIRST NAME}' => $user->firstname ?? '',
351+
'{LAST NAME}' => $user->lastname ?? '',
352+
'{COURSE SHORT NAME}' => $course ? $course->shortname : '',
353+
'{COURSE FULL NAME}' => $course ? $course->fullname : '',
354+
'{DATE}' => $issuedate,
355+
];
356+
357+
// Handle group if needed.
358+
$groups = groups_get_all_groups($course->id, $user->id);
359+
if (!empty($groups)) {
360+
$groupnames = array_map(function($g) {
361+
return $g->name;
362+
}, $groups);
363+
$values['{GROUP}'] = implode(', ', $groupnames);
364+
} else {
365+
$values['{GROUP}'] = '';
366+
}
367+
368+
// Replace placeholders with actual values.
369+
$filename = strtr($filenamepattern, $values);
370+
371+
// Remove trailing dot to avoid "..pdf" issues.
372+
$filename = rtrim($filename, '.');
373+
}
374+
325375
// This is the logic the TCPDF library uses when processing the name. This makes names
326376
// such as 'الشهادة' become empty, so set a default name in these cases.
327377
$filename = preg_replace('/[\s]+/', '_', $filename);
328378
$filename = preg_replace('/[^a-zA-Z0-9_\.-]/', '', $filename);
329379

380+
// If filename ends up empty (e.g. after removing unsupported characters), use default string.
330381
if (empty($filename)) {
331382
$filename = get_string('certificate', 'customcert');
332383
}
333384

385+
// Remove existing ".pdf" extension if present to avoid duplication.
386+
$filename = preg_replace('/\.pdf$/i', '', $filename);
387+
388+
// Clean the final filename and append ".pdf".
334389
$filename = clean_filename($filename . '.pdf');
390+
391+
// Set the PDF document title (for metadata, not the filename itself).
392+
$pdf->SetTitle($filename);
393+
335394
// Loop through the pages and display their content.
336395
foreach ($pages as $page) {
337396
// Add the page to the PDF.

db/upgrade.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,5 +316,23 @@ function xmldb_customcert_upgrade($oldversion) {
316316
upgrade_plugin_savepoint(true, 2024042210, 'mod', 'customcert');
317317
}
318318

319+
if ($oldversion < 2025062100) {
320+
$table = new xmldb_table('customcert');
321+
322+
// Add 'usecustomfilename' field.
323+
$field = new xmldb_field('usecustomfilename', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'deliveryoption');
324+
if (!$dbman->field_exists($table, $field)) {
325+
$dbman->add_field($table, $field);
326+
}
327+
328+
// Add 'customfilenamepattern' field.
329+
$field = new xmldb_field('customfilenamepattern', XMLDB_TYPE_TEXT, null, null, null, null, null, 'usecustomfilename');
330+
if (!$dbman->field_exists($table, $field)) {
331+
$dbman->add_field($table, $field);
332+
}
333+
334+
// Savepoint reached.
335+
upgrade_mod_savepoint(true, 2025062100, 'customcert');
336+
}
319337
return true;
320338
}

lang/en/customcert.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2323
*/
2424

25+
$string['Upper/lower/digits'] = '6aOdbLEuoC (Upper/lower/digits random string)';
2526
$string['activity'] = 'Activity';
2627
$string['addcertpage'] = 'Add page';
2728
$string['addelement'] = 'Add element';
@@ -63,6 +64,10 @@
6364
$string['customcert:viewallcertificates'] = 'View all certificates';
6465
$string['customcert:viewreport'] = 'View course report';
6566
$string['customcertsettings'] = 'Custom certificate settings';
67+
$string['customfilenamepattern'] = 'Custom file name pattern';
68+
$string['customfilenamepattern_help'] = 'Enter the pattern for naming certificate files. You can use placeholders such as {firstname}, {lastname}, {group}, {coursename}, {date}.';
69+
$string['custompattern'] = 'First name, Last name, Course short name, Issue date';
70+
$string['defaultpattern'] = 'Default (certificate name)';
6671
$string['deletecertpage'] = 'Delete page';
6772
$string['deleteconfirm'] = 'Delete confirmation';
6873
$string['deleteelement'] = 'Delete element';
@@ -71,10 +76,14 @@
7176
$string['deleteissuedcertificates'] = 'Delete issued certificates';
7277
$string['deletepageconfirm'] = 'Are you sure you want to delete this certificate page?';
7378
$string['deletetemplateconfirm'] = 'Are you sure you want to delete this certificate template?';
79+
$string['deliveryoption'] = 'Delivery option';
80+
$string['deliveryoption_help'] = 'Choose how the certificate should be delivered to users.';
7481
$string['deliveryoptiondownload'] = 'Send to the browser and force a file download';
7582
$string['deliveryoptioninline'] = 'Send the file inline to the browser';
7683
$string['deliveryoptions'] = 'Delivery options';
7784
$string['description'] = 'Description';
85+
$string['digits-with-hyphens'] = '0123-4567-8901 (Digits with hyphens)';
86+
$string['download'] = 'Force download';
7887
$string['downloadallissuedcertificates'] = 'Download all issued certificates';
7988
$string['downloadallsitecertificates'] = 'Download all site certificates';
8089
$string['downloadallsitecertificatesdesc'] = 'This will download all the certificates on the site in a zip file.';
@@ -123,6 +132,8 @@
123132
$string['eventtemplatedeleted'] = 'Custom certificate template deleted';
124133
$string['eventtemplateupdated'] = 'Custom certificate template updated';
125134
$string['exampledatawarning'] = 'Some of these values may just be an example to ensure positioning of the elements is possible.';
135+
$string['filenamepattern'] = 'File name pattern (legacy)';
136+
$string['filenamepattern_help'] = 'Choose the pattern for naming certificate files (legacy setting).';
126137
$string['font'] = 'Font';
127138
$string['font_help'] = 'The font used when generating this element.';
128139
$string['fontcolour'] = 'Colour';
@@ -135,6 +146,7 @@
135146
$string['height_help'] = 'This is the height of the certificate PDF in mm. For reference an A4 piece of paper is 297mm high and a letter is 279mm high.';
136147
$string['includeinnotvisiblecourses'] = 'Include certificates in hidden courses';
137148
$string['includeinnotvisiblecourses_desc'] = 'Certificates from hidden courses are not proccesed by default. If you want to include them, enable this setting.';
149+
$string['inline'] = 'Display inline';
138150
$string['invalidcode'] = 'Invalid code supplied.';
139151
$string['invalidcolour'] = 'Invalid colour chosen, please enter a valid HTML colour name, or a six-digit, or three-digit hexadecimal colour.';
140152
$string['invalidelementwidthorheightnotnumber'] = 'Please enter a valid number.';
@@ -235,6 +247,8 @@
235247
$string['useadhoc_desc'] = 'When enabled, emails related to certificates will be handled immediately through an ad-hoc task created for each issue. When disabled, emails will be managed by the regular scheduled task.
236248
237249
Enabling this option may improve the performance of the scheduled task by offloading email processing to ad-hoc tasks.';
250+
$string['usecustomfilename'] = 'Use custom file name pattern';
251+
$string['usecustomfilename_help'] = 'If enabled, you can define a custom file name pattern for certificates using placeholders such as {FIRST NAME}, {LAST NAME}, {GROUP}, {COUSRE SHORT NAME}, {DATE}.';
238252
$string['userlanguage'] = 'Use user preferences';
239253
$string['userlanguage_help'] = 'You can force the language of the certificate to override the user\'s language preferences.';
240254
$string['verified'] = 'Verified';
@@ -249,4 +263,3 @@
249263
$string['verifycertificatedesc'] = 'This link will take you to a new screen where you will be able to verify certificates on the site';
250264
$string['width'] = 'Width';
251265
$string['width_help'] = 'This is the width of the certificate PDF in mm. For reference an A4 piece of paper is 210mm wide and a letter is 216mm wide.';
252-

mod_form.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,26 @@ public function definition() {
6666
$mform->addElement('select', 'deliveryoption', get_string('deliveryoptions', 'customcert'), $deliveryoptions);
6767
$mform->setDefault('deliveryoption', certificate::DELIVERY_OPTION_INLINE);
6868

69+
// Checkbox to enable custom file name pattern.
70+
$mform->addElement('advcheckbox', 'usecustomfilename', get_string('usecustomfilename', 'customcert'));
71+
$mform->addHelpButton('usecustomfilename', 'usecustomfilename', 'customcert');
72+
$mform->setDefault('usecustomfilename', 0);
73+
74+
// Text field for custom file name pattern.
75+
$mform->addElement('text', 'customfilenamepattern', get_string('customfilenamepattern', 'customcert'), ['size' => '50']);
76+
$mform->setType('customfilenamepattern', PARAM_TEXT);
77+
$mform->addHelpButton('customfilenamepattern', 'customfilenamepattern', 'customcert');
78+
$mform->disabledIf('customfilenamepattern', 'usecustomfilename', 'notchecked');
79+
80+
if ($this->current) {
81+
if (property_exists($this->current, 'usecustomfilename')) {
82+
$mform->setDefault('usecustomfilename', $this->current->usecustomfilename);
83+
}
84+
if (property_exists($this->current, 'customfilenamepattern')) {
85+
$mform->setDefault('customfilenamepattern', $this->current->customfilenamepattern);
86+
}
87+
}
88+
6989
if (has_capability('mod/customcert:manageemailstudents', $this->get_context())) {
7090
$mform->addElement('selectyesno', 'emailstudents', get_string('emailstudents', 'customcert'));
7191
$mform->setDefault('emailstudents', get_config('customcert', 'emailstudents'));

version.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
2626

27-
$plugin->version = 2024042212; // The current module version (Date: YYYYMMDDXX).
27+
$plugin->version = 2025062100; // The current module version (Date: YYYYMMDDXX).
2828
$plugin->requires = 2024042200; // Requires this Moodle version (4.4).
2929
$plugin->cron = 0; // Period for cron to check this module (secs).
3030
$plugin->component = 'mod_customcert';

0 commit comments

Comments
 (0)