Jump to content
bernhard

RockPdf - mPDF helper module

Recommended Posts

On 10/20/2018 at 1:23 PM, charger said:

However, the problem remains: the PDFs do get saved correctly, but when trying to download them (either via wireSendFile() or RockPDF’s download()), they are blank or corrupted.

I was able to solve the problem meanwhile. It was related to my template file structure. I’m using the delayed output strategy together with some nested wireRenderFile() calls which lead to the problem.

  • Thanks 1

Share this post


Link to post
Share on other sites
1 hour ago, charger said:

The following line in RockPdf.module.php returns a wrong URL if the PW installation lives in a subdirectory (subdirectory is applied twice):


'httpUrl' => rtrim($this->pages->get(1)->httpUrl, '/') . $url,

Thx for reporting that. Could you please provide a working solution so that I don't need to setup a completely new environment using a subdir? Thx

Share this post


Link to post
Share on other sites

I can do that, but you don’t have to set up a new environment. You just grab the PW files and put them in a newly created folder in your webserver’s root.

Share this post


Link to post
Share on other sites
On 10/13/2018 at 11:20 AM, ceberlin said:

I have problems printing images embedded into a textarea if the config.php has this setting: $config->pagefileSecure=true

 ERROR: Could not find image file (.............. /site/assets/files/2922/unterschrift.jpg)

The file actually is stored under this path: ............... /site/assets/files/-2922/unterschrift.jpg

It seems that you have 

$config->pagefileSecure = true;
$config->pagefileSecurePathPrefix = '-';

in your config, is that correct? I had the same and to fix it you have to use the disk-filepath instead of an URL because the URL is protected via .htaccess.

So I used 

$page->getUnformatted($fieldName)->first()->filename

instead.

Sorry, I did not read your comment correctly. If you use images in a textarea I think you could replace the relative image url with a textformatter.

  • Thanks 2

Share this post


Link to post
Share on other sites
7 hours ago, jmartsch said:

Sorry, I did not read your comment correctly. If you use images in a textarea I think you could replace the relative image url with a textformatter.

Thank you... sounds like a cool idea. The textformatter would not be the way to go for me as I - in general - like PW's pagefileSecure feature.

Right now I am thinking of a workaround (not tested yet). Since the pagefileSecure blocking is only active on (1. pages that are hidden from "guest" users by rights restrictions (or 2. pages are unpublished), I will try to publish some innocent blank page that remains visible to users and load the needed images there into some file field in the backend. Then I would reference those (not blocked) images in the textarea of the PDF source page -  and the rights problem is maybe bypassed.

  • Like 1

Share this post


Link to post
Share on other sites

@bernhard Servus Bernhard,

I was playing around with RockPDF today... I was wondering if you maybe disabled some mPDF functions (intentionally or not)... I tried e.g. setting header styles or use hyphenation, but those don't seem to work.

// either of these returns 
// Exception: Call to undefined method Mpdf\Mpdf::defaultheaderfontsize() on line: 50 in /home/mysite/www/dev.mysite/site/modules/RockPdf/RockPdf.module.php
$pdf->defaultheaderfontsize=9;
$pdf->defaultheaderfontstyle='I';

// same here: Exception: Call to undefined method Mpdf\Mpdf::SHYlang()
$pdf->SHYlang = 'de';

These functions are straight from the official docs...

oh, and btw: How do I adjust the default download path and filename? (using something else than "output.pdf")

d'oh: $pdf->save('foo.pdf');

Edited by dragan
  • Like 1

Share this post


Link to post
Share on other sites
2 hours ago, bernhard said:

Can you try to set those settings via $pdf->settings([ yoursettingsarray ]) ?

Thanks. That works!

I was playing around a bit more with it, and during that I managed to completely trash Tracy (it was gone all of a sudden), had massive problems with PW's file compiler and Tracy Cache, plus PHP memory limits and whatnot... Most probably not related to mPDF or RockPDF at all, I guess I was using wireRenderFile() wrong...

Here's a little example (generates a 24-pages PDF with limited rights, meta-data, and custom font in approx. 3 seconds while in debug mode)

<?
@ini_set('memory_limit', '8192M'); // just to be on the safe side
@set_time_limit(600); // ditto
$pdf = $modules->get('RockPdf');
$pdf->settings([
    'mode' => 'utf-8', 
    'defaultheaderfontsize' => 9,
    'defaultheaderfontstyle' => 'I',
    'defaultheaderline' => 0,
    'SHYlang' => 'de', // doesn't work
    'hyphens' => 'auto', // doesn't work - I have this also in my CSS
    'margin-top' => 20, // doesn't seem to work either, for some reason
    'fontdata' => [
    "inter" => [
        'R' => "Inter-Regular.ttf",
        'B' => "Inter-Black.ttf",
        'I' => "Inter-Italic.ttf",
        'BI' => "Inter-BlackItalic.ttf",
    ]],
    'default_font' => 'inter'
]);
$pdf->set('SetHeader', 'Offerte Steuerrechner Kanton Zürich 2019, Test AG, ' . date('H:i:s'));
$pdf->set('SetFooter', '{PAGENO}');
$pdf->set('SetTitle', 'Offerte Steuerrechner Kanton Zürich 2019');
$pdf->set('SetAuthor', 'Me Myself and I');
$pdf->set('SetCreator', 'Test AG');
$pdf->set('SetSubject', 'Offerte Steuerrechner');
$pdf->set('SetKeywords', 'Steuerrechner, Offerte, Angebot, Test AG, Frontend-Entwicklung');
$pdf->set('SetProtection', array('copy', 'print', 'print-highres'));
$myOffer = 11568; // each offer has a parent page with meta-data, and "chapters" as children. We pass this to the template on the next line
$str = wireRenderFile("/home/mysitecom/www/dev.test/site/templates/offer-index-dev.php", array("offer_index_page_id" => $myOffer));
$fn = $pages->get($myOffer)->name; // will be used to generate filename.pdf
$pdf->write($str);
d($pdf->save("/home/mysitecom/www/dev.test/site/assets/files/$myOffer/$fn.pdf")); // generate pdf in PW default file assets folder


// in offer-index-dev.php, I have this at the top
if(!isset($offer_index_page_id)) {
    return $this->halt();
    exit();
}

if(isset($offer_index_page_id)) {
    $offer_index = $pages->get($offer_index_page_id);
}

// I then use $offer_index->title etc. instead of $page->title further below

Not exactly rocket science, but maybe somebody else can use bits of it as first baby-steps 🙂

  • Like 2

Share this post


Link to post
Share on other sites

I was wondering why PW didn't automatically recognize that a new file has been uploaded to the assets folder (it's just the way PW works; as long as there is no entry in the DB, PW doesn't care what else is in that folder)... after a quick search I found this thread

I added/replaced now the last couple of lines to:

$path = "/home/mysite/www/dev.test/site/assets/files/$myOffer/$fn.pdf";
d($pdf->save($path));
$myOfferPage->of(false);
$myOfferPage->files->add($path);
$myOfferPage->save('files');

That way, site editors "automatically" see the generated PDF in the backend, and don't have to re-generate a new one each time.

  • Like 1

Share this post


Link to post
Share on other sites

@bernhard

many thanks for this great module. I am currently testing how it works and I will be able to use it in the future.

Unfortunately there is one important question for me at the moment:
How do you integrate it into your site? 🤔
I would like to put the whole code into an own file (the pdf generation doesn't have to be done every time the page is loaded) and then trigger the pdf output via a link/button on my content page.

A tip in the readme how this could look like in a live version (not only in tracy) would be great. Sorry to be stuck on this point.

Share this post


Link to post
Share on other sites

Hi @Ralf, what exactly is the problem? The example in the readme shows how you generate the pdf. You'll get an object with properties url, path and httpUrl. Then you can use the file for whatever you want and however you want...

Share this post


Link to post
Share on other sites

@bernhard

many thanks for your PM help.

For everyone else who might have the same problem as me, here are my implementation steps (no guarantee - I'm not a programmer)

1. activate URL segments
  (a good introduction can be found here: https://processwire.com/docs/front-end/how-to-use-url-segments/)
2. create my page WITHOUT URL segment (this shows the content + a button)
3. create a new page for the URL segment (e.g. /pdf) - this creates the PDF and displays it e.g. with show().
4. it works 😎
 

My Code from No 2 (content + button) - mytemplate.php

<?php
if(strlen($input->urlSegment2)) throw new Wire404Exception();

switch($input->urlSegment1) {
	case '':
	  // Segment 1 is empty so display main content
		<!-- my main content -->
	  // My button to the PDF-creation-code
		echo "<a href='". $page->url ."pdf/' target='_new'>generate PDF</a>";
    break;

    case 'pdf':
      // Display the PDF
      include 'mytemplate-pdf.php';
      break;

    default:
      // Anything else? Throw a 404
      throw new Wire404Exception();
}
?>

 

My code for example from No 3 (PDF creation) - mytemplate-pdf.php

<?php
$pdf = $modules->get('RockPdf');
$mpdf = $pdf->mpdf;

$pdf->set('SetHeader', 'This is my header text');

// Two different ways to generate an output
$mpdf->WriteHTML('Hello World ' . date('H:i:s'));
$pdf->write('<!-- my custom comment --> Foo Bar Foo Bar ...');

// Output
$pdf->show(); // to directly show your file in the browser
?>

 

  • Like 1

Share this post


Link to post
Share on other sites

Could anyone shed any light on why the example on the module page by @bernhard is outputting as in the attached file. It's like the Hello world and date html is being converted to another charachter set?

Screenshot 2019-12-06 at 21.08.35.jpg

Share this post


Link to post
Share on other sites

@bernhard

It's so bizarre. I get the following through Tracy Debugger console.

Screenshot 2019-12-09 at 11.20.31.jpg

Share this post


Link to post
Share on other sites

@bernhard I tried setting the header type in the console before the code however this didn't work.

However for my template file which outputs the PDF I tried disabling auto prepend and append of my _init.php and _main.php file and this resolved the matter.

So it would appear that somewhere in the setup the content type is being set even after I've set it in the template file or Tracy Debugger.

For reference - https://mpdf.github.io/troubleshooting/strange-character-output-in-browser.html

Share this post


Link to post
Share on other sites

Great you found the reason. Maybe you can just do a die() or $this->halt() after $pdf->show() ?

Share this post


Link to post
Share on other sites

Just updated all the dependencies of this module to the newest versions:

Package operations: 0 installs, 4 updates, 0 removals
  - Updating myclabs/deep-copy (1.7.0 => 1.9.5): Downloading (100%)
  - Updating paragonie/random_compat (v2.0.12 => v9.99.99): Downloading (100%)
  - Updating psr/log (1.0.2 => 1.1.2): Downloading (100%)
  - Updating mpdf/mpdf (v7.1.0 => v7.1.9): Downloading (100%)

v1.0.2

  • Like 2

Share this post


Link to post
Share on other sites

BTW @alexmercenary the Tracy Console can of course not handle the output of a $pdf->show() call since that sends the generated PDF directly to the browser! Just replace it by $pdf->save() and you get a correct result:

ZRayRQC.png

  • Like 1

Share this post


Link to post
Share on other sites

Just realized that mPDF version maximum was set to 7.x - RockPdf 2.0.0 uses mPDF library v8.0.5 and might introduce some breaking changes - so be careful with the update or just use RockPdf <= 1.0.2

Updating dependencies (including require-dev)
Package operations: 0 installs, 2 updates, 0 removals
  - Updating setasign/fpdi (1.6.2 => v2.3.0): Downloading (100%)
  - Updating mpdf/mpdf (v7.1.9 => v8.0.5): Downloading (100%)

v2.0.0

  • Like 3

Share this post


Link to post
Share on other sites

Another update - RockPdf now supports FontAwesome 5 in mPDF library 🥳😎

This works using webfonts (after I've unsuccessfully tried with SVG) and it supports resizing and coloring icons via CSS or LESS (wich didn't work when using SVG). I've updated the readme:

Using FontAwesome 5 with mPDF

  • Download a copy of fontawesome (https://fontawesome.com/download, eg Free for Web)
  • Copy the TTF file into your /site/assets/RockPdf/fonts/ folder
  • Add your font to your settings and start using icons in your PDFs
// tracy console
$pdf = $modules->get('RockPdf');
$pdf->settings([
  'fontdata' => (new \Mpdf\Config\FontVariables())->getDefaults()['fontdata'] + [
    "far" => [
      'R' => "fa-regular-400.ttf",
      'I' => "fa-regular-400.ttf",
    ],
  ],
]);
$icon = "<i style='font-family: far;'>&#xf118;</i> ";
$pdf->write($icon.'Hello World ' . date('H:i:s'));
d($pdf->save());

img

You'll notice that we used the unicode representation of the icon. You can find all the codes on the cheatsheet (https://fontawesome.com/cheatsheet) or on the details page of the icon: https://fontawesome.com/icons/smile?style=regular

Be careful to use the correct style (regular, solid, etc) and unicode! Special thx to jamesfairhurst

Using metadata to get the unicode

Too complicated? RockPdf comes with a helper so that you do not need to take care of all this and just use the regular fontawesome classes that you might already be familiar with! To make that work, just copy the icons.json file that is shipped with fontawesome in the metadata folder into the RockPdf assets folder /site/assets/RockPdf/fonts.

// tracy console
$pdf = $modules->get('RockPdf');
$pdf->settings([
  'fontdata' => (new \Mpdf\Config\FontVariables())->getDefaults()['fontdata'] + [
    "far" => [
      'R' => "fa-regular-400.ttf",
      'I' => "fa-regular-400.ttf",
    ],
  ],
]);
$pdf->write("<style>.far { font-family: far; color: blue; }</style>");
$icon = $pdf->icon('far fa-smile');
$pdf->write($icon.'Hello World ' . date('H:i:s'));
d($pdf->html()); // print content to console
$pdf->save(); // save file to file system

img img

Using this technique you can easily style your icons using CSS or even LESS (when using RockLESS).

Another example

Unfortunately duotone icons do not work (if you know how to make them work please drop me a line!). Also styling the icons is sometimes a bit tricky - some CSS selectors work while others don't. Using classes directly on the icon worked best for me:

$icons = $pdf->icon('fas fa-guitar red-2x')
  .$pdf->icon('far fa-guitar red-2x')
  .$pdf->icon('fal fa-guitar red-2x')
  .$pdf->icon('fad fa-guitar red-2x');
.fab { font-family: fab; }
.fad { font-family: fad; }
.fal { font-family: fal; }
.far { font-family: far; }
.fas { font-family: fas; }
.red-2x { font-size: 10mm; color: red; }

2fzYFjo.png

v2.0.1

  • Like 2

Share this post


Link to post
Share on other sites

Sorry, didn't fully read your post (re: SVG) - pls ignore this post.

  • Haha 1

Share this post


Link to post
Share on other sites

Yeah... using inline SVGs works just fine... until you want to style fills or strokes via CSS.

I have updated rockPDF just now, and noticed that there's something buggy with using custom fonts.

Quote

Exception: Cannot find TTF TrueType font file "Inter-Regular.ttf" in configured font directories. on line: 33 in /home/foo/www/dev.foo/site/modules/RockPdf/vendor/mpdf/mpdf/src/Fonts/FontFileFinder.php

I have the fonts both in site/templates/fonts/ as well as in site/assets/RockPDF/fonts/. I have now also placed them in site/modules/RockPdf/vendor/mpdf/mpdf/ttfonts, cleared modules cache, but the error persists.

I've looked into the module code, and presumably somewhere here the paths are defined:

  public function init($options = []) {
    // make sure the assets folder exists
    $this->wire->files->mkdir($this->wire->config->paths->assets . $this->className . '/fonts', true);

    $this->settings($options);
  }

  public function settings($options = []) {
    // merge defaults
    $defaults = [
      'tempDir' => $this->wire->files->tempDir('RockPdf'),
      'fontDir' => [
        __DIR__ . '/vendor/mpdf/mpdf/ttfonts',
        $this->wire->config->paths->assets . $this->className . '/fonts',
      ],
    ];
    $options = array_merge($defaults, $options);

Any clues how to fix this?

Share this post


Link to post
Share on other sites

Another issue: If I use wireRenderFile(), I get this fatal error:

Quote

Exception: Invalid output file location or specified file does not exist. on line: 518 in /home/foo/www/dev.foobar/wire/modules/PageRender.module

This used to work just fine with the previous version (v.7x), and the assets/file/ folder definitely exists.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By robert
      I often had the need for an overview of all used fields and their contents for a specific page/template while developing new websites without switching to the backend, so I made a small module which lists all the needed information in a readable manner (at least for me):
      Debug Page Fields
      https://github.com/robertweiss/ProcessDebugPageFields
      It adds two new properties to all pages:
      $page->debugFieldValues – returns an object with all (sub-)fields, their labels, fieldtypes and values $page->debugFieldTypes – returns an object with all fieldtypes and their corresponding fields // List all values of a pages $page->debugFieldValues // List a specific field $page->debugFieldValues->fieldname // List all used fieldtypes of a page $page->debugFieldTypes I recommend using it in combination with Tracy Debugger, Ray, Xdebug etc. as it returns an object and is only meant for developing/debugging uses. 
      For now, the fieldtype support includes mostly fieldtypes I use in my projects, but can easily be extended by adding a new FieldtypeFIELDNAME method to the module. I use it with five different client installations (all PW 3.0.*), but of course there might be some (or more) field configurations which are not covered correctly yet.
      Supported fieldtypes
      Button Checkbox Color Combo Datetime Email FieldsetPage * File FontIconPicker Functional Image ImageReference MapMarker Multiplier Mystique Options Page PageIDs PageTitle Radio Repeater * RepeaterMatrix * RockAwesome SeoMaestro Table Text Textarea Textareas Toggle URL * The fields with complete subfield-support also list their corresponding subfields.
      Installation
      Download the zip file at Github or clone the repo into your site/modules directory. If you downloaded the zip file, extract it in your sites/modules directory. In your admin, go to Modules > Refresh, then Modules > New, then click on the Install button for this module. As this is my first ›public‹ module, I hope I did not miss any important things to mention here.
    • By horst
      Wire Mail SMTP

      An extension to the (new) WireMail base class that uses SMTP-transport

      This module integrates EmailMessage, SMTP and SASL php-libraries from Manuel Lemos into ProcessWire. I use this continously evolved libraries for about 10 years now and there was never a reason or occasion not to do so. I use it nearly every day in my office for automated composing and sending personalized messages with attachments, requests for Disposition Notifications, etc. Also I have used it for sending personalized Bulkmails many times.

      The WireMailSmtp module extends the new email-related WireMail base class introduced in ProcessWire 2.4.1 (while this writing, the dev-branch only).
       
      Here are Ryans announcement.



      Current Version 0.6.0
      Changelog: https://github.com/horst-n/WireMailSmtp/blob/master/CHANGELOG.md
      get it from the Modules Directory Install and Configure

      Download the module into your site/modules/ directory and install it.

      In the config page you fill in settings for the SMTP server and optionaly the (default) sender, like email address, name and signature.
      You can test the smtp settings directly there. If it says "SUCCESS! SMTP settings appear to work correctly." you are ready to start using it in templates, modules or bootstrap scripts.


      Usage Examples
      The simplest way to use it:
      $numSent = wireMail($to, $from, $subject, $textBody); $numSent = wireMail($to, '', $subject, $textBody); // or with a default sender emailaddress on config page This will send a plain text message to each recipient.
       
      You may also use the object oriented style:
      $mail = wireMail(); // calling an empty wireMail() returns a wireMail object $mail->to($toEmail, $toName); $mail->from = $yourEmailaddress; // if you don't have set a default sender in config // or if you want to override that $mail->subject($subject); $mail->body($textBody); $numSent = $mail->send(); Or chained, like everywhere in ProcessWire:
      $mail = wireMail(); $numSent = $mail->to($toEmail)->subject($subject)->body($textBody)->send(); Additionaly to the basics there are more options available with WireMailSmtp. The main difference compared to the WireMail BaseClass is the sendSingle option. With it you can set only one To-Recipient but additional CC-Recipients.
      $mail = wireMail(); $mail->sendSingle(true)->to($toEmail, $toName)->cc(array('person1@example.com', 'person2@example.com', 'person3@example.com')); $numSent = $mail->subject($subject)->body($textBody)->send(); The same as function call with options array:
      $options = array( 'sendSingle' => true, 'cc' => array('person1@example.com', 'person2@example.com', 'person3@example.com') ); $numSent = wireMail($to, '', $subject, $textBody, $options); There are methods to your disposal to check if you have the right WireMail-Class and if the SMTP-settings are working:
      $mail = wireMail(); if($mail->className != 'WireMailSmtp') { // Uups, wrong WireMail-Class: do something to inform the user and quit echo "<p>Couldn't get the right WireMail-Module (WireMailSmtp). found: {$mail->className}</p>"; return; } if(!$mail->testConnection()) { // Connection not working: echo "<p>Couldn't connect to the SMTP server. Please check the {$mail->className} modules config settings!</p>"; return; }  
      A MORE ADVANCED DEBUG METHOD!
      You can add some debug code into a template file and call a page with it:
      $to = array('me@example.com'); $subject = 'Wiremail-SMTP Test ' . date('H:i:s') . ' äöü ÄÖÜ ß'; $mail = wireMail(); if($mail->className != 'WireMailSmtp') { echo "<p>Couldn't get the right WireMail-Module (WireMailSmtp). found: {$mail->className}</p>"; } else { $mail->from = '--INSERT YOUR SENDER ADDRESS HERE --'; // <--- !!!! $mail->to($to); $mail->subject($subject); $mail->sendSingle(true); $mail->body("Titel\n\ntext text TEXT text text\n"); $mail->bodyHTML("<h1>Titel</h1><p>text text <strong>TEXT</strong> text text</p>"); $dump = $mail->debugSend(1); } So, in short, instead of using $mail->send(), use $mail->debugSend(1) to get output on a frontend testpage.
      The output is PRE formatted and contains the areas: SETTINGS, RESULT, ERRORS and a complete debuglog of the server connection, like this one:
       
      Following are a ...


      List of all options and features


      testConnection () - returns true on success, false on failures


      sendSingle ( true | false ) - default is false

      sendBulk ( true | false ) - default is false, Set this to true if you have lots of recipients (50+)


      to ($recipients) - one emailaddress or array with multiple emailaddresses

      cc ($recipients) - only available with mode sendSingle, one emailaddress or array with multiple emailaddresses

      bcc ($recipients) - one emailaddress or array with multiple emailaddresses

       
      from = 'person@example.com' - emailaddress, can be set in module config (called Sender Emailaddress) but it can be overwritten here

      fromName = 'Name Surname' - optional, can be set in module config (called Sender Name) but it can be overwritten here


      priority (3) - 1 = Highest | 2 = High | 3 = Normal | 4 = Low | 5 = Lowest

      dispositionNotification () or notification () - request a Disposition Notification


      subject ($subject) - subject of the message

      body ($textBody) - use this one alone to create and send plainText emailmessages

      bodyHTML ($htmlBody) - use this to create a Multipart Alternative Emailmessage (containing a HTML-Part and a Plaintext-Part as fallback)

      addSignature ( true | false ) - the default-behave is selectable in config screen, this can be overridden here
      (only available if a signature is defined in the config screen)

      attachment ($filename, $alternativeBasename = "") - add attachment file, optionally alternative basename


      send () - send the message(s) and return number of successful sent messages


      debugSend(1) - returns and / or outputs a (pre formatted) dump that contains the areas: SETTINGS, RESULT, ERRORS and a complete debuglog of the server connection. (See above the example code under ADVANCED DEBUG METHOD for further instructions!)


      getResult () - returns a dump (array) with all recipients (to, cc, bcc) and settings you have selected with the message, the message subject and body, and lists of successfull addresses and failed addresses,


      logActivity ($logmessage) - you may log success if you want

      logError ($logmessage) - you may log warnings, too. - Errors are logged automaticaly
       
       
      useSentLog (true | false) - intended for usage with e.g. third party newsletter modules - tells the send() method to make usage of the sentLog-methods - the following three sentLog methods are hookable, e.g. if you don't want log into files you may provide your own storage, or add additional functionality here

      sentLogReset ()  - starts a new LogSession - Best usage would be interactively once when setting up a new Newsletter

      sentLogGet ()  - is called automaticly within the send() method - returns an array containing all previously used emailaddresses

      sentLogAdd ($emailaddress)  - is called automaticly within the send() method
      Changelog: https://github.com/horst-n/WireMailSmtp/blob/master/CHANGELOG.md
       
       
    • By Cybermano
      Food Allergens Module
      A simple List of Food Allergens
      My needs were to provide a simple list of food allergens for our clients with restaurant related activity.
      The idea was to simply output the list (to speed up the data entry) without leaving the food menu editing, eg. opening another page in new tab or window.
      This isn't a perfect solution, but it works fine for my needs and I decided to share the base idea.
      This could also be easily used to show little notes or short "vademecum", not only for the list of food allergens.
      ---
      Main features
      The basis
      All moves from a short editing of the module in this tutorial: How to create custom admin pages by @bernhard
      First of all it creates an empty admin page, with a dedicated permission to let safe-user to see it (this permission has to be created as a new ones, manually or by the module).
      Once the page is created, I have hooked its behaviour into the ready.php, to show the content (basically a list).
      A step further
      With the tips of  @bernhard, @Soma (and many others), see here , the magic happens. 
      The new page will be shown as a panel, so editors will not abandon their data entry to have a quick view to the list.
      A little further
      Why scroll to the top of the page to click a link?
      The next step was to create a sticky button only in the food menu pages.
      Again with a @bernhard tip I moved into the customization of this simple module and the related hook.
      ---
      How to use this module
      After installed, it creates the page /admin/page/allergens/ and the module is to be setted up. The first field is a CKEditor with multi-language. This is the place where to write the informations that will be shown into the page. The next field is a simply text-area where to place a bit of JS that will be appended to the markup of the text (omit the 'script' tags). I also putted a checkbox with a silly statement: this to think at least twice on the safety of the written JS. Now comes the first way to display the link to the page
      Field Note with Link. Enable and save it. The module will display a new row with 4 selects (1 standard and 3 ASM):
      View mode (to show the page as Panel or as Modal PopUp); Templates to select: select one or more and save before proceed, so the  asm-select of the pages will be populated showing all the pages of the selected templates. Pages to select: also here select at least one and save before proceed to populate the asm-select for fields only with the ones that belong to the selected pages. Select the fields where to place the note and save again. That's all: now you will find into the notes of the selected fields the link "See the List of Allergens".
      At the same way, the option for the sticky button, but with a plus
      The field select is obviously unnecessary, but you could play with the last row: the inline styles to fix your sticky button where you like. Here you could set the sticky position of the <div> and the absolute ones of the <a>.

      Video Explanation
      In these screencasts you could see a custom JS that show a "copy" button near a "hanna-code" call.
      This because I've set a specific one for each allergen to show up a tooltip in the front end.

      Registrazione #33.mp4  

      Registrazione #34.mp4 ---
      Last but not the least
      Actually it works fine for my needs, even if it's much improvable: I'm working on the permissions creation, the uninstall section, a separate configs and defaults and how to include the hook into the module leaving free the ready.php. According to a simpler uninstall. Also I would make the link text as a dynamic text field, so it will be more flexible.
      I always learn a lot here, so I would share my code for whom it could be interested.
      I removed the hanna code references, but I provide you the html list of the allergens, English and Italian too, so you can paste them into the "source" of the CKEditor field to have a ready to use module.
      Obviously you are free to modify the code as per your needs.
      Please, keep in mind that I'm not a pro coder and I beg your pardon for my verbosity (speaking and coding). 😉
      I hope be helpful or for inspiration.
      Bye
      ready.phpList-ITA.htmlList-ENG.htmlAllergens.module
      README.md
    • By Robin S
      This module is sort of an upgrade to my earlier ImageToMarkdown module, and might be useful to anyone working with Markdown in ProcessWire.
      Copy Markdown
      Adds icons to images and files that allow you to copy a Markdown string to the clipboard. When you click the icon a message at the top left of the screen notifies you that the copying has occurred.
      Screencast

      Note: in the screencast an EasyMDE inputfield is used to preview the Markdown. It's not required to use EasyMDE - an ordinary textarea field could be used.
      Usage: Images
      When you hover on an item in an Images field an asterisk icon appears on the thumbnail. Click the icon to copy an image Markdown string to clipboard. If the "Description" field is populated it is used as the alt text.
      You can also open the "Variations" modal for an image and click the asterisk icon to copy an image Markdown string for an individual variation.
      Usage: Files
      When you hover on an item in a Files field an asterisk icon appears next to the filename. Click the icon to copy a link Markdown string to the clipboard. If the "Description" field is populated it is used as the link text, otherwise the filename is used.
       
      https://github.com/Toutouwai/CopyMarkdown
      https://processwire.com/modules/copy-markdown/
    • By BitPoet
      I've realized that I've been jumping back and forth between the PW API docs and the source code for site modules far too much. The idea to hold all necessary documentation locally in one place has occurred to me before, but getting PHPDocumentor et al set up and running reliably (and producing readable output) as always been too much of a hassle. Today I was asked how I find the right hooks and their arguments, and that inspired me to finally get my backside down on the chair and whip something up, namely the
      Module Api Doc Viewer
      ProcessModuleApiDoc
      It lets you browse the inline documentation and public (optionally also protected) class/method/property information for all modules, core classes and template files in the ProcessWire instance. The documentation is generated on the fly, so you don't have to remember to update your docs whenever you update a module.
      The module is quite fresh, so expect some bugs there. Behind the scenes it uses PHP-Parser together with a custom class that extracts the information I needed, and the core TextformatterMarkdownExtra module for rendering the description part in the phpdoc style comments.
      This is not a replacement / competitor to the API Viewer included in the commercial ProDevTools package. There is quite some information included in the inline documentation that my module can't (and won't) parse, but which makes up parts of the official ProcessWire API docs.
      This, instead, is a kind of Swiss army knife to view PHPDoc style information and get a quick class or function reference.
      If you feel daring and want to give it a spin, or if you just want to read a bit more, visit the module's GitHub repository.
      This is the overview page under "Setup" -> "Module API Docs":

      And this is what the documentation for an individual class looks like:

      The core module documentation can of course be found online, but it didn't make sense not to include them.
      Let me know what you think!

×
×
  • Create New...