Skip to content

Article templates

Intro

The templates are configured by default in app/config/cms/templates.yml

yaml
wf_cms_base_admin:
    article_templates:
        default: ~
        opinion:
          category_bound: opinion
        mam:
            category_bound: 
              - live
              - mam
        special_article:
           category_bound:
              main: video
              secondary:
                 - deportes
                 - politica
        static:
            type: static

There are various types of article templates (in the example above):

  • generic: the default type of articles, used if you don't specify anything

  • category_bound: the editor can choose only a subcategory of the category with slug specified as category_bound option. If that category has no subcategories, the category dropdown won't be displayed at all - it's being replaced with a hidden input.

    The value for the category_bound can be:

    • a string: the category slug to which the bind the template - this will allow selecting children of the given category
    • an array of strings: the category slugs to which to bind the template - this will allow selecting children of any of the given categories
    • an array with main (required) and secondary (optional) keys. Both these keys can have either a string value or an array of strings value. This allows binding the template to the category or categories specified in main, but also adds the secondaryCategories field and binds them to the category or categories specified in the secondary key
  • static: a special type of category_bound article, bound to category pages. MAKE SURE you have a category with slug pages when enabling this option. Besides being bound to this category, the articles also have some options on whether to display or not the title and the sidebar.

The templates will be looked for in __CMS_BUNDLE__/Resources/views/Templates/Article/__TEMPLATE_ID__.html.twig and in __CMS_ADMIN_BUNDLE___/Resources/public/javascripts/page_template/article/__TEMPLATE_ID__.js.

Javascript templates

The JS template is optional, the CMS will use a generic JS template file if there's no __TEMPLATE_ID__.js file at the correct location. The JS templates are an optional mechanism to extend the base behavior of the CMS.

Here are a few examples we've encountered:

Hoverable board container

If the board is displayed inside a container that only shows up when hovering a certain element, it's useful to add a class to that container so it stays open while the editor is also open, even if the user moves the mouse outside the container (and the default behaviour is that the board's container is hidden):

js
define([
    'base_editor'
], function(
            Base
){

    return Base.extend({

        initialize: function(options) {
            Base.prototype.initialize.call(this, options);
            this.$el.parent().addClass('wf-editor-open');
            this.listenTo(this.viewModel, 'change:closed', this.onClosedChanged);
        },
        onClosedChanged: function() {
            if (this.viewModel.get('closed')) {
                this.$el.parent().removeClass('wf-editor-open');
            }
        }

    });
});

Maximum number of modules allowed

This example removes the + button on the modules if there are 5 modules added to each of the selectors. This example loops for all the modules, in all selectors (_.each(this.modules)) - it was done for a board that had only one selector - but it could also loop through the modules of only one selector (_.each(this.modules['.selector .that .allows .only .five .modules'])). In this case it was prefered to have a board with a single selector as the developer could've broke the behavior if they changed the selector.

Note: For v7+, check out the wf-max wf-directive.

js
define([
    'base_editor'
], function(
            Base
){

    return Base.extend({
        initialize: function() {
            Base.prototype.initialize.apply(this, arguments);

            this.on('module-add', this.epModuleAdd.bind(this));
            this.on('module-remove', this.epModuleAdd.bind(this));
            this.on('template-ready', this.cierreCount.bind(this));
        },

        epModuleAdd: function(ev) {
            this.cierreCount();
        },

        cierreCount: function() {
            _.each(this.modules, function(collection, selector) {
                var allowAdd = collection.length < 5;

                collection.each(function (module) {
                    var view = module.getView();
                    var toolbar = view.toolbarView;

                    if (!toolbar) {
                        return view.options.allowAdd = allowAdd;
                    }

                    if (allowAdd) {
                        if (toolbar.$('.icon-add').length)  {
                            return;
                        }

                        toolbar.addRightMenuButton('add', 'add', true);
                    } else {
                        toolbar.removeRightMenuButton('add');
                    }
                })
            });
        }
    });
});