Merge pull request #585 from adrexia/Documentation

Update Tutorials (part 1 and 2)
This commit is contained in:
Sam Minnée 2012-06-27 21:29:33 -07:00
commit 7d16e4caf0
10 changed files with 220 additions and 222 deletions

View File

@ -4,8 +4,7 @@
Welcome to the first in this series of tutorials on the SilverStripe Content Management System (CMS). Welcome to the first in this series of tutorials on the SilverStripe Content Management System (CMS).
These tutorials are designed to take you from an absolute beginner to being able to build large, complex websites with These tutorials are designed to take you from an absolute beginner to being able to build large, complex websites with SilverStripe. We assume to begin with, that you have some XHTML, CSS and PHP knowledge. This first tutorial provides an absolute
SilverStripe. We assume to begin with, that you have some XHTML, CSS and PHP knowledge. This first tutorial provides an absolute
introduction to building a simple website using SilverStripe. It will also teach you how to use the content management system at a basic level. introduction to building a simple website using SilverStripe. It will also teach you how to use the content management system at a basic level.
## What are we working towards? ## What are we working towards?
@ -16,8 +15,7 @@ templates - one for the home page, and one for the rest of the site.
## Installation ## Installation
You need to [download the SilverStripe software](http://www.silverstripe.org/stable-download) and install it to your local You need to [download the SilverStripe software](http://www.silverstripe.org/stable-download) and install it to your local machine or to a webserver.
machine or to a webserver.
For more infomation about installing and configuring a webserver read the [Installation instructions and videos](../installation). For more infomation about installing and configuring a webserver read the [Installation instructions and videos](../installation).
@ -27,7 +25,7 @@ This tutorial uses the SilverStripe CMS default theme 'Simple' which you will fi
After installation, open up the folder where you installed SilverStripe. After installation, open up the folder where you installed SilverStripe.
If you installed on windows with WAMP, it will likely be at *c:\wamp\wwww*. On Mac OS X with MAMP, it will likely be at */Applications/MAMP/htdocs/* If you installed on windows with WAMP, it will likely be at *c:\wamp\wwww*. On Mac OS X, using the built in webserver, it will be in your sites directory */Sites/* (with MAMP, it will likely be at */Applications/MAMP/htdocs/*)
Let's have a look at the folder structure. Let's have a look at the folder structure.
@ -36,8 +34,8 @@ Let's have a look at the folder structure.
| assets/ | | Contains images and other files uploaded via the SilverStripe CMS. You can also place your own content inside it, and link to it from within the content area of the CMS. | | assets/ | | Contains images and other files uploaded via the SilverStripe CMS. You can also place your own content inside it, and link to it from within the content area of the CMS. |
| cms/ | | Contains all the files that form the CMS area of your site. Its structure is similiar to the mysite/ directory, so if you find something interesting, it should be easy enough to look inside and see how it was built. | | cms/ | | Contains all the files that form the CMS area of your site. Its structure is similiar to the mysite/ directory, so if you find something interesting, it should be easy enough to look inside and see how it was built. |
| framework/ | | The framework that builds both your own site and as the CMS that powers it. Youll be utilizing files in this directory often, both directly and indirectly. | | framework/ | | The framework that builds both your own site and as the CMS that powers it. Youll be utilizing files in this directory often, both directly and indirectly. |
| mysite/ | | Contains all your sites code (mainly PHP and JavaScript) | | mysite/ | | Contains all your sites code (mainly PHP) |
| themes/ | | Combines all images, stylesheets and templates powering your website into a reusable "theme" | | themes/ | | Combines all images, stylesheets, javascript and templates powering your website into a reusable "theme" |
When designing your site you should only need to modify the *mysite*, *themes* and *assets* folders. The rest of the folders contain files and data that are not specific to any site. When designing your site you should only need to modify the *mysite*, *themes* and *assets* folders. The rest of the folders contain files and data that are not specific to any site.
@ -47,43 +45,34 @@ When designing your site you should only need to modify the *mysite*, *themes* a
![](_images/tutorial1_cms-basic.jpg) ![](_images/tutorial1_cms-basic.jpg)
The CMS is the area in which you can manage your site content. You can access the cms at http://localhost/admin (or http://yourdomain.com/admin if you are using you own domain name). You The CMS is the area in which you can manage your site content. You can access the cms at http://localhost/your_site_name/admin (or http://yourdomain.com/admin if you are using you own domain name). You
will be presented with a login screen. You can login with the details you provided at installation. After logging in you will be presented with a login screen. Login using the details you provided at installation. After logging in you
should be greeted with the CMS and a list of the pages currently in the CMS. Here you can add, delete and reorganize the pages using the buttons at the top. Clicking on a page will open it in the page editing interface pictured below (we've entered some test content). should see the CMS interface with a list of the pages currently on your website (the site tree). Here you can add, delete and reorganize pages. If you need to delete, publish, or unpublish a page, first check "multi-selection" at the top. You will then be able to perform actions on any checked files using the "Actions" dropdown. Clicking on a page will open it in the page editing interface pictured below (we've entered some test content).
![](_images/tutorial1_cms-numbered.jpg) ![](_images/tutorial1_cms-numbered.jpg)
1. These buttons allow you to move between the different sections in the CMS. There are four core sections in the CMS - "Pages", "Files", "Users" and "Settings". Modules may have their own sections here as well, if any are installed. In this tutorial we will be focusing on the "Pages" section. 1. This menu allows you to move between different sections of the CMS. There are four core sections - "Pages", "Files", "Users" and "Settings". If you have modules installed, they may have their own sections here. In this tutorial we will be focusing on the "Pages" section.
2. While in "Pages" you can quickly move between the pages in the CMS by clicking the vertical bar between the CMS menu and the editor. This will slide out a sidebar. To hide this, click the arrow at the bottom of the sidebar. 2. The breadcrumbs on the left will show you a direct path to the page you are currently looking at. You can use this path to navigate up through a page's heirarchy. On the left there are tabs you may use to flick between different aspects of a page. By default, you should be shown three tabs: "Content", "Settings", and "History".
* Content - Allows you to set the title, wysiwyg content, URL and Meta data for your page.
![](_images/tutorial1_cms-numbered-2b.jpg) * Settings - Here you set the type of page behavior, parent page, show in search, show in menu, and who can view or edit the page.
* History - This allows you to view previous version of your page, compare change and revert to previous version if need be.
3. This section allows you to edit the content for the currently selected page, as well as changing other properties of the page such as the page name and URL. The content editor has full [WYSIWYG](http://en.wikipedia.org/wiki/WYSIWYG) abilities, allow you to change formatting and insert links, images and tables. 3. Within the "Pages" section (provided you are in the "Content", or "Settings" tab) you can quickly move between pages in the CMS using the site tree. To collapse and expand this sidebar, click the arrow at the bottom. If you are in the history tab, you will notice the site tree has been replaced by a list of the alterations to the current page.
4. These buttons allow you to save your changes to the draft copy, publish your draft copy, unpublish from the live website or remove a page from the draft website. ![](_images/tutorial1_cms-numbered-3.jpg)
The SilverStripe CMS workflow stores two copies of a page, a draft and a published one. By having separate draft & published copies, we can preview draft changes in the site before publishing them to the live website. You can quickly preview your draft pages without leaving the CMS by clicking the "Preview" button. 4. This section allows you to edit the content for the currently selected page, as well as changing other properties of the page such as the page name and URL. The content editor has full [WYSIWYG](http://en.wikipedia.org/wiki/WYSIWYG) abilities, allow you to change formatting and insert links, images and tables.
5. These buttons allow you to save your changes to the draft copy, publish your draft copy, unpublish from the live website or remove a page from the draft website. The SilverStripe CMS workflow stores two copies of a page, a draft and a published one. By having separate draft & published copies, we can preview draft changes in the site before publishing them to the live website. You can quickly preview your draft pages without leaving the CMS by clicking the "Preview" button.
### Page Editor
Once you have selected a page to modify from the Pages section your page will open in the Page Editior.
The Edit Page section has 3 main areas in which you can edit the content of the page, change the settings and track your revision history (These will be covered in more detail further on in the tutorials).
![](_images/tutorial1_editpage-numbered.jpg)
1. *Content* - Allows you to set the title, wysiwyg content, URL and Meta data for your page.
2. *Settings* - Here you set the type of page behavior, parent page, show in search, show in menu, and who can view or edit the page.
3. *History* - This allow you to view previous version of your page, compare change and revert to previous version if need be.
![](_images/tutorial1_cms-numbered-5.jpg)
### Try it ### Try it
There are three pages already created for you - "Home", "About Us" and "Contact Us", as well as a 404 page. Experiment There are three pages already created for you - "Home", "About Us" and "Contact Us", as well as a 404 page. Experiment
with the editor - try different formatting, tables and images. When you are done, click "Save" to save the page or "Save with the editor - try different formatting, tables and images. When you are done, click "Save Draft" or "Save
& Publish" to post the content to the live site. & Publish" to post the content to the live site.
When you create a new page, you are given a drop down that allows you to set the structure of the page (Top level or Under another page) and the page type. ### New pages
The page type specifies the templates used to render the page, the fields that are able to be edited in the CMS, and page specific To create a new page, click the add new button above the site tree.
behavior. We will explain page types in more depth as we progress; for now, make all pages of the type "Page". When you create a new page, you are given the option of setting the structure of the page (Top level or Under another page) and the page type.
The page type specifies the templates used to render the page, the fields that are able to be edited in the CMS, and page specific behavior. We will explain page types in more depth as we progress; for now, make all pages of the type "Page".
![](_images/tutorial1_addpage.jpg) ![](_images/tutorial1_addpage.jpg)
@ -116,31 +105,47 @@ for a template file in the *simple/templates* folder, with the name `<PageType>`
Open *themes/simple/templates/Page.ss*. It uses standard HTML apart from these exceptions: Open *themes/simple/templates/Page.ss*. It uses standard HTML apart from these exceptions:
`<% base_tag %>` is replaced with the HTML [base element](http://www.w3.org/TR/html401/struct/links.html#h-12.4). This :::ss
<% base_tag %>
The base_tag variable is replaced with the HTML [base element](http://www.w3.org/TR/html401/struct/links.html#h-12.4). This
ensures the browser knows where to locate your site's images and css files. ensures the browser knows where to locate your site's images and css files.
*$MetaTitle, $Title, and $SiteConfig.Title* in the html <title> tag are replaced by the title set in the Meta tags, Page Name, or Settings -> Site Title. :::ss
$MetaTitle
$Title
$SiteConfig.Title
*$Title* is simply replaced with the name of the page ('Page name' on the 'Main' tab in the editor). These three variables are found within the html <title> tag, and are replaced by the text set in the Meta Title, Page Name, or Settings -> Site Title in the CMS.
:::ss
$MetaTags
*$MetaTags* adds meta tags for search engines, as well as the page title ('Title' on the 'Meta-data' tab in the The MetaTags variable will add meta tags, which are used by search engines. You can define your meta tags in the tab fields at the bottom of the content editor in the CMS.
editor). You can define your metatags in the meta-data tab off the content editor in the CMS. :::ss
$Layout
*$Layout* is replaced with the contents of a template file with the same name as the page type we are using. The Layout variable is replaced with the contents of a template file with the same name as the page type we are using.
Open *themes/simple/templates/Layout/Page.ss*. You will see more HTML and more SilverStripe template replacement tags and variables. Open *themes/simple/templates/Layout/Page.ss*. You will see more HTML and more SilverStripe template replacement tags and variables.
:::ss
$Content
*$Content* is replaced with the content of the page currently being viewed. This allows you to make all changes to The Content variable is replaced with the content of the page currently being viewed. This allows you to make all changes to
your site's content in the CMS. your site's content in the CMS.
These template markers are processed by SilverStripe into HTML before being sent to your These template markers are processed by SilverStripe into HTML before being sent to your
browser and are formatted either with a *$* at the beginning or are between the SilverStripe template tags *`<% %>`*. browser and are formatted either with a *$* at the beginning or are between the SilverStripe template tags:
:::ss
<% %>
**Flushing the cache** **Flushing the cache**
Whenever we edit a template file, we need to append *?flush=1* onto the end of the URL, e.g. Whenever we edit a template file, we need to append *?flush=all* onto the end of the URL, e.g.
http://localhost/home/?flush=1. SilverStripe stores template files in a cache for quicker load times. Whenever there are http://localhost/your_site_name/?flush=all. SilverStripe stores template files in a cache for quicker load times. Whenever there are
changes to the template, we must flush the cache in order for the changes to take effect. changes to the template, we must flush the cache in order for the changes to take effect.
## The Navigation System ## The Navigation System
@ -149,16 +154,23 @@ We are now going to look at how the navigation system is implemented in the temp
Open up *themes/simple/templates/Includes/Navigation.ss* Open up *themes/simple/templates/Includes/Navigation.ss*
Menu for our site are created using a **loop**. Loops allow us to iterate over a data set, and render each item using a sub-template. The The Menu for our site is created using a **loop**. Loops allow us to iterate over a data set, and render each item using a sub-template.
**loop** *Menu(1)* returns the set of the first level menu items. We can then use the template variable
*$MenuTitle* to show the title of the page we are linking to, $Link for the URL of the page and $LinkingMode to help style our menu with CSS (explained in more detail shortly). :::ss
<% loop Menu(1) %>
returns a set of first level menu items. We can then use the template variable
*$MenuTitle* to show the title of the page we are linking to, *$Link* for the URL of the page and *$LinkingMode* to help style our menu with CSS (explained in more detail shortly).
> *$Title* refers to **Page Name** in the CMS, whereas *$MenuTitle* refers to (the often shorter) **Navigation label**
> $Title refers to *Page Name* in the CMS, whereas $MenuTitle refers to (the often shorter) *Navigation label*
:::ss :::ss
<ul> <ul>
<% loop Menu(1) %> <% loop Menu(1) %>
<li class="$LinkingMode"><a href="$Link" title="$Title.XML">$MenuTitle.XML</a></li> <li class="$LinkingMode">
<a href="$Link" title="$Title.XML">$MenuTitle.XML</a>
</li>
<% end_loop %> <% end_loop %>
</ul> </ul>
@ -171,20 +183,41 @@ This creates the navigation at the top of the page:
## Highlighting the current page ### Highlighting the current page
A useful feature is highlighting the current page the user is looking at. We can do this with the template variable A useful feature is highlighting the current page the user is looking at. We can do this with the template variable:
*$LinkingMode* which we mentioned before. *$LinkingMode* returns one of three values: :::ss
$LinkingMode
* *current* - This page is being visited, and should be highlighted *$LinkingMode* returns one of three values:
* *link* - The page is not currently being visited, so shouldn't be highlighted
* *section* - A page under this page is being visited so you probably want to highlight it.
> For example: if you were visiting a staff member such as "Home > Company > Staff > Bob Smith", you would want to highlight 'Company' to say you are in that section. * *current* - This page is being visited
* *link* - This page is not currently being visited
* *section* - A page under this page is being visited
Highlighting the current page is easy, simply assign a css class based on the value of *$LinkingMode*. Then provide a different style for current/section in css, as has been provided for you in *simple/css/layout.css*. > For example, if you were here: "Home > Company > Staff > Bob Smith", you may want to highlight 'Company' to say you are in that section. If you add $LinkingMode to your navigation elements as a class, ie:
:::ss
<li class="$LinkingMode">
<a href="$Link" title="$Title.XML">$MenuTitle.XML</a>
</li>
![](_images/tutorial1_menu-highlighted.jpg) you will then be able to target a section in css (*simple/css/layout.css*), ie:
:::css
.section {
background:#ccc;
}
You may also style the link to the current page this way, eg:
:::css
.current {
/* Your styles here */
}
Or, target links that are neither current nor in the same section as the current link, eg:
:::css
.link {
/* Your styles here */
}
## A second level of navigation ## A second level of navigation
@ -201,16 +234,19 @@ Either way, your site tree should now look something like this:
![](_images/tutorial1_2nd_level-cut.jpg) ![](_images/tutorial1_2nd_level-cut.jpg)
Great, we now have a hierarchical site structure, let's now look at how this is created and displayed in our template. Great, we now have a hierarchical site structure! Let's look at how this is created and displayed in our template.
Adding a second level menu is very similar to adding the first level menu. Adding a second level menu is very similar to adding the first level menu. Open up */themes/simple/templates/Includes/Sidebar.ss* template and look at the following code:
Open up */themes/simple/templates/Includes/Sidebar.ss* template and look at the following code:
:::ss :::ss
<ul> <ul>
<% loop Menu(2) %> <% loop Menu(2) %>
<li class="$LinkingMode"><a href="$Link" title="Go to the $Title.XML page"><span class="arrow">&rarr;</span><span class="text">$MenuTitle.XML</span></a></li> <li class="$LinkingMode">
<a href="$Link" title="Go to the $Title.XML page">
<span class="arrow">&rarr;</span>
<span class="text">$MenuTitle.XML</span>
</a>
</li>
<% end_loop %> <% end_loop %>
</ul> </ul>
@ -228,7 +264,12 @@ like this:
... ...
<ul> <ul>
<% loop Menu(2) %> <% loop Menu(2) %>
<li class="$LinkingMode"><a href="$Link" title="Go to the $Title.XML page"><span class="arrow">&rarr;</span><span class="text">$MenuTitle.XML</span></a></li> <li class="$LinkingMode">
<a href="$Link" title="Go to the $Title.XML page">
<span class="arrow">&rarr;</span>
<span class="text">$MenuTitle.XML</span>
</a>
</li>
<% end_loop %> <% end_loop %>
</ul> </ul>
... ...
@ -244,37 +285,45 @@ Open up */themes/simple/templates/Includes/BreadCrumbs.ss* template and look at
:::ss :::ss
<% if Level(2) %> <% if Level(2) %>
<div id="Breadcrumbs"> <div id="Breadcrumbs">
$Breadcrumbs $Breadcrumbs
</div> </div>
<% end_if %> <% end_if %>
Breadcrumbs are only useful on pages that aren't in the top level. We can ensure that we only show them if we aren't in Breadcrumbs are only useful on pages that aren't in the top level. We can ensure that we only show them if we aren't in
the top level with another if statement. the top level with another if statement.
The *Level* page control allows you to get data from the page's parents, e.g. if you used *Level(1)*, you could use The *Level* page control allows you to get data from the page's parents, e.g. if you used *Level(1)*, you could use:
*$Level(1).Title* to get the top level page title. In this case, we merely use it to check the existence of a second
level page; if one exists then we include the breadcrumbs. :::ss
$Level(1).Title
This shows how the two level navigation system functions. Both menus should be updating and highlighting as you move to get the top level page title. In this case, we merely use it to check the existence of a second level page: if one exists then we include breadcrumbs.
from page to page. They will also mirror changes done in the SilverStripe CMS, such as renaming pages or moving them
around. Both the top menu, and the sidebar menu should be updating and highlighting as you move from page to page. They will also mirror changes done in the SilverStripe CMS, such as renaming pages or moving them around.
![](_images/tutorial1_menu-two-level.jpg) ![](_images/tutorial1_menu-two-level.jpg)
Feel free to experiment with the if and loop blocks, for example you could create a drop down style menu from the top navigation using a combination of the if blocks, loop blocks and some CSS to style it. This uses a *Children* if and loop block which checks to see if there is any sub-pages available within each top level navigation item, you will need to come up with your own CSS to correctly style this approach. Feel free to experiment with the if and loop statements, for example you could create a drop down style menu from the top navigation using a combination of if statements, loops and some CSS to style it.
::ss The following example runs an if statement, and a loop on *Children*, checking to see if any sub-pages exist within each top level navigation item, you will need to come up with your own CSS to correctly style this approach.
:::ss
<ul> <ul>
<% loop Menu(1) %> <% loop Menu(1) %>
<li class="$LinkingMode"> <li class="$LinkingMode">
<a href="$Link" title="$Title.XML">$MenuTitle.XML</a> <a href="$Link" title="$Title.XML">$MenuTitle.XML</a>
<% if Children %> <% if Children %>
<ul> <ul>
<% loop Children %> <% loop Children %>
<li class="$LinkingMode"><a href="$Link" title="Go to the $Title.XML page"><span class="arrow">&rarr;</span><span class="text">$MenuTitle.XML</span></a></li> <li class="$LinkingMode">
<% end_loop %> <a href="$Link" title="Go to the $Title.XML page">
<ul> <span class="arrow">&rarr;</span>
<span class="text">$MenuTitle.XML</span>
</a>
</li>
<% end_loop %>
<ul>
<% end_if %> <% end_if %>
</li> </li>
<% end_loop %> <% end_loop %>
@ -282,7 +331,6 @@ Feel free to experiment with the if and loop blocks, for example you could creat
## Using a different template for the home page ## Using a different template for the home page
So far, a single template layout *Layouts/Page.ss* is being used for the entire site. This is useful for the purpose of this So far, a single template layout *Layouts/Page.ss* is being used for the entire site. This is useful for the purpose of this
@ -294,8 +342,7 @@ banner to welcome visitors.
### Creating a new page type ### Creating a new page type
Earlier we stated that every page in a SilverStripe site has a **page type**, and that SilverStripe will look for a Earlier we stated that every page in a SilverStripe site has a **page type**, and that SilverStripe will look for a
template or template layout corresponding to the page type. Therefore, the first step to get the homepage using a different template is to template, or template layout, corresponding to the page type. Therefore, the first step when switching the homepage template is to create a new page type.
create a new page type.
Each page type is represented by two php classes: a *data object* and a *controller*. Don't worry about the details of page Each page type is represented by two php classes: a *data object* and a *controller*. Don't worry about the details of page
types right now, we will go into much more detail in tutorial two. types right now, we will go into much more detail in tutorial two.
@ -321,7 +368,7 @@ Create a new file *HomePage.php* in *mysite/code*. Copy the following code into
Every page type also has a database table corresponding to it. Every time we modify the database, we need to rebuild it. Every page type also has a database table corresponding to it. Every time we modify the database, we need to rebuild it.
We can do this by going to [http://localhost/dev/build?flush=1](http://localhost/dev/build?flush=1) or replace *localhost* with your own domain name. We can do this by going to [http://localhost/your_site_name/dev/build?flush=all](http://localhost/your_site_name/dev/build?flush=1) (replace *localhost/your_site_name* with your own domain name if applicable).
It may take a moment, so be patient. This add tables and fields needed by your site, and modifies any structures that have changed. It It may take a moment, so be patient. This add tables and fields needed by your site, and modifies any structures that have changed. It
does this non-destructively - it will never delete your data. does this non-destructively - it will never delete your data.
@ -332,7 +379,7 @@ As we have just created a new page type, SilverStripe will add this to the list
After building the database, we can change the page type of the homepage in the CMS. After building the database, we can change the page type of the homepage in the CMS.
Navigate in the CMS to the "Home" page and under the "Behaviour" tab in the "Edit Page > Settings" section. Change it to *Home Page*, and click "Save & Publish". In the CMS, navigate to the "Home" page and switch to the "Settings" tab. Change "Page type" to *Home Page*, and click "Save & Publish".
![](_images/tutorial1_homepage-type.jpg) ![](_images/tutorial1_homepage-type.jpg)
@ -345,11 +392,20 @@ to the template of the page type's parents.
### Creating a new template ### Creating a new template
To create a new template layout, create a copy of *Page.ss* (found in *themes/simple/templates/Layouts*) and call it *HomePage.ss*. If we flush the cache (*?flush=1*), SilverStripe should now be using *HomePage.ss* for the homepage, and *Page.ss* for the rest of the site. Now let's customize the *HomePage* template. To create a new template layout, create a copy of *Page.ss* (found in *themes/simple/templates/Layouts*) and call it *HomePage.ss*. If we flush the cache (*?flush=all*), SilverStripe should now be using *HomePage.ss* for the homepage, and *Page.ss* for the rest of the site. Now let's customize the *HomePage* template.
First, remove the breadcrumbs and the secondary menu by removing the `<% include SideBar %>` line of code; we don't need them for the homepage. Let's replace the title with an image. Add this line above the *$Content* variable. First, remove the breadcrumbs and the secondary menu by removing:
:::ss
<% include SideBar %>
we don't need it for the homepage.
Now add the following to replace the `<h1>$Title</h1>` code in your template: Let's replace the title with an image. Find this line:
:::ss
<h1>$Title</h1>
and replace it with:
:::ss :::ss
<div id="Banner"> <div id="Banner">
@ -365,21 +421,16 @@ Your Home page should now look like this:
SilverStripe first searches for a template in the *themes/simple/templates* folder. Since there is no *HomePage.ss*, SilverStripe first searches for a template in the *themes/simple/templates* folder. Since there is no *HomePage.ss*,
it will use the *Page.ss* for both *Page* and *HomePage* page types. When it comes across the *$Layout* tag, it will it will use the *Page.ss* for both *Page* and *HomePage* page types. When it comes across the *$Layout* tag, it will
then descend into the *themes/simple/templates/Layout* folder, and will use *Page.ss* for the *Page* page type, and then descend into the *themes/simple/templates/Layout* folder, and will use *Page.ss* for the *Page* page type, and
*HomePage.ss* for the *HomePage* page type. So while you could create a HomePage.ss in the *themes/simple/templates/* it is better to reuse the navigation and footer common to both our Home page and the rest of the pages on our website and lets you write less code to achieve the end result. *HomePage.ss* for the *HomePage* page type. So while you could create a HomePage.ss in the *themes/simple/templates/* it is better to reuse the navigation and footer common to both our Home page and the rest of the pages on our website.
![](_images/tutorial1_subtemplates-diagram.jpg) ![](_images/tutorial1_subtemplates-diagram.jpg)
## Summary ## Summary
We have introduced template variables, controls and if blocks, and we have used these So far we have taken a look at the different areas and functionality within the pages area of the CMS. We have learnt about template variables, controls and if statements and used these to build a basic, but fully functional, website. We have also briefly covered page types, and looked at how they correspond to templates and sub-templates. Using this knowledge, we have customized our website's homepage design.
to build a basic but fully functional site. You have also been briefly introduced to page types, and seen how they
correspond to templates and sub-templates. By using these templates, you have seen how to customize the site content
according to the page type of the page you are displaying.
In the next tutorial, [Extending a Basic Site](2-extending-a-basic-site), we will explore page types on a In the next tutorial, [Extending a Basic Site](2-extending-a-basic-site), we will explore page types on a deeper level, and look at customising our own page types to extend the functionality of SilverStripe.
deeper level, and see how you can customize your own page types to extend SilverStripe to do much more interesting
things.
[Next Tutorial >>](2-extending-a-basic-site) [Next Tutorial >>](2-extending-a-basic-site)

View File

@ -3,58 +3,49 @@
## Overview ## Overview
In the [first tutorial](1-building-a-basic-site) we learned how to create a basic site using SilverStripe. This In the [first tutorial](1-building-a-basic-site) we learnt how to create a basic site using SilverStripe. This tutorial will build on that, and explore extending SilverStripe by creating our own page types. After doing this we should have a better understanding of how SilverStripe works.
tutorial builds on what you have learned in [the first tutorial](1-building-a-basic-site), so it is recommended
that you complete it first.
In this tutorial you will explore extending SilverStripe by creating your own page types. In doing this you will get a
good overview of how SilverStripe works.
## What are we working towards? ## What are we working towards?
Throughout this tutorial we are going to work on adding two new sections to the site we built in the first tutorial. The We are going to work on adding two new sections to the site we built in the first tutorial.
first is a news section, with a recent news listing on the homepage and an RSS feed. The second is a staff section,
which demonstrates more complex database structures by associating an image with each staff member. The first of these new sections will be *News*, with a recent news listing on the homepage and an RSS feed:
![](_images/tutorial2_newslist.jpg) ![](_images/tutorial2_newslist.jpg)
The second will be a *Staff* section, to demonstrate more complex database structures (such as associating an image with each staff member):
![](_images/tutorial2_einstein.jpg) ![](_images/tutorial2_einstein.jpg)
## The SilverStripe data model ## The SilverStripe data model
A large part of designing complex SilverStripe sites is the creation of your own page types. Before we progress any A large part of designing complex SilverStripe sites is the creation of our own page types. Before we progress any further, it is important to understand what a page type is and how the SilverStripe data model works.
further, it is important to understand what a page type is, and how the SilverStripe data model works.
SilverStripe is based on the **"Model-View-Controller"** design pattern. This means that SilverStripe attempts to separate SilverStripe is based on the **"Model-View-Controller"** design pattern. This means that SilverStripe attempts to separate data, logic and presentation as much as possible. Every page has three separate parts which are combined to give you the
data, logic and presentation as much as possible. Every page has three separate parts which are combined to give you the
final page. Lets look at each one individually: final page. Lets look at each one individually:
### Model ### Model
All content on your site is stored in a database. There is a table in the database corresponding for every class that is All content on our site is stored in a database. Each class that is a child of the `[api:DataObject]` class will have its own table in our database.
a child of the `[api:DataObject]` class. Every object of that class corresponds to a row in that table -
this is your "data object", the **"model"** of Model-View-Controller. A page type has a data object that represents all the data for your page - rather than inheriting Every object of such a class will correspond to a row in that table -
directly from data object it inherits from `[api:SiteTree]`. We generally create a "Page" data object, and subclass this for this is our "data object", the **"model"** of Model-View-Controller. A page type has a data object that represents all the data for our page. Rather than inheriting
the rest of the page types. This allows us to define behavior that is consistent across all pages in our site. directly from `[api:DataObject]`, it inherits from `[api:SiteTree]`. We generally create a "Page" data object, and subclass this for all other page types. This allows us to define behavior that is consistent across all pages in our site.
### View ### View
The **"view"** is the presentation of your site. As we have already seen, the templates SilverStripe uses to render a page The **"view"** is the presentation of our site. As we have already seen, the templates SilverStripe uses to render a page are dependent on the page type. Using templates and css, we are able to have full control over the
is dependent on the page type. Using both your templates and css, you are able to have full control over the presentation of our website.
presentation of your site.
### Controller ### Controller
A page type also has a **"controller"**. A controller contains all the code used to manipulate your data before it is Each page type also has a **"controller"**. The controller contains all the code used to manipulate our data before it is rendered. For example, suppose we were making an auction site, and we only wanted to display the auctions closing in the next ten minutes. We would implement this logic in the controller. The controller for a page should inherit from `[api:ContentController]`. Just as we create a "Page" data object and subclass it for the rest of the site, we also create a "Page_Controller" that is subclassed.
rendered. For example, suppose you were making an auction site, and you only wanted to display the auctions closing in
the next ten minutes. You would implement this in the controller. The controller for a page should inherit from
`[api:ContentController]`. Just as we create a "Page" data object and subclass it for the rest of the
site, we also create a "Page_Controller" that is subclassed.
Creating a new page type simply requires creating these three things. You can then have full control over presentation,
the database, which fields can be edited in the CMS, and can use code to make our pages do much more clever things. Creating a new page type requires creating each of these three elements. We will then have full control over presentation, the database, and editable CMS fields.
A more in-depth introduction of Model-View-Controller can be found A more in-depth introduction of Model-View-Controller can be found
[here](http://www.slash7.com/articles/2005/02/22/mvc-the-most-vexing-conundrum). [here](http://www.slash7.com/articles/2005/02/22/mvc-the-most-vexing-conundrum).
@ -63,13 +54,9 @@ A more in-depth introduction of Model-View-Controller can be found
## Creating the news section page types ## Creating the news section page types
Let's make our news section. We'll need two new page types for this. The first one is obvious: we need an *ArticlePage* To create a news section we'll need two new page types. The first one is obvious: we need an *ArticlePage* page type. The second is a little less obvious: we need an *ArticleHolder* page type to contain our article pages.
page type. The second is a little less obvious: we need an *ArticleHolder* page type that contains our articles.
We'll start with the *ArticlePage* page type. First we create the model, a class called "ArticlePage". We put the We'll start with the *ArticlePage* page type. First we create the model, a class called "ArticlePage". We put the *ArticlePage* class into a file called "ArticlePage.php" inside *mysite/code*. All other classes relating to *ArticlePage* should be placed within "ArticlePage.php", this includes our controller (*ArticlePage_Controller*).
*ArticlePage* class into a file called "ArticlePage.php" inside *mysite/code*. We also put the controller,
*ArticlePage_Controller*, in here. Any other classes that are related to *ArticlePage* for example, the class
*ArticlePage_AnythingElse* - will also go into "ArticlePage.php".
**mysite/code/ArticlePage.php** **mysite/code/ArticlePage.php**
@ -91,9 +78,7 @@ We'll start with the *ArticlePage* page type. First we create the model, a class
Here we've created our data object/controller pair, but we haven't actually extended them at all. Don't worry about the Here we've created our data object/controller pair, but we haven't extended them at all. Don't worry about the *$db* and *$has_one* arrays just yet, we'll explain them shortly. SilverStripe will use the template for the *Page* page type as explained in the first tutorial, so we don't need
*$db* and *$has_one* arrays just yet, we'll explain them soon, as well as other ways in which you can extend your page
types. SilverStripe will use the template for the *Page* page type as explained in the first tutorial, so we don't need
to specifically create the view for this page type. to specifically create the view for this page type.
Let's create the *ArticleHolder* page type. Let's create the *ArticleHolder* page type.
@ -119,17 +104,12 @@ Let's create the *ArticleHolder* page type.
} }
Here we have done something interesting: the *$allowed_children* field. This is one of a number of static fields we can Here we have done something interesting: the *$allowed_children* field. This is one of a number of static fields we can define to change the properties of a page type. The *$allowed_children* field is an array of page types that are allowed
define to change the properties of a page type. The *$allowed_children* field is an array of page types that are allowed to be children of the page in the site tree. As we only want **news articles** in the news section, we only want pages of the type *ArticlePage* as children. We can enforce this in the CMS by setting the *$allowed_children* field within this class.
to be children of the page in the site tree. As we only want news articles in the news section, we only want
*ArticlePage* pages for children. We can enforce this in the CMS by setting the *$allowed_children* field.
We will be introducing other fields like this as we progress; there is a full list in the documentation for We will be introduced to other fields like this as we progress; there is a full list in the documentation for `[api:SiteTree]`.
`[api:SiteTree]`.
Now that we have created our page types, we need to let SilverStripe rebuild the database. If we rebuild the database by Now that we have created our page types, we need to let SilverStripe rebuild the database: [http://localhost/your_site_name/dev/build?flush=all](http://localhost/your_site_name/dev/build?flush=all). SilverStripe should detect that there are two new page types, and add them to the list of page types in the database.
going to [http://localhost/dev/build?flush=1](http://localhost/dev/build?flush=1), SilverStripe will detect that there are two
new page types and add them to the list of page types in the database.
> It is SilverStripe convention to suffix general page types with "Page", and page types that hold other page types with > It is SilverStripe convention to suffix general page types with "Page", and page types that hold other page types with
> "Holder". This is to ensure that we don't have URLs with the same name as a page type; if we named our *ArticleHolder* > "Holder". This is to ensure that we don't have URLs with the same name as a page type; if we named our *ArticleHolder*
@ -139,7 +119,7 @@ new page types and add them to the list of page types in the database.
Now that we have an *ArticlePage* page type, let's make it a little more useful. Remember the *$db* array? We can use Now that we have an *ArticlePage* page type, let's make it a little more useful. Remember the *$db* array? We can use
this array to add extra fields to the database. It would be nice to know when each article was posted, and who posted this array to add extra fields to the database. It would be nice to know when each article was posted, and who posted
it. Change the *$db* array in the *ArticlePage* class so it looks like this: it. Change the *$db* array in the *ArticlePage* class to look like this:
:::php :::php
<?php <?php
@ -153,17 +133,14 @@ it. Change the *$db* array in the *ArticlePage* class so it looks like this:
} }
Every entry in the array is a key-value pair. The key is the name of the field, and the value is the type. We have a Every entry in the array is a *key => value* pair. The **key** is the name of the field, and the **value** is the type. See *`[api:Date]`* for a complete list of data types associated with *Date*.
`[api:Date]` for a complete list of different data types.
> Note: The names chosen for the fields you add must not already be used. Be careful using field names such as Title, > Note: The names chosen for the fields you add must not already be used. Be careful using field names such as Title,
> Content etc. as these may already be defined in the page types your new page is extending from. > Content etc. as these may already be defined in the page types your new page is extending from.
If we rebuild the database, we will see that now the *ArticlePage* table is created. Even though we had an *ArticlePage* When we rebuild the database, we will see that the *ArticlePage* table has been created. Even though we had an *ArticlePage* page type before, a table was not created because there were no fields unique to the article page type. There are now extra fields in the database, but still no way of changing them.
page type before, the table was not created because we had no fields that were unique to the article page type. We now
have the extra fields in the database, but still no way of changing them. To add these fields to the CMS we have to To add our new fields to the CMS we have to override the *getCMSFields()* method, which is called by the CMS when it creates the form to edit a page. Add the method to the *ArticlePage* class.
override the *getCMSFields()* method, which is called by the CMS when it creates the form to edit a page. Add the
method to the *ArticlePage* class.
:::php :::php
<?php <?php
@ -201,19 +178,26 @@ returned is a `[api:FieldList]` object.
We can then add our new fields with *addFieldToTab*. The first argument is the tab on which we want to add the field to: We can then add our new fields with *addFieldToTab*. The first argument is the tab on which we want to add the field to:
"Root.Main" is the tab which the content editor is on (another is "Root.Metadata". The second argument is the field to add; this is not a database field, but a `[api:FormField]` - see the documentation for more details. "Root.Main" is the tab which the content editor is on. The second argument is the field to add; this is not a database field, but a `[api:FormField]` - see the documentation for more details.
We add two fields: A simple `[api:TextField}` and a `[api:DateField]`. There are many more FormFields available in the default installation, please refer to [Form Field Types](form-field-types) for the list. > Note: By default, the CMS only has one tab. Creating new tabs is much like adding to existing tabs. For instance:
> $fields->addFieldToTab('Root.NewTab', new TextField('Author'));
> would create a new tab called "New Tab", and a single "Author" textfield inside.
We have added two fields: A simple `[api:TextField]` and a `[api:DateField]`.
There are many more FormFields available in the default installation, please refer to [Form Field Types](form-field-types) for the list.
:::php :::php
return $fields; return $fields;
Finally, we return the fields to the CMS. If we flush the cache (by adding ?flush=1 at the end of the URL), we will be able Finally, we return the fields to the CMS. If we flush the cache (by adding ?flush=all at the end of the URL), we will be able to edit the fields in the CMS.
to edit the fields in the CMS.
Now that we have created our page types, let's add some content. Go into the CMS and create an *ArticleHolder* page Now that we have created our page types, let's add some content. Go into the CMS and create an *ArticleHolder* page named "News", then create a few *ArticlePage*'s within it.
named "News", and create some *ArticlePage*s inside it.
![](_images/tutorial2_news-cms.jpg) ![](_images/tutorial2_news-cms.jpg)
@ -259,24 +243,22 @@ Set *showCalendar* to true to have a calendar appear underneath the Date field w
:::php :::php
$dateField->setConfig('dateformat', 'dd/MM/YYYY'); $dateField->setConfig('dateformat', 'dd/MM/YYYY');
*dateFormat* allows you to specify how you wish the date to be entered and displayed in the CMS field. *dateFormat* allows you to specify how you wish the date to be entered and displayed in the CMS field. See the `[api:DateField]` documentation for more details of the DateField configuration.
:::php :::php
$fields->addFieldToTab('Root.Content', new TextField('Author','Author Name'), 'Content'); $fields->addFieldToTab('Root.Content', new TextField('Author','Author Name'), 'Content');
By default the field name *'Date'* or *'Author'* is shown as the title, however this might not be that helpful so to change the title, By default the field name *'Date'* or *'Author'* is shown as the title, however this might not be that helpful so to change the title, add the new title as the second argument.
add the new title as the second argument. See the `[api:DateField]` documentation for more details of the DateField configuration.
## Creating the templates ## Creating the templates
We can already look at the content of news pages on our site, because the article holder page and the article pages Because our new pages inherit their templates from *Page*, we can view anything entered in the content area when navigating to these pages on our site. However, as there is no reference to the date or author fields in the *Page* template this data is not being displayed.
inherit their templates from Page. But we're not getting the author and date fields displayed in either case.
So let's create a template for each of our new page types. We'll put these in *themes/tutorial/templates/Layout* so we To fix this we will create a template for each of our new page types. We'll put these in *themes/tutorial/templates/Layout* so we only have to define the page specific parts: SilverStripe will use *themes/tutorial/templates/Page.ss* for the basic
only have to define the page specific parts: SilverStripe will use *themes/tutorial/templates/Page.ss* for the basic
page layout. page layout.
###ArticlePage Template
First, the template for displaying a single article: First, the template for displaying a single article:
**themes/simple/templates/Layout/ArticlePage.ss** **themes/simple/templates/Layout/ArticlePage.ss**
@ -299,13 +281,9 @@ First, the template for displaying a single article:
Most of the code is just like the regular Page.ss, we include an informational div with the date and the author of the Article. Most of the code is just like the regular Page.ss, we include an informational div with the date and the author of the Article.
We use *$Date* and *$Author* to access the new fields. In fact, all template variables and page controls come from To access the new fields, we use *$Date* and *$Author*. In fact, all template variables and page controls come from either the data object or the controller for the page being displayed. The *$Title* variable comes from the *Title* field of the `[api:SiteTree]` class. *$Date* and *$Author* come from the *ArticlePage* table through your custom Page. *$Content* comes from the *SiteTree* table through the same data object. The data for your page is
either the data object or the controller for the page being displayed. The *$Title* variable comes from the
*Title* field of the `[api:SiteTree]` class. *$Date* and *$Author* come from the *ArticlePage* table through
your custom Page. *$Content* comes from the *SiteTree* table through the same data object. The data for your page is
spread across several tables in the database matched by id - e.g. *Content* is in the *SiteTree* table, and *Date* and spread across several tables in the database matched by id - e.g. *Content* is in the *SiteTree* table, and *Date* and
*Author* are in the *ArticlePage* table. SilverStripe matches these records by their ids and collates them into the single *Author* are in the *ArticlePage* table. SilverStripe matches this data, and collates it into a single data object.
data object.
![](_images/tutorial2_data-collation.jpg) ![](_images/tutorial2_data-collation.jpg)
@ -315,8 +293,8 @@ database.
![](_images/tutorial2_news.jpg) ![](_images/tutorial2_news.jpg)
Now we'll create a template for the article holder: we want our news section to show a list of news items, each with a ###ArticleHolder Template
summary. We'll now create a template for the article holder. We want our news section to show a list of news items, each with a summary and a link to the main article (our Article Page).
**themes/simple/templates/Layout/ArticleHolder.ss** **themes/simple/templates/Layout/ArticleHolder.ss**
@ -339,22 +317,18 @@ summary.
<% include SideBar %> <% include SideBar %>
Here we use the page control *Children*. As the name suggests, this control allows you to iterate over the children of a Here we use the page control *Children*. As the name suggests, this control allows you to iterate over the children of a page. In this case, the children are our news articles. The *$Link* variable will give the address of the article which we can use to create a link, and the *FirstParagraph* function of the `[api:HTMLText]` field gives us a nice summary of the article. The function strips all tags from the paragraph extracted.
page, which in this case is our news articles. The *$Link* variable will give the address of the article which we can
use to create a link, and the *FirstParagraph* function of the `[api:HTMLText]` field gives us a nice summary of the
article. The function strips all tags from the paragraph extracted.
![](_images/tutorial2_articleholder.jpg) ![](_images/tutorial2_articleholder.jpg)
### Using include files in templates ### Using include files in templates
You can make your templates more modular and easier to maintain by separating commonly-used pieces into include files. We can make our templates more modular and easier to maintain by separating commonly-used components in to *include files*. We are already familiar with the `<% include Sidebar %>` line from looking at the menu in the [first tutorial](1-building-a-basic-site).
You are already familiar with the `<% include Sidebar %>`-Line for the menu.
We'll separate the display of linked articles as we want to reuse this code later on. We'll separate the display of linked articles as we want to reuse this code later on.
Replace the code in *ArticleHolder.ss** with an include statement: Cut the code in *ArticleHolder.ss** and replace it with an include statement:
**themes/simple/templates/Layout/ArticleHolder.ss** **themes/simple/templates/Layout/ArticleHolder.ss**
@ -365,7 +339,7 @@ Replace the code in *ArticleHolder.ss** with an include statement:
<% end_loop %> <% end_loop %>
... ...
and paste the code in a new include snippet: Paste the code that was in ArticleHolder into a new include file called ArticleTeaser.ss:
**themes/simple/templates/Includes/ArticleTeaser.ss** **themes/simple/templates/Includes/ArticleTeaser.ss**
@ -397,9 +371,7 @@ This will change the icons for the pages in the CMS.
## Showing the latest news on the homepage ## Showing the latest news on the homepage
It would be nice to greet page visitors with a summary of the latest news when they visit the homepage. This requires a It would be nice to greet page visitors with a summary of the latest news when they visit the homepage. This requires a little more code though - the news articles are not direct children of the homepage, so we can't use the *Children* control. We can get the data for news articles by implementing our own function in *HomePage_Controller*.
little more code though - the news articles are not direct children of the homepage, so we can't use the *Children*
control. We can get the data for the news articles by implementing our own function in *HomePage_Controller*.
**mysite/code/HomePage.php** **mysite/code/HomePage.php**
@ -412,9 +384,7 @@ control. We can get the data for the news articles by implementing our own funct
... ...
This function simply runs a database query that gets the latest news articles from the database. By default, this is This function simply runs a database query that gets the latest news articles from the database. By default, this is five, but you can change it by passing a number to the function. See the [Data Model](../topics/datamodel) documentation for details. We can reference this function as a page control in our *HomePage* template:
five, but you can change it by passing a number to the function. See the [Data Model](../topics/datamodel) documentation for
details. We can reference this function as a page control in our *HomePage* template:
**themes/tutorial/templates/Layout/Homepage.ss** **themes/tutorial/templates/Layout/Homepage.ss**
@ -428,14 +398,9 @@ details. We can reference this function as a page control in our *HomePage* temp
... ...
When SilverStripe comes across a variable or page control it doesn't recognize, it first passes control to the When SilverStripe comes across a variable or page control it doesn't recognize, it first passes control to the controller. If the controller doesn't have a function for the variable or page control, it then passes control to the data object. If it has no matching functions, it then searches its database fields. Failing that it will return nothing.
controller. If the controller doesn't have a function for the variable or page control, it then passes control to the
data object. If it has no matching functions, it then searches its database fields. Failing that it will return nothing.
The controller for a page is only created when page is actually visited, while the data object is available when the The controller for a page is only created when page is actually visited, while the data object is available when the page is referenced in other pages, e.g. by page controls. A good rule of thumb is to put all functions specific to the page currently being viewed in the controller; only if a function needs to be used in another page should you put it in the data object.
page is referenced in other pages, e.g. by page controls. A good rule of thumb is to put all functions specific to the
page currently being viewed in the controller; only if a function needs to be used in another page should you put it in
the data object.
![](_images/tutorial2_homepage-news.jpg) ![](_images/tutorial2_homepage-news.jpg)
@ -443,8 +408,7 @@ the data object.
## Creating a RSS feed ## Creating a RSS feed
An RSS feed is something that no news section should be without. SilverStripe makes it easy to create RSS feeds by An RSS feed is something that no news section should be without. SilverStripe makes it easy to create RSS feeds by providing an `[api:RSSFeed]` class to do all the hard work for us. Create the following function in the
providing an `[api:RSSFeed]` class to do all the hard work for you. Create the following function in the
*ArticleHolder_Controller*: *ArticleHolder_Controller*:
:::php :::php
@ -454,18 +418,13 @@ providing an `[api:RSSFeed]` class to do all the hard work for you. Create the f
} }
This function simply creates an RSS feed of all the news articles, and outputs it to the browser. If you go to This function creates an RSS feed of all the news articles, and outputs it to the browser. If we go to [http://localhost/your_site_name/news/rss](http://localhost/your_site_name/news/rss) we should see our RSS feed. When there is more to a URL after a page's base URL, "rss" in this case, SilverStripe will call the function with that name on the controller if it exists.
[http://localhost/news/rss](http://localhost/news/rss) you will see our RSS feed. What happens here is that
when there is more to a URL after the page's base URL - "rss" in this case - SilverStripe will call the function with
that name on the controller if it exists.
Depending on your browser, you should see something like the picture below. If your browser doesn't support RSS, you Depending on your browser, you should see something like the picture below. If your browser doesn't support RSS, you will most likely see the XML output instead. For more on RSS, see `[api:RSSFeed]`
will most likely see the XML output instead.
![](_images/tutorial2_rss-feed.jpg) ![](_images/tutorial2_rss-feed.jpg)
Now all we need is to let the user know that our RSS feed exists. The `[api:RSSFeed]` in your controller, it will be Now all we need is to let the user know that our RSS feed exists. Add this function to *ArticleHolder_Controller*:
called when the page is requested. Add this function to *ArticleHolder_Controller*:
:::php :::php
public function init() { public function init() {
@ -474,17 +433,11 @@ called when the page is requested. Add this function to *ArticleHolder_Controlle
} }
This automatically generates a link-tag in the header of our template. The *init* function is then called on the parent This automatically generates a link-tag in the header of our template. The *init* function is then called on the parent class to ensure any initialization the parent would have done if we hadn't overridden the *init* function is still called. Depending on your browser, you can see the RSS feed link in the address bar.
class to ensure any initialization the parent would have done if we hadn't overridden the *init* function is still
called. Depending on your browser, you can see the RSS feed link in the address bar:
![](_images/tutorial2_rss.jpg)
## Adding a staff section ## Adding a staff section
Now that we have a complete news section, let's move on to the staff section. We need to create *StaffHolder* and Now that we have a complete news section, let's take a look at the staff section. We need to create *StaffHolder* and *StaffPage* page types, for an overview on all staff members and a detail-view for a single member. First let's start with the *StaffHolder* page type.
*StaffPage* page types, for an overview on all staff members and a detail-view for a single member. First let's start
with the *StaffHolder* page type.
**mysite/code/StaffHolder.php** **mysite/code/StaffHolder.php**
@ -505,9 +458,7 @@ with the *StaffHolder* page type.
} }
Nothing here should be new. The *StaffPage* page type is more interesting though. Each staff member has a portrait Nothing here should be new. The *StaffPage* page type is more interesting though. Each staff member has a portrait image. We want to make a permanent connection between this image and the specific *StaffPage* (otherwise we could simply insert an image in the *$Content* field).
image. We want to make a permanent connection between this image and the specific *StaffPage* (otherwise we could simply
insert an image in the *$Content* field).
**mysite/code/StaffPage.php** **mysite/code/StaffPage.php**
@ -535,10 +486,7 @@ insert an image in the *$Content* field).
} }
Instead of adding our *Image* as a field in *$db*, we have used the *$has_one* array. This is because an *Image* is not Instead of adding our *Image* as a field in *$db*, we have used the *$has_one* array. This is because an *Image* is not a simple database field like all the fields we have seen so far, but has its own database table. By using the *$has_one* array, we create a relationship between the *StaffPage* table and the *Image* table by storing the id of the respective *Image* in the *StaffPage* table.
a simple database field like all the fields we have seen so far, but has its own database table. By using the *$has_one*
array, we create a relationship between the *StaffPage* table and the *Image* table by storing the id of the respective
*Image* in the *StaffPage* table.
We then add an `[api:UploadField]` in the *getCMSFields* function to the tab "Root.Images". Since this tab doesn't exist, We then add an `[api:UploadField]` in the *getCMSFields* function to the tab "Root.Images". Since this tab doesn't exist,
the *addFieldToTab* function will create it for us. The *UploadField* allows us to select an image or upload a new one in the *addFieldToTab* function will create it for us. The *UploadField* allows us to select an image or upload a new one in
@ -546,7 +494,7 @@ the CMS.
![](_images/tutorial2_photo.jpg) ![](_images/tutorial2_photo.jpg)
Rebuild the database ([http://localhost/dev/build?flush=1](http://localhost/dev/build?flush=1)) and open the CMS. Create Rebuild the database ([http://localhost/your_site_name/dev/build?flush=1](http://localhost/your_site_name/dev/build?flush=1)) and open the CMS. Create
a new *StaffHolder* called "Staff", and create some *StaffPage*s in it. a new *StaffHolder* called "Staff", and create some *StaffPage*s in it.
![](_images/tutorial2_create-staff.jpg) ![](_images/tutorial2_create-staff.jpg)
@ -601,14 +549,13 @@ The *StaffPage* template is also very straight forward.
</div> </div>
<% include SideBar %> <% include SideBar %>
Here we also use the *SetWidth* function to get a different sized image from the same source image. You should now have Here we use the *SetWidth* method to get a different sized image from the same source image. You should now have
a complete staff section. a complete staff section.
![](_images/tutorial2_einstein.jpg) ![](_images/tutorial2_einstein.jpg)
## Summary ## Summary
In this tutorial we have explored the concept of page types. In the process of creating and extending page types you In this tutorial we have explored the concept of page types. In the process of creating and extending page types we have covered many of the concepts required to build a site with SilverStripe.
have been introduced to many of the concepts required to build a site with SilverStripe.
[Next Tutorial >>](3-forms) [Next Tutorial >>](3-forms)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 16 KiB