How to Set up an Online Multi-Language Magazine with Sulu

We previously demonstrated the proper way to get started with Sulu CMS by setting up a Hello World installation on a Vagrant machine. Simple stuff, but can be tricky.

If you’re a stranger to Vagrant and isolated environments, our excellent book about that very thing is available for purchase.

This time we’ll look into basic Sulu terminology, explain how content is formed, created, stored, and cached, and look into building a simple online magazine with different locales (languages).

Sulu logo


Recommended reading before you continue:


Pages and Page Templates

A page is exactly what you’d expect it to be: a block of content, often composed of smaller blocks. A page template is a two-part recipe for how a page is assembled.

A page template has two parts: the twig template, and the XML configuration. The Twig part is responsible for rendering the content of the page’s sub-blocks, like so:

{% extends "master.html.twig" %}

{% block meta %}
    {% autoescape false %}
        {{ sulu_seo(extension.seo, content, urls, shadowBaseLocale) }}
    {% endautoescape %}
{% endblock %}

{% block content %}
    <h1 property="title">{{ content.title }}</h1>

    <div property="article">
        {{ content.article|raw }}
    </div>
{% endblock %}

This is the full content of the default twig template that comes with sulu-minimal, found at app/Resources/Views/Templates/default.html.twig. It extends a master layout, defines some blocks, and renders their content.

The XML configuration on the other hand is a bit more convoluted (as most things with XML are):

...
    <key>default</key>

    <view>templates/default</view>
    <controller>SuluWebsiteBundle:Default:index</controller>
    <cacheLifetime>2400</cacheLifetime>

    <meta>
        <title lang="en">Default</title>
        <title lang="de">Standard</title>
    </meta>

    <properties>
        <section name="highlight">
            <properties>
                <property name="title" type="text_line" mandatory="true">
                    <meta>
                        <title lang="en">Title</title>
                        <title lang="de">Titel</title>
                    </meta>
                    <params>
                        <param name="headline" value="true"/>
                    </params>

                    <tag name="sulu.rlp.part"/>
                </property>

...

If you’re new to Sulu, none of this will make sense yet – but we’ll get there. For now, we’re introducing concepts. The main takeaways from the above snippet of XML are:

  • the key is the unique slug of the template, and its entry into the admin template selection menu (it must be identical to the filename of the xml file, without the extension).
  • the view is where its twig counterpart can be found. A template will only appear in the menu if it has both the XML and corresponding Twig file!
  • the controller is where its logic is executed. We’ll go into more detail on controllers later on, but in general you can leave this at its default value for simple content.
  • meta data is how the template will appear in the admin template selection menu, depending on the language selected in the UI:
    Admin selection menu
  • properties are various elements of the page – in this case, a field to input a title and a non-editable URL field

You define new page types (templates) by defining new combinations of properties in this XML file, and then rendering them out in the corresponding twig file.

As an experiment, try using the menu in the admin interface to switch the Homepage to the Default template, then in the master.html.twig layout file (one folder above), add nonsense into the HTML. Feel free to also populate the article property in the UI.

A modified home page

...
        <form action="{{ path('sulu_search.website_search') }}" method="GET">
            <input name="q" type="text" placeholder="Search" />
            <input type="submit" value="Go" />
        </form>
Lalala
        <section id="content" vocab="http://schema.org/" typeof="Content">
            {% block content %}{% endblock %}
        </section>
...

If you click Save and Publish in the top left corner now and refresh the homepage, you should see the changes.

A changed live homepage

For the curious: you may be wondering why they took the XML route instead of having users manage everything in the database. Reason one is being able to version-control these files. Reason two is that even if one were to add a property in a GUI, it would still be missing from the twig template. At that point, they would either have to make twig templates editable in the GUI via a DB too, or the user would again be forced to edit files – and if they’re already editing them, they may as well edit XML files.

Pages Vs Themes

So what’s a theme in all this?

A theme is a collection of page types. Contrary to popular belief, a theme is not a master layout which is then extended by the page template twigs – it’s a whole collection of page templates and master layouts to use. A theme will also contain all the necessary assets to fully render a site: CSS, JS, images, fonts, and more.

For the curious: We won’t be dealing with themes in this tutorial but feel free to read up on them here.

About Caching

If the homepage content doesn’t change when you modify it and refresh, it might have something to do with cache. Here are important things to keep in mind:

  • during development, your server setup should set Symfony development environment variables. This allows you to deploy the app directly to production without modifying the environment value manually in files like web/admin.php or web/website.php, and makes your app highly debuggable in development. The values are SYMFONY_ENV and SYMFONY_DEBUG, and are automatically set if you’re using Homestead Improved. If not, copy them over from here if you’re on Nginx.
  • the command line of Symfony apps (so, when using bin/adminconsole or bin/websiteconsole in the project) defaults to the dev environment. In order to execute commands for another environment, pass the --env= flag with the environment to match, like so: bin/adminconsole cache:clear --env=prod. This might trip you up if your app is in prod mode and you’re trying to clear cache but nothing is happening – could be the environments don’t match, and the command is clearing the wrong cache.

An Online Magazine

Let’s consider wanting to launch an online magazine. By definition, such a magazine has:

  • pages that explain things, like “About”, “Contact”, “Careers”, etc.
  • many articles, often grouped by month (as evident by the common URL pattern: mysite.com/05/2017/some-title-goes-here)
  • different permissions for different staff member levels (author, editor, guest, admin…)
  • a media library in which to store static files for inclusion in posts and pages (images, CSS, JS, etc.)

These are all things Sulu supports, with a caveat. When building something like this, we need keep storage in Sulu in mind.

Jackawhat?

This section might sound confusing. There’s no way to make it easier to understand. Be comforted by the fact that you don’t need to know anything about it at all, and treat it as “for those who want to know more” material.

Jackalope is a PHP implementation of PHPCR which is a version of JCR. The rabbit hole is very deep with these terms, so I recommend avoiding trying to learn more about them. If you insist, it’s somewhat covered in this gist.

In a nutshell, if you don’t need to version your content, you’re fine with the default Jackalope-Doctrine-DBAL package that Sulu pulls in automatically. It’ll store content in a usual RDBMS (e.g. MySQL) but without versions.

If you do need versioning, you need to install Jackrabbit – an Apache product that’s basically a database server with a non-obvious twist, and use a different PHP implementation to store the content: Jackalope-Jackrabbit (also pulled in automatically). Note that an RDBMS is still needed – Jackrabbit merely augments it by providing a different storage mechanism for the actual content, but permissions, settings, etc. are still stored in a regular database.

The catch is that Jackrabbit (and PHPCR in general) has a limit of 10000 children per node. Since articles on online magazines and blogs are usually sequential and don’t have a hierarchy (i.e. they’re flat), they would end up being children of “root”, and after 10k posts you’d be in trouble.

This is why the Sulu team have developed a bundle which will auto-shard content by month and emulate a flat structure. By setting each month as a parent, each month can have 10000 posts. If need be, this can be further fragmented by week, or even by day. Keep this in mind:

The ArticleBundle is a prerequisite if you’re building a news site, blog site, or magazine because otherwise, after 10000 units of content, you’d be in trouble.

Note: The ArticleBundle is currently under heavy development, and is likely to have some API changes before a 1.0 release. Use with caution.

Okay, let’s install the ArticleBundle to get support for our online magazine website.

Continue reading %How to Set up an Online Multi-Language Magazine with Sulu%


Source: Sitepoint