Entering and Evaluating Magic Data Expressions Inside Blocks

If all you need is to evaluate Magic Data tokens embedded into the text of a block, please see Integrating Magic Data Tokens with other blocks. It is all about what you want to do and is far simpler. In fact, if you have not read it yet, read it now as a primer before continuing here!

This note is about deeper integration of Magic Data within blocks. Situations where a Magic Data expression is entered directly in the block edit interface and is then evaluated to control some aspect of the blocks behaviour. To help you get the idea, here are a few examples

  • In Universal Content Puller, you can edit a magic data expression to determine whether or not the block is shown. You can do something like that with permissions, but this goes further because with Magic Data you can use all sorts of site information to make that decision. When the block is rendered, the Magic Data expression is evaluated and if it returns false, the rendering stops there with no output. If it returns true, rendering of the view is completed.
  • In Front End File Uploader, you can opt to use a Magic Data expression to determine who will have access to the upload popup. As with UCP, the Magic Data expression is evaluated when the block is rendered, and the uploader functionality provided if the expression returns true.
  • Also in Front End File Uploader, you can opt to use a Magic Data expression to decide where a file is uploaded to. This time the Magic Data expression is evaluated within the tool that handles the upload, returning a File ID or a list of File Set IDs. The upload is then placed in that File ID or into the File Set IDs.
  • Integrating with Front End File Uploader is Front End Fileset Tools (currently in the PRB), using Magic Data in a similar way to provide a complete front end solution for managing a fileset.
  • In Sorcerer's Map the entire block interface is built on Magic Data expressions. Magic Data expressions are evaluated when the block is rendered to determine the location for the map, the zoom level, the map title and caption.
  • Similarly in Sorcerer's Gallery, Magic Data expressions are evaluated when the block is rendered to the files to show in the gallery. A range of block templates then enable the files to be shown as thumbnail galleries with lightboxes, sliders, slideshows and more.
  • Uber List uses Magic Data to build a list of anything on your site: users, pages, eCommerce products, customers and more. Each list item then uses a stack as a template where Magic Data is used more conventionally to fill in the details of each item. Many of the lists on this site are built using Uber List.
  • Blocks by AJAX provides ajax loading and reloading of blocks and stacks. Used with a form and a Magic Data template, the ajax loaded block or stack can evaluate magic data to provide ajax interactions responding to user inputs, all with no php or JavaScript programming.

Entering Magic Data Expressions in a Block interface

Providing a data entry field for Magic Data expressions is the easy part. In the database db.xml you should allow an X or X2 field. You never know how complex an expression your users will want to write. In essence, this could be a simple text field or text area. However, you can make it much easier for your users by using a Magic Data Symbol Area. This is like a text area, but with built in symbol tester.

50-_edit_location.pngUsing it is very similar to using any of the core concrete5 extended form controls, like the assets helper. In an edit dialog you start by loading the helper directly from the Magic Data package:

$mdsth = Loader::helper('md_symbol_area', 'jl_magic_data');

Then to create a text area with built in symbol tester, within the block edit form you use the helper to render the text area:

echo $mdsth -> render( 'my_dom_id_name',
    t('Enter Magic Data symbols here and they will be evaluated to provide my own special behaviour for this block')

The first parameter is a string providing an overall wrapper id. Like any html element id, it must be unique within a dialog and within a page.

The second parameter is a string with the name used for the form element. For convenience, this is usually best made the same as the field name in the db.xml. That way, you can let concrete5 look after saving the result and avoid having to provide a save() method in the block controller (unless other parameters require it).

The third parameter is a php variable containing initial data for the text area and will usually be the php variable set by concrete5 when it extracts the field from the db.xml, so the same literal text as the second parameter, but with a $ in front.

You could get away with just those three parameters and let default values take care of everything else. However, you usually would use the fourth parameter to provide a snippet of explanatory text like "Enter Magic Data symbols here and they will be evaluated to provide a File Set ID."

There are a whole bunch of remaining parameters that can further customise the helper. The defaults are good for most block edit interfaces, so to keep things simple I will not be explaining them further here.

That's it! You now have a Magic Data symbol edit area in your block edit dialog. You can have as many such areas in an edit dialog as you like. Because the symbol tester can take up a fair bit of space with its diagnostics, it is usually best to have a fairly wide block dialog and allow a bit of height, 800 x 600 works well, but you can use other dimensions. If there are more than one in a dialog, I usually find it clearest to place them in separate tabs or accordion sections.

Evaluating Magic Data Expressions directly

Having provided your block edit dialog with entry fields for Magic Data expressions, the other part of the process is to evaluate those expressions.

First you need to decide when a set of symbols need to be evaluated. On block save? In the on_page_view event handler? In the controller view() method? In the block view.php or other template? As a callback to the block controller? In an AJAX action handler?

All of these are equally feasible. My preference is to leave it as late in the rendering process as possible while still having the expression evaluated in the right context.

With that decision made, we want to directly execute an entire variable as a Magic Data expression. This is a little different than processing a text area for embedded tokens. You could always wrap an expression to make it look like a token and render it with a symbols helper, but that would be less efficient and would not enable fine control of the context.

To make it easy, we have another standard set of helper code you can include in your package or site root helpers directory. This returns a php string or array and is also more efficient because it doesn’t need to parse text for tokens.

To load and use it:

$mdeh = Loader::helper('magic_data_expression', 'your_package_name');
$result = $mdeh->evaluate($your_expression);

Bear in mind that the result could be null, a single value, or a JSON encoded list of results, so if any of that is relevant to the place you are using the expression within your block, you need to make appropriate checks.

While a token embedded in text, if incorrect, will just result in faulty text displayed, an expression used to control the behaviour of a block could result in a more serious issue. So where possible you should also add sanity checks to the value(s) returned by evaluating an expression to make sure it is safe to use further, then provide alternate behaviour or a sensible default.

Warning: require_once(/homepages/42/d160576717/htdocs/c5magic/cms2/packages/oembed/helpers/oembed.php): failed to open stream: No such file or directory in /homepages/42/d160576717/htdocs/c5magic/cms2/concrete/core/libraries/loader.php on line 344

Fatal error: require_once(): Failed opening required '/homepages/42/d160576717/htdocs/c5magic/cms2/packages/oembed/helpers/oembed.php' (include_path='/homepages/42/d160576717/htdocs/c5magic/cms2/libraries/3rdparty:/homepages/42/d160576717/htdocs/c5magic/cms2/concrete/libraries/3rdparty:.:/usr/lib/php7.4') in /homepages/42/d160576717/htdocs/c5magic/cms2/concrete/core/libraries/loader.php on line 344