How to create a Blog from scratch with Pimcore

A tutorial for learning pillars of Pimcore DXP

In my last article about Digital Transformation, I explained how much it is important to have an excellent platform for implementing our digital strategy.

I don’t want to bore you again with the same old story, just a small recap to refresh why we are looking at Pimcore as a solution for the CMS\DPX :

  • Opensource
  • Decoupled\Headless presentation
  • MDM engine that avoids time-wasting on reading\writing data
  • Powerful CMS Engine

That doesn’t mean that Pimcore is the solution to all evils, but

In this article, I will try to show all the Pimcore capabilities building a blog from scratch.

I will cover the most important topic on Pimcore with a step by step explanation.

After this tutorial, you will be able to start working on a Pimcore website. Moreover, reading this article will help to understand if this solution suits you.

The Roadmap

I don’t’ want to annoy with a pure theoretical explanation, so I created a hands-on-code tutorial that leads to a blog site creation.

This article is divided into the following part:

  1. How to install Pimcore
  2. Setup the theme (and manage CMS pages)
  3. The Blog Data (custom data entry)
  4. The BlogRoll (Bricks and widget for custom UI)

All the source code is available on GitHub (link at the bottom).

Photo by Frank Vessia on Unsplash

How to install Pimcore

The easier solution is to use the docker image. You can use the following docker-compose file.

Then running docker-compose up your environment will start in a while, downloading all required dependencies. The main issue relating to the setup about the meaning of “docker image.” The Pimcore docker image is not a ready-to-go setup, but an environment suitable for running a Pimcore environment. In simple words, you have the webserver, the right PHP version, all tuning done, but you have to install Pimcore inside the container.

Installing Pimcore needs a few steps, and you can use the following commands:

# enter the container
docker exec -it pimcore-php bash

COMPOSER_MEMORY_LIMIT=-1 composer create-project pimcore/skeleton tmp
mv tmp/.[!.]* .
mv tmp/* .
rmdir tmp

#run installer (need database credential, creates admin user)
./vendor/bin/pimcore-install --mysql-host-socket=mysql --mysql-username=pimcore --mysql-password=pimcore --mysql-database=pimcore

Because the process needs a lot of files it can take a while, please be patient and do not shut down the console while it is thinking.

The most tricky part is the installation one. When we create a folder for the install, the command-line tool does something like:

+- your folder
+ web
+ other pimcore folder

The /web folder is the one that contains the bootstrap files and has to be set up as the document root. Because the standard Pimcore image uses […]/www/html/web as the document root, the script simply moves the files one step back to avoid changes in the apache settings.

Since that point, you are able to navigate Pimcore using any browser at HTTP://localhost:7080/admin.

The volume mapping

This docker-compose file is intended for development purposes only and aims to keep all files self-contained and committable. The goal is to isolate all files in a folder and simplify all operations like switching from one project to another or sharing the project with a colleague. I used a folder for each container and inside a folder for each mapping topic.

+ config
+ logs
+ www
+ data
+ config
+ config

Another big benefit of this configuration is that we can simply open the root folder with Visual Studio Code and get full control over all the parts of the project. This is good because you don’t need to switch tools or context during the development.

For the production environment, this configuration is not optimal and needs some performance tuning.

Setting up your theme

During the installation, we start from the skeleton scenario, that’s an empty website. This is very useful for learning Pimcore because you have anything ready, and you cannot improvise.

The first point is to create a layout file and a default template.

In this template, we can see:

  • the $this->template() helper that render some views, header, and footer in this case
  • the $this->slots()->output(‘_content’) that delegates to the page the content definition

After we got a layout, we need a default template. Each page can have it’s own, but having a good fallback is good to avoid unnecessary work.

In the snipped above, we refer to the layout we just created, and then we add a simple structure of blocks composed by header and text.

This snippet introduces the “editables”; these objects work in edit and view mode. For example, by using $this-input(“name”), you add a textbox that the user can fill in edit mode, and in the view mode, the text is used for rendering the page. Using the block editable, you get the result of replicating the format.

Creating a Bootstrap layout

In the previous example, we see the editor in action. We were able to add a set of paragraphs on a page in WYSIWYG mode. That is very cool, but on modern websites, we need more flexibility. To prove how it is easy to create a template, I worked on the example above, getting a bootstrap grid layout.

The basic is to iterate over a set of rows (blocks) and then iterate over a set of columns (inner blocks). Then, I give the options to add any object inside the cell of the matrix. Easy, right?

Note the part with the conditions print of the table element. This is because, during edit mode, there isn’t any bootstrap 4 support, so I fall back to the table for dividing horizontal space.

Another tricky part is the computation of CSS col classes. When the division is not exact, I spread the rest to the right element. For example, if I have 5 cols, 12/5 = 2, and I have 2 columns left, so I will have the first 3 columns with class col-2 and the last two with length col-3.

This solution makes the right elements a little bit larger than others when the fit is not perfect but avoids the wrong spaces. An advanced solution would be adding a numeric input for overriding the sizes or adding the opportunity of overriding the class.

The result in the editor is the following:

And you can add how many rows and columns you want.

Header and footer

I created two templates for the header and footer, but I make them parametric.

Inside Settings > WebsiteSettings you I added the variables I need:

Then I can use these variable as follows:

The Blog data

For the blog article created two different object type:

  • Article
  • Category

The category field is a relation to the category entity. After this setup, we are able to enter blog articles.

At that point, we have data, but we have work on the presentation. As you know, Pimcore lets you create a document for each page, but in this case, we have a dynamic rendering.

The solution is articulated in two steps

  1. Create the routing
  2. Creating the template

For creating a custom route, you just need to enter your settings from admin.

The input is very simple, and you just need to specify:

  • a name for the rule
  • the regular expression that captures a link
  • The name of the parameters extracted from the link
  • The rule for generating an URL from parameters

The last point is essential for generating URL automatically and avoid hardcoded address or rules.

In this example, I linked the /blog/{slug} address to the BlogController, and I pass the slug variable to it.

By convention, the BlogController uses the default.html.php template inside the blog folder in the /app/resources/views folder.

The following code implements the controller, and fetch items basing on the slug field.

The method used to send data to the template is to set a property directly using $this->view->variablename

The following code implements the page render.

After this step, we have a blog page visible.

The Blogroll

At that point, we have a CMS engine that can create custom pages, data entry for the article entity, and the rendering of a single article page. What we need next is a blog roll on the home page. A simple solution could be to edit the template directly, but I prefer another solution that gives us the opportunity to learn another important pillar of Pimcore CMS.

We are going to create a widget (brick in the Pimcore slang) that can be added to any CMS pages. This widget will be parametric and will work in WYSIWYG mode. Hard? Not so much.

We need to follow a few steps:

  • Create the brick class (this have to be inside /src/AppBundle/Document/Areabrick/ folder)
  • Enable the Brick from bundles page
  • Reload the cache
  • Create two templates (one for editing mode and one for the rendering mode)

Let’s start with the easier one.

Please remember: for auto-discovery, the namespace has to be the one specified in this sample, no matter where the file is. Otherwise, you will need manual registration. The override of getTemplateLocation lets you use the standard template folder instead of the bundle one.

At that point, the brick is discovered but not enabled, and you can do it by the UI.

After this step, a cache reload is needed.

Since the brick is active, you can select it into the CMS.

The brick is configured for working in edit mode, so you see the data rendered inside the editor, like in the public web site (of course, using different styles, some details may vary). By clicking the edit button, a popup with the view edit is shown, and you can set data.

The result in edit mode is that one:

And in view mode the page is something like this:

For getting this result, I used the following templates.

Edit template

In the edit template, we use inputs to get the limit of the article numbers and the view mode. The $this->select command render a drop-down menu with two options.

View template

The view template fetches blog articles and includes the right template basing on the user selection. The entries could have also been filtered in the controller action. The article list is passed as an argument to the template (that manages only the presentation logic).

List template

The difference between list and grid is just some CSS class and markup, so I add here just the list template (all code available in GitHub).

The important part of this script is the usage of $this->path() that creates the URL dynamically basing on the custom route (robust to changes to the route). Another good point is the image usage. I added the option of creating a thumbnail for the image, so using $entry->getImage()->getThumbnail(“small-grid”) i get the path automatically. The thumbnail is generated by Pimcore without any effort on your side, and you just need to add a preset.

What to take home

By the way, you need some extra work at the beginning to get something usable. Thanks to the Pimcore flexibility, if you work well, all the time you invest in the setup will save a lot of issues later, and you will be able to scale without any friction. Anyway, if you are looking for a quick and dirty approach like downloading a theme and be online in a day… well, this is not the right tool.

In this article, we explored the pillars and the basics for creating web sites, covering all the topics for stating working in it.

We covered:

  • Entities (Data Object\Classes)
  • CMS Pages (Documents)
  • Templating (layouts and pages)
  • Widgets (Bricks)
  • Routing and MVC basics
  • Installation

Remember also that this solution is based on containers, this is good because you can easily deploy to cloud solutions like Google Cloud, Amazon AWS, Microsoft Azure, or IBM Cloud Stories.


All the source code is hosted in GitHub, and the solution is ready to go in one click (data are with the source code, not the best practice, but useful to let you test what you see without wasting time).

working hard to build a better tomorrow

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store