Messages System: How to add custom message shortcodes
The messages system provides multiple shortcodes used to output various data for each object available to it. However sometimes you may want some details which we do not have a shortcode for or maybe a specific shortcode’s default behaviour is not suitable for your event/registration and you need a custom shortcode with it’s own functionality.
Shortcodes for each data type are stored within their own individual class which we call a library, for example, the EE_Datetime_Shortcodes library stores all of the shortcodes related to EE_Datetimes within the system. When a shortcode is found within the content of the message being generated a ‘parser’ function is called to process that shortcode with whatever functionality is needed.
So in order to add a custom shortcode we first need to add said shortcode to the list of ‘valid’ shortcodes and then hook into the parser to add our own function for that shortcode.
Adding a valid custom shortcode
To add any shortcode to the system we first need to determine the type of shortcode it needs to be and then hook into the correct library to add the shortcode to.
If we continue using the EE_Datetime example, we’ll look into adding a shortcode that outputs the Datetime ID as its not currently available within the system and is one of the simplest libraries to start on. The method used to add a shortcode is the same for all of the different shortcode libraries although the way in which we parse the shortcode and pull the data needed may change depending on the shortcode type.
First we need to determine the shortcode type, to do that we need to know the object it relates to, we mentioned the Datetime ID above so this shortcode obviously relates to a Datetime and that helps us identify the library we add it to. For example, if we know the shortcode is for an EE_Datetime it is unlikely we add that to say an EE_Event_Shortcodes library as even though an EE_Event has a relationship to an EE_Datetime, an Event could have many datetimes so a shortcode such as [DATETIME_ID]
would not know which of those datetimes related to the event it should use if it was an Event based shortcode. We would simple know we wanted ‘a’ datetime for the event passed to the parser, which is a little too vague for most use cases.
There are a couple of ways to determine the type of shortcode you need, in this case we already know that this shortcode is related to a Datetime so we can check the available shortcode libraries within core and see if any of those appear to be close to what we need. The core shortcode libraries are listed HERE and we can see there are 2 libraries that relate to datetimes in some way, EE_Datetime_List_Shortcodes.lib.php
and EE_Datetime_Shortcodes.lib.php
.
List shortcodes
The _List_
shortcodes are basically used to add a shortcode to pull in the ‘List’ sections of the templates (‘Datetime List’, ‘Ticket List’, ‘Event List’ etc), those sections loop over all of the objects related to that section, parsing the shortcodes for each individual object as it does. Say we have an Event with 4 Datetimes, the ‘Datetime List’ section loops over all 4 datetimes and parses whatever is in that section for each individual datetime. If we open up a message template this is a little easier to see:
Event Espresso -> Messages -> Default Message Templates -> Registration Approved -> Edit Registrant
Note the various ‘List’ sections shown there:
Whilst each of those sections relates to an object type (Datetime List relates to Datetimes) it is basically just a loop and shortcodes for that section relate to the loop itself rather than the object within that loop. This means the _List_
libraries are unlikely to be what we are looking for when adding a shortcode for a specific object.
Object shortcodes
With List shortcodes out of the equation, that leaves us with EE_Datetime_Shortcodes.lib.php
and if we open that file the label and description fields (see an example) show us this is a library used to hold shortcodes specific to datetimes, meaning this is likely the library we need. Take note that EE_Datetime_Shortcodes
extends EE_Shortcodes
, as do all of the shortcode libraries, this means they are all children of EE_Shortcodes and this is important a little later on.
Identify shortcode type using the default shortcodes
Another option to find the library is to look in a message template that pulls details related to what we are looking for and search the Event Espresso code-base for that shortcode to find its library. For example we want a Datetime ID so if we find something that calls a field related to a datetime, say the ‘Datetime Start’ (which would be the [DATETIME_START]
shortcode) it is likely going to be from the same library we need.
Inside the Registration Approved message template we opened earlier, we can look for similar shortcodes or a related section, we know from the above that the ‘Datetime List’ section is for looping over datetimes on an event so we can look to see what shortcodes are available in that section:
Searching for any of those shortcodes in our text editor with Event Espresso loaded shows the shortcode is in use in a few different files:
The first is within EE_Line_Item.class.php
, which is a partial match and it is a function, not a shortcode, so that’s unrelated. The next 3 are shortcodes, but they are all within .template.php
files so would point to locations that the shortcode is used (those are the template files used to create the message templates), again no use in this case, then finally we find the EE_Datetime_Shortcodes.lib.php
location, that’s a shortcode library which would appear to be exactly what we need.
Adding a valid shortcode and ‘parser’
So now we know we want to add a shortcode to the EE_Datetime_Shortcodes
library, our next step is to hook into that library and add it as a valid shortcode, EE provides filters to do exactly that. We mentioned earlier that the shortcode libraries are all children of EE_Shortcodes and the reason that is important is the EE_Shortcodes
class provides the filter to add and parse your own shortcodes within the system:
The FHEE__EE_Shortcodes__shortcodes filter allows you to hook in an add custom shortcodes to the libraries.
Then FHEE__EE_Shortcodes__parser_after allows you to hook in and parse (process) the shortcode we added.
This will make more sense once we have an example to work through.
Add a valid shortcode
This is how we can add a shortcode to the EE_Datetime_Shortcodes
library.
<?php /* This filter allows you to add custom shortcodes to the message system * $shortcodes is an array of the available shortcodes for the current library * $lib is the current shortcode library */ function ee_register_new_custom_messages_shortcodes( $shortcodes, EE_Shortcodes $lib ) { //Add a shortcode to be used with the EE Datetimes within messages if ( $lib instanceof EE_Datetime_Shortcodes ) { //Add your shortcode to the add as the key, the value should be a description of the shortcode. $shortcodes['[DATETIME_ID]'] = _('The ID of the current Datetime'); } //Return the shortcodes. return $shortcodes; } add_filter( 'FHEE__EE_Shortcodes__shortcodes', 'ee_register_new_custom_messages_shortcodes', 10, 2 );
Visit the row on Git: https://gist.github.com/Pebblo/63e60f5cc060052b89f22feef8a337d8#file-ee_register_new_custom_messages_shortcodes-php
To break this down, we hook into FHEE__EE_Shortcodes__shortcodes
with our own callback function called ee_register_new_custom_messages_shortcodes
. The filter passes 2 variables to the function:$shortcodes
is an array of valid shortcodes for that shortcode library
$lib
is the current shortcode library being processed.
As we want to add our shortcode to the EE_Datetime_Shortcodes
library we check if $lib
is an instance of that library on line 9, if it is we can add our shortcode(s) for that library to the $shortcodes
array. This is an associative array with the key being the shortcode you want to add and the value being a description of the shortcode used in the help section.
We then return the $shortcodes
array, which has our custom shortcode added to it for EE to use.
So at this point, we have added a new shortcode to the system and it will show as a shortcode wherever the EE_Datetime_Shortcode library is called in the templates. If you open up the Registration Approved message template again (refresh it if you already have it open) and look in the ‘Datetime List’ section, clicking the icon to the right lists all of the valid shortcodes for that section, the [DATETIME_ID]
shortcode will now show there.
Add a ‘parser’ (the shortcode function)
Next we need to tell EE what to do when it finds our shortcode as right now although we have added a valid shortcode we don’t hook in the ‘parser’ to add our functionality for that shortcode, so it does nothing. To add our own parser we use the FHEE__EE_Shortcodes__parser_after
filter:
<?php /* * This filter allows you to hook in to the shortcode parser, check for a shortcode added above and return a value for it using the data passed to the parser. * $parsed are the current values being parsed. * $shortcode is the current shortcode passed to the parser. * $data is the current data available, this can be different types of objects depending on the parser. * $extra_data is a collaction of various data available within the messages system. */ function ee_register_new_custom_messages_shortcodes_parser( $parsed, $shortcode, $data, $extra_data, EE_Shortcodes $lib ) { //Check for the datetime shortcodes library as that's one of the libraries we added a custom shortcode to above. //also check that $data is the expected object (in this case an EE_Datetime as its for the EE_Datetime_Shortcodes library) if ( $lib instanceof EE_Datetime_Shortcodes && $data instanceof EE_Datetime ) { //Then check if we are parsing one of our custom shortcodes above. if ( $shortcode === '[DATETIME_ID]' ) { //Do whatever you need to do here and return the value for that specific datetime. //In this example it simply returns the ID of the related EE_Datetime. return $data->ID(); } } //If not within the correct section, or parsing the correct shortcode, //Return the currently parsed content. return $parsed; } add_filter( 'FHEE__EE_Shortcodes__parser_after', 'ee_register_new_custom_messages_shortcodes_parser', 10, 5 );
Visit the row on Git: https://gist.github.com/Pebblo/f6991ebb41ca7a6c31ba6eb6d25db342#file-ee_register_new_custom_messages_shortcodes_parser-php
Here we hook into FHEE__EE_Shortcodes__parser_after
with our ee_register_new_custom_messages_shortcodes_parser
function. This filter passes multiple variables so let’s break each of those down:$parsed
is the content to be returned through the parser, usually, you will return a value for your shortcode or you return $parsed
back to EE for it to continue on if it isn’t your shortcode being filtered.
$shortcode
is the current shortcode that is being parsed, you check if this matches the shortcode your parser is intended for and then return a value for that shortcode if it is.
$data
is the current data you have available, this can be various different object types depending on the library being parsed and the message type used.
$extra_data
is a collection of data the message system has, again this differs depending on the message type.
$lib
is the current shortcode library we are parsing, this allows you to only check for related shortcodes within specific libraries.
The first step we take is to confirm we are parsing a library that we have added a custom shortcode to, in our case we check if $lib
is an instance of EE_Datetime_Shortcodes
as that is the library our shortcode was added to earlier. We then check if $data
is an instance of an EE_Datetime
, if its not we don’t have an object we can use to return the ID from (we can’t return the ID of a Datetime, if we don’t have a Datetime) so we skip our functionality and return $parsed
.
Once we know we are in the correct library and have the correct data for our shortcode, we can check we are parsing the shortcode we added earlier and we do this by checking if $shortcode
matches our custom shortcode.
If it does, then we know we are parsing our shortcode and that $data
is am EE_Datetime, so we return $data->ID();
for our shortcode as that will be the Datetime ID.
Finally, if none of the above applies we return $parsed
back to EE for it continue processing, we are not processing one of our shortcodes or we don’t have the required data so just return what we were given.
Conclusion
Congratulations, you’ve just added your own valid shortcode (and parser) to the EE messages system.
You now have a valid [DATETIME_ID]
shortcode you can use in any location where the EE_Datetime_Shortcodes
library is used, mainly the ‘Datetime List’ section. This is a simple example but you can add almost any shortcode type to the message system using this method, as long as you can find the shortcode library and find the data you need from what has been passed to the parse (which you can, in most cases).
Next steps
Above we have 2 functions that add a custom shortcode into the messages system and parse that shortcode, however, the Datetime library is always passed an EE_Datetime object so we always know what data we have, that isn’t the case for all parsers so what do we do if we don’t have the correct data type? Let’s break that down a little more with this example:
<?php /* This filter allows you to add custom shortcodes to the message system * $shortcodes is an array of the available shortcodes for the current library * $lib is the current shortcode library */ function ee_register_new_custom_message_shortcodes( $shortcodes, EE_Shortcodes $lib ) { //Add a shortcode to be used with the EE Datetimes within messages if ( $lib instanceof EE_Datetime_Shortcodes ) { //Add your shortcode to the add as the key, the value should be a description of the shortcode. $shortcodes['[CUSTOM_DATETIME_SHORTCODE]'] = _('This is a custom DATETIME shortcode!'); } //Add a shortcode to be used with the EE Event List within messages if ( $lib instanceof EE_Event_Shortcodes ) { //Add your shortcode to the add as the key, the value should be a description of the shortcode. $shortcodes['[CUSTOM_EVENT_SHORTCODE]'] = _('This is a custom EVENT shortcode!'); } //Add a shortcode to be used with the EE Recipient within messages if ( $lib instanceof EE_Recipient_Details_Shortcodes ) { //Add your shortcode to the add as the key, the value should be a description of the shortcode. $shortcodes['[CUSTOM_RECIPIENT_SHORTCODE]'] = _('This is a custom RECIPIENT shortcode!'); } //Return the shortcodes. return $shortcodes; } add_filter( 'FHEE__EE_Shortcodes__shortcodes', 'ee_register_new_custom_message_shortcodes', 10, 2 ); /* * This filter allows you to hook in to the shortcode parser, check for a shortcode added above and return a value for it using the data passed to the parser. * $parsed are the current values being parsed. * $shortcode is the current shortcode passed to the parser. * $data is the current data available, this can be different types of objects depending on the parser. * $extra_data is a collaction of various data available within the messages system. */ function ee_register_new_custom_messages_shortcode_parser( $parsed, $shortcode, $data, $extra_data, EE_Shortcodes $lib ) { //Check for the datetime shortcodes library as that's one of the libraries we added a custom shortcode to above. //also check that $data is the expected object (in this case an EE_Datetime as its for the EE_Datetime_Shortcodes library) if ( $lib instanceof EE_Datetime_Shortcodes && $data instanceof EE_Datetime ) { //Then check if we are parsing one of our custom shortcodes above. if ( $shortcode === '[CUSTOM_DATETIME_SHORTCODE]' ) { //Do whatever you need to do here and return the value for that specific datetime. //In this example it simply returns the ID of the related EE_Datetime. return $data->ID(); } } //Check for the EE Events shortcodes library as that's one of the libraries we added a custom shortcode to above. //$data may not be an EE_Event object, but either $data or $extra_data will be an instance of EE_Messages_Addressee //Using that object you can pull an EE_Event object if ( $lib instanceof EE_Event_Shortcodes ) { //Then check if we are parsing one of our custom shortcodes above. if ( $shortcode === '[CUSTOM_EVENT_SHORTCODE]' ) { //Now pull the related Event object using all of the available data we have. //First check if we have an event object in $data $event = $data instanceof EE_Event ? $data : null; //If no event, then let's see if there is a reg_obj. If there IS, then we'll try and grab the event from the reg_obj instead. if ( empty( $event ) ) { $aee = $data instanceof EE_Messages_Addressee ? $data : null; $aee = $extra_data instanceof EE_Messages_Addressee ? $extra_data : $aee; $event = $aee instanceof EE_Messages_Addressee && $aee->reg_obj instanceof EE_Registration ? $aee->reg_obj->event() : null; } //Check we do now actually have an event object. if ( !empty( $event ) ) { //Do whatever you need to do using the event object. //In this example it simply returns the ID of the related EE_Event. return $event->ID(); } } } //Check for the EE Recipient Details shortcodes library as that's one of the libraries we added a custom shortcode to above. //$data or $extra_data will be an instance of EE_Messages_Addressee which can be used to pull the required details. if ( $lib instanceof EE_Recipient_Details_Shortcodes ) { if ( $shortcode === '[CUSTOM_RECIPIENT_SHORTCODE]' ) { //Make sure we end up with a copy of the EE_Messages_Addressee object $recipient = $data instanceof EE_Messages_Addressee ? $data : null; $recipient = ! $recipient instanceof EE_Messages_Addressee && is_array($data) && isset($data['data']) && $data['data'] instanceof EE_Messages_Addressee ? $data['data'] : $recipient; $recipient = ! $recipient instanceof EE_Messages_Addressee && ! empty($extra_data['data']) && $extra_data['data'] instanceof EE_Messages_Addressee ? $extra_data['data'] : $recipient; //Confirm we have a valid receipient if (! $recipient instanceof EE_Messages_Addressee) { return ''; } //Confirm we have a valid EE_Attendee object $attendee = $recipient->att_obj; if (! $attendee instanceof EE_Attendee) { return ''; } return $attendee->ID(); } } //If not within the correct section, or parsing the correct shortcode, //Return the currently parsed content. return $parsed; } add_filter( 'FHEE__EE_Shortcodes__parser_after', 'ee_register_new_custom_message_shortcodes_parser', 10, 5 );
Visit the row on Git: https://gist.github.com/Pebblo/89058e64c05bd44a4b61eae13878401f#file-ee_new_custom_message_shortcodes-php
In this example we add multiple different shortcode types within a single function, again we check that we add the correct shortcode to the correct library:
Datetime related shortcodes to EE_Datetime_Shortcodes,
Event related shortcodes to EE_Event_Shortcodes,
Recipient/Attendee related shortcodes to EE_Recipient_Details_Shortcodes
We’ve seen most of this before, the above just combines adding multiple different shortcode types into a single function and then multiple parsers into a single callback function, it still checks for the correct library and correct shortcode for each case but for some message types, it jumps through some hoops to make sure we can pull the related object.
The EE_Datetime_Shortcode example we discussed above, is exactly the same and has the EE_Datetime passed to it.
For the EE_Event_Shortcodes section we check if $data
is an instance of an EE_Event and if not start looking for an EE_Messages_Addressee
object, checking if $data
or $extra_data
is that object type, pulling the registration object from it and then the event from the registration object. You can see how all of the data relates to each in this case and how if we have specific objects, we can pull the objects related to those objects for what we need.
The EE_Messages_Addressee class holds all of the data the message system has on the current recipient, in short the messages system pulls all of the data if can, adds it to the EE_Messages_Addressee
object and then uses that throughout the messages system, if you have that object, you can usually pull any object you need (if it doesn’t have it already).
One option you have when working out how to pull the data you need, is to check the default shortcode library for the type you are using and see what that does to pull the data in, for example, within the EE_Recipient_Details_Shortcode library you can see we used the exact same method to pull the Attendee object our parse above, obviously the example isn’t within a class so references to $this
have been removed but functionally it is the same.