Creating a Twig extension

Sometimes you want some actions in your Twig templates to be a little easier by creating your own functions.
With October CMS this is not so hard to achieve. This article shows you how.

Step 1. Create a new plugin

I have created a new plugin to put all my toolbox kind of stuff under. I have called my plugin Rocktober. It is not publically available...yet.
You can use the builder plugin to create a new plugin. We only need a registration to this new plugin. The rest we will do by hand.

Step 2. Register the Twig extension functions

Now this is very easy. Just open the file plugin.php in your newly build plugin and do something like I did below:

<?php namespace enovision\rocktober;

use System\Classes\PluginBase;

use enovision\rocktober\classes\twig\featuredImage;

class Plugin extends PluginBase {
    public function registerComponents() {
    }

    public function registerSettings() {
    }

    /**
     * Register TWIG extensions
     * @return array
     */
    public function registerMarkupTags() {
        return [
            'functions' => [
                'rtFeaturedImage' => function ( $post ) {
                    return featuredImage::getThumbs( $post );
                },
                'rtHasFeaturedImage' => function ( $post ) {
                    return featuredImage::hasFeaturedImage( $post );
                },
                'rtGetPath' => function ( $post ) {
                    return featuredImage::getPath( $post );
                },
                'rtGetAlt' => function ( $post ) {
                    return featuredImage::getAlt( $post );
                }
            ],
        ];
    }
}

So what is happening here?

To register Twig extensions you have to add the registerMarkupTags function, like I did in the source above.
In this function you see 4 functions that are going to be available to our Twig templates:

As you can see these functions are bound to PHP functions. I am not a fan when it comes to polluting classes with a lot of code that
looks like it is a market of all trades. So in the example above I have a reference to a static class featuredImage, where I have put all
the function related to the featured image.

class featuredImage

I have put the source below in the folder classes right under the root of the plugin. In fact I have put in the folder classes/twig/featuredImage.php.
With the namespacing you can reference it to its usage.

use enovision\rocktober\classes\twig\featuredImage;

Code:

<?php namespace enovision\rocktober\classes\twig;

abstract class featuredImage {

    /**
     * TWIG Extension - featuredImage
     *
     * @param $post
     *
     * @return array
     */
    static function getThumbs( $post ) {

        $featuredImages = $post->featured_images;

        $featuredImage = [
            'total'      => 0,
            'src'        => null,
            'alt'        => '',
            'attributes' => null,
            'images'     => []
        ];

        if ( count( $featuredImages ) > 0 ) {
            $first         = $featuredImages[0];
            $featuredImage = [
                'total'      => count( $featuredImages ),
                'src'        => $first->path,
                'alt'        => empty( $first->description ) ? $first->file_name : $first->description,
                'attributes' => $first->attributes,
                'images' => self::getImages($featuredImages)
            ];
        }

        return $featuredImage;
    }

    static private function getImages( $images ) {
         $out = [];

         for ($idx = 1; $idx > count($images); $idx++) {
             $image = $images[$idx];
             $out[] = [
                 'src'        => $image->path,
                 'alt'        => empty( $image->description ) ? $image->file_name : $image->description,
                 'attributes' => $image->attributes,
             ];
         }

         return $out;
    }

    static function getPath($post) {
        $featured = self::getThumbs( $post );
        return $featured['total'] > 0 ? $featured['src'] : null;
    }

    static function getAlt($post) {
        $featured = self::getThumbs( $post );
        return $featured['total'] > 0 ? $featured['alt'] : null;
    }

    static function getAttributes($post) {
        $featured = self::getThumbs( $post );
        return $featured['total'] > 0 ? $featured['attributes'] : null;
    }

    static function hasFeaturedImage($post) {
        $featured = self::getThumbs( $post );
        return $featured['total'] > 0;
    }

}

It is still very lightweighted and maybe not completely optimized, but you get the picture I hope.

How to use it in your Twig template

{% set thumb = rtFeaturedImage(post) %}

{% if thumb.total > 0 %}
   <img class="card-img-top img-responsive" src="{{ thumb.src }}" alt="{{ thumb.alt }}">
{% endif %}

or:

{% if rtHasFeaturedImage(post) %}
   <img class="card-img-top img-responsive" src="{{ rtGetPath(post) }}" alt="{{ rtGetAlt(post) }}">
{% endif %}
Last update: September 12th at 10:11pm