Create Custom <s:...> Tags

Custom <s:...> tags are supported, which provide short hand for larger HTML snippets, interopability across different themes, and additional PHP backed functionality. There is a default set of tags with details available on the Template Tags page of the designer documentation, but it's also quite easy to add your own tags.

There are two different methods available to create custom tags. Only one is required, although both are available for each new tag created.

tags.txt File

Every theme contains a tags.txt file, for example /views/themes/default/tags.txt, which contains the various HTML snippets corresponding to the <s:...> tag names, and should be rather self exclamatory. For example, the <s:data_table> tag uses the HTML snippet found within the [[data_table]] entry within the tags.txt file.

Each item within this file is formatted in the same manner:

[[tag_name]]
@required(name, var2)
@default(label=Some Label, width=500px)

... html code here, until next tag header is encountered...

A few notes about the above definition:

  • The @required(...) line is optional, and is a comma delimited list of required attributes which if not defined the tag will be replaced with an error message upon rendering instead of the actual HTML snippet.
  • The @optional(...) line is optional, and is a comma delimited list of key=value pairs that define the default attribute values for the tag for cases where the attribute is used within the HTML snippet, but is not required.
  • Within the HTML snippet you may use any variables desired, which are alphanumeric strings surrounded by ˜ tilde marks. For example, ~title~ will be replaced with the value of the title attribute if present within the tag, or the value within the @optional() line if present.
  • For tags that include a closing tag (eg. <s:tag_name> ... </s:tag_name>), you may use the ˜contents˜ merge field which will be replaced with the contents between the opening and closing tags.

Simple, Non-Closing Tags

To add a new tag, simply add a new entry to the tags.txt filed such as:

[[test123]]]
@optional(name=John, city=Toronto)
<h3>Hello ~name~ from ~city~!</h3>

Once added, place the following tag within any template:

<s:test123 city="London">

View the page in your web browser, and the above tag will be replaced with:

<h3>Hello John from London!</h3>

Closing Tags

For another example, add the following to the tags.txt file:

[[profile]]
@required(username)
<div class="profile~">
    Username: ~username~<br />
    ~contents~
</div>

Once added, add the following tag within any template:

&lt;s:profile username="jsmith"&gt;
    An excellent description about my profile...
</s:profile>

Open the page in your web browser, and the above tag will be replaced with:

<div class="profile~">
    Username: jsmith~<br />
    An excellent description about my profile...
</div>

t_* PHP Classes

Every tag may also optionally contain PHP functionality. This method can be used separately, or in conjunction with adding an entry into the tags.txt file. You may create a new tag via the create html-tag CLI Command, for example:

apex create html-tag demo add

The above will create a new file at /src/Demo/Opus/Tags/t_Add.ph. Every occurrence of the <s:add> tag will execute this PHP class to process any necessary functionality. This PHP class contains only one render() method, which takes the following parameters:

Variable Type Description
$html string The HTML snippet from the tags.txt file, with available variables already replaced with their attribute values. If this tag does not exist within tags.txt, this variable will be a blank string.
$e StackElement An object representing the tokenized tag instance within the stack. Contains various methods to get attributes, body and children. Please see the StackElement Object page for details.

This method simply returns a string of HTML which the instance of this tag within the template is replaced with. This provides you the ability to perform any desired functionality for the tag, and replace it with any output you wish.

For example, replace the contents of the /src/Demo/Opus/Tags/t_add.php file with the following:

namespace App\Demo\Opus\Tags;

use Apex\Syrus\Parser\StackElement;
use Apex\Syrus\Interfaces\TagInterface;

class t_add implements TagInterface

    /**
     * Add
     */
    public function render(string $html, StackElement $e):string
    {

        // Get attributes
        $attr = $e->getAttrAll();
        return(string) ($attr[x'] + $attr['y']);
    }
}

Save the file, and within any template add the tag:

<s:add x="15" y="8">

Load the page in your browser, and you will see the above tag is simply replaced with 23.

Real World Example

Let's add a <s:stock_quote> tag that includes both, a definition within the tags.txt file, and a PHP class. Open the ~/views/themes/default/tags.txt file, and add the following to the bottom:

[[stock_quote]]
@required(symbol)
<div class="stock-quote">
    <h3>~symbol~</h3>
    Open: ~open~<br />
    High / Low: ~high~ / ~low~
</div>

Run the following command to generate the PHP class:

apex create html-tag demo stock_quote

This will create a new file at /src/Demo/Opus/Tags/t_stock_quote.php. Replace the contents of the file with:

namespace App\Demo\Opus\Tags;

use Apex\Syrus\Parser\StackElement;
use Apex\Interfaces\TagInterface;

class t_stock_quote implements TagInterface
{

    /**
     * Render
     */
    public function render(string $html, StackElement $e):string
    {

        // Get symbol
        $symbol = $e->getAttr('symbol');

        // Get stock quote from database, or where ever, set $replace vars
        $replace = [
            '~open~' => '$24.14', 
            '~high~' => '$26.01', 
            '~low~' => '$23.97'
        ];

        // Replace and return
        return strtr($html, $replace);
    }
}

Once saved, add the following tag into any template:

<s:stock_quote symbol="GOOG">

Load the page in your web browser, and the tag will be replaced with:

<div class="stock-quote">
    <h3>GOOG</h3>
    Open: $24.14<br />
    High / Low: $26.01~ / $23.97
</div>