Tidy up templates guide

This commit is contained in:
Will Rossiter 2014-10-13 20:49:30 +13:00 committed by Cam Findlay
parent c54dee5452
commit 7fc6110a6f
22 changed files with 1709 additions and 1910 deletions

View File

@ -1,285 +0,0 @@
# Building templates for page types
Much of your work building a SilverStripe site will involve the creation of
templates for your own page types. SilverStripe has its own template language.
Its basic features like variables, blocks and loops are described in our ["templates" reference guide](/reference/templates).
In this guide, we'll show you specific uses for creating page layouts.
This assumes you are familiar with the concept of ["page types"](/topics/page-types).
To get a feel for what those templates look like, let's have a look at an abbreviated example. In your webroot, these templates are usually located in `themes/<your-theme>/templates`.
Replace the `<your-theme>` placeholder accordingly, most likely you're using a theme called "simple")
Most of the magic happens in `Page.ss` and `Layout/Page.ss`.
`themes/<your-theme>/templates/Page.ss`
:::ss
<html>
<head>
<% base_tag %>
<title>$SiteConfig.Title | $Title</title>
$MetaTags(false)
</head>
<body>
<div id="Container">
<header>
<h1>Bob's Chicken Shack</h1>
</header>
<navigation>
<% if $Menu(1) %>
<ul>
<% loop $Menu(1) %>
<li><a href="$Link" class="$LinkingMode">$MenuTitle</a></li>
<% end_loop %>
</ul>
<% end_if %>
</navigation>
<div class="typography">
$Layout
</div>
</div>
</body>
</html>
`themes/<your-theme>/templates/Layout/Page.ss`
<h2>$Title</h2>
$Content
$Form
### Template inheritance through $Layout
Our example shows two templates, both called `Page.ss`.
One is located in the `templates/` "root" folder, the other one in a `templates/Layout/` subfolder.
This "inner template" is used by the `$Layout` placeholder in the "root template",
and is inherited based on the underlying PHP classes (read more about template inheritance
on the ["page types" topic](/topics/page-types)).
"Layout" is a fixed naming convention,
you can't use the same pattern for other folder names.
### Page Content
:::ss
$Content
This variable in the `Layout` template contains the main content of the current page,
edited through the WYSIWIG editor in the CMS.
It returns the database content of the `SiteTree.Content` property.
Please note that this database content can be "staged",
meaning that draft content edited in the CMS can be different from published content
shown to your website visitors. In templates, you don't need to worry about this distinction.
The `$Content` variable contain the published content by default,
and only preview draft content if explicitly requested (e.g. by the "preview" feature in the CMS)
(see the ["versioning" topic](topics/versioning) for more details).
### Menu Loops
:::ss
<% loop $Menu(1) %>...<% end_loop %>
`$Menu(1)` is a built-in page control that defines the top-level menu.
You can also create a sub-menu using `$Menu(2)`, and so forth.
The `<% loop $Menu(1) %>...<% end_loop %>` block defines a repeating element.
It will change the "scope" of your template, which means that all of the template variables you use inside it will refer to a menu item. The template code will be repeated once per menu item, with the scope set to that menu item's page. In this case, a menu item refers to an instance
of the `Page` class, so you can access all properties defined on there, for example `$Title`.
Note that pages with the `ShowInMenus` property set to FALSE will be filtered out
(its a checkbox in the "Settings" panel of the CMS).
### Children Loops
:::ss
<% loop $Children %>...<% end_loop %>
Will loop over all children of the current page context.
Helpful to create page-specific subnavigations.
Most likely, you'll want to use `<% loop $Menu %>` for your main menus,
since its independent of the page context.
:::ss
<% loop $ChildrenOf(<my-page-url>) %>...<% end_loop %>
Will create a list of the children of the given page,
as identified by its `URLSegment` value. This can come in handy because its not dependent
on the context of the current page. For example, it would allow you to list all staff member pages
underneath a "staff" holder on any page, regardless if its on the top level or elsewhere.
:::ss
<% loop $allChildren %>...<% end_loop %>
This will show all children of a page even if the `ShowInMenus` property is set to FALSE.
### Access to Parent and Level Pages
:::ss
<% with $Level(1) %>
$Title
<% end_with %>
Will return a page in the current path, at the level specified by the numbers.
It is based on the current page context, looking back through its parent pages.
For example, imagine you're on the "bob marley" page,
which is three levels in: "about us > staff > bob marley".
* `$Level(1).Title` would return "about us"
* `$Level(2).Title` would return "staff"
* `$Level(3).Title` would return "bob marley"
To simply retrieve the parent page of the current context (if existing), use the `$Parent` variable.
### Access to a specific Page
:::ss
<% with $Page(my-page) %>...<% end_with %>`
"Page" will return a single page from the site tree, looking it up by URL. You can use it in the `<% loop %>` format.
Can't be called using `$Page(my-page).Title`.
### Title and Menu Title
The CMS provides two fields to label a page: "Title" and "Menu Title".
"Title" is the title in its full length, while "Menu Title" can be
a shorter version suitable for size-constrained menus.
If "Menu Title" is left blank by the CMS author, it'll just default to "Title".
### Links and Linking Modes
:::ss
$LinkingMode
Each menu item we loop over knows its location on the website, so can generate a link to it.
This happens through the `[api:SiteTree->Link()]` method behind the scenes.
We're not using the direct database property `SiteTree.URLSegment` here
because pages can be nested, so the link needs to be generated on the fly.
In the template syntax, there's no distinction between a method and a property though.
The link is relative by default (see `<% base_tag %>`),
you can get an absolute one including the domain through [$AbsoluteLink](api:SiteTree->AbsoluteLink())`.
In addition, each menu item gets some context information relative
to the page you're currently viewing, contained in the `$LinkingMode` placeholder.
By setting a HTML class to this value, you can distinguish the styling of
the currently selected menu item. It can have the following values:
* `link`: You are neither on this page nor in this section.
* `current`: You are currently on this page.
* `section`: The current page is a child of this menu item, so the current "section"
More common uses:
* `$LinkOrCurrent`: Determines if the item is the current page. Returns "link" or "current" strings.
* `$LinkOrSection`: Determines if the item is in the current section, so in the path towards the current page. Useful for menus which you only want to show a second level menu when you are on that page or a child of it. Returns "link" or "section" strings.
* `InSection(page-url)`: This if block will pass if we're currently on the page-url page or one of its children.
Example: Only show the menu item linked if its the current one:
:::ss
<% if $LinkOrCurrent = current %>
$Title
<% else %>
<a href="$Link">$Title</a>
<% end_if %>
### Breadcrumbs
Breadcrumbs are the path of parent pages which needs to be taken
to reach the current page, and can be a great navigation aid for website users.
While you can achieve breadcrumbs through the `<% Level(<level>) %>` control already,
there's a nicer shortcut: The `$Breadcrumbs` control.
It uses its own template defined in `BreadcrumbsTemplate.ss`.
Simply place a file with the same name in your `themes/<your-theme>/templates`
folder to customize its output. Here's the default template:
:::ss
<% if $Pages %>
<% loop $Pages %>
<% if $Last %>$Title.XML<% else %><a href="$Link">$MenuTitle.XML</a> &raquo;<% end_if %>
<% end_loop %>
<% end_if %>
For more customization options like limiting the amount of breadcrumbs,
take a look at `[api:SiteTree->Breadcrumbs()]`.
### SiteConfig: Global settings
:::ss
$SiteConfig.Title
The ["SiteConfig"](/reference/siteconfig) object allows content authors
to modify global data in the CMS, rather than PHP code.
By default, this includes a website title and tagline
(as opposed to the title of a specific page).
It can be extended to hold other data, for example a logo image
which can be uploaded through the CMS.
The object is available to all page templates through the `$SiteConfig` placeholder.
### Meta Tags
The `$MetaTags` placeholder in a template returns a segment of HTML appropriate for putting into the `<head>` tag. It
will set up title, keywords and description meta-tags, based on the CMS content and is editable in the 'Meta-data' tab
on a per-page basis. If you dont want to include the title-tag `<title>` (for custom templating), use
`$MetaTags(false)`.
By default `$MetaTags` renders:
:::ss
<title>Title of the Page</title>
<meta name="generator" http-equiv="generator" content="SilverStripe 3.0" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
#### URLSegment
This returns the part of the URL of the page you're currently on.
Shouldn't be used for linking to a page, since the link
is a composite value based on all parent pages as well (through the `$Link` variable).
#### ClassName
Returns the class of the underlying `Page` record.
This can be handy to add to your `<body>` tag to influence
CSS styles and JavaScript behaviour based on the page type used:
:::ss
<body class="$ClassName">
In case you want to include parent PHP classes in this list as well,
use the `$CSSClasses` placeholder instead.
#### BaseHref
Returns the base URL for the current site.
This is used to populate the `<base>` tag by default.
Can be handy to prefix custom links (not generated through `SiteTree->Link()`),
to ensure they work correctly when the webroot is hosted in a subfolder
rather than its own domain (a common development setup).
### Forms
:::ss
$Form
Very often, a page will contain some content and a form of some kind. For example, the log-in page has a log-in form. If you are on such a page, the `$Form` variable will contain the HTML content of the form. Placing it just below `$Content` is a good default. Behind the scenes,
it maps to the `Page_Controller->Form()` method. You can add more forms by implementing
new methods there (see ["forms" topic](/topics/forms) for details).
### More Advanced Controls
Template variables and controls are just PHP properties and methods
on the underlying controllers and model classes.
We've just shown you the most common once, in practice
you can use any public API on those classes, and [extend](/reference/dataextension) them
with your own. To get an overview on what's available to you,
we recommend that you dive into the API docs for the following classes:
* `[api:ContentController]`: The main controller responsible for handling pages
* `[api:Controller]`: Generic controller (not specific to pages)
* `[api:DataObject]`: Underlying model class for page objects
* `[api:ViewableData]`: Underlying object class for pretty much anything displayable

View File

@ -0,0 +1,487 @@
title: Template Syntax
summary: A look at the operations, variables and language controls you can use within templates.
# Template Syntax
SilverStripe templates are plain text files that have `.ss` extension and located within the `templates` directory of
a module, theme, or your `mysite` folder. A template can contain any markup language (e.g HTML, CSV, JSON..) and before
being rendered to the user, they're processed through [api:SSViewer]. This process replaces placeholders such as `$Var`
with real content from your [model](../model) and allows you to define logic controls like `<% if $Var %>`.
An example of a SilverStripe template is below:
**mysite/templates/Page.ss**
:::ss
<html>
<head>
<% base_tag %>
<title>$Title</title>
<% require themedCSS("screen") %>
</head>
<body>
<header>
<h1>Bob's Chicken Shack</h1>
</header>
<% with $CurrentMember %>
<p>Welcome $FirstName $Surname.</p>
<% end_with %>
<% if $Dishes %>
<ul>
<% loop $Dishes %>
<li>$Title ($Price.Nice)</li>
<% end_loop %>
</ul>
<% end_if %>
<% include Footer %>
</body>
</html>
<div class="note">
Templates can be used for more than HTML output. You can use them to output your data as JSON, XML, CSV or any other
text based format.
</div>
## Variables
Variables are placeholders that will be replaced with data from the [DataModel](../model/) or the current
[Controller](../controllers). Variables are prefixed with a `$` character. Variable names must start with an
alphabetic character or underscore, with subsequent characters being alphanumeric or underscore:
:::ss
$Title
This inserts the value of the Title database field of the page being displayed in place of `$Title`.
Variables can be chained together, and include arguments.
:::ss
$Foo
$Foo(param)
$Foo.Bar
These variables will call a method / field on the object and insert the returned value as a string into the template.
* `$Foo` will call `$obj->Foo()` (or the field `$obj->Foo`)
* `$Foo(param)` will call `$obj->Foo("param")`
* `$Foo.Bar` will call `$obj->Foo()->Bar()`
If a variable returns a string, that string will be inserted into the template. If the variable returns an object, then
the system will attempt to render the object through its' `forTemplate()` method. If the `forTemplate()` method has not
been defined, the system will return an error.
<div class="note" markdown="1">
For more detail around how variables are inserted and formatted into a template see
[Formating, Modifying and Casting Variables](casting)
</div>
Variables can come from your database fields, or custom methods you define on your objects.
**mysite/code/Page.php**
:::php
public function UsersIpAddress() {
return $this->request->getIP();
}
**mysite/code/Page.ss**
:::html
<p>You are coming from $UsersIpAddress.</p>
The variable's that can be used in a template vary based on the object currently in [scope](#scope). Scope defines what
object the methods get called on. For the standard `Page.ss` template the scope is the current [api:Page_Controller]
class. This object gives you access to all the database fields on [api:Page_Controller], its corresponding [api:Page]
record and any subclasses of those two.
**mysite/code/Layout/Page.ss**
:::ss
$Title
// returns the page `Title` property
$Content
// returns the page `Content` property
## Conditional Logic
The simplest conditional block is to check for the presence of a value (does not equal 0, null, false).
:::ss
<% if $CurrentMember %>
<p>You are logged in as $CurrentMember.FirstName $CurrentMember.Surname.</p>
<% end_if %>
A conditional can also check for a value other than falsey.
:::ss
<% if $MyDinner == "kipper" %>
Yummy, kipper for tea.
<% end_if %>
<div class="notice" markdown="1">
When inside template tags variables should have a '$' prefix, and literals should have quotes.
</div>
Conditionals can also provide the `else` case.
:::ss
<% if $MyDinner == "kipper" %>
Yummy, kipper for tea
<% else %>
I wish I could have kipper :-(
<% end_if %>
`else_if` commands can be used to handle multiple `if` statements.
:::ss
<% if $MyDinner == "quiche" %>
Real men don't eat quiche
<% else_if $MyDinner == $YourDinner %>
We both have good taste
<% else %>
Can I have some of your chips?
<% end_if %>
### Negation
The inverse of `<% if %>` is `<% if not %>`.
:::ss
<% if not $DinnerInOven %>
I'm going out for dinner tonight.
<% end_if %>
### Boolean Logic
Multiple checks can be done using `||`, `or`, `&&` or `and`.
If *either* of the conditions is true.
:::ss
<% if $MyDinner == "kipper" || $MyDinner == "salmon" %>
yummy, fish for tea
<% end_if %>
If *both* of the conditions are true.
:::ss
<% if $MyDinner == "quiche" && $YourDinner == "kipper" %>
Lets swap dinners
<% end_if %>
### Inequalities
You can use inequalities like `<`, `<=`, `>`, `>=` to compare numbers.
:::ss
<% if $Number >= "5" && $Number <= "10" %>
Number between 5 and 10
<% end_if %>
## Includes
Within SilverStripe templates we have the ability to include other templates from the `template/Includes` directory
using the `<% include %>` tag.
:::ss
<% include SideBar %>
The `include` tag can be particularly helpful for nested functionality and breaking large templates up. In this example,
the include only happens if the user is logged in.
:::ss
<% if $CurrentMember %>
<% include MembersOnlyInclude %>
<% end_if %>
Includes can't directly access the parent scope when the include is included. However you can pass arguments to the
include.
:::ss
<% with $CurrentMember %>
<% include MemberDetails Top=$Top, Name=$Name %>
<% end_with %>
## Looping Over Lists
The `<% loop %>` tag is used to iterate or loop over a collection of items such as [api:DataList] or a [api:ArrayList]
collection.
:::ss
<h1>Children of $Title</h1>
<ul>
<% loop $Children %>
<li>$Title</li>
<% end_loop %>
</ul>
This snippet loops over the children of a page, and generates an unordered list showing the `Title` property from each
page.
<div class="notice" markdown="1">
$Title inside the loop refers to the Title property on each object that is looped over, not the current page like
the reference of `$Title` outside the loop.
This demonstrates the concept of [Scope](#scope). When inside a <% loop %> the scope of the template has changed to the
object that is being looped over.
</div>
### Altering the list
`<% loop %>` statements iterate over a [api:DataList] instance. As the template has access to the list object,
templates can call [api:DataList] methods.
Sort the list by a given field.
:::ss
<ul>
<% loop $Children.Sort(Title, ASC) %>
<li>$Title</li>
<% end_loop %>
</ul>
Limiting the number of items displayed.
:::ss
<ul>
<% loop $Children.Limit(10) %>
<li>$Title</li>
<% end_loop %>
</ul>
Reversing the loop.
:::ss
<ul>
<% loop $Children.Reverse %>
<li>$Title</li>
<% end_loop %>
</ul>
Filtering the loop
:::ss
<ul>
<% loop $Children.Filter('School', 'College') %>
<li>$Title</li>
<% end_loop %>
</ul>
Methods can also be chained
:::ss
<ul>
<% loop $Children.Filter('School', 'College').Sort(Score, DESC) %>
<li>$Title</li>
<% end_loop %>
</ul>
### Position Indicators
Inside the loop scope, there are many variables at your disposal to determine the current position in the list and
iteration.
* `$Even`, `$Odd`: Returns boolean, handy for zebra striping
* `$EvenOdd`: Returns a string, either 'even' or 'odd'. Useful for CSS classes.
* `$First`, `$Last`, `$Middle`: Booleans about the position in the list
* `$FirstLast`: Returns a string, "first", "last", or "". Useful for CSS classes.
* `$Pos`: The current position in the list (integer). Will start at 1.
* `$TotalItems`: Number of items in the list (integer)
:::ss
<ul>
<% loop $Children.Reverse %>
<% if First %>
<li>My Favourite</li>
<% end_if %>
<li class="$EvenOdd">Child $Pos of $TotalItems - $Title</li>
<% end_loop %>
</ul>
<div class="info" markdown="1">
A common task is to paginate your lists. See the [Pagination](how_tos/pagination) how to for a tutorial on adding
pagination.
</div>
### Modulus and MultipleOf
$Modulus and $MultipleOf can help to build column and grid layouts.
:::ss
// returns an int
$Modulus(value, offset)
// returns a boolean.
$MultipleOf(factor, offset)
<% loop $Children %>
<div class="column-{$Modulus(4)}">
...
</div>
<% end_loop %>
// returns <div class="column-3">, <div class="column-2">,
<div class="hint" markdown="1">
`$Modulus` is useful for floated grid CSS layouts. If you want 3 rows across, put $Modulus(3) as a class and add a
`clear: both` to `.column-1`.
</div>
$MultipleOf(value, offset) can also be utilized to build column and grid layouts. In this case we want to add a `<br>`
after every 3th item.
:::ss
<% loop $Children %>
<% if $MultipleOf(3) %>
<br>
<% end_if %>
<% end_loop %>
### Escaping
Sometimes you will have template tags which need to roll into one another. Use `{}` to contain variables.
:::ss
$Foopx // will returns "" (as it looks for a `Foopx` value)
{$Foo}px // returns "3px" (CORRECT)
Or when having a `$` sign in front of the variable such as displaying money.
:::ss
$$Foo // returns ""
${$Foo} // returns "$3"
You can also use a backslash to escape the name of the variable, such as:
:::ss
$Foo // returns "3"
\$Foo // returns "$Foo"
<div class="hint" markdown="1">
For more information on formatting and casting variables see [Formating, Modifying and Casting Variables](casting)
</div>
## Scope
In the `<% loop %>` section, we saw an example of two **scopes**. Outside the `<% loop %>...<% end_loop %>`, we were in
the scope of the top level `Page`. But inside the loop, we were in the scope of an item in the list (i.e the `Child`)
The scope determines where the value comes from when you refer to a variable. Typically the outer scope of a `Page.ss`
layout template is the [api:Page_Controller] that is currently being rendered.
When the scope is a `Page_Controller` it will automatically also look up any methods in the corresponding `Page` data
record. In the case of `$Title` the flow looks like
$Title --> [Looks up: Current Page_Controller and parent classes] --> [Looks up: Current Page and parent classes].
The list of variables you could use in your template is the total of all the methods in the current scope object, parent
classes of the current scope object, and any [api:Extension] instances you have.
### Navigating Scope
#### Up
When in a particular scope, `$Up` takes the scope back to the previous level.
:::ss
<h1>Children of '$Title'</h1>
<% loop $Children %>
<p>Page '$Title' is a child of '$Up.Title'</p>
<% loop $Children %>
<p>Page '$Title' is a grandchild of '$Up.Up.Title'</p>
<% end_loop %>
<% end_loop %>
Given the following structure, it will output the text.
My Page
|
+-+ Child 1
| |
| +- Grandchild 1
|
+-+ Child 2
Children of 'My Page'
Page 'Child 1' is a child of 'My Page'
Page 'Grandchild 1' is a grandchild of 'My Page'
Page 'Child 2' is a child of 'MyPage'
#### Top
While `$Up` provides us a way to go up one level of scope, `$Top` is a shortcut to jump to the top most scope of the
page. The previous example could be rewritten to use the following syntax.
:::ss
<h1>Children of '$Title'</h1>
<% loop $Children %>
<p>Page '$Title' is a child of '$Top.Title'</p>
<% loop $Children %>
<p>Page '$Title' is a grandchild of '$Top.Title'</p>
<% end_loop %>
<% end_loop %>
### With
The `<% with %>` tag lets you change into a new scope. Consider the following example:
:::ss
<% with $CurrentMember %>
Hello $FirstName, welcome back. Your current balance is $Balance.
<% end_with %>
Outside the `<% with %>.`, we are in the page scope. Inside it, we are in the scope of `$CurrentMember` object. We can
refer directly to properties and methods of the [api:Member] object. `$FirstName` inside the scope is equivalent to
`$CurrentMember.FirstName`.
<div class="info" markdown="1">
Why would you use `with`? This keeps the markup clean, and if the scope is a complicated expression we don't
have to repeat it on each reference of a property.
</div>
## Comments
Using standard HTML comments is supported. These comments will be included in the published site.
:::ss
$EditForm <!-- Some public comment about the form -->
However you can also use special SilverStripe comments which will be stripped out of the published site. This is useful
for adding notes for other developers but for things you don't want published in the public html.
:::ss
$EditForm <%-- Some hidden comment about the form --%>
## Related
[CHILDREN]
## How to's
[CHILDREN How_Tos]
## API Documentation
* [api:SSViewer]
* [api:SS_TemplateManifest]

View File

@ -1,719 +0,0 @@
# Templates
## Introduction
SilverStripe templates consist of HTML code augmented with special control codes, described below. Because of this, you
can have as much control of your site's HTML code as you like.
Because the SilverStripe templating language is a string processing language it can therefore be used to make other
text-based data formats, such as XML or RTF.
Here is a very simple template:
:::ss
<html>
<head>
<% base_tag %>
<title>$Title</title>
<% require themedCSS("screen") %>
</head>
<body>
<header>
<h1>Bob's Chicken Shack</h1>
</header>
<% with $CurrentMember %>
<p>Welcome $FirstName $Surname.</p>
<% end_with %>
<% if $Dishes %>
<ul>
<% loop $Dishes %>
<li>$Title ($Price.Nice)</li>
<% end_loop %>
</ul>
<% end_if %>
<% include Footer %>
</body>
</html>
More sophisticated use of templates for pages managed in the CMS,
including template inheritance and navigation loops
is documented in the [page types](/topics/page-types) topic.
# Template elements
## Variables
Variables are things you can use in a template that grab data from the page and put in the HTML document. For example:
:::ss
$Title
This inserts the value of the Title field of the page being displayed in place of `$Title`. This type of variable is called a **property**. It is often something that can be edited in the CMS. Variables can be chained together, and include arguments.
:::ss
$Property
$Property(param)
$Property.SubProperty
These **variables** will call a method/field on the object and insert the returned value as a string into the template.
* `$Property` will call `$obj->Property()` (or the field `$obj->Property`)
* `$Property(param)` will call `$obj->Property("param")`
* `$Property.SubProperty` will call `$obj->Property()->SubProperty()` (or field equivalents)
If a variable returns a string, that string will be inserted into the template. If the variable returns an object, then
the system will attempt to render the object through its forTemplate() method. If the `forTemplate()` method has not been
defined, the system will return an error.
SilverStripe provides many additional properties on the `SiteTree` class,
see [Page Type Templates](/topics/page-type-templates) for details.
### Escaping
Sometimes you will have template tags which need to roll into one another. This can often result in SilverStripe looking
for a "FooBar" value rather than a "Foo" and then "Bar" value or when you have a string directly before or after the
variable you will need to escape the specific variable. In the following example `$Foo` is `3`.
:::ss
$Foopx // returns "" (as it looks for a Foopx value)
{$Foo}px // returns "3px" (CORRECT)
Or when having a `$` sign in front of the variable
:::ss
$$Foo // returns ""
${$Foo} // returns "$3"
You can also use a backslash to escape the name of the variable, such as:
:::ss
$Foo // returns "3"
\$Foo // returns "$Foo"
## Includes
Within SilverStripe templates we have the ability to include other templates from the Includes directory using the SS
'include' tag. For example, the following code would include the `Includes/SideBar.ss` code:
:::ss
<% include SideBar %>
The "include" tag can be particularly helpful for nested functionality. In this example, the include only happens if
a variable is true
:::ss
<% if $CurrentMember %>
<% include MembersOnlyInclude %>
<% end_if %>
Includes can't directly access the parent scope of the scope active when the include is included. However you can
pass arguments to the include, which are available on the scope top within the include
:::ss
<% with $CurrentMember %>
<% include MemberDetails PageTitle=$Top.Title, PageID=$Top.ID %>
<% end_with %>
You can also perform includes using the Requirements Class via the template controls. See the section on
[Includes in Templates](requirements#including_inside_template_files) for more details and examples.
:::ss
<% require themedCSS("LeftNavMenu") %>
### Including CSS and JavaScript files (a.k.a "Requirements")
See [CSS](/topics/css) and [Javascript](/topics/javascript) topics for individual including of files and
[requirements](reference/requirements) for good examples of including both Javascript and CSS files.
## Conditional Logic
You can conditionally include markup in the output. That is, test for something
that is true or false, and based on that test, control what gets output.
The simplest if block is to check for the presence of a value.
:::ss
<% if $CurrentMember %>
<p>You are logged in as $CurrentMember.FirstName $CurrentMember.Surname.</p>
<% end_if %>
The following compares a page property called `MyDinner` with the value in
quotes, `kipper`, which is a **literal**. If true, the text inside the if-block
is output.
:::ss
<% if $MyDinner=="kipper" %>
Yummy, kipper for tea.
<% end_if %>
Note that inside a tag like this, variables should have a '$' prefix, and
literals should have quotes. SilverStripe 2.4 didn't include the quotes or $
prefix, and while this still works, we recommend the new syntax as it is less
ambiguous.
This example shows the use of the `else` option. The markup after `else` is
output if the tested condition is *not* true.
:::ss
<% if $MyDinner=="kipper" %>
Yummy, kipper for tea
<% else %>
I wish I could have kipper :-(
<% end_if %>
This example shows the user of `else_if`. There can be any number of `else_if`
clauses. The conditions are tested from first to last, until one of them is true,
and the markup for that condition is used. If none of the conditions are true,
the markup in the `else` clause is used, if that clause is present.
:::ss
<% if $MyDinner=="quiche" %>
Real men don't eat quiche
<% else_if $MyDinner==$YourDinner %>
We both have good taste
<% else %>
Can I have some of your chips?
<% end_if %>
This example shows the use of `not` to negate the test.
:::ss
<% if not $DinnerInOven %>
I'm going out for dinner tonight.
<% end_if %>
You can combine two or more conditions with `||` ("or"). The markup is used if
*either* of the conditions is true.
:::ss
<% if $MyDinner=="kipper" || $MyDinner=="salmon" %>
yummy, fish for tea
<% end_if %>
You can combine two or more conditions with `&&` ("and"). The markup is used if
*both* of the conditions are true.
:::ss
<% if $MyDinner=="quiche" && $YourDinner=="kipper" %>
Lets swap dinners
<% end_if %>
You can use inequalities like `<`, `<=`, `>`, `>=` to compare numbers.
:::ss
<% if $Number>="5" && $Number<="10" %>
Number between 5 and 10
<% end_if %>
## Looping Over Lists
The `<% loop %>...<% end_loop %>` tag is used to **iterate** or loop over a
collection of items. For example:
:::ss
<ul>
<% loop $Children %>
<li>$Title</li>
<% end_loop %>
</ul>
This loops over the children of a page, and generates an unordered list showing
the `Title` property from each one. Note that `$Title` *inside* the loop refers
to the `Title` property on each object that is looped over, not the current page.
This is know as the `Scope` of the template. For more information about `Scope`
see the section below.
To refer to the current page's `Title` property inside the loop, you can do
`$Up.Title`. More about `Up` later.
`$Me` can be used to refer to the current object context the template is rendered
with.
### Position Indicators
Inside the loop scope, there are many variables at your disposal to determine the
current position in the list and iteration:
* `$Even`, `$Odd`: Returns boolean, handy for zebra striping
* `$EvenOdd`: Returns a string, either 'even' or 'odd'. Useful for CSS classes.
* `$First`, `$Last`, `$Middle`: Booleans about the position in the list
* `$FirstLast`: Returns a string, "first", "last", or "". Useful for CSS classes.
* `$Pos`: The current position in the list (integer). Will start at 1.
* `$TotalItems`: Number of items in the list (integer)
### Altering the list
`<% loop %>` statements iterate over a `[api:DataList]` instance. As the
template has access to the list object, templates can call `[api:DataList]`
functions. For instance, see the following examples:
Providing a custom sort.
:::ss
<ul>
<% loop $Children.Sort(Title) %>
<li>$Title</li>
<% end_loop %>
</ul>
Limiting the number of items displayed.
:::ss
<ul>
<% loop $Children.Limit(10) %>
<li>$Title</li>
<% end_loop %>
</ul>
Reversing the loop.
:::ss
<ul>
<% loop $Children.Reverse %>
<li>$Title</li>
<% end_loop %>
</ul>
The `DataList` class also supports chaining methods. For example, to reverse
the list and output the last 3 items we would write:
:::ss
<ul>
<% loop $Children.Reverse.Limit(3) %>
<li>$Title</li>
<% end_loop %>
</ul>
### Modulus and MultipleOf
$Modulus and $MultipleOf can help to build column layouts.
:::ss
$Modulus(value, offset) // returns an int
$MultipleOf(factor, offset) // returns a boolean.
The following example demonstrates how you can use $Modulus(4) to generate
custom column names based on your loop statement. Note that this works for any
control statement (not just children).
:::ss
<% loop $Children %>
<div class="column-{$Modulus(4)}">
...
</div>
<% end_loop %>
Will return you column-3, column-2, column-1, column-0, column-3 etc. You can
use these as styling hooks to float, position as you need.
You can also use $MultipleOf(value, offset) to help build columned layouts. In
this case we want to add a <br> after every 3th item.
:::ss
<% loop $Children %>
<% if $MultipleOf(3) %>
<br>
<% end_if %>
<% end_loop %>
## Scope
In the `<% loop %>` section, we saw an example of two **scopes**. Outside the
`<% loop %>...<% end_loop %>`, we were in the scope of the page. But inside the
loop, we were in the scope of an item in the list. The scope determines where
the value comes from when you refer to a variable. Typically the outer scope of
a page type's layout template is the page that is currently being rendered.
The outer scope of an included template is the scope that it was included into.
### Up
When we are in a scope, we sometimes want to refer to the scope outside the
<% loop %> or <% with %>. We can do that easily by using `$Up`. `$Up` takes
the scope back to the previous level. Take the following example:
:::ss
$Title
--
<% loop $Children %>
$Title
$Up.Title
--
<% loop $Children %>
$Title
$Up.Title
<% end_loop %>
<% end_loop %>
With a page structure (Blog -> Blog entry -> Child blog entry) the
above will produce:
:::ss
Blog
--
Blog entry
Blog
--
Child blog entry
Blog entry
### Top
While `$Up` provides us a way to go up 1 scope, `$Top` is a shortcut to jump to
the top most scope of the page. Using the previous example but expanded to
include `$Top`:
:::ss
$Title
--
<% loop $Children %>
$Title
$Up.Title
$Top.Title
--
<% loop $Children %>
$Title
$Up.Title
$Top.Title
<% end_loop %>
<% end_loop %>
Will produce
:::ss
Blog
--
Blog entry
Blog
Blog
--
Child blog entry
Blog entry
Blog
### With
The `<% with %>...<% end_with %>` tag lets you introduce a new scope. Consider
the following example:
:::ss
<% with $CurrentMember %>
Hello $FirstName, welcome back. Your current balance is $Balance.
<% end_with %>
Outside the `<% with %>...<% end_with %>`, we are in the page scope. Inside it,
we are in the scope of `$CurrentMember`. We can refer directly to properties and
methods of that member. So $FirstName is equivalent to $CurrentMember.FirstName.
This keeps the markup clean, and if the scope is a complicated expression we don't
have to repeat it on each reference of a property.
`<% with %>` also lets us use a collection as a scope, so we can access
properties of the collection itself, instead of iterating over it. For example:
:::ss
$Children.Count
returns the number of items in the $Children collection.
## Pagination
Lists can be paginated, and looped over to generate pagination. For this to
work, the list needs to be wrapped in a `[api:PaginatedList]`. The process is
explained in detail on the ["pagination" howto](/howto/pagination).
The list is split up in multiple "pages", each . Note that "page" is this context
does not necessarily refer to a `Page` class (although it often happens to be one).
* `$MoreThanOnePage`: Returns true when we have a multi-page list, restricted with a limit.
* `$NextLink`, `$PrevLink`: This returns links to the next and previous page in a multi-page datafeed. They will return blank if there's no appropriate page to go to, so `$PrevLink` will return blank when you're on the first page.
* `$CurrentPage`: Current page iterated on
* `$TotalPages`: Total number of pages
* `$TotalItems`: This returns the total number of items across all pages.
* `$Pages`: The actual (limited) list of records, use in an inner loop
* `$PageNum`: Page number, starting at 1 (within `$Pages`)
* `$Link`: Links to the current controller URL, setting this page as current via a GET parameter (within `$Pages`)
* `$CurrentBool`: Returns true if you're currently on that page (within `$Pages`)
## Formatting and Casting
Properties are usually auto-escaped in templates to ensure consistent representation,
and avoid format clashes like displaying unescaped ampersands in HTML.
By default, values are escaped as `XML`, which is equivalent to `HTML` for this purpose.
There's some exceptions to this rule, see the ["security" topic](/topics/security).
In case you want to explicitly allow unescaped HTML input,
the property can be cast as `[api:HTMLText]`.
The following example takes the `Content` field in a `SiteTree` class,
which is of this type. It forces the content into an explicitly escaped format.
:::ss
$Content.XML // transforms e.g. "<em>alert</em>" to "&lt;em&gt;alert&lt;/em&gt;"
Apart from value formatting, there's many methods to transform them as well,
For example, the built in `$Now` placeholder is an instance of `[api:Date]`,
and returns the current date in a standard system format.
Since its an object, you can use the helper methods to return other formats:
:::ss
$Now.Year // Current year
$Now.Nice // Localized date, based on i18n::get_locale()
See [data-types](/topics/data-types) for more information.
## Translations
Translations are easy to use with a template, and give access to SilverStripe's translation facilities. Here is an example:
<%t Member.WELCOME 'Welcome {name} to {site}' name=$Member.Name site="Foobar.com" %>
Pulling apart this example we see:
* `Member.WELCOME` is an identifier in the translation system, for which different translations may be available. This string may include named placeholders, in braces.
* `'Welcome {name} to {site}'` is the default string used, if there is no translation for Member.WELCOME in the current locale. This contains named placeholders.
* `name=$Member.Name` assigns a value to the named placeholder `name`. This value is substituted into the translation string wherever `{name}` appears in that string. In this case, it is assigning a value from a property `Member.Name`
* `site="Foobar.com"` assigns a literal value to another named placeholder, `site`.
## Comments
Using standard HTML comments is supported. These comments will be included in the published site.
:::ss
$EditForm <!-- Some public comment about the form -->
However you can also use special SilverStripe comments which will be stripped out of the published site. This is useful
for adding notes for other developers but for things you don't want published in the public html.
:::ss
$EditForm <%-- Some hidden comment about the form --%>
## Partial Caching
Partial caching lets you define blocks of your template that are cached for better performance. See [Partial Caching](/reference/partial-caching) for more information.
### Base Tag
The `<% base_tag %>` placeholder is replaced with the HTML base element. Relative links within a document (such as `<img
src="someimage.jpg" />`) will become relative to the URI specified in the base tag. This ensures the browser knows where
to locate your sites images and css files. So it is a must for templates!
It renders in the template as `<base href="http://www.mydomain.com" /><!--[if lte IE 6]></base><![endif]-->`
## CurrentMember
Returns the currently logged in member, if there is one.
All of their details or any special Member page controls can be called on this.
Alternately, you can use `<% if $CurrentMember %>` to detect whether someone has logged
in.
:::ss
<% if $CurrentMember %>
Welcome Back, $CurrentMember.FirstName
<% end_if %>
## Custom Template Variables and Controls
There are two ways you can extend the template variables you have available. You can create a new database field in your
`$db` or if you do not need the variable to be editable in the cms you can create a function which returns a value in your
`Page.php` class.
:::php
// mysite/code/Page.php
public function MyCustomValue() {
return "Hi, this is my site";
}
Will give you the ability to call `$MyCustomValue` from anywhere in your template.
:::ss
I've got one thing to say to you: <i>$MyCustomValue</i>
// output "I've got one thing to say to you: <i>Hi, this is my site</i>"
Your function could return a single value as above or it could be a subclass of `[api:ArrayData]` for example a
`[api:DataObject]` with many values then each of these could be accessible via a control loop
:::php
// ...
public function MyCustomValues() {
return new ArrayData(array("Hi" => "Kia Ora", "Name" => "John Smith"));
}
And now you could call these values by using
:::ss
<% with $MyCustomValues %>
$Hi , $Name
<% end_with %>
// output "Kia Ora , John Smith"
Or by using the dot notation you would have
:::ss
$MyCustomValues.Hi , $MyCustomValues.Name
// output "Kia Ora , John Smith"
### Side effects
All functions that provide data to templates must have no side effects, as the value is cached after first access. For example, this controller method
:::php
private $counter = 0;
public function Counter() {
$this->counter += 1;
return $this->counter;
}
and this template
:::ss
$Counter, $Counter, $Counter
will render as "1, 1, 1", not "1, 2, 3"
## .typography style
By default, SilverStripe includes the `theme/css/typography.css` file into the Content area. So you should always include the
typography style around the main body of the site so both styles appear in the CMS and on the template. Where the main body of
the site is can vary, but usually it is included in the /Layout files. These files are included into the main Page.ss template
by using the `$Layout` variable so it makes sense to add the .typography style around $Layout.
:::ss
<div class="typography">
$Layout
</div>
## Calling templates from PHP code
This is all very well and good, but how do the templates actually get called?
Templates do nothing on their own. Rather, they are used to render *a particular object*. All of the `<% if %>`, `<%control %>`,
and variable codes are methods or parameters that are called *on that object*. All that is necessary is
that the object is an instance of `[api:ViewableData]` (or one of its subclasses).
The key is `[api:ViewableData::renderWith()]`. This method is passed a For example, within the controller's default action,
there is an instruction of the following sort:
:::php
$controller->renderWith("TemplateName");
Here's what this line does:
* First `renderWith()` constructs a new object: `$template = new SSViewer("TemplateName");`
* `[api:SSViewer]` will take the content of `TemplateName.ss`, and turn it into PHP code.
* Then `renderWith()` passes the controller to `$template->process($controller);`
* `SSViewer::process()` will execute the PHP code generated from `TemplateName.ss` and return the results.
`renderWith()` returns a string - the populated template. In essence, it uses a template to cast an object to a string.
`renderWith()` can also be passed an array of template names. If this is done, then `renderWith()` will use the first
available template name.
Below is an example of how to implement renderWith. In the example below the page is rendered using the myAjaxTemplate
if the page is called by an ajax function (using `[api:Director::is_ajax()]`). Note that the index function is called by
default if it exists and there is no action in the url parameters.
:::php
class MyPage_Controller extends Page_Controller {
private static $allowed_actions = array('index');
public function init(){
parent::init();
}
public function index() {
if(Director::is_ajax()) {
return $this->renderWith("myAjaxTemplate");
} else {
return Array();// execution as usual in this case...
}
}
}
## Anchor Link rewriting
Anchor links are links with a "#" in them. A frequent use-case is to use anchor links to point to different
sections of the current page. For example, we might have this in our template.
For, example, we might have this on http://www.example.com/my-long-page/
:::ss
<ul>
<li><a href="#section1">Section 1</a></li>
<li><a href="#section2">Section 2</a></li>
</ul>
So far, so obvious. However, things get tricky because of we have set our `<base>` tag to point to the root of your
site. So, when you click the first link you will be sent to http://www.example.com/#section1 instead of
http://www.example.com/my-long-page/#section1
In order to prevent this situation, the SSViewer template renderer will automatically rewrite any anchor link that
doesn't specify a URL before the anchor, prefixing the URL of the current page. For our example above, the following
would be created:
:::ss
<ul>
<li><a href="my-long-page/#section1">Section 1</a></li>
<li><a href="my-long-page/#section2">Section 2</a></li>
</ul>
There are cases where this can be unhelpful. HTML anchors created from Ajax responses are the most common. In these
situations, you can disable anchor link rewriting by setting the
`SSViewer.rewrite_hash_links` configuration value to `false`.
### More Advanced Controls
Template variables and controls are just PHP properties and methods
on the underlying controllers and model classes.
We've just shown you the most common once, in practice
you can use any public API on those classes, and [extend](/reference/dataextension) them
with your own. To get an overview on what's available to you,
we recommend that you dive into the API docs for the following classes:
* `[api:Controller]`: Generic controller class
* `[api:DataObject]`: Generic model class
* `[api:ViewableData]`: Underlying object class for pretty much anything displayable
## Designing reusable templates
Although SilverStripe is ultimately flexible in how you create your templates, there's a couple of best practices. These
will help you to design templates for modules, and make it easier for other site developers to integrate them into their
own base templates.
* Most of your templates should be `Layout` templates
* Build your templates as a [Theme](/topics/themes) so you can easily re-use and exchange them
* Your layout template should include a standard markup structure (`<div id="Layout">$Layout</div>`)
* Layout templates only include content that could be completely replaced by another module (e.g. a forum thread). It
might be infeasible to do this 100%, but remember that every piece of navigation that needs to appear inside `$Layout`
will mean that you have to customise templates when integrating the module.
* Any CSS applied to layout templates should be flexible width. This means the surrounding root template can set its
width independently.
* Don't include any navigation elements in your `Layout` templates, they should be contained in the root template.
* Break down your templates into groups of includes. Site integrators would then have the power to override individual
includes, rather than entire templates.
## Related
* [Built in page controls](/reference/built-in-page-controls)
* [Page Type Templates](/topics/page-type-templates)
* [Typography](/reference/typography)
* [Themes](/topics/themes)
* [Widgets](/topics/widgets)
* [Images](/reference/image)
* [Tutorial 1: Building a basic site](/tutorials/1-building-a-basic-site)
* [Tutorial 2: Extending a basic site](/tutorials/2-extending-a-basic-site)
* [Developing Themes](/topics/theme-development)
* [Templates: formal syntax description](/reference/templates-formal-syntax)

View File

@ -1,94 +0,0 @@
# CSS #
## Introduction ##
SilverStripe strives to keep out of a template designer's way as much as possible -
this also extends to how you want to write your CSS.
## Adding CSS to your template ##
You are free to add `<style>` and `<link>` tags to your template (typically `themes/yourtheme/templates/Page.ss`).
SilverStripe provides a management layer for javascript and CSS files on top of that with the [Requirements](/reference/requirements) class,
by adding some simple PHP calls to your controller or template. Some files are automatically included,
depending on what functionality you are using (e.g. SilverStripe forms automatically include `framework/css/Form.css`).
In your controller (e.g. `mysite/code/Page.php`):
:::php
class Page_Controller {
public function init() {
// either specify the css file manually
Requirements::css("mymodule/css/my.css", "screen,projection");
// or mention the css filename and SilverStripe will get the file from the current theme and add it to the template
Requirements::themedCSS('print', null,'print');
}
}
Or in your template (e.g. `themes/yourtheme/templates/Page.ss`):
:::ss
<% require css("mymodule/css/my.css") %>
Management through the `Requirements` class has the advantage that modules can include their own CSS files without modifying
your template. On the other hand, you as a template developer can "block" or change certain CSS files that are included from
thirdparty code.
## WYSIWYG editor: typography.css and editor.css
This stylesheet is used to "namespace" rules which just apply in a rendered site and the WYSIWYG-editor of the CMS. This
is needed to get custom styles in the editor without affecting the remaining CMS-styles.
An example of a good location to use `class="typography"` is the container element to your WYSIWYG-editor field. The
`$Content` WYSIWYG editor field already comes with SilverStripe out-of-the-box:
:::html
<!--
This is a good way, you're only applying class="typography"
to where the WYSIWYG editor is, and not the entire layout.
-->
`<div id="Main">`
`<div id="LeftContent">`
`<p>`We have a lot of content to go here.`</p>`
`</div>`
`<div id="Content" class="typography">`
$Content
`</div>`
`</div>`
The `typography.css` file should contain only styling for these elements (related to the WYSIWYG editor):
* **Headers (h1 - h6)**
* **Text (p, blockquote, pre)**
* **Lists (ul, li)**
* **CSS alignment (img.left, .left, .right etc)**
* **Tables**
* **Miscellaneous (hr etc)**
The advantages are that it's fully styled, as a default starting point which you can easily tweak. It also doesn't
affect the CMS styling at all (except for the WYSIWYG), which is what we want.
It's also separated from the rest of the layout. If you wanted to change typography only, for where you usually edit the
content you don't need to go wading through other CSS files related to the actual layout.
To get these styles working in the CMS. Eg you use a font you want in the CMS area you need to create an editor.css
file. Then with this file you can define styles for the CMS or just import the styles from typography. Unlike
`typography.css`, `editor.css` is NOT included in the front end site. So this is `themes/your_theme/css/editor.css`
:::css
/* Import the common styles from typography like link colors. */
@import 'typography.css';
/* We want the backend editor to have a bigger font as well though */
.typography * { font-size: 200% }
See [typography](/reference/typography) for more information.
## Related ##
* [javascript](javascript)
* ["Compass" module](http://silverstripe.org/compass-module/): Allows writing CSS in SASS/LESS syntax, with better code management through mixins, includes and variables
* [Reference: CMS Architecture](../reference/cms-architecture)
* [Howto: Extend the CMS Interface](../howto/extend-cms-interface)

View File

@ -0,0 +1,409 @@
title: Common Variables
summary: Some of the common variables and methods your templates can use.
# Common Variables
The page below describes a few of common variables and methods you'll see in a SilverStripe template. This is not an
exhaustive list. From your template you can call any method, database field, or relation on the object which is
currently in scope as well as its' subclasses or extensions.
Knowing what methods you can call can be tricky, but the first step is to understand the scope you're in. Scope is
explained in more detail on the [syntax](syntax#scope) page.
<div class="notice" markdown="1">
Want a quick way of knowing what scope you're in? Try putting `$ClassName` in your template. You should see a string
such as `Page` of the object that's in scope. The methods you can call on that object then are any functions, database
properties or relations on the `Page` class, `Page_Controller` class as well as anything from their subclasses **or**
extensions.
</div>
Outputting these variables is only the start, if you want to format or manipulate them before adding them to the template
have a read of the [Formating, Modifying and Casting Variables](casting) documentation.
<div class="alert" markdown="1">
Some of the following only apply when you have the `CMS` module installed. If you're using the `Framework` alone, this
functionality may not be included.
</div>
## Base Tag
:::ss
<head>
<% base_tag %>
..
</head>
The `<% base_tag %>` placeholder is replaced with the HTML base element. Relative links within a document (such as <img
src="someimage.jpg" />) will become relative to the URI specified in the base tag. This ensures the browser knows where
to locate your sites images and css files.
It renders in the template as `<base href="http://www.yoursite.com" /><!--[if lte IE 6]></base><![endif]-->`
<div class="alert" markdown="1">
A `<% base_tag %>` is nearly always required or assumed by SilverStripe to exist.
</div>
## CurrentMember
Returns the currently logged in [api:Member] instance, if there is one logged in.
:::ss
<% if $CurrentMember %>
Welcome Back, $CurrentMember.FirstName
<% end_if %>
## Title and Menu Title
:::ss
$Title
$MenuTitle
Most objects within SilverStripe will respond to `$Title` (i.e they should have a `Title` database field or at least a
`getTitle()` method).
The CMS module in particular provides two fields to label a page: `Title` and `MenuTitle`. `Title` is the title
displayed on the web page, while `MenuTitle` can be a shorter version suitable for size-constrained menus.
<div class="notice" markdown="1">
If `MenuTitle` is left blank by the CMS author, it'll just default to the value in `Title`.
</div>
## Page Content
:::ss
$Content
It returns the database content of the `Content` property. With the CMS Module, this is the value of the WYSIWYG editor
but it is also the standard for any object that has a body of content to output.
<div class="info" markdown="1">
Please note that this database content can be `versioned`, meaning that draft content edited in the CMS can be different
from published content shown to your website visitors. In templates, you don't need to worry about this distinction.
The `$Content` variable contains the published content by default,and only preview draft content if explicitly
requested (e.g. by the "preview" feature in the CMS) (see the [versioning documentation](/../model/versioning) for
more details).
</div>
### SiteConfig: Global settings
<div class="notice" markdown="1">
`SiteConfig` is a module that is bundled with the `CMS`. If you wish to include `SiteConfig` in your framework only
web pages. You'll need to install it via `composer`.
</div>
:::ss
$SiteConfig.Title
The [SiteConfig](../configuration/siteconfig) object allows content authors to modify global data in the CMS, rather
than PHP code. By default, this includes a Website title and a Tagline.
`SiteConfig` can be extended to hold other data, for example a logo image which can be uploaded through the CMS or
global content such as your footer content.
## Meta Tags
The `$MetaTags` placeholder in a template returns a segment of HTML appropriate for putting into the `<head>` tag. It
will set up title, keywords and description meta-tags, based on the CMS content and is editable in the 'Meta-data' tab
on a per-page basis.
<div class="notice" markdown="1">
If you dont want to include the title tag use `$MetaTags(false)`.
</div>
By default `$MetaTags` renders:
:::ss
<title>Title of the Page</title>
<meta name="generator" http-equiv="generator" content="SilverStripe 3.0" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
`$MetaTags(false)` will render
:::ss
<meta name="generator" http-equiv="generator" content="SilverStripe 3.0" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
If using `$MetaTags(false)` we can provide a more custom `title`.
:::ss
$MetaTags(false)
<title>$Title - Bob's Fantasy Football</title>
## Links
:::ss
<a href="$Link">..</a>
All objects that could be accessible in SilverStripe should define a `Link` method and an `AbsoluteLink` method. Link
returns the relative URL for the object and `AbsoluteLink` outputs your full website address along with the relative
link.
:::ss
$Link
<!-- returns /about-us/offices/ -->
$AbsoluteLink
<!-- returns http://yoursite.com/about-us/offices/ -->
### Linking Modes
:::ss
$LinkingMode
When looping over a list of `SiteTree` instances through a `<% loop Menu %>` or `<% loop Children %>`, `$LinkingMode`
will return context about the page relative to the currently viewed page. It can have the following values:
* `link`: You are neither on this page nor in this section.
* `current`: You are currently on this page.
* `section`: The current page is a child of this menu item, so the current "section"
For instance, to only show the menu item linked if it's the current one:
:::ss
<% if $LinkingMode = current %>
$Title
<% else %>
<a href="$Link">$Title</a>
<% end_if %>
`$LinkingMode` is reused for several other variables and utility functions.
* `$LinkOrCurrent`: Determines if the item is the current page. Returns "link" or "current" strings.
* `$LinkOrSection`: Determines if the item is in the current section, so in the path towards the current page. Useful
for menus which you only want to show a second level menu when you are on that page or a child of it. Returns "link"
or "section" strings.
* `InSection(page-url)`: This if block will pass if we're currently on the page-url page or one of its children.
:::ss
<% if InSection(about-us) %>
<p>You are viewing the about us section</p>
<% end_if %>
### URLSegment
This returns the part of the URL of the page you're currently on. For example on the `/about-us/offices/` web page the
`URLSegment` will be `offices`. `URLSegment` cannot be used to generate a link since it does not output the full path.
It can be used within templates to generate anchors or other CSS classes.
:::ss
<div id="section-$URLSegment">
</div>
<!-- returns <div id="section-offices"> -->
## ClassName
Returns the class of the current object in [scope](syntax#scope) such as `Page` or `HomePage`. The `$ClassName` can be
handy for a number of uses. A common use case is to add to your `<body>` tag to influence CSS styles and JavaScript
behavior based on the page type used:
:::ss
<body class="$ClassName">
<!-- returns <body class="HomePage">, <body class="BlogPage"> -->
## Children Loops
:::ss
<% loop $Children %>
<% end_loop %>
Will loop over all Children records of the current object context. Children are pages that sit under the current page in
the `CMS` or a custom list of data. This originates in the `Versioned` extension's `getChildren` method.
<div class="alert" markdown="1">
For doing your website navigation most likely you'll want to use `$Menu` since its independent of the page
context.
</div>
### ChildrenOf
:::ss
<% loop $ChildrenOf(<my-page-url>) %>
<% end_loop %>
Will create a list of the children of the given page, as identified by its `URLSegment` value. This can come in handy
because it's not dependent on the context of the current page. For example, it would allow you to list all staff member
pages underneath a "staff" holder on any page, regardless if its on the top level or elsewhere.
### AllChildren
Content authors have the ability to hide pages from menus by un-selecting the `ShowInMenus` checkbox within the CMS.
This option will be honored by `<% loop Children %>` and `<% loop Menu %>` however if you want to ignore the user
preference, `AllChildren` does not filter by `ShowInMenus`.
:::ss
<% loop $AllChildren %>
...
<% end_loop %>
### Menu Loops
:::ss
<% loop $Menu(1) %>
...
<% end_loop %>
`$Menu(1)` returns the top-level menu of the website. You can also create a sub-menu using `$Menu(2)`, and so forth.
<div class="notice" markdown="1">
Pages with the `ShowInMenus` property set to `false` will be filtered out.
</div>
## Access to a specific Page
:::ss
<% with $Page(my-page) %>
$Title
<% end_with %>
Page will return a single page from site, looking it up by URL.
## Access to Parent and Level Pages
### Level
:::ss
<% with $Level(1) %>
$Title
<% end_with %>
Will return a page in the current path, at the level specified by the numbers. It is based on the current page context,
looking back through its parent pages. `Level(1)` being the top most level.
For example, imagine you're on the "bob marley" page, which is three levels in: "about us > staff > bob marley".
* `$Level(1).Title` would return "about us"
* `$Level(2).Title` would return "staff"
* `$Level(3).Title` would return "bob marley"
### Parent
:::ss
<!-- given we're on 'Bob Marley' in "about us > staff > bob marley" -->
$Parent.Title
<!-- returns 'staff' -->
$Parent.Parent.Title
<!-- returns 'about us' -->
## Navigating Scope
### Me
`$Me` outputs the current object in scope. This will call the `forTemplate` of the object.
:::ss
$Me
### Up
When in a particular scope, `$Up` takes the scope back to the previous level.
:::ss
<h1>Children of '$Title'</h1>
<% loop $Children %>
<p>Page '$Title' is a child of '$Up.Title'</p>
<% loop $Children %>
<p>Page '$Title' is a grandchild of '$Up.Up.Title'</p>
<% end_loop %>
<% end_loop %>
Given the following structure, it will output the text.
My Page
|
+-+ Child 1
| |
| +- Grandchild 1
|
+-+ Child 2
Children of 'My Page'
Page 'Child 1' is a child of 'My Page'
Page 'Grandchild 1' is a grandchild of 'My Page'
Page 'Child 2' is a child of 'MyPage'
### Top
While `$Up` provides us a way to go up one level of scope, `$Top` is a shortcut to jump to the top most scope of the
page. The previous example could be rewritten to use the following syntax.
:::ss
<h1>Children of '$Title'</h1>
<% loop $Children %>
<p>Page '$Title' is a child of '$Top.Title'</p>
<% loop $Children %>
<p>Page '$Title' is a grandchild of '$Top.Title'</p>
<% end_loop %>
<% end_loop %>
## Breadcrumbs
Breadcrumbs are the path of pages which need to be taken to reach the current page, and can be a great navigation aid
for website users.
While you can achieve breadcrumbs through the `<% Level(<level>) %>` control manually, there's a nicer shortcut: The
`$Breadcrumbs` variable.
:::ss
$Breadcrumbs
By default, it uses the template defined in `cms/templates/BreadcrumbsTemplate.ss`
:::ss
<% if $Pages %>
<% loop $Pages %>
<% if $Last %>$Title.XML<% else %><a href="$Link">$MenuTitle.XML</a> &raquo;<% end_if %>
<% end_loop %>
<% end_if %>
<div class="info" markdown="1">
To customize the markup that the `$Breadcrumbs` generates. Copy `cms/templates/BreadcrumbsTemplate.ss` to
`mysite/templates/BreadcrumbsTemplate.ss`, modify the newly copied template and flush your SilverStripe cache.
</div>
## Forms
:::ss
$Form
A page will normally contain some content and potentially a form of some kind. For example, the log-in page has a the
SilverStripe log-in form. If you are on such a page, the `$Form` variable will contain the HTML content of the form.
Placing it just below `$Content` is a good default.
You can add your own forms by implementing new form instances (see the [Forms tutorial](../tutorials/forms)).
## Related
* [Casting and Formating Variables](casting)
* [Template Inheritance](template_inheritance)
## API Documentation
* `[api:ContentController]`: The main controller responsible for handling pages.
* `[api:Controller]`: Generic controller (not specific to pages.)
* `[api:DataObject]`: Underlying model class for page objects.
* `[api:ViewableData]`: Underlying object class for pretty much anything displayable.

View File

@ -0,0 +1,190 @@
title: Requirements
summary: How to include and require other assets in your templates such as javascript and CSS files.
# Requirements
The requirements class takes care of including CSS and JavaScript into your applications. This is preferred to hard
coding any references in the `<head>` tag of your template, as it enables a more flexible handling through the
[api:Requirements] class.
## Template Requirements API
**mysite/templates/Page.ss**
:::ss
<% require css("cms/css/TreeSelector.css") %>
<% require themedCSS("TreeSelector") %>
<% require javascript("cms/javascript/LeftAndMain.js") %>
<div class="alert" markdown="1">
Requiring assets from the template is restricted compared to the PHP API.
</div>
## PHP Requirements API
It is common practice to include most Requirements either in the *init()*-method of your [controller](../controller), or
as close to rendering as possible (e.g. in `[api:FormField]`.
:::php
<?php
class MyCustomController extends Controller {
public function init() {
parent::init();
Requirements::javascript("cms/javascript/LeftAndMain.js");
Requirements::css("cms/css/TreeSelector.css");
}
}
### CSS Files
:::php
Requirements::css($path, $media);
If you're using the CSS method a second argument can be used. This argument defines the 'media' attribute of the
`<link>` element, so you can define 'screen' or 'print' for example.
:::php
Requirements::css("cms/css/TreeSelector.css", "screen,projection");
### Javascript Files
:::php
Requirements::javascript($path);
A variant on the inclusion of custom javascript is the inclusion of *templated* javascript. Here, you keep your
JavaScript in a separate file and instead load, via search and replace, several PHP-generated variables into that code.
:::php
$vars = array(
"EditorCSS" => "cms/css/editor.css",
);
Requirements::javascriptTemplate("cms/javascript/editor.template.js", $vars);
### Custom Inline CSS or Javascript
You can also quote custom script directly. This may seem a bit ugly, but is useful when you need to transfer some kind
of 'configuration' from the database in a raw format. You'll need to use the `heredoc` syntax to quote JS and CSS,
this is generally speaking the best way to do these things - it clearly marks the copy as belonging to a different
language.
:::php
Requirements::customScript(<<<JS
alert("hi there");
JS
);
Requirements::customCSS(<<<CSS
.tree li.$className {
background-image: url($icon);
}
CSS
);
## Combining Files
You can concatenate several CSS or javascript files into a single dynamically generated file. This increases performance
by reducing HTTP requests.
:::php
Requirements::combine_files(
'foobar.js',
array(
'mysite/javascript/foo.js',
'mysite/javascript/bar.js',
)
);
<div class="alert" markdown='1'>
To make debugging easier in your local environment, combined files is disabled when running your application in `dev`
mode.
</div>
By default it stores the generated file in the assets/ folder but you can configure this by pointing the
`Requirements.combined_files_folder` configuration setting to a specific folder.
**mysite/_config/app.yml**
:::yml
Requirements:
combined_files_folder: '_combined'
<div class="info" markdown='1'>
If SilverStripe doesn't have permissions on your server to write these files it will default back to including them
individually. SilverStripe **will not** rewrite your paths within the file.
</div>
You can also combine CSS files into a media-specific stylesheets as you would with the `Requirements::css` call - use
the third paramter of the `combine_files` function:
:::php
$printStylesheets = array(
"$themeDir/css/print_HomePage.css",
"$themeDir/css/print_Page.css",
);
Requirements::combine_files('print.css', $printStylesheets, 'print');
## Clearing assets
:::php
Requirements::clear();
Clears all defined requirements. You can also clear specific requirements.
:::php
Requirements::clear('jsparty/prototype.js');
<div class="alert" markdown="1">
Depending on where you call this command, a Requirement might be *re-included* afterwards.
</div>
## Blocking
Requirements can also be explicitly blocked from inclusion, which is useful to avoid conflicting JavaScript logic or
CSS rules. These blocking rules are independent of where the `block()` call is made. It applies both for already
included requirements, and ones included after the `block()` call.
One common example is to block the core `jquery.js` added by various form fields and core controllers, and use a newer
version in a custom location. This assumes you have tested your application with the newer version.
:::php
Requirements::block(THIRDPARTY_DIR . '/jquery/jquery.js');
<div class="alert" markdown="1">
The CMS also uses the `Requirements` system, and its operation can be affected by `block()` calls. Avoid this by
limiting the scope of your blocking operations, e.g. in `init()` of your controller.
</div>
## Inclusion Order
Requirements acts like a stack, where everything is rendered sequentially in the order it was included. There is no way
to change inclusion-order, other than using *Requirements::clear* and rebuilding the whole set of requirements.
<div class="alert" markdown="1">
Inclusion order is both relevant for CSS and Javascript files in terms of dependencies, inheritance and overlays - be
careful when messing with the order of requirements.
</div>
## Javascript placement
By default, SilverStripe includes all Javascript files at the bottom of the page body, unless there's another script
already loaded, then, it's inserted before the first `<script>` tag. If this causes problems, it can be configured.
**mysite/_config/app.yml**
:::yml
Requirements:
write_js_to_body: true
force_js_to_bottom: true
`Requirements.force_js_to_bottom`, will force SilverStripe to write the Javascript to the bottom of the page body, even
if there is an earlier script tag.
## API Documentation
* [api:Requirements]

View File

@ -0,0 +1,89 @@
title: Rendering data to a template
summary: Call and render SilverStripe templates manually.
# Rendering data to a template
Templates do nothing on their own. Rather, they are used to render a particular object. All of the `<% if %>`,
`<% loop %>` and other variables are methods or parameters that are called on the current object in
[scope](syntax#scope). All that is necessary is that the object is an instance of [api:ViewableData] (or one of its
subclasses).
The following will render the given data into a template. Given the template:
**mysite/templates/Coach_Message.ss**
:::ss
<strong>$Name</strong> is the $Role on our team.
Our application code can render into that view using `renderWith`. This method is called on the [api:ViewableData]
instance with a template name or an array of templates to render.
**mysite/code/Page.php**
:::php
$arrayData = new ArrayData(array(
'Name' => 'John',
'Role' => 'Head Coach'
));
echo $arrayData->renderWith('Coach_Message');
// returns "<strong>John</strong> is the Head Coach on our team."
<div class="info" markdown="1">
Most classes in SilverStripe you want in your template extend `ViewableData` and allow you to call `renderWith`. This
includes [api:Controller], [api:FormField] and [api:DataObject] instances.
</div>
:::php
$controller->renderWith(array("MyController", "MyBaseController"));
Member::currentUser()->renderWith('Member_Profile');
`renderWith` can be used to override the default template process. For instance, to provide an ajax version of a
template.
:::php
<?php
class Page_Controller extends ContentController {
private static $allowed_actions = array('iwantmyajax');
public function iwantmyajax() {
if(Director::is_ajax()) {
return $this->renderWith("AjaxTemplate");
} else {
return $this->httpError(404);
}
}
}
Any data you want to render into the template that does not extend `ViewableData` should be wrapped in an object that
does, such as `ArrayData` or `ArrayList`.
:::php
<?php
class Page_Controller extends ContentController {
..
public function iwantmyajax() {
if(Director::is_ajax()) {
$experience = new ArrayList();
$experience->push(new ArrayData(array(
'Title' => 'First Job'
)));
return $this->customize(new ArrayData(array(
'Name' => 'John',
'Role' => 'Head Coach',
'Experience' => $experience
))->renderWith("AjaxTemplate");
} else {
return $this->httpError(404);
}
}
}

View File

@ -1,210 +0,0 @@
# Requirements
## Introduction
The requirements class takes care of including CSS and JavaScript into your applications. This is preferred to
hardcoding any references in the `<head>`-tag of your template, as it enables a more flexible handling.
## Including inside PHP Code
It is common practice to include most Requirements either in the *init()*-method of your [controller](/topics/controller), or
as close to rendering as possible (e.g. in `[api:FormField]`
:::php
Requirements::javascript("cms/javascript/LeftAndMain.js");
Requirements::css("cms/css/TreeSelector.css");
If you're using the CSS method a second argument can be used. This argument defines the 'media' attribute of the `<link>`
element, so you can define 'screen' or 'print' for example.
Requirements::css("cms/css/TreeSelector.css", "screen,projection");
## Including inside Template files
If you do not want to touch the PHP (for example you are constructing a generic theme) then you can include a file via
the templates
<% require css("cms/css/TreeSelector.css") %>
<% require themedCSS("TreeSelector") %>
<% require javascript("cms/javascript/LeftAndMain.js") %>
## Combining Files
You can concatenate several CSS or javascript files into a single dynamically generated file. This increases performance
reducing HTTP requests. Note that for debugging purposes combined files is disabled in devmode.
:::php
// supports CSS + JS
Requirements::combine_files(
'foobar.js',
array(
'mysite/javascript/foo.js',
'mysite/javascript/bar.js',
)
);
By default it stores the generated file in the assets/ folder but you can configure this by pointing
the `Requirements.combined_files_folder` configuration setting to a specific folder.
If SilverStripe doesn't have permissions on your server to write these files it will default back to including them
individually .
You can also combine CSS files into a media-specific stylesheets as you would with the `Requirements::css` call - use
the third paramter of the `combine_files` function:
:::php
$printStylesheets = array(
"$themeDir/css/print_HomePage.css",
"$themeDir/css/print_Page.css",
);
Requirements::combine_files('print.css', $printStylesheets, 'print');
## Custom Inline Scripts
You can also quote custom script directly. This may seem a bit ugly, but is useful when you need to transfer some kind
of 'configuration' from the database to the javascript/css. You'll need to use the "heredoc" syntax to quote JS and
CSS, this is generally speaking the best way to do these things - it clearly marks the copy as belonging to a different
language.
:::php
Requirements::customScript(<<<JS
alert("hi there");
JS
);
Requirements::customCSS(<<<CSS
.tree li.$className {
background-image: url($icon);
}
CSS
);
## Templated javascript
A variant on the inclusion of custom javascript is the inclusion of *templated* javascript. Here, you keep your
JavaScript in a separate file and instead load, via search and replace, several PHP-generated variables into that code.
:::php
$vars = array(
"EditorCSS" => "mot/css/editor.css",
);
Requirements::javascriptTemplate("cms/javascript/editor.template.js", $vars);
## Clearing
You may want to clear all of the requirements mentioned thus far. I've used this when you've put an iframe generator as
an action on the controller that uses it. The iframe has a completely different set of scripting and styling
requirements, and it's easiest to flush all the default stuff and start again.
:::php
Requirements::clear();
You can also clear specific Requirements:
:::php
Requirements::clear('jsparty/prototype.js');
Caution: Depending on where you call this command, a Requirement might be *re-included* afterwards.
## Blocking
Requirements can also be explicitly blocked from inclusion,
which is useful to avoid conflicting JavaScript logic or CSS rules.
These blocking rules are independent of where the `block()` call is made:
It applies both for already included requirements, and ones
included after the `block()` call.
One common example is to block the core `jquery.js` include
added by various form fields and core controllers,
and use a newer version in a custom location.
:::php
Requirements::block(THIRDPARTY_DIR . '/jquery/jquery.js');
Caution: The CMS also uses the `Requirements` system, and its operation can be
affected by `block()` calls. Avoid this by limiting the scope of
your blocking operations, e.g. in `init()` of your controller.
## Inclusion Order
Requirements acts like a stack, where everything is rendered sequentially in the order it was included. There is no way
to change inclusion-order, other than using *Requirements::clear* and rebuilding (=guessing) the whole set of
requirements. Caution: Inclusion order is both relevant for CSS and Javascript files in terms of dependencies,
inheritance and overlays - please be careful when messing with the order of Requirements.
### Javascript placement
By default, SilverStripe includes all Javascript files at the bottom of the page body, unless there's another script already loaded, then, it's inserted before the first `<script>` tag. If this causes problems for you,
for example if you're using animation that ends up showing everything until the bottom of the page loads, or shows
buttons that rely on Javascript to work, you can change this behaviour. See below.
With the `Requirements.write_js_to_body`, you can configure if Javascript requirements are written to the head (false) or body (true).
With the `Requirements.force_js_to_bottom`, you can force Silverstripe to write the Javascript to the bottom of the page body, even if there is an earlier script tag. For example, when you have asynchronous scripts for Twitter earlier in your body (and stop speedtests from explaining about "scripts above the fold")
## CMS Requirements
The SilverStripe core includes a lot of Requirements by itself. Most of these are collated in `[api:LeftAndMain]` first.
## Motivation
Every page requested is made up of a number of parts, and many of those parts require their own CSS or JavaScript.
Rather than force the developer to put all of those requests into the template, or the header function, you can
reference required files anywhere in your application.
This lets you create very modular units of PHP+JavaScript+CSS, which a powerful concept but must be managed carefully.
## Managing Generic CSS styling
One of the aims of this is to create units of functionality that can be reasonably easily deployed as-is, while still
giving developers the option to customise them. The logical solution to this is to create 'generic' CSS to be applied
to these things. However, we must take great care to keep the CSS selectors very nonspecific. This precludes us from
adding any CSS that would "override customisations" in the form - for example, resetting the width of a field where 100%
width isn't appropriate.
Another solution would be to include some "generic CSS" for form elements at the very high level, so that fixed widths
on forms were applied to the generic form, and could therefore be overridden by a field's generic stylesheet. Similar
to this is mandating the use of "form div.field input" to style form input tags, whether it's a generic form or a custom
one.
Perhaps we could make use of a Requirements::disallowCSS() function, with which we could prevent the standard CSS from
being included in situations where it caused problems. But the complexity could potentially balloon, and really, it's a
bit of an admission of defeat - we shouldn't need to have to do this if our generic CSS was well-designed.
## Ideas/Problems
### Ajax
The whole "include it when you need it" thing shows some weaknesses in areas such as the CMS, where Ajax is used to load
in large pieces of the application, which potentially require more CSS and JavaScript to be included. At this stage,
the only workaround is to ensure that everything you might need is included on the first page-load.
One idea is to mention the CSS and JavaScript which should be included in the header of the Ajax response, so that the
client can load up those scripts and stylesheets upon completion of the Ajax request. This could be coded quite
cleanly, but for best results we'd want to extend prototype.js with our own changes to their Ajax system, so that every
script had consistent support for this.
### Lots of files
Because everything's quite modular, it's easy to end up with a large number of small CSS and JavaScript files. This has
problems with download time, and potentially maintainability.
We don't have any easy answers here, but here are some ideas:
* Merging the required files into a single download on the server. The flip side of this is that if every page has a
slightly different JS/CSS requirements, the whole lot will be refetched.
* Better: "Tagging" each required file for different use-cases, and creating a small set of common functionalities
(e.g. everything tagged "base" such as prototype.js would always be included)
* Do lazy fetching of scripts within an ajax-call. This seems to be possible, but very tricky due to the asynchronous
nature of an ajax-request. Needs some more research
## API Documentation
`[api:Requirements]`

View File

@ -0,0 +1,102 @@
title: Template Inheritance
summary: Override and extend module and core markup templates from your application code.
# Template Inheritance
Bundled within SilverStripe are default templates for any markup the framework outputs for things like Form templates,
Emails or RSS Feeds. These templates are provided to make getting your site up and running quick with sensible defaults
but it's easy to replace and customize SilverStripe (and add-on's) by providing custom templates in your own
`mysite/templates` folder or in your `themes/your_theme/templates` folder.
Take for instance the `GenericEmail` template in SilverStripe. This is the HTML default template that any email created
in SilverStripe is rendered with. It's bundled in the core framework at `framework/templates/email/GenericEmail.ss`.
Instead of editing that file to provide a custom template for your application, simply define a template of the same
name in the `mysite/templates/email` folder or in the `themes/your_theme/templates/email` folder if you're using themes.
**mysite/templates/email/GenericEmail.ss**
:::ss
$Body
<p>Thanks from Bob's Fantasy Football League.</p>
All emails going out of our application will have the footer `Thanks from Bob's Fantasy Football Leaguee` added.
<div class="alert" markdown="1">
As we've added a new file, make sure you flush your SilverStripe cache by visiting `http://yoursite.com/?flush=1`
</div>
Template inheritance works on more than email templates. All files within the `templates` directory including `includes`,
`layout` or anything else from core (or add-on's) template directory can be overridden by being located inside your
`mysite/templates` directory. SilverStripe keeps an eye on what templates have been overridden and the location of the
correct template through a [api:SS_TemplateManifest].
## Template Manifest
The location of each template and the hierarchy of what template to use is stored within a [api:SS_TemplateManifest]
instance. This is a serialized object containing a map of template names, paths and other meta data for each template
and is cached in your applications `TEMP_FOLDER` for performance. For SilverStripe to find the `GenericEmail` template
it does not check all your `template` folders on the fly, it simply asks the `manifest`.
The manifest is created whenever you flush your SilverStripe cache by appending `?flush=1` to any SilverStripe URL. For
example by visiting `http://yoursite.com/?flush=1`. When your include the `flush=1` flag, the manifest class will search
your entire project for the appropriate `.ss` files located in `template` directory and save that information for later.
It will each and prioritize templates in the following priority:
1. mysite (or other name given to site folder)
2. themes
3. modules
4. framework.
<div class="warning">
Whenever you add or remove template files, rebuild the manifest by visiting `http://yoursite.com/?flush=1`. You can
flush the cache from any page, (.com/home?flush=1, .com/admin?flush=1, etc.). Flushing the cache can be slow, so you
only need to do it when you're developing new templates.
</div>
## Nested Layouts through `$Layout`
SilverStripe has basic support for nested layouts through a fixed template variable named `$Layout`. It's used for
storing top level template information separate to individual page layouts.
When `$Layout` is found within a root template file (one in `templates`), SilverStripe will attempt to fetch a child
template from the `templates/Layout` directory. It will do a full sweep of your modules, core and custom code as it
would if it was looking for a new root template.
This is better illustrated with an example. Take for instance our website that has two page types `Page` and `HomePage`.
Our site looks mostly the same across both templates with just the main content in the middle changing. The header,
footer and navigation will remain the same and we don't want to replicate this work across more than one spot. The
`$Layout` function allows us to define the child template area which can be overridden.
**mysite/templates/Page.ss**
<html>
<head>
..
</head>
<body>
<% include Header %>
<% include Navigation %>
$Layout
<% include Footer %>
</body>
**mysite/templates/Layout/Page.ss**
<p>You are on a $Title page</p>
$Content
**mysite/templates/Layout/HomePage.ss**
<h1>This is the homepage!</h1>
<blink>Hi!</blink>

View File

@ -1,96 +0,0 @@
# Formal Treatment of the Template Language
This document gives you the maximum level of detail of how the template engine works. If you just want to know how to write templates, you probably want to read [this page](/reference/templates) instead.
## White space
## Expressions
### Literals
Definition:
literal := number | stringLiteral
number := digit { digit }*
stringLiteral := "\"" { character } * "\"" |
"'" { character } * "'"
Notes:
* digits in a number comprise a single token, so cannot have spaces
* any printable character can be included inside a string literal except the opening quote, unless
prefixed by a backslash (TODO: check this assumption with Hamish - its probably not right)
### Words
A word is used to identify a name of something, e.g. a property or method name. Words must start
with an alphabetic character or underscore, with subsequent characters being alphanumeric or underscore:
word := A-Za-z_ { A-Za-z0-9_ }*
### Properties and methods (variables)
Examples:
$PropertyName.Name
$MethodName
$MethodName("foo").SomeProperty
$MethodName("foo", "bar")
$MethodName("foo", $PropertyName)
Definition:
injection := "$" lookup | "{" "$" lookup "}"
call := word [ "(" argument { "," argument } ")" ]
lookup := call { "." call }*
argument := literal |
lookup |
"$" lookup
Notes:
* A word encountered with no parameter can be parsed as either a property or a method. TODO:
document the exact rules for resolution.
* TODO: include Up and Top in here. Not syntactic elements, but worth mentioning their semantics.
* TODO: consider the 2.4 syntax literals. These have been excluded as we don't want to encourage their
use.
### Operators
<exp> == <exp>
<exp> = <exp>
<exp> != <exp>
<exp> || <exp>
<exp> && <exp>
* TODO: document operator precedence, and include a descripton of what the operators do. || and && are short-circuit? Diff
between = and == or are they equivalent.
## Comments
## If
if := ifPart elseIfPart* elsePart endIfPart
ifPart := "<%" "if" ifCondition "%>" template
elseIfPart := "<%" "else_if" ifCondition "%>" template
elsePart := "<%" "else" "%>" template
endIfPart := "<%" "end_if" "%>"
ifCondition := TODO
template := TODO
## Require
## Loop
## With
## Translation
## Cache block
TODO to be elaborated
<cached arguments>...<end_cached>
<cacheblock arguments>...<end_cacheblock>
<uncached>...<uncached>

View File

@ -1,36 +1,60 @@
title: Themes
summary: What makes up a SilverStripe Theme. How to install one or write your own theme.
# Themes
## Introduction
Themes can be used to kick start your SilverStripe projects, and generally make you look good.
Themes can be used to kick start your SilverStripe projects, can be stored outside of your application code and your
application can provide multiple unique themes (i.e a mobile theme).
## Downloading
Head to the [ Themes ](http://www.silverstripe.org/themes) area of the website to check out the wide range of themes
the community has built. Each theme has a page with links you can use to preview and download it. The theme is provided
Head to the [ Themes ](http://www.silverstripe.org/themes) area of the website to check out the range of themes the
community has built. Each theme has a page with links you can use to preview and download it. The theme is provided
as a .tar.gz file.
## Installing
## Installation
1. Unpack the contents of the zip file into the `themes` directory in your SilverStripe installation.
2. Change the site to the theme. You can do this either by:
- Altering the `SSViewer.theme` setting in your `[config.yml](/topics/configuration)`
- changing the theme in the Site Configuration panel in the CMS
3. Visit your homepage with ?flush=all appended to the URL. `http://localhost?flush=all`
### Manually
Unpack the contents of the zip file you download into the `themes` directory in your SilverStripe installation. The
theme should be accessible at `themes/theme_name`.
### Via Composer
If a theme has `composer` support you can require it directly through `composer`.
:::bash
composer require "author/theme_name" "dev/master"
<div class="alert" markdown="1">
As you've added new files to your SilverStripe installation, make sure you clear the SilverStripe cache by appending
`?flush=1` to your website URL (e.g http://yoursite.com/?flush=1).
</div>
After installing the files through either method, update the current theme in SilverStripe. This can be done by
either altering the `SSViewer.theme` setting in a [config.yml](../configuration) or by changing the current theme in
the Site Configuration panel (http://yoursite.com/admin/settings)
**mysite/_config/app.yml**
:::yml
SSViewer:
theme: theme_name
## Developing your own theme
See [Developing Themes](theme-development) to get an idea of how themes actually work and how you can develop your own.
A `theme` within SilverStripe is simply a collection of templates and other front end assets such as javascript and css.
located within the `themes` directory.
![themes:basicfiles.gif](/_images/basicfiles.gif)
## Submitting your theme to SilverStripe
If you want to submit your theme to the SilverStripe directory then check
* You should ensure your templates are well structured, modular and commented so it's easy for other people to
customise them.
* Templates should not contain text inside images and all images provided must be open source and not break any copyright or license laws.
This includes any icons your template uses in the frontend or the backend CMS.
* A theme does not include any PHP files. Only CSS, HTML, Images and Javascript.
* You should ensure your templates are well structured, modular and commented so it's easy for other people to customize
* Templates should not contain text inside images and all images provided must be open source and not break any
copyright or license laws. This includes any icons your template uses.
* A theme does not include any PHP files. Only CSS, HTML, Images and javascript.
Your theme file must be in a .tar.gz format. A useful tool for this is - [7 Zip](http://www.7-zip.org/). Using 7Zip you
must select the your_theme folder and Add to archive, select TAR and create. Then after you have the TAR file right

View File

@ -0,0 +1,39 @@
title: Caching
summary: Reduce rending time with cached templates and understand the limitations of the ViewableData object caching.
# Caching
## Object caching
All functions that provide data to templates must have no side effects, as the value is cached after first access. For
example, this controller method will not behave as you might imagine.
:::php
private $counter = 0;
public function Counter() {
$this->counter += 1;
return $this->counter;
}
:::ss
$Counter, $Counter, $Counter
// returns 1, 1, 1
When we render `$Counter` to the template we would expect the value to increase and output `1, 2, 3`. However, as
`$Counter` is cached at the first access, the value of `1` is saved.
## Partial caching
Partial caching is a feature that allows the caching of just a portion of a page. Instead of fetching the required data
from the database to display, the contents of the area are fetched from the `TEMP_FOLDER` file-system pre-rendered and
ready to go. More information about Partial caching is in the [Performance](../performance) guide.
:::ss
<% cached 'MyCachedContent', LastEdited %>
$Title
<% end_cached %>

View File

@ -1,283 +0,0 @@
# Developing Themes
## Introduction
[Tutorial 1](/tutorials/1-building-a-basic-site#templates) shows you how to create page templates. This guide will help
you create your own SilverStripe website theme.
Developing your own theme in SilverStripe is a piece of cake thanks to a very straight forward and clean templating
language.
## What is a Theme?
A theme is a set of HTML/CSS/Javascript and images that can be used to provide a skin for a site. A theme does not
include any PHP: instead it should be separate from the code which allows the portability of a design. After all, this
is an MVC framework!
## Getting started - Folder Structure
To start your theme you first need to create the basic folder structure for the theme. Check out the image below for the
layout of your folders. First you need to create a folder in the themes directory called the name of your theme (we're
using "simple"). Please note that underscores in the theme name are reserved to denote "sub-themes" (e.g.
"blackcandy_blog").
![themes:basicfilestructure.gif](_images/basicfilestructure.gif)
Inside your theme, you need the css, images and templates folders. Each of these folders contain parts of your theme and
keeping a good folder structure is super important. Now we have this structure we can put our CSS in the css folder,
Images in the images folder and all our HTML in the templates folder. This keeps our workspace clean and easy to use.
After you have created the templates folder you need to create 2 more folders within - Includes and Layout (Note the
uppercase initial letters). These are 2 different types of templates you will use in your theme - Includes contain
snippets of HTML that you want to break out and share between templates (for example the Header can be an include,
Footer, Navigation etc) whereas Layout templates are the base page templates. So you can have several includes in a
Layout template.
## Getting started - Core Files
### HTML Templates
Once you have created your folders you need to start to fill it out with a couple 'Core' files. First and most
importantly is we need a HTML template for our design. Read the [Tutorial 1](/tutorials/1-building-a-basic-site#templates)
and the HTML pages for more in-depth discussion about the HTML templates and how they work. At the very least
we need a Page.ss file (note the .ss extenstion - Don't worry its just HTML and any text editor will still read it). So
go ahead and create 2 Page.ss files. One in templates, the other in Layout.
![themes:basicfiles.gif](_images/basicfiles.gif)
Whats with the 2 Page.ss files? Well we have 2 so when the user visits a page they get redirected to the top level
Page.ss then, depending on what page they are on, we can have a custom template for that page in the Layout folder. If
you dont get it now, you will hopefully pick it up over the rest of this.
So you have 2 blank Page.ss files. What are we going to do with them? How bout we put some HTML in them so we can see
our theme in action. The code for mine is below.
** yourtheme/templates/Page.ss **
:::ss
<!DOCTYPE html>
<html lang="en">
<head>
<% base_tag %>
$MetaTags(false)
<title>Bob's Chicken Shack | $Title</title>
</head>
<body>
<div id="Container">
<div id="Header">
<h1>Bob's Chicken Shack</h1>
</div>
<div id="Navigation">
<% if $Menu(1) %>
<ul>
<% loop $Menu(1) %>
<li><a href="$Link" title="Go to the $Title page" class="$LinkingMode">$MenuTitle</a></li>
<% end_loop %>
</ul>
<% end_if %>
</div>
<div id="Layout">
$Layout
</div>
<div id="Footer">
<p>Copyright $Now.Year - Bob's Chicken Shack.</p>
</div>
</div>
</body>
</html>
** yourtheme/templates/Layout/Page.ss **
:::ss
<h1>$Title</h1>
$Content
$Form
All you have to do now is tell your site to use your new theme. This is defined through
the YAML config, for example in `mysite/_config/config.yml`.
:::yml
SSViewer:
theme: 'mythemename'
Go to http://localhost?flush=1 and check it out. You should be using your new theme! Not really that awesome or amazing is
it? Next we need to add some CSS Magic!
See [Templates](/reference/themes) for more information about templates.
### CSS Files
By standard SilverStripe uses 3 CSS Files for your site -
* **layout.css** contains the layout and design of the site
* **typography.css** contains the styling for the text/fonts/links (used in both front and back ends)
* **form.css** styling for forms.
You can add more stylesheets using the template tag `<% require themedCSS("filename") %>`, which will load filename.css from
your css directory.
Note: If you're using a default install of Silverstripe and notice that you're getting layout.css, typography.css and
forms.css included without asking for them, they may be being called on lines 21-23 in mysite/code/Page.php. Remove
these three Requirements::themedCSS lines, and you will be free to add your own styles.
## Dividing your site the correct way!
Most Web page designers 10 years ago used a table-based layout to achieve a consistent look. Now, (Thankfully) there's a
different way to achieve the same look.
Using CSS and tags (including `DIV`s) reduces markup code, speeds up page downloads, separates content from
its visual presentation, and brings your code closer to web standards compliance--all while making your website more
appealing to search engine spiders.
For layout we tend to use `DIV` tags as the `DIV` tag defines a division/section in a document.
Let's have a look at part of a Page.ss for the main layout elements defining a 2 column layout.
:::ss
<div id="Container">
<div id="Header">
<!-- Header -->
</div>
<div id="Navigation">
<!-- The Main Site Nav -->
</div>
<div id="Layout">
<!-- The whole site content has to sit inside here! Anything you want to sub template (eg each page will be different, needs to be contained in $Layout. This calls the file /Layout/Page.ss or anyother sub page template -->
$Layout
</div>
<div id="Footer">
</div>
</div>
As you can see we normally wrap the site in a container. For this we use the ID 'Container'. Then we divide the main
template into sections.
:::ss
<div id="Header"><!-- markup goes here --></div>
We have the Header section which includes things like any banner images/ mastheads/ logos or any stuff that belongs at
the top of the page, This might vary on the design of the page
:::ss
<div id="Navigation"><!-- markup goes here --></div>
Next is a division for the main navigation. This may contain something like:
:::ss
<div id="Navigation">
<% if $Menu(1) %>
<ul>
<% loop $Menu(1) %>
<li><a href="$Link" title="Go to the $Title page" class="$LinkingMode">$MenuTitle</a></li>
<% end_loop %>
</ul>
<% end_if %>
</div>
This is the standard for creating the main Navigation. As you can see it outputs the Menu 1 in a unordered list.
Before stepping into a loop it's good practise to check if it exists first. This is not only
important in manipulating SilverStripe templates, but in any programming language!
:::ss
<% if $MyFunction %>
<% loop $MyFunction %>
$Title
<% end_loop %>
<% end_if %>
Last and probably least is the Footer division. Here is where you put all the Footer related stuff for your website.
Maybe even a nice link saying Website Powered by SilverStripe to show your support.
:::ss
<div id="Footer">
<!-- markup goes here -->
</div>
## Resources
A bunch of resources feel free to use to make your template awesome
* [http://kuler.adobe.com](http://kuler.adobe.com) - Kuler is a great color scheming tool
* [http://blog.html.it/layoutgala/](http://blog.html.it/layoutgala/) - 40 super cool CSS layouts for you to use
* [http://designmeltdown.com](http://designmeltdown.com) - Great gallery of websites. Browse through and get inspired.
* [http://validator.w3.org/](http://validator.w3.org/) - Your template must pass 'or get near' validation.
* [http://famfamfam.com/lab/icons/](http://famfamfam.com/lab/icons/) - free, beautiful icons.
* [http://cssremix.com](http://cssremix.com) - Another CSS site gallery for inspiration.
* [http://www.maxdesign.com.au/presentation/process/](http://www.maxdesign.com.au/presentation/process/) - a good process for creating a design
## Reference
### Overriding
The templating system will search for the appropriate files in the following order:
1. mysite (or other name given to site folder)
2. themes
3. module (eg blog)
So if, for example, you had a typography.css file for a module in the module folder (eg blog/css/), in the theme module
directory (eg themes/simple/css/), and in your site folder (eg mysite/css/), the system would use the file
mysite/css/typography.css
<div class="notice" markdown='1'>
Note: This only applies for CSS and template files. PHP files **do not** get overridden!
</div>
### Requirements
The `[api:Requirements::themedCSS()]` function will
do the search specified above. This avoids the need to type a full path to the css file, and also provides better
ambiguity for themes.
### Subthemes
If you have a theme called mytheme_forum, it is considered to be a 'subtheme' of the mytheme theme. This lets module
developers release extensions to popular themes that will let their module work with that theme.
A subtheme overrides the files in the module. So for instance, if you have the forum setup instead of editing the files
within the forum/ module you would create a themes/yourtheme_forum/ folder.
### ThemeDir
If you want to refer to an image or other file asset in a .ss template, use $ThemeDir. For example:
:::ss
<img src="$ThemeDir/images/log.gif" />
If your image is in a subtheme, you can refer to that with an argument to ThemeDir. For example, if your image was in
mytheme_forum, you could use the following code:
:::ss
<img src="$ThemeDir(forum)/images/log.gif" />
## Conventions, standards and guidelines
Following some set standards and conventions makes life easy for you and I.
Some conventions for SilverStripe websites, which we suggest following. Take a look at each:
* [Coding-Conventions](/misc/coding-conventions)
* [Typography](/reference/typography)
We also suggest following various [industry standards](http://www.w3.org/) and conventions.

View File

@ -0,0 +1,30 @@
title: Translations
summary: Definition of the syntax for writing i18n compatible templates.
# Translations
Translations are easy to use with a template, and give access to SilverStripe's translation facilities. Here is an
example:
<%t Foo.BAR 'Bar' %>
<%t Member.WELCOME 'Welcome {name} to {site}' name=$Member.Name site="Foobar.com" %>
`Member.WELCOME` is an identifier in the translation system, for which different translations may be available. This
string may include named placeholders, in braces.
`'Welcome {name} to {site}'` is the default string used, if there is no translation for Member.WELCOME in the current
locale. This contains named placeholders.
`name=$Member.Name` assigns a value to the named placeholder `name`. This value is substituted into the translation
string wherever `{name}` appears in that string. In this case, it is assigning a value from a property `Member.Name`
`site="Foobar.com"` assigns a literal value to another named placeholder, `site`.
## Related
* [i18n](../i18n)
## API Documentation
* [api:i18n]

View File

@ -0,0 +1,107 @@
title: Formating, Modifying and Casting Variables
summary: Information on casting, security, modifying data before it's displayed to the user and how to format data within the template.
# Formatting and Casting
All objects that are being rendered in a template should be a [api:ViewableData] instance such as `DataObject`,
`DBField` or `Controller`. From these objects, the template can include any method from the object in
[scope](syntax#scope).
For instance, if we provide a [api:HtmlText] instance to the template we can call the `FirstParagraph` method. This will
output the result of the [api:HtmlText::FirstParagraph] method to the template.
**mysite/code/Page.ss**
:::ss
$Content.FirstParagraph
<!-- returns the result of HtmlText::FirstParagragh() -->
$LastEdited.Format("d/m/Y")
<!-- returns the result of SS_Datetime::Format("d/m/Y") -->
Any public method from the object in scope can be called within the template. If that method returns another
`ViewableData` instance, you can chain the method calls.
:::ss
$Content.FirstParagraph.NoHTML
<!-- "First Paragraph" -->
<p>Copyright {$Now.Year}</p>
<!-- "Copyright 2014" -->
<div class="$URLSegment.LowerCase">
<!-- <div class="about-us"> -->
<div class="notice" markdown="1">
See the API documentation for [api:HtmlText], [api:StringField], [api:Text] for all the methods you can use to format
your text instances. For other objects such as [api:SS_Datetime] objects see their respective API documentation pages.
</div>
## forTemplate
When rendering an object to the template such as `$Me` the `forTemplate` method is called. This method can be used to
provide default template for an object.
**mysite/code/Page.php**
:::php
<?php
class Page extends SiteTree {
public function forTemplate() {
return "Page: ". $this->Title;
}
}
**mysite/templates/Page.ss**
:::ss
$Me
<!-- returns Page: Home -->
## Casting
Methods which return data to the template should either return an explicit object instance describing the type of
content that method sends back, or, provide a type in the `$casting` array for the object. When rendering that method
to a template, SilverStripe will ensure that the object is wrapped in the correct type and values are safely escaped.
:::php
<?php
class Page extends SiteTree {
private static $casting = array(
'MyCustomMethod' => 'HTMLText'
);
public function MyCustomMethod() {
return "<h1>This is my header</h1>";
}
}
When calling `$MyCustomMethod` SilverStripe now has the context that this method will contain HTML and escape the data
accordingly.
<div class="note" markdown="1">
By default, all content without a type explicitly defined in a `$casting` array will be assumed to be `Text` content
and HTML characters encoded.
</div>
## Escaping
Properties are usually auto-escaped in templates to ensure consistent representation, and avoid format clashes like
displaying un-escaped ampersands in HTML. By default, values are escaped as `XML`, which is equivalent to `HTML` for
this purpose.
<div class="note" markdown="1">
There's some exceptions to this rule, see the ["security" guide](../security).
</div>
In case you want to explicitly allow un-escaped HTML input, the property can be cast as `[api:HTMLText]`. The following
example takes the `Content` field in a `SiteTree` class, which is of this type. It forces the content into an explicitly
escaped format.
:::ss
$Content.XML
// transforms e.g. "<em>alert</em>" to "&lt;em&gt;alert&lt;/em&gt;"

View File

@ -1,21 +0,0 @@
# How to create a navigation menu
In this how-to, we'll create a simple menu which
you can use as the primary navigation for your website.
Add the following code to your main template,
most likely the "Page" template in your theme,
located in `themes/<mytheme>/templates/Page.ss`.
:::ss
<ul>
<% loop $Menu(1) %>
<li>
<a href="$Link" title="Go to the $Title page" class="$LinkingMode">
<span>$MenuTitle</span>
</a>
</li>
<% end_loop %>
</ul>
More details on creating a menu are explained as part of ["Tutorial 1: Building a basic site"](/tutorials/1-building-a-basic-site), as well as ["Page type templates" topic](/topics/page-type-templates).

View File

@ -1,95 +0,0 @@
# Paginating A List
Adding pagination to a `[api:SS_List]` is quite simple. All
you need to do is wrap the object in a `[api:PaginatedList]` decorator, which takes
care of fetching a sub-set of the total list and presenting it to the template.
In order to create a paginated list, you can create a method on your controller
that first creates a `SS_List` that will return all pages, and then wraps it
in a `[api:PaginatedList]` object. The `PaginatedList` object is also passed the
HTTP request object so it can read the current page information from the
"?start=" GET var.
The paginator will automatically set up query limits and read the request for
information.
:::php
/**
* Returns a paginated list of all pages in the site.
*/
public function PaginatedPages() {
return new PaginatedList(Page::get(), $this->request);
}
Note that the concept of "pages" used in pagination does not necessarily
mean that we're dealing with `Page` classes, its just a term to describe
a sub-collection of the list.
## Setting Up The Template
Now all that remains is to render this list into a template, along with pagination
controls. There are two ways to generate pagination controls:
`[api:PaginatedList->Pages()]` and `[api:PaginatedList->PaginationSummary()]`. In
this example we will use `PaginationSummary()`.
The first step is to simply list the objects in the template:
:::ss
<ul>
<% loop $PaginatedPages %>
<li><a href="$Link">$Title</a></li>
<% end_loop %>
</ul>
By default this will display 10 pages at a time. The next step is to add pagination
controls below this so the user can switch between pages:
:::ss
<% if $PaginatedPages.MoreThanOnePage %>
<% if $PaginatedPages.NotFirstPage %>
<a class="prev" href="$PaginatedPages.PrevLink">Prev</a>
<% end_if %>
<% loop $PaginatedPages.Pages %>
<% if $CurrentBool %>
$PageNum
<% else %>
<% if $Link %>
<a href="$Link">$PageNum</a>
<% else %>
...
<% end_if %>
<% end_if %>
<% end_loop %>
<% if $PaginatedPages.NotLastPage %>
<a class="next" href="$PaginatedPages.NextLink">Next</a>
<% end_if %>
<% end_if %>
If there is more than one page, this block will render a set of pagination
controls in the form `[1] ... [3] [4] [[5]] [6] [7] ... [10]`.
## Paginating Custom Lists
In some situations where you are generating the list yourself, the underlying
list will already contain only the items that you wish to display on the current
page. In this situation the automatic limiting done by `[api:PaginatedList]`
will break the pagination. You can disable automatic limiting using the
`[api:PaginatedList->setLimitItems()]` method when using custom lists.
## Setting the limit of items to be displayed on a page ##
To set the limit of items displayed in a paginated page use the `[api:PaginatedList->setPageLength()]` method. e.g:
:::php
/**
* Returns a paginated list of all pages in the site, and limits the items displayed to 4 per page.
*/
public function PaginatedPagesLimit() {
$paginatedItems = new PaginatedList(Page::get(), $this->request);
$paginatedItems->setPageLength(4);
return $paginatedItems;
}
## Related
* [Howto: "Grouping Lists"](/howto/grouping-dataobjectsets)

View File

@ -0,0 +1,34 @@
title: How to Create a Navigation Menu
# How to Create a Navigation Menu
In this how-to, we'll create a simple menu which you can use as the primary navigation for your website. This outputs a
top level menu with a nested second level using the `Menu` loop and a `Children` loop.
**mysite/templates/Page.ss**
:::ss
<ul>
<% loop $Menu(1) %>
<li>
<a href="$Link" title="Go to the $Title page" class="$LinkingMode">
$MenuTitle
</a>
<% if $LinkOrSection == section %>
<% if $Children %>
<li><ul class="secondary">
<% loop $Children %>
<li class="$LinkingMode"><a href="$Link">$MenuTitle</a></li>
<% end_loop %>
</ul></li>
<% end_if %>
<% end_if %>
</li>
<% end_loop %>
</ul>
## Related
* [Template Syntax](../syntax)
* [Common Variables](../command_variables)

View File

@ -0,0 +1,110 @@
title: How to Create a Paginated List
# How to Create a Paginated List
In order to create a paginated list, create a method on your controller that first creates a `SS_List` that contains
all your record, then wraps it in a [api:PaginatedList] object. The `PaginatedList` object should also passed the
[api:SS_HTTPRequest] object so it can read the current page information from the "?start=" GET var.
The `PaginatedList` will automatically set up query limits and read the request for information.
**mysite/code/Page.php**
:::php
/**
* Returns a paginated list of all pages in the site.
*/
public function PaginatedPages() {
$list = Page::get();
return new PaginatedList($list, $this->request);
}
<div class="notice" markdown="1">
Note that the concept of "pages" used in pagination does not necessarily mean that we're dealing with `Page` classes,
it's just a term to describe a sub-collection of the list.
</div>
There are two ways to generate pagination controls: [api:PaginatedList->Pages] and
[api:PaginatedList->PaginationSummary]. In this example we will use `PaginationSummary()`.
The first step is to simply list the objects in the template:
**mysite/templates/Page.ss**
:::ss
<ul>
<% loop $PaginatedPages %>
<li><a href="$Link">$Title</a></li>
<% end_loop %>
</ul>
By default this will display 10 pages at a time. The next step is to add pagination controls below this so the user can
switch between pages:
**mysite/templates/Page.ss**
:::ss
<% if $PaginatedPages.MoreThanOnePage %>
<% if $PaginatedPages.NotFirstPage %>
<a class="prev" href="$PaginatedPages.PrevLink">Prev</a>
<% end_if %>
<% loop $PaginatedPages.Pages %>
<% if $CurrentBool %>
$PageNum
<% else %>
<% if $Link %>
<a href="$Link">$PageNum</a>
<% else %>
...
<% end_if %>
<% end_if %>
<% end_loop %>
<% if $PaginatedPages.NotLastPage %>
<a class="next" href="$PaginatedPages.NextLink">Next</a>
<% end_if %>
<% end_if %>
If there is more than one page, this block will render a set of pagination controls in the form
`[1] ... [3] [4] [5] [6] [7] ... [10]`.
## Paginating Custom Lists
In some situations where you are generating the list yourself, the underlying list will already contain only the items
that you wish to display on the current page. In this situation the automatic limiting done by [api:PaginatedList]
will break the pagination. You can disable automatic limiting using the [api:PaginatedList->setLimitItems] method
when using custom lists.
:::php
$myPreLimitedList = Page::get()->limit(10);
$pages = new PaginatedList($myPreLimitedList, $this->request);
$pages->setLimitItems(false);
## Setting the limit of items
:::php
$pages = new PaginatedList(Page::get(), $this->request);
$pages->setPageLength(25);
## Template Variables
| Variable | Description |
| -------- | -------- |
| `$MoreThanOnePage` | Returns true when we have a multi-page list, restricted with a limit. |
| `$NextLink`, `$PrevLink` | They will return blank if there's no appropriate page to go to, so `$PrevLink` will return blank when you're on the first page. |
| `$CurrentPage` | Current page iterated on. |
| `$TotalPages` | The actual (limited) list of records, use in an inner loop |
| `$TotalItems` | This returns the total number of items across all pages. |
| `$Pages` | Total number of pages. |
| `$PageNum` | Page number, starting at 1 (within `$Pages`) |
| `$Link` | Links to the current controller URL, setting this page as current via a GET parameter |
| `$CurrentBool` | Returns true if you're currently on that page |
## API Documentation
* [api:PaginatedList]

View File

@ -0,0 +1,46 @@
title: Disable Anchor Rewriting
# Disable Anchor Rewriting
Anchor links are links with a "#" in them. A frequent use-case is to use anchor links to point to different sections of
the current page. For example, we might have this in our template:
:::ss
<ul>
<li><a href="#section1">Section 1</a></li>
<li><a href="#section2">Section 2</a></li>
</ul>
Things get tricky because of we have set our `<base>` tag to point to the root of the site. So, when you click the
first link you will be sent to http://yoursite.com/#section1 instead of http://yoursite.com/my-long-page/#section1
In order to prevent this situation, the SSViewer template renderer will automatically rewrite any anchor link that
doesn't specify a URL before the anchor, prefixing the URL of the current page. For our example above, the following
would be created in the final HTML
:::ss
<ul>
<li><a href="my-long-page/#section1">Section 1</a></li>
<li><a href="my-long-page/#section2">Section 2</a></li>
</ul>
There are cases where this can be unhelpful. HTML anchors created from Ajax responses are the most common. In these
situations, you can disable anchor link rewriting by setting the `SSViewer.rewrite_hash_links` configuration value to
`false`.
**mysite/_config/app.yml**
SSViewer:
rewrite_hash_links: false
Or, a better way is to call this just for the rendering phase of this particular file:
:::php
public function RenderCustomTemplate() {
Config::inst()->update('SSViewer', 'rewrite_hash_links', false);
$html = $this->renderWith('MyCustomTemplate');
Config::inst()->update('SSViewer', 'rewrite_hash_links', true);
return $html;
}

View File

@ -1,8 +1,17 @@
title: Templates and Views
summary: This guide showcases the SilverStripe template engine and learn how to build your own themes.
introduction: SilverStripe comes with it's own templating engine. This guide walks you through the features of the template engine, how to create custom templates and ways to customize your data output.
[CHILDREN]
Most of what will be public on your website comes from template files that are defined in SilverStripe. Either in the
core framework, the modules or themes you install, and your own custom templates.
## How-to
SilverStripe templates are simple text files that have `.ss` extension. They can contain any markup language (e.g HTML,
XML, JSON..) and are processed to add features such as `$Var` to output variables and logic controls like
`<% if $Var %>`. In this guide we'll look at the syntax of the custom template engine [api:SSViewer] and how to render
templates from your controllers.
[CHILDREN How_To]
[CHILDREN Exclude=How_Tos]
## How to's
[CHILDREN Folder=How_Tos]

View File

@ -1,20 +1,10 @@
# JavaScript
title: Javascript Development
summary: Advanced documentation about writing and customizing javascript within SilverStripe.
**Important: Parts of this guide apply to the SilverStripe 2.4 release, particularly around the jQuery.entwine
library.**
# Javascript Development
This page describes best practices for developing with JavaScript in SilverStripe. This includes work in the CMS
interface, form widgets and custom project code. It is geared towards our "library of choice", jQuery, but most
practices can be applied to other libraries as well.
## File Inclusion
SilverStripe-driven code should use the `[api:Requirements]` class to manage clientside dependencies like CSS and JavaScript
files, rather than including `<script>` and `<link>` tags in your templates. This has the advantage that a registry
of requirements can be built up from different places outside of the main controller, for example included `[api:FormField]`
instances.
See [requirements](/reference/requirements) documentation.
The following document is an advanced guide on building rich javascript interactions within the SilverStripe CMS and
a list of our best practices for contributing and modifying the core javascript framework.
## jQuery, jQuery UI and jQuery.entwine: Our libraries of choice
@ -27,21 +17,13 @@ SilverStripe CMS uses [jQuery UI](http://ui.jquery.com) on top of jQuery.
For any custom code developed with jQuery, you have four choices to structure it: Custom jQuery Code, a jQuery Plugin, a
jQuery UI Widget, or a `jQuery.entwine` behaviour. We'll detail below where each solution is appropriate.
<div class="hint" markdown='1'>
**Important**: Historically we have been using [PrototypeJS](http://prototypejs.com), which is now discouraged. SilverStripe as a framework doesn't impose a choice of library. It
tries to generate meaningful markup which you can alter with other JavaScript libraries as well. Only the CMS itself and
certain form widgets require jQuery to function correctly. You can also use jQuery in parallel with other libraries, see
[here](http://docs.jquery.com/Using_jQuery_with_Other_Libraries).
</div>
## Custom jQuery Code
### Custom jQuery Code
jQuery allows you to write complex behaviour in a couple of lines of JavaScript. Smaller features which aren't likely to
jQuery allows you to write complex behavior in a couple of lines of JavaScript. Smaller features which aren't likely to
be reused can be custom code without further encapsulation. For example, a button rollover effect doesn't require a full
plugin. See "[How jQuery Works](http://docs.jquery.com/How_jQuery_Works)" for a good introduction.
You should write all your custom jQuery code in a closure. This will prevent jQuery from conflicting from any prototype
code or any other framework code.
You should write all your custom jQuery code in a closure.
:::javascript
(function($) {
@ -50,18 +32,10 @@ code or any other framework code.
})
})(jQuery);
### Custom jQuery/JavaScript in the CMS
## jQuery Plugins
To call additional Javascript or jQuery files in to the CMS, edit your mysite/config/config.yml file as follows:
:::javascript
LeftAndMain:
extra_requirements_javascript:
- '/path/to/file.js'
### jQuery Plugins
A jQuery Plugin is essentially a method call which can act on a collection of DOM elements. It is contained within the `jQuery.fn` namespace, and attaches itself automatically to all jQuery collections. The basics for are outlined in the
A jQuery Plugin is essentially a method call which can act on a collection of DOM elements. It is contained within the
`jQuery.fn` namespace, and attaches itself automatically to all jQuery collections. The basics for are outlined in the
official [jQuery Plugin Authoring](http://docs.jquery.com/Plugins/Authoring) documentation.
There a certain [documented patterns](http://www.learningjquery.com/2007/10/a-plugin-development-pattern) for plugin
@ -120,7 +94,7 @@ Usage:
})(jQuery);
### jQuery UI Widgets
## jQuery UI Widgets
UI Widgets are jQuery Plugins with a bit more structure, targeted towards interactive elements. They require jQuery and
the core libraries in jQuery UI, so are generally more heavyweight if jQuery UI isn't already used elsewhere.
@ -186,7 +160,7 @@ Usage:
})(jQuery);
### entwine: Defining Behaviour and Public APIs
### jQuery.Entwine
jQuery.entwine is a third-party plugin, from its documentation:
"A basic desire for jQuery programming is some sort of OO or other organisational method for code. For your
@ -603,55 +577,7 @@ Example: JSpec Shopping cart test (from [visionmedia.github.com](http://visionme
end
end
### Javascript in the CMS {#javascript-cms}
The CMS has a number of Observer-pattern hooks you can access: (The elements which are notified are listed in brackets.)
* Close -- when 'folder' in SiteTree is closed. (form?)
* BeforeSave -- after user clicks 'Save', before AJAX save-request (#Form_EditForm)
* PageLoaded -- after new SiteTree page is loaded. (#Form_EditForm)
* PageSaved -- after AJAX save-request is successful (#Form_EditForm)
* SelectionChanged -- when new item is chosen from SiteTree (.cms-tree)
Here's an example of hooking the 'PageLoaded' and 'BeforeSave' methods:
:::javascript
/*
* Observe the SiteTree 'PageLoaded' event, called whenever a SiteTree page is
* opened or reloaded in the CMS.
*
* Also observe 'BeforeSave' which is called when the Save button is pressed,
* before the AJAX call to save the page is sent.
*/
Behaviour.register({
'#Form_EditForm' : {
initialize : function() {
this.observeMethod('PageLoaded', this.pageLoaded);
this.observeMethod('BeforeSave', this.beforeSave);
this.pageLoaded(); // call pageload initially too.
},
pageLoaded : function() {
alert("You loaded a page");
},
beforeSave: function() {
alert("You clicked save");
}
} // #Form_EditForm
});
See ['onload' javascript in the CMS](/reference/leftandmain#onload-javascript)
### Break the rules!
The guidelines are not intended to be hard and fast rules; they cover the most common cases but not everything. Don't be
afraid to experiment with using other approaches.
## Related
* [css](css)
* [Unobtrusive Javascript](http://www.onlinetools.org/articles/unobtrusivejavascript/chapter1.html)
* [Quirksmode: In-depth Javascript Resources](http://www.quirksmode.org/resources.html)