Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

UncleCheese
19th December 2014

In this tutorial, we’ll start using SilverStripe’s native template syntax to inject dynamic content into our site, such as navigation, page titles, CMS content, and more.

Adding Dynamic Content

Level: Beginner

Duration: 7:10

In this lesson:

Adding primary navigation

To create our main menu, we’ll use a global method that SilverStripe provides to all your templates: the $Menu function. $Menu returns a list of all the pages in a given section of the site. Because it returns a set rather than a single value, we’ll need to loop through the result to create a menu of varying length. Inside the <ul> tag that wraps the primary navigation, remove the hardcoded <li> tags and add the following syntax:

<% loop $Menu(1) %>
  <li><a class=”$LinkingMode” href=”$Link” title=”Go to the $Title page”>$MenuTitle</a></li>
<% end_loop %>

Let’s examine what each piece of syntax does:

<% loop $Menu(1) %> Begins a loop through all the menu items, repeating all the HTML that is in the loop for each one. By passing (1) as an argument, we are asking the CMS to give us all the pages at level 1 of the hierarchy. Changing that to (2) would give us all the pages at the second level of the hierarchy in the current section, and so on.

$Link The link to the page in the current iteration of the loop. 

$Title The title of the page in the current iteration of the loop

$MenuTitle SilverStripe distinguishes between the title of a page (i.e. in your <h1> tag) and the title that should appear in the context of navigation. Often times these are the same, but since the user is given the option to customise the title in menus, we use the $MenuTitle variable here.

$LinkingMode A helper method that indicates the state of our menu. For each item in the list, this method will return one of three strings:

  • link: the page is not active
  • current: this is the current page
  • section: the current page is a descendant of this page (i.e. on the URL /about-us/company, the “company” page is current, and the “about-us” page is “section.”

Refresh the page. You should now see the three default pages SilverStripe creates for you in the primary navigation: Home, About Us, and Contact Us.

Adding a base URL

Let’s try navigating to one of the pages, say, “About Us.” The site breaks! What’s going on here?

Taking a look at the web inspector again, you’ll see that the browser is looking for our assets in the wrong place (about-us/themes/one-ring/). We’ve used relative paths for everything, so we need to insure that all the assets load relative to our project root. We could use a leading slash (“/”) for this, but if you’re working in a subdirectory of localhost (e.g. http://localhost:8888/tutorial) that will look too far up the tree.

For this reason, it’s strongly recommended that you add a <base /> tag to the head of your document in all templates. Fortunately, there’s an easy helper tag provided by SilverStripe to give you exactly what you need. Simply add the syntax <% base_tag %> to the top of your section.

Reload the page, and things should look a bit less insane now.

More common template variables

Now that we have a coherent, navigable set of templates, we can start adding some more template variables that are common to all pages.

We can start with our meta tags. While it is highly likely that you’ll want to have a granular level of control over these, SilverStripe does offer the helper method $MetaTags that we recommend using. It outputs some boilerplate tags, including the character set, generator, as well as contextual metadata that is pulled from the CMS, such as the page description. By default, this method will include the <title> tag, as well, but if you’d prefer something more custom, simply use $MetaTags(false) to suppress it. Keep in mind that you’re free to augment these meta tags with anything else you like. They’re merely used to get you started.

Let’s remove the “charset” meta tag along with the <title> tag, and replace them with $MetaTags. We’ll leave the “viewport” meta tag, as we need that for our responsive design.

Next let’s look at the main content area, where most of our page content will display. We can update our <h1> tag to use the $Title variable. This will pull in the current page title as it is defined in the CMS.

Below that, we have some breadcrumbs hardcoded into the template. This is likely to be an area of your design that you want to customize, but for now, we’ll use the magic variable $Breadcrumbs to output of string of rich text representing the breadcrumbs. In later tutorials, we’ll cover how to customize the output of this method.

Replace the contents of <div class=”breadcrumb” /> with $Breadcrumbs.

The most important section of our page is the main content area. In our mockup, we have a few paragraphs of lipsum text that we can remove in favor of pulling real content from the CMS. In SilverStripe, the $Content variable refers to the main body of content added to the rich text editor when editing a page.

Replace the contents of <div class="main col-sm-9" /> with $Content.

Alongside the content, we have a sidebar that contains subnavigation. Earlier in this tutorial we created a loop for primary navigation using $Menu(1). Similarly, we can create subnavigation using $Menu(2). We don’t want to include this block of content unless subnavigation exists, so we’ll wrap the whole thing in an <% if $Menu(2) %> block.

Replace the contents of the sidebar as follows:

<% if $Menu(2) %>
  <h3>In this section</h3>
    <ul class="subnav">  
      <% loop $Menu(2) %>
        <li><a class="$LinkingMode" href="$Link">$MenuTitle</a></li>
      <% end_loop %>
    </ul>
<% end_if %>

Let’s look quickly at the login page to the CMS by accessing the /admin/ URL. Notice that we’re not presented with any login form. In order to get the form to show, we’ll need to add a $Form variable, which primarily serves as a placeholder for the login form. SilverStripe doesn’t have a custom template for the login form by default. Instead, it injects it into your default page type. We want to make sure it is positioned in a place that makes sense.

Add a $Form variable below $Content.

Lastly, our template uses the convention of a hyperlinked logo to go to the home page. In the static markup, we have a hardcoded link to index.html. We want to make sure this links to the base URL of our website. Let’s use the $AbsoluteBaseURL variable in the link around the logo.

Questions and Feedback

Subnavigation part doesn´t work. I changued...

...

In this section

    <ul class="categories subnav">
    <li><a href="#">Company</a></li>
    <li><a href="#">FAQ</a></li>
    <li><a href="#">Careers</a></li>
    <li><a href="#">Contact Us</a></li>
    <li><a href="#">Terms of Use</a></li>
    <li><a href="#">Privacy Policy</a></li>
</ul>

... for ... <% if $Menu(2) %>

In this section

<% end_if %> ...

Shows nothing...

by Francisco at 02:56am, 18 March 2015

Author

Do you have any sub pages in that section? It won't show unless you have sub navigation.

If you're having a hard time with part of a lesson, you should checkout the branch for the next lesson, in this case lesson-4, which starts with the completed code for Lesson 3, and compare your work.

by UncleCheese at 09:46am, 18 March 2015

Hello, i have two doubt. First: on the minute 2:25 you put finally the class section or $LinkingMode. Second: on the minute 2:40 when you access to about-us, your browser show us something like that (localhost:8888/tutorial/about-us/) but i need put on the browser (http://localhost/example/index.php/about-us/) to access. My doubt is, why i need put "index.php" to access?

Thanks.

by Arcax at 09:11pm, 18 March 2015

Author

Hi, Arcax,

I'm not sure why that might be happening. Are you running Linux or Windows? It sounds like it could be an issue with your .htaccess.

by UncleCheese at 05:28pm, 19 March 2015

Hi UncleCheese, i'm running on Windows 8.1. My .htaccess is:

### SILVERSTRIPE START ###

# Deny access to templates (but allow from localhost)
<Files *.ss>
    Order deny,allow
    Deny from all
    Allow from 127.0.0.1
</Files>

# Deny access to IIS configuration
<Files web.config>
    Order deny,allow
    Deny from all
</Files>

# Deny access to YAML configuration files which might include sensitive information
<Files ~ "\.ya?ml$">
    Order allow,deny
    Deny from all
</Files>

# Route errors to static pages automatically generated by SilverStripe
ErrorDocument 404 /assets/error-404.html
ErrorDocument 500 /assets/error-500.html

<IfModule mod_rewrite.c>
    SetEnv HTTP_MOD_REWRITE On
    RewriteEngine On

    # Enable HTTP Basic authentication workaround for PHP running in CGI mode
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Deny access to potentially sensitive files and folders
    RewriteRule ^vendor(/|$) - [F,L,NC]
    RewriteRule silverstripe-cache(/|$) - [F,L,NC]
    RewriteRule composer\.(json|lock) - [F,L,NC]

    # Process through SilverStripe if no file with the requested name exists.
    # Pass through the original path as a query parameter, and retain the existing parameters.
    RewriteCond %{REQUEST_URI} ^(.*)$
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule .* framework/main.php?url=%1 [QSA]

    # If framework isn't in a subdirectory, rewrite to installer
    RewriteCond %{REQUEST_URI} ^(.*)/framework/main.php$
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule . %1/install.php? [R,L]

</IfModule>
### SILVERSTRIPE END ###

Thanks.

by Arcax at 07:43pm, 19 March 2015

My solucion was uninstall wampp (wampserver2.5-Apache-2.4.9-Mysql-5.6.17-php5.5.12-32b) server and install xampp (xampp-win32-5.6.3-0-VC11), the main problem is the version Apache from 2.4 (inclusive). But I could seen different solution: 1.- Remove index.php 2.- On .htaccess (before the mod_rewrite section):

           <IfModule mod_dir.c>
                 DirectoryIndex disabled
          </IfModule>

3.- Change On file index.php:

define('BASE_SCRIPT_URL','index.php/'); to
define('BASE_SCRIPT_URL','');

I hope to help.

by Arcax at 11:54pm, 26 March 2015

I was wondering the same, but your solution doesn't work for me, could you please shared your .htaccess?

thx

by Erick at 08:50am, 10 April 2015

I dont understand this part very well, does any body could explain me a little bit more?

"SilverStripe doesn’t have a custom template for the login form by default. Instead, it injects it into your default page type".

Thx

by Erick at 08:54am, 10 April 2015

Author

Hi, Erick,

Yeah, good question. So some CMSes like Wordpress have a custom page for the login. It's usually a really barebones, otherwise empty page, with a login form in the middle of the screen. In SilverStripe, the login is displayed on your Page.ss template, so shown in the context of your theme. That isn't to say you can't create a more streamlined login template, but by default, it just wants to render as part of your page content.

Take notice of how the login form displays in our project. It's treated almost the same as plain page content, beneath the main navigation, with the banner, footer, and all the other standard components of a page.

by UncleCheese at 04:31pm, 11 April 2015

Remember you that i used XAMPP not MAMP. My .htaccess is:

### SILVERSTRIPE START ###

# Deny access to templates (but allow from localhost)
<Files *.ss>
    Order deny,allow
    Deny from all
    Allow from 127.0.0.1
</Files>

# Deny access to IIS configuration
<Files web.config>
    Order deny,allow
    Deny from all
</Files>

# Deny access to YAML configuration files which might include sensitive information
<Files ~ "\.ya?ml$">
    Order allow,deny
    Deny from all
</Files>

# Route errors to static pages automatically generated by SilverStripe
ErrorDocument 404 /assets/error-404.html
ErrorDocument 500 /assets/error-500.html

<IfModule mod_rewrite.c>

    # Turn off index.php handling requests to the homepage fixes issue in apache >=2.4
    <IfModule mod_dir.c>
        DirectoryIndex disabled
    </IfModule>

    SetEnv HTTP_MOD_REWRITE On
    RewriteEngine On

    # Enable HTTP Basic authentication workaround for PHP running in CGI mode
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Deny access to potentially sensitive files and folders
    RewriteRule ^vendor(/|$) - [F,L,NC]
    RewriteRule silverstripe-cache(/|$) - [F,L,NC]
    RewriteRule composer\.(json|lock) - [F,L,NC]

    # Process through SilverStripe if no file with the requested name exists.
    # Pass through the original path as a query parameter, and retain the existing parameters.
    RewriteCond %{REQUEST_URI} ^(.*)$
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule .* framework/main.php?url=%1 [QSA]

    # If framework isn't in a subdirectory, rewrite to installer
    RewriteCond %{REQUEST_URI} ^(.*)/framework/main.php$
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule . %1/install.php? [R,L]

</IfModule>
### SILVERSTRIPE END ###

I hope to help, you're welcome.

by Arcax at 09:02am, 10 April 2015

well, I think you could use pastebin for that, but thanks

by Erick at 03:38am, 11 April 2015

How would you arrange the if and loop for three levels of navigation? I'm following the tutorials a second time first time was with one-ring, now with our boat club website using an HTML5 template and three levels of navigation, so we have About Us / Boat Ramps / Public as an example.

I have used the loop from the tutorial which works perfectly for two levels, but add a third I tried replacing $Menu(2) with $Children while this works the side navigation frame is still present at the third level.

<% if $Menu(2) %>

in this section

<% end_if %>

by BaldBish at 10:39am, 26 April 2015

Author

Hi, BaidBish, what do you mean by the "side navigation frame?" Do you not want the navigation to display when on the third level?

by UncleCheese at 02:00pm, 27 April 2015

Hi UncleCheese

I was hoping to be able to only show "in this section" if there was sub pages to display for three levels of navigation rather than the two (as in the tutorial), if there is no sub page the "in this section" would not display.

Currently using $Children when at the third level the "in this section" block is visible.

by BaldBish at 08:19am, 28 April 2015

Author

Hi, BaldBish,

You can use <% if $Menu(3) %> to check if there are three levels of navigation.

by UncleCheese at 04:31pm, 29 April 2015

Can confirm that there are three levels of navigation - 1st Level = About Us, 2nd Level = Boat Ramps, 3rd Level = Public. When using $Children at the 3rd Level the "in this section" shows but with no navigation links as there is no 4th Level page under Public in the CMS.

by BaldBish at 09:53am, 30 April 2015

Author

Yeah, in that case, you want to show the peer navigation, not the children, so <% loop $Menu(3) %> is what you want there.

by UncleCheese at 10:55am, 30 April 2015

I've already tried Menu(3) which doesn't work, when I navigate to Boat Ramps page there is no "in this section" for the third level displayed at all using Menu(3)

by BaldBish at 04:32pm, 30 April 2015

Author

What you'll want to do in that case is create separate menus.

<% if $Level(3) %>
  <% loop $Menu(3) %>
    ....
  <% end_loop %>
<% else %>
  <% loop $Children %>
    ...
  <% end_loop %>
<% end_if %>

by UncleCheese at 11:22am, 2 June 2015

The whole admin part is not working at all for me. Putting /admin in the browser just gives me a 404. Using Windows 8.1, WAMP, so far the tutorial has been a rather smooth ride.

by Joel at 05:06am, 13 October 2015

Try using /index.php/admin instead - I had this problem as well (though I'm using Ubuntu), and it was a mod_rewrite issue (when you installed SilverStripe, I expect there was a warning about mod_rewrite not being active or something) - I found this explanation to sort it out on Windows, but not having WAMP on Windows I don't know if it works or not I'm afraid! www.orchidbox.com/post.php?title=How_to_enable_mod_rewrite_module_in_apache_in_xampp_wamp

by Richard at 12:44pm, 26 October 2015

When I want to go to about us from the home page (localhost/silversprite/about-us) it does not work but i have to go to (localhost/silversprite/mysite/about-us)

by Tim at 01:52am, 13 April 2016

What happens if i have some pages I don't want to show in my menus?

For example I have "thank you" page which shows up when somebody send inquiry via web form, but I don't want people to see it in my menu?

Can i somehow exclude this page from menu?

by Fran at 08:57am, 28 October 2016

Nice tutorials. I love learning from them. very briefly explained. just one questions: When we add nav menu, it picks up menus of the simple template, where does the nav menu of our new theme goes and how can we call that menu in our theme.

by Himanshu at 07:38pm, 3 March 2017

Stuck on something? Have something to share? Don't be shy!

Keep learning!

Migrating static templates into your theme

In this tutorial, we’ll migrate a static site into your SilverStripe project. HTML, CSS, and JavaScript will provide a nice common ground and starting point for...

Creating your first theme

In this tutorial, we’ll cover how to build your first theme in SilverStripe. The SilverStripe installer ships with its own default theme -- Simple, but more...

Up and Running: Setting up a local SilverStripe dev environment

In this introductory lesson, we cover installing a local webserver (e.g. MAMP), installing and using Composer, and configuring an _ss_environment.php file. Having a finely tuned local...