Sulu 2.0 Documentation

Size: px
Start display at page:

Download "Sulu 2.0 Documentation"

Transcription

1 Sulu 2.0 Documentation Release 1.0 alpha Sulu Team January 10, 2017

2

3 Contents 1 What s in our documentation? The Book Cookbook Reference Bundles Developer Guide i

4 ii

5 Sulu makes Content Management awesome. Here s the perfect place to get started and find everything you need to know to code with Sulu. We got The Book, Cookbook, Reference, Bundles and Developer Guide. Be sure to visit our website. There s a lot of information about Sulu and how we do things. Sulu aims to manage business content in a beautiful interface based on solid, extendable state of the art technology. Contents 1

6 2 Contents

7 CHAPTER 1 What s in our documentation? 1.1 The Book When you work through the book you ll build a website based on Sulu from the scratch. At first we explain some of our very basic design decisions. Based on that we ll get your project started. Be sure to know a thing or two about Symfony. Sulu is based on Symfony and structured according to the Symfony standards. If you don t know how to work within the Symfony framework you might encounter some problems when using Sulu. What s in the book? Introduction We created Sulu because we believe some things could work different - in terms of content management - than they do at the moment. In Sulu there s a lot of discussion, reflection, experience and passion. We made a lot of decisions and want to give you a short overview on why we chose to do things the way we do them. When is Sulu the right choice? Sulu isn t made for everyone. There are some requirements where other Content Management Systems are better. Sulu is the right choice when you can answer some of the following questions with yes. Do you want to work with the Symfony stack? You got a running app based on Symfony and want to add a content management layer? Do you need a clean, solid development setup? Default solutions won t fit the requirements? You want to create a modern website based on modern technology? Do you need total freedom over your frontend code? Does your project require multiple languages? Should there be several portals? Usability and design of the backend are important? Answering some of the following questions with yes, may be a hint that another technology may be a better pick. You want to chose from tons of ready to use templates? 3

8 4 Chapter 1. What s in our documentation?

9 You want to create a simple blog? You have never used Symfony before? You want to host the website yourself and have no experience in server setup? No matter what the outcome of our little survey is, we d love to show you more about Sulu. What is a Content Management Platform? When it comes to Content Management a lot of terms are in the wild. CMS, CMF, CMP... What else could you imagine? We see Sulu more as a Content Management Platform as it isn t made for websites only and we want to keep it highly customizable. A Content Management Platform is a set of components and modules that can be used to build a content administration and publishing environment customized to the individual needs of the project. It s used for data driven systems, web-apps or large scale web platforms. A Content Management System (CMS) is a more or less standardized software with a fixed set of functionalities mainly focused on the management of websites. Sulu is a Content Management Platform which comes with all necessary modules to be used as a CMS. In this documentation we will focus mainly on the usage as a Content Management System. Sulu is capable of managing the content of websites and fully support the 4-step Content Life Cycle ( 1. Content creation/collection 2. Revision/approval 3. Publishing 4. Archiving The standard publishing format is HTML but the platform is multi-channel, meaning other formats (such as e.g. XML) can be easily applied. Other strengths are the support of multi-languages and multi-site structures with shareable content. Sulu was designed to create webpages with high performance in the current state of the Internet. This means a high focus on web standards (as described in the W3C standards and search engine optimization. Although Sulu focuses on more complex websites it still provides an UI that is easy to understand, fast to learn and enjoyable to use. The software runs on modern browsers without the need of any plugins and will work on a standard state-of-the-art PC or tablet. We already covered some of Sulu s strength. The next chapter will stake out the main focus. On what does Sulu focus? While developing Sulu we had a special vision in mind. Besides Content management made awesome we wanted to create a technology that supports what a business needs. looks good and is easy to use. helps developers excel The Book 5

10 Business Our world is going global. Businesses target several markets where several languages are spoken. Companies are splited into brands with dozens of products. Complex structures arise. With Sulu we build up a data pool which feeds a set of portals in a couple of languages. Design We put a lot of love and manpower into the design and user interface of our administration area. Editors are guided intuitive through a clean set of organized screens. The live preview provides immediate and robust visual feedback. You can t create ugly content, it will directly get back on you. Technology Developers should focus on building awesome applications. They should not think about where they put things and how to structure them. They also shouldn t think about on how to hack stuff. That s why we chose Symfony as a base. A clean, modern framework that allows developers to adapt, extend and modify functionality where ever they want. We learned what Sulu focus on. Next we ll show what comes with Sulu in a basic installation. How Sulu is structured? This graphic shows how the core of Sulu is setup. 6 Chapter 1. What s in our documentation?

11 Data Symfony uses PHPCR, Doctrine and MySQL, MariaDB or Jackrabbit. Basic Frameworks Sulu is based on Symfony and the Symfony CMF. Sulu Everything else is Sulu. In the next step there is more information about the components. Which components are packed into Sulu? The standard installation of Sulu comes with a set of components (called modules ) required for the content management process: 1.1. The Book 7

12 Contacts The Contact module has two main purposes: The first (and in many cases most important) is managing the users that have access to the administration backend of the website. The second is organizing the user-data collected through the website (e.g. newsletter registrations etc.). In more complex environments this module can also be used to manage community members, online-shop customers or other contact based data. Assets The Assets module let you upload and organize any type of documents such as pictures, text documents (PDF, Word, Excel etc.), videos or audio clips. Once uploaded an asset can be used in as many webpages as required remaining its single source in the Assets module. This means if you would like to change a document that it used in several different webpages you would only have to replace it once in Assets. Pictures will be automatically transformed to web-compatible formats and resized to the required formats of the templates while the original file will be stored as well. All other document types remain in their original format. Webspaces A Webspace is the place where the actual website structure and content will be created. Within a Webspace one single content-structure will be defined but by using e.g. multiple languages and sub-domains an unlimited number of websites that share the same structure may be available. Furthermore an unlimited number of webspaces can be managed in one Sulu installation. Confused? Maybe this example helps: ACME Inc. has a website that needs to be published in English, German and French. The easy way to do this is to let the user choose their desired language and stay on the same domain displaying the required content using sub-domains such as e.g. For the user or a search engine this would mean 1 website with 3 languages sharing the same content structure. Now lets assume that ACME Inc. wants to dedicate each language to its correspondent market by using top-leveldomains. This would of course be more marketing oriented and search engine friendly. The English content would be published in the German in and the French in Let s go even further and say each website s design should be a little different, maybe with a different header color. The user and the search engine would now have 3 separate websites, each with 1 language and individual design but all with the same content-structure. Any of this scenarios can be implemented with Sulu using one webspace. Got it? Great! (Don t worry if not, we go a lot deeper into this later.) Settings As the title implies this module gives you access to all internal adjustments of Sulu. One very important section is Permissions where you can create user roles with access right which then can be applied to a user in the Contacts module. This gives you complete control over the access rights of your website administrators. In addition you can manage meta information such as categories or tags that are used in other modules. So now that you know all the components of Sulu we ll have a closer look to one of the paradigms we committed ourselves to. The separation of concerns. 8 Chapter 1. What s in our documentation?

13 Separation of Concerns As most of the modern Content Management Systems Sulu completely separates content from design. It urges template based content rendering. Due to the fact that usability, web standards and SEO are of such great importance the templates take a big role in the creation of a Sulu based web platform. To ensure that the templates make use of all the possibilities that the CMS delivers, Sulu provides a set of functionalities and development guidelines. Many of these can be found in this documentation and we strongly recommend to carefully read through and use them as much as possible. By doing so your content will be much easier to mange, the performance of your system will be optimized and your website will be more accessible for users, search engines or third party applications. Here are some of the separations we did. Template vs. Theme As usual in Symfony the structure of data is separated from its presentation layer. In Sulu the structure of a Page, a so called Template is defined. The Template defines how the administration interface of the page looks and how the data is passed to the theme. The Theme itself is - by default - a set of Twig Templates. We already heard some content specific terms on this page. On the next page we ll have detailed look on the Content Architecture. Content Architecture Our content is heavily structured. As mentioned in How Sulu is structured? we rely on the Symfony CMF on top of PHPCR. On this page we ll get into the Sulu Content Architecture. Sulu Instance At first you create a Sulu Instance. It could be seen as a single installation or one pool of data. Its real live mapping could be a company or an organization. Webspace On your instance you ll define webspaces. Webspaces could represent your brands and corporations. A landing page could be a single webspace. Languages Once you created your webpsaces you could define languages. Pages could then be translated or mapped to another language as shadow- or ghost-pages. Page As already heard in Separation of Concerns pages are configured in templates. They are created in webspaces and represent an entry in a certain menu. These pages are contained within your webspace. Once you got your Setup a website! right, you could easily explore the Sulu default structure in the backend The Book 9

14 Content-Type A template is build up of several Content-Types. A blogpost for example could consist of the following content-types: Single line text (Title) Multi line text (Infobox) Richtext (Content) Date (Event-Date) List of Tags (Tags) A detailed list of all the content-types is covered in Adding a template. Assets Assets are media files like images and downloads. They are shared through all the Websites on the instance. Snippets Snippets are very similar to assets. They are small pieces of content that could be shown on several pages in several webspaces. Contacts Contacts represent personal information. They are also used to manage Sulu Users itself. Whatever you want Sulu is very extensible. You got existing content you want to integrate through DBAL? Do it. An API that delivers content? Integrate it. Other Symfony bundles you ve already coded. Integrate them. A more detailled documentation could be found in the section About the Sulu Content Architecture. Now you are really deep into the concepts of Sulu. So the next step is to get started. Getting Started It is important to understand the underlaying concepts of Sulu, but if you want to skip this part and start coding, head over to Getting Started Getting Started Awesome, you are going a step further. We hope your project lifts off like a rocket. In this section you ll configure everything so that you re ready for Creating a basic website. That s what we ll do System Requirements Sulu needs a System to run on. Here are the requirements. For successfully running Sulu you ll have to fulfill the following system requirements: 10 Chapter 1. What s in our documentation?

15 Mac OSX, Linux or Windows Webserver (apache or nginx with enabled URL rewriting) PHP 5.5 or higher Database (MySQL, PostgreSQL or any other database supported by doctrine) composer Some of the following links may help you: LAMP (Linux) WAMP (Windows) MAMP (MacOS) LAMP Server on a VirtualBox Following optional requirements are recommended: Apache Jackrabbit If you want to build parts of the system on your own, you will additionally need: nodejs grunt ruby Compass Hopefully you got your Server running, so you re ready to start over with Sulu. Installation After working through this page you ll have a running Sulu instance. At first we ll load Sulu and afterwards dependent packages. Get the code First of all you have to clone the sulu-standard repository on GitHub and change into the cloned directory. $ git clone After the clone has finished, you can change to the cloned directory, and checkout the latest version of Sulu: $ cd sulu-standard $ git checkout master Install dependencies We use composer to install the correct versions of Sulu s dependencies: composer install 1.1. The Book 11

16 At the end of the installation you will be asked for some parameters. The following table describes these parameters, whereby most of the default values should be fine for simple installations. Parameter Description database_driver Defines which database driver will be used database_host The address of the server, on whch the database is running database_port The port number to access the database on that server database_name The name of the database database_user The name of the database user database_passwordthe password of the database user mailer_transport The protocol to send mails (currently not used) mailer_host The server from which the mails will be sent (currently not used) mailer_user The username for sending mails (currently not used) mailer_password The password for sending mails (currently not used) locale The default locale for the system secret An unique key needed by the symfony framework sulu_admin.namea name, which will be shown in the administration interface sulu_admin. administrator address content_fallback_intervall The intervall in milliseconds, between content preview update in the http polling mode websocket_port The port which will be used for the content preview in the http polling mode websocket_url The url which will be used for the content preview in the http polling mode phpcr_backend The PHPCR backend definition, defaults to the doctrine-dbal, check for more configuration options phpcr_workspace The PHPCR workspace which will be used phpcr_user The user for phpcr phpcr_pass The password for phpcr phpcr_cache PHPCR caching type Congratulations! You have just installed Sulu. Continue with Setup a website! to setup your first Sulu website. Setup a website! On this page you ll learn how to configure your website. You ll define webspaces and languages, create templates, set the correct permissions and create a user. Webspaces The content management part of Sulu is built upon Webspaces. Each of these webspaces configure a content tree, which can be managed with different localizations. For the start you can just copy the delivered file: cp app/resources/webspaces/sulu.io.xml.dist app/resources/webspaces/sulu.io.xml Basically you can name the file however you want, as long as it is ending with.xml. After copying you should adjust the file according to you installation. Basically you have to change the key-tag to a unique value across all webspaces of this installation, the name and the URLs. These values are written in squared brackets in the following example: <?xml version="1.0" encoding="utf-8"?> <webspace xmlns=" xmlns:xsi=" xsi:schemalocation=" Chapter 1. What s in our documentation?

17 <name>[name]</name> <key>[key]</key> <localizations> <localization language="en" shadow="auto"> <localization language="en" country="us" shadow="auto"/> </localization> <localization language="de"> <localization language="de" country="at"/> </localization> </localizations> <theme> <key>default</key> <default-templates> <default-template type="page">example</default-template> <default-template type="homepage">default</default-template> </default-templates> </theme> <navigation> <contexts> <context key="main"> <meta> <title lang="de">hauptnavigation</title> <title lang="en">mainnavigation</title> </meta> </context> <context key="footer"> <meta> <title lang="de">footernavigation</title> <title lang="en">footernavigation</title> </meta> </context> </contexts> </navigation> <portals> <portal> <name>sulu.io</name> <key>sulu_io</key> <resource-locator> <strategy>tree</strategy> </resource-locator> <localizations> <localization language="en" default="true"/> <localization language="de" x-default="true"/> </localizations> <environments> <environment type="prod"> <urls> <url language="en" country="us">sulu.us</url> <url language="de" country="at"> <url>sulu.lo/{localization</url> </urls> </environment> 1.1. The Book 13

18 <environment type="stage"> <urls> <url>stage.sulu.lo/{localization</url> <url>sulu.lo/{localization</url> </urls> </environment> <environment type="dev"> <urls> <url>[url]</url> <url language="en" country="us">localhost</url> </urls> </environment> </environments> </portal> </portals> </webspace> Note: You have to insert the name of your webspace at [name], the key at [key], and the URL of your installation at [url]. If you want to run Sulu in different environments you also have to change the URLs in the other environment tags. Sulu needs these URLs in order to match the given requests to a certain portal and webspace. Otherwise it would not be possible to know the content of which webspace should be loaded. In the portal localization configuration you can define a default and a x-default localization. The default will be used to determine the locale if no locale was specified in a requested url. The x-default will be used to generate the hreflang tags for seo optimization. This locale will be used as a kind of fallback for search-engines. Templates All created pages are based on templates, which need to be configured. So you need some templates to add pages to the system. Therefore, you have to add some XML-files to the specified folder. These files describe the structure of the pages, i.e. what kind of content the pages can consist of. For the start you can just copy some of the delivered files. If you want to learn more about the templates browsing through the copied file might give you a good idea on how they look and what they might do for you. cp app/resources/pages/default.xml.dist app/resources/pages/default.xml cp app/resources/pages/overview.xml.dist app/resources/pages/overview.xml cp app/resources/snippets/default.xml.dist app/resources/snippets/default.xml With this configuration you will be able to create default pages, which just contain the most basic content types (a title, an URL, links to other pages, images, and a text editor), and overview pages, which can aggregate multiple pages. We also copied a default snippet. Feel free to create your own custom templates. Complete the installation After the installation you have to clear the caches, add some empty folders and set the appropriate permissions to the cache folders: Use the following commands for Linux: rm -rf app/cache/* rm -rf app/logs/* 14 Chapter 1. What s in our documentation?

19 mkdir app/data sudo setfacl -R -m u:www-data:rwx -m u:`whoami`:rwx app/cache app/logs uploads/media web/uploads/medi sudo setfacl -dr -m u:www-data:rwx -m u:`whoami`:rwx app/cache app/logs uploads/media web/uploads/med Or these commands for Mac OSX: rm -rf app/cache/* rm -rf app/logs/* mkdir app/data APACHEUSER=`ps aux grep -E '[a]pache [h]ttpd' grep -v root head -1 cut -d\ -f1` sudo chmod +a "$APACHEUSER allow delete,write,append,file_inherit,directory_inherit" app/cache app/lo sudo chmod +a "`whoami` allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs Or these commands for Windows (with IIS web server): rd app\cache\* -Recurse -Force rd app\logs\* -Recurse -Force md app\data $rule = New-Object System.Security.AccessControl.FileSystemAccessRule $folders = "app\cache", "app\logs", "app\data", "uploads\media", "web\uploads\media" foreach ($f in $folders) { $acl = Get-Acl $f; $acl.setaccessrule($rule); Set-Acl $f $acl; Thanks to the MassiveBuildBundle we can complete the installation with another single command, which executes some build targets. These targets cover the initialization of the database and PHPCR (based on the previously created configuration files) and loads the fixtures: app/console sulu:build prod If you want to also create a user with the credentials admin/admin you can also execute the following command: app/console sulu:build dev Note: If you omit the build target as the last parameter you will see a list of all available build targets. Warning: The name of the build targets should not be confused with the Symfony environments, although they are most likely to be executed in the ones named after them. Create a new user In order to login into Sulu you need to create a user. Before you can do that you have to create the administrator role. You can easily add this role with the following command: $ app/console sulu:security:role:create Name the role and choose Sulu as the system. Afterwards you just have to enter the following command on the command line, which will guide you through the creation in an interactive manner: $ app/console sulu:security:user:create Just follow the instructions. Afterwards you ll be able to login into the Sulu Backend, which is accessible by on one of your configured URLs on the site /admin. So your basic setup is almost ready. Next we ll take a quick tour through the admin interface The Book 15

20 The Sulu Admin Interface In the last steps you setup your own Sulu website. The admin area should already be accessible. It gives a nice impression of the features of Sulu. And that s just what this page does: Give you a short glance on the Sulu admin interface. Everything else you ll learn by exploring it. There won t be a dedicated documentation. Dashboard We got big plans for the dashboard, but at the moment it gives you a starting point with the implemented search. Just enter whatever you want to work on and it will give you direct links. 16 Chapter 1. What s in our documentation?

21 Contacts Contacts on the one hand cover the handling of personal informations on the other hand they are also the user provider for Sulu Users. You re also able to create organizations and connect people with them. Assets Sulu saves assets like images or downloadable files in a global pool. They could be shared throughout webspaces. Settings In the settings section, stuff that is closer to the system is defined. We got user roles, categories, tags and the cache. User Roles You could define several roles. The admin interface looks like this: Categories You could categorize stuff with categories. Tags Sulu also got a tagging system. Snippets A Snippet is a global piece of content, that could be used in every webspace The Book 17

22 18 Chapter 1. What s in our documentation?

23 1.1. The Book 19

24 20 Chapter 1. What s in our documentation?

25 Content The main part of the administration area is the content. You could edit whatever you defined before. Though it is not the biggest part on this page, this is where Sulu happens. Profile You could edit the personal information of your user in this section. Now you should have an overview on what Sulu could provides and how it looks. There s one last step to get started: Configure your local Webserver and then we are ready to create a basic website. Configure your local Webserver You need to configure a virtual host for your webserver in order to run a clean Sulu instance. If you ve already done so, skip this section. Note: It is a good decision to create a virtual host for each of your Sulu projects. They are separated by domain and you ll got full control on what you expose. Here is an example for Apache and Nginx The Book 21

26 Apache 2.2 In your virtual hosts file you should configure something like: <VirtualHost *:80> DocumentRoot "/var/www/sulu.lo/web" ServerName sulu.lo <Directory "/var/www/sulu.lo/web"> Options Indexes FollowSymLinks AllowOverride All Order allow,deny Allow from all <IfModule mod_expires.c> ExpiresActive On ExpiresDefault "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/jpg "access plus 1 month" ExpiresByType text/javascript "access plus 1 month" ExpiresByType text/css "access plus 1 month" </IfModule> <IfModule mod_deflate.c> SetOutputFilter DEFLATE SetEnvIfNoCase Request_URI \.(?:gif jpe?g png)$ no-gzip dont-vary SetEnvIfNoCase Request_URI \.(?:exe t?gz zip bz2 sit rar)$ no-gzip dont-vary 22 Chapter 1. What s in our documentation?

27 SetEnvIfNoCase Request_URI \.pdf$ no-gzip dont-vary BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bmsie!no-gzip!gzip-only-text/html </IfModule> </Directory> </VirtualHost> Nginx The Nginx configuration could look something like. server { listen 8081; server_name sulu.lo; root /var/www/sulu.lo/web; error_log /var/log/nginx/sulu.lo.error.log; access_log /var/log/nginx/sulu.lo.at.access.log; # strip app.php/ prefix if it is present rewrite ^/app\.php/?(.*)$ /$1 permanent; location /admin { index admin.php; try_files { rewrite ^(.*)$ /admin.php/$1 last; location / { index website.php; try_files # expire location ~* \.(?:ico css js gif jpe?g png)$ { try_files $uri /website.php/$1; access_log off; expires 30d; add_header Pragma public; add_header Cache-Control "public"; { rewrite ^(.*)$ /website.php/$1 last; # pass the PHP scripts to FastCGI server from upstream phpfcgi location ~ ^/(website admin app app_dev config)\.php(/ $) { include fastcgi_params; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_buffers 16 16k; 1.1. The Book 23

28 fastcgi_buffer_size 32k; fastcgi_split_path_info ^(.+\.php)(/.*)$; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SYMFONY_ENV dev; fastcgi_param HTTPS off; Warning: Be sure to also configure your local host-file, if running Sulu locally. Now, your Sulu instance is ready. Start your engines. Now! Creating a basic website In Getting Started we got Sulu running. Now it is time to create a website. We ll have another look at the Sulu content architecture and afterwards work through the process of building a website. We ll define webspaces and templates, add a theme, write twig templates and get a little bit into smart content and localization. About the Sulu Content Architecture We already heard something about Content Architecture in the introduction. Now we are starting to code will dig a little bit deeper. Sulu uses PHPCR as a persistence layer, and therefore follows its structure. Additionally Sulu adds another layer called webspaces, which have already been explained in the section about the Which components are packed into Sulu?. These webspaces contain an arbitrary number of pages, which are ordered in a tree in a hierarchical way. Each of these pages can contain content in many different localizations. This tree also represents the actual structure of the website, so that no additional navigation tree is required. Pages can be enabled in the navigation, and will then appear in the right spot on the navigation of the website. The pages in Sulu have a specific template applied. The template defines which properties the page will have, whereby each of these properties are further specified by a content type. The content type will have a direct impact on the possible values and configuration possibilities of the property it is applied to. There is also a further reference of all the available Content types. There are also some advanced features regarding the pages in Sulu. Besides the content management using the properties and content types already described there is also the possibility to define internal and external links. Internal links redirect to other pages managed by the content management section of Sulu, and external link to an arbitrary URL. Another useful feature is the shadow page functionality. It allows to use the content of another localization. So if a webspace defines localizations for American and British English, it is possible to use the content of the American English for the British English, without managing the exactly same content again. This is especially useful if there are e.g. different contact addresses for each country, but the rest of the page should be exactly the same. With the content architecture on our mind we ll create a webspace. Setup a Webspace In this chapter we will have a look at webspaces. Therefore we will create a configuration for a basic website. This will result in a single portal website with multiple localizations. 24 Chapter 1. What s in our documentation?

29 As already described in the section before, a webspace also creates a new content tree. These trees are accessible by the navigation in the Sulu administration interface. Sulu allows you to create pages and sub pages in these trees and fill them with content. Have a closer look at Adding a template for more details on the content management process. Normally you ll create a webspace for a new website, a landingpage or a portal, that should run on your Sulu instance. The following file shows the simplest configuration possible. These lines will be explained in the following paragraphs. <?xml version="1.0" encoding="utf-8"?> <webspace xmlns=" xmlns:xsi=" xsi:schemalocation=" <name>example</name> <key>example</key> <localizations> <localization language="en"/> </localizations> <theme> <key>default</key> <default-templates> <default-template type="page">example</default-template> <default-template type="homepage">default</default-template> </default-templates> </theme> <navigation> <contexts> <context key="main"> <meta> <title lang="en">mainnavigation</title> </meta> </context> </contexts> </navigation> <portals> <portal> <name>example</name> <key>example</key> <resource-locator> <strategy>tree</strategy> </resource-locator> <environments> <environment type="prod"> <urls> <url language="en">example.org</url> </urls> </environment> <environment type="dev"> <urls> <url language="en">example.lo</url> </urls> </environment> </environments> </portal> 1.1. The Book 25

30 </portals> </webspace> As you probably already have encountered, the root tag for our webspace definition is webspace. Afterwards you see a name, which is displayed in the administration interface. But even more important is the key, which is used internally to generate some files and define some paths. Therefore it is really important that the webspace key is unique across all webspaces in a single installation. Localizations In the localizations-tag you can list all the available localizations in this webspace. In the example we are simply adding the English language, but you can also define country specific language if you add a country attribute to the localization, so for instance the following tag would add Austrian German to the available localizations: <localization language="de" country="at" /> For a more complete explanation you should have a look at Adding localizations. Themes The theme is described by a key. This key leads to a certain theme, implemented by a developer in the system. Read more about themes in the section Adding a theme. Navigation It s also possible to define some so called navigation contexts, which allows the user to add pages to different kind of navigations. The different contexts can be defined in the navigation-section, and this selection will be available to choose from in the administration interface. Afterwards the developer can retrieve the navigation for a given context by using some Twig-extensions delivered with Sulu. Portals A webspace can itself consist of multiple portals. In our simple configuration file we make use of only one portal. The idea is that the same content can be shared among different portals and URLs. The portals can then also define for themselves in which localization they publish the content, so that you can spread different localizations over different URLs. Our sample file defines just one portal, which includes a name and a key just as the webspace, whereby the key for the portal hast to be unique for the entire installation, not only within this webspace. Then the strategy for the resource-locator is defined, which influences the design of the URLs for the content. Currently there is only the tree-option available resulting in exposing the entire content tree in the URL. URLs The most important part of the portal configuration are the environments, because they are including the URLs for the portal. A portal can have multiple environments, which have to match the environments defined in Symfony. Usually dev, stage and prod are available. Each environment can define its own set of URLs. The URLs also have to include the localization somehow. You have two possibilities to do so: 26 Chapter 1. What s in our documentation?

31 Fixing an URL to a specific localization The above example shows this possibility, where you fix one URL to exactly one localization. The following fragment shows again how to this: <url language="de" country="at"> Since it is possible to define localizations without a country, this attribute is also optional here. However, the combination of language and country here must result in an existing localization. Using placeholders in the URL definition at the following line for an example: Another possibility is to create the URL with a placeholder. Have a look <url> Placeholder are expressions in curly braces, which will be expanded to every possible value. For the above example that means, that an URL for every localization defined will be generated. So if you have a localization de-at and en-gb, the system will create URLs for and In the following table all the possible placeholders are listed, and explains the values of them by using the de-atlocalization: Placeholder Description Example for de-at {localization The name of the entire localization de-at {language The name of the language de {country The name of the country, only makes sense in combination with {language at Now you got your webspace ready, we will create a template for a page that could be added to the webspace. Adding a template After defining a webspace creating a template file is the next step towards a Sulu website. We ll learn about Content types and how a template definition should look like. In Sulu a template consists of multiple content types, whereby a content type describes the way the data is stored in the database and how to enter them in the administration interface. Pages in the Sulu content section will be based on one of these templates. On this page there are the available content types described, how to define these values in our template configuration file, what you should consider when creating the HTML templates, and finally how to connect the data from Sulu to the HTML template. Available content types The following list shows the content types delivered by a standard Sulu installation. The first column shows the key, which acts as an unique identifier. The second one describes the appearance in the administration interface, and the last one how the content is returned to the HTML template The Book 27

32 Key Appearance Value text_line simple text line text text_area text area text text_editor text editor with formatting capabilities formatted text color color picker text date date picker text time text line with a time validation text url text line with an URL validation text text line with an validation text password password field text phone text line for a phone number text internal_links widget for adding links to other pages resolved pages as defined in parameters single_internal_link widget for selecting a single internal link resolved page as defined in parameters smart_content widget for configuring smart contents, a content type for aggregating multiple pages resolved pages as defined in parameters resource_locator widget for entering the URL for the page text tag_list autocomplete field for entering and adding tags array of texts media_selection widget for adding media (images, documents) to the page array containing another array with urls for every format Add a template definition To add a new template to your Sulu installation, you just create a new xml file in app/resources/pages named by a unique template key. See the following file for an example of a template definition: <?xml version="1.0"?> <template xmlns=" xmlns:xsi=" xsi:schemalocation=" <key>default</key> <view>clientwebsitebundle:templates:default</view> <controller>suluwebsitebundle:default:index</controller> <cachelifetime>2400</cachelifetime> <meta> <title lang="en">default</title> </meta> <properties> <property name="title" type="text_line" mandatory="true"> <meta> <title lang="en">title</title> </meta> <tag name="sulu.rlp.part"/> </property> <property name="url" type="resource_locator" mandatory="true"> <meta> <title lang="en">resourcelocator</title> </meta> 28 Chapter 1. What s in our documentation?

33 <tag name="sulu.rlp"/> </property> <property name="images" type="media_selection"> <meta> <title lang="en">images</title> </meta> </property> <property name="article" type="text_editor"> <meta> <title lang="de">artikel</title> <title lang="en">article</title> </meta> <params> <param name="godmode" value="true"/> <param name="links" value="true"/> <param name="tables" value="true"/> </params> </property> </properties> </template> The root element of this xml file is template, which first child element is a key, which has to match the filename without the file extension (e.g. the file default.xml has the key default). The next xml tags contains some information about rendering the template. This includes the view, which is the reference to the twig template, and the controller-tag references the controller, which is used to render the given template. For standard templates you don t have to define your own controllers, because you can use the index-action of the DefaultController in the SuluwebsiteBundle. Both the template and controller have to be referenced as described in the Template Naming and Locations (with the addition of the LiipThemeBundle) and Controller Naming Pattern in the Symfony documentation. The meta-tag consists of another title-tag for each available language, which will be displayed in the template selection of the Sulu administration interface. The next tag is for all the properties in this template. A property is the instance of one of the previous listed content types. The property s type attribute is the key from the list above, and the name identifies this particular property. The first child element is another meta-tag containing the title for each language, which will be displayed in the content management form in the Sulu administration. Depending on the content type you can/must add some more parameters, as for the article-property in the example above. The example is enabling the godmode, the icon for adding links and the icon for adding tables. Note: Every template has to define a property named title, because it is used internally for generating URLs and storing. We ve learned how to define the template. The next step is to write corresponding theme. Adding a theme In the theme we ll define how things look to the user. You know HTML, CSS, JS and such stuff The Book 29

34 What is a theme A theme defines the way the content from Sulu is presented on the website. In general it s not more than a simple folder containing all the required twig templates, images, scripts, fonts and all the other assets you want to use in this specific theme. You can have multiple themes in one Sulu installation. Every webspace can decide which theme to use, by a simple key in the webspace configuration file already described in Setup a Webspace. This means that it is also very easy to switch between different themes. Create a theme Creating a theme is as easy as creating a new folder in the Resources/themes/ folder of your bundle with the name of the new theme. Afterwards you have to fill this folder with all the used templates in the webspace. These templates go into another subfolder in your theme, which you have to reference later. We recommend to name this folder templates. It is also recommended to create a folder views for more general templates, like the master template, an error page, etc., and a folder blocks for reusable templates, like the seo information. For more concrete information about the structure of these templates you should check the Adding a template. Enable the theme For resolving the templates we are using the LiipThemeBundle, which requires you to register your themes. You can do that in your application configuration located at app/config/config.yml. Add the name of your theme folder to the following list: liip_theme: themes: ["default", "your-new-shiny-theme"] Configure image formats If you are using images, you probably also care about the available image formats. Sulu also supports you with that issue. You can define different image formats, which Sulu will then create for every uploaded image. This generation is based on your configuration. You can define the formats in the file Resources/themes/<theme>/config/imageformats.xml. Take a look at the following file for an example: <?xml version="1.0" encoding="utf-8"?> <formats xmlns=" xmlns:xsi=" xsi:schemalocation=" <format> <name>640x480</name> <commands> <command> <action>resize</action> <parameters> <parameter name="x">640</parameter> <parameter name="y">480</parameter> </parameters> </command> </commands> </format> </formats> 30 Chapter 1. What s in our documentation?

35 With the format tag you are creating a new image format. You have to name this format, and create a list of commands to execute on it. The example will resize the uploaded image to the size defined with the two parameters. The next table shows the standard commands available with its parameters. Command Resize Scale Crop Parameters x: the new width y: the new height x: the new width y: the new height x: x-coordinate of the startpoint y: y-coordinate of the startpoint w: the with of the new image h: the height of the new image With the theme we got the container for our Twig-templates. That s what we ll do next: Writing awesome Twig files. Creating a Twig Template Twig is an awesome option for rendering HTML. It got some nice features like blocks and inheritance. That s why we use and love Twig. Build the HTML template We recommend to build the HTML templates in a first draft with plain HTML and some dummy texts. That means absolutely no placeholders for template engines. This ensures that your HTML is working across all browsers (at least if you test it correctly), and it is easier to test, since there are guaranteed no errors caused by the some wrong template variables. Please make also sure that your HTML is valid, and use HTML tags in a semantic way, so that your website will achieve the best results in terms of search engine optimization. Which Twig-Template is used? In Adding a template we learned how to define a template. 1 <?xml version="1.0"?> 2 <template xmlns=" 3 xmlns:xsi=" 4 xsi:schemalocation=" <key>default</key> 7 8 <view>clientwebsitebundle:templates:default</view> 9 <controller>suluwebsitebundle:default:index</controller> </template> In the page template the view could be set. Rendering the Content If you don t use your custom controller and modify the output the Sulu Controller renders, Sulu passes some default variables to Twig The Book 31

36 Content In the content everything you defined in your template is saved. If you got a title you could easily obtain it from the content-var. <h1>{{ content.title </title> Extension In the extension var Sulu writes content from Sulu extensions. Typically stuff that is defined in separate Tabs in the Sulu content section. At the moment there is the SEO and the excerpt extension, that could be used. This extensions are available on every page no matter which template you chose. Here is an example how it could look like in the backend. Notice the Excerpt & Categories tab next to the SEO tab. You could include the SEO meta tags like this: {{ sulu_seo(extension, content) The excerpt is available in: {{ extension.excerpt Navigation There is a Twig function that obtains the menu. You need to pass the key of the navigation context you defined in your webspace (Setup a Webspace). While editing a page the navigation context could be defined in settings > Navigation context. Here we ll render the main navigation. 1 <ul> 2 {% for item in sulu_navigation_root_tree('main') % 3 <li> 32 Chapter 1. What s in our documentation?

37 4 <a href="{{ sulu_content_path(item.url) " 5 title="{{ item.title ">{{ item.title </a> 6 {% if item.children length > 0 % 7 <ul> 8 {% for child in item.children % 9 <li><a href="{{ sulu_content_path(child.url) " 10 title="{{ child.title "> 11 {{ child.title 12 </a></li> 13 {% endfor % 14 </ul> 15 {% endif % 16 </li> 17 {% endfor % 18 </ul> Images If there are images defined in your template you could render them by using this code: 1 {% for image in content.images % 2 <div> 3 <img src="{{ image.thumbnails['200x100'] " alt="{{ image.name "/> 4 <p>{{ image.title </p> 5 </div> 6 {% endfor % Image formats need to be defined in the image_formats.xml in your config. More examples You could find more examples of how content could be accessed in our example file. Default Template Just have a look at our default theme, that ships with our standard installation as long with our default page templates over at github. Using smart content What is smart content? The smart content is one of our most powerful content types. It allows the content editor to dynamically configure an aggregation of content, whereby content does not only mean pages. This is possible due to the data providers, which can be registered in the system. A data provider defines which options are supported, and is responsible for loading the data. Sulu is already shipped with different data providers, one for pages from the content management section, and another two for contacts and accounts. The configuration will be resolved to a set of arrays, which can easily be used in a twig template. Configure a smart content The smart content is configured in the template definition. The template definition is already described in Adding a template. All that has to be done is to add another property for the smart content. This configuration can look 1.1. The Book 33

38 something like the following typical XML fragment: <property name="pages" type="smart_content"> <meta> <title lang="en">smart Content</title> </meta> <params> <param name="properties" type="collection"> <param name="title" value="title"/> <param name="description" value="excerpt.description"/> </param> <param name="present_as" type="collection"> <param name="one"> <meta> <title lang="en">one column</title> </meta> </param> <param name="two"> <meta> <title lang="en">two column</title> </meta> </param> </param> </params> </property> In this XML fragment a smart_content property named pages is defined. For pages there is also the possibility to define a properties parameter, as you can see in the previous fragment. In this collection property can be defined which properties of the page should be returned in the array passed to the twig template. The name of the parameter describes how the property will be accessible in the twig template, and the value is the name of the property on the page. Additionally there is the excerpt extension, which can be used as well, there has just excerpt. to be prefixed. This extension is available for all pages, so it is a safe bet. The problem with other properties is that you have to make sure or at least check in the twig template if the property exists. The value of the present_as property is injected into a dropdown, where the content editor can choose between different styles, which of course have to be implemented by the creator of the twig template. Popular options here are one or two columns with variations like with or without images. There are also more parameters to tweak the smart content, for a deeper understanding of this there is the reference documentation of the Smart content. Use the smart content in a twig template Using the pages that are returned from the smart content in a twig template is very easy. As already described the data is returned as an array in the twig template in the content variable. In the view variable the configuration data of the smart content is stored. This way it is really simple to display this information using a twig template: {% for page in content.pages % <div class="{{ view.pages.present_as "> <h2><a href="{{ sulu_content_path(page.url) ">{{ page.title </a></h2> <p>{{ page.description </p> </div> {% endfor % The pages in content.pages refers to the name of the property in the template definition. Every page being 34 Chapter 1. What s in our documentation?

39 returned by the filter described in the smart content has its own array in this variable, so that we can iterate over it. In the view variable the configuration of the smart content is accessible, which can be used e.g. as a CSS class in this example. This way the one or two column layout can be created by using CSS. The page loop variable can then be used to access the actual content from the page. A Sulu twig extension provides the sulu_content_path method, which builds the final URL with all the additional information required. For more and deeper information about twig there is the excellent twig documentation. The next step is how to add localization to Sulu. Adding localizations Sulu is built for companies with an international focus, translating pages into multiple different languages is a very important task for a content editor using Sulu. Sulu also considers the different variations of a language among different countries. The combination of these two factors is called a localization. Configuring localizations Localizations for the content are configured in the webspaces, as already described in Setup a Webspace. Adding another localization is as easy as adding another localization tag to the webspace configuration file. Localizations can also be nested, which has no impact on the representation in all the dropdowns, but it will help the system to find better fallbacks. So a good example using english and german as a language might look something like the following fragment. <localizations> <localization language="en"> <localization language="en" country="us"/> <localization language="en" country="gb"/> </localization> <localization language="de"> <localization language="de" country="de"/> <localization language="de" country="at"/> <localization language="de" country="ch"/> </localization> </localizations> With this configuration the system will contain seven different content localizations: en, en-us, en-gb, de, de-de, de-at, de-ch, whereby en-us and en-gb are falling back to en, and de-de, de-at and de-ch are falling back to de. Usage of localizations For the developer the only touching points with localizations are the configuration and the eventual use of a language switcher on the homepage. For the language switcher the urls variable delivered to the twig template can be used, which contains an associative array with the localization code being the code and the value the URL to the current page in this language. The template itself does not have to be adapted for usage with multiple localizations. The twig variables are the same for every language, only the content is different, and this is handled by Sulu for the developer. The nesting of the localizations is very important for the column navigation of the content. In case there is a ghost page - which means that the page is not translated into the current localization - this tree will be used to determine the closest language available The Book 35

40 At first we ll have another look at the content architecture on a technical level and afterwards we will create stuff. Lots of fun with Sulu. We hope you ll find the love we put in it while creating it. 1.2 Cookbook Here are some awesome recepies for lunch. The Cookbook covers some advanced topics which each covers a very special problem. Create your very own menu with our recipes. Our recepies 36 Chapter 1. What s in our documentation?

41 1.2.1 Caching with Varnish Varnish is a HTTP caching proxy server which can be used to radically improve the response time of your website. Sulu is bundled with a soft caching proxy, the Symfony HttpCache, but using Varnish is a more optimal solution for a large website, especially if it has lots of traffic. In addition to being twice as fast as the default caching implementation it also supports better cache invalidation, which means that your website will appear more up-to-date. Note: Twice as fast is relative. The default cache implementation can respond in 0.02s compared to varnishes 0.01s - the difference here is imperceptible - but varnish will scale better and supports better invalidation. This tutorial will walk you through the process of setting up Varnish on your own server and configuring it to work with Sulu. This tutorial assumes that: You are using the Apache2 web server You are running Ubuntu or Debian The steps should apply equally to other variants. Install Varnish On Ubuntu/Debian install Varnish as follows: apt-get install varnish This should install and start the Varnish daemon. Server Configurations Web Server Note: You may skip this section if you intend to run varnish in a development environment and do not want to change the default port of your web server. For a caching server to serve pages to your users, it will need to pretend to be the web server. Web servers listen to requests on port 80 by default. We must make Varnish listen for connections on port 80 and make the web server listen on a different port. Note: We are going to make the web server listen on port 8090 but there is nothing special about this port and it can be anything as long as it does not conflict with any existing services. Change the Listen directive in /etc/apache2/ports.conf to Listen 8090: # /etc/apache2/ports.conf #... Listen 8090 And change any and all virtual hosts to now listen on 8090: 1.2. Cookbook 37

42 # /etc/apache2/conf.d/sites-available/sulu.conf #... <VirtualHost \*:8090> #... </VirtualHost> Now you will need to configure varnish. Varnish Note: Skip this section if you are in a development environment and prefer to access varnish via. its default port (explained later). By default Varnish will listen for connections on port 6081 (at least on Debian systems). If you are running a production system you will need to change this to the default HTTP port, port 80. Verify which port Varnish is listening to: $ ps ax grep varnish 6585? SLs 0:00 varnishd -f /home/daniel/.varnish/sulu.vcl -s malloc,1g -T : ? Sl 0:07 varnishd -f /home/daniel/.varnish/sulu.vcl -s malloc,1g -T : The -a option indicates where Varnish is listening - it is listening on port 8083, which is incorrect. Under Debiae/Ubuntu we can change the initialization script: # /etc/default/varnish #... DAEMON_OPTS="-a :80 \ -T localhost:6082 \ -f /etc/varnish/default.vcl \ -S /etc/varnish/secret \ -s malloc,256m Now restart the daemon: /etc/init.d/varnishd restart Varnish Configuration The following will add full caching support for Sulu: # /etc/varnish/default.vcl vcl 4.0; acl invalidators { "localhost"; backend default {.host = " ";.port = "8090"; 38 Chapter 1. What s in our documentation?

43 sub vcl_recv { if (req.method == "PURGE") { if (!client.ip ~ invalidators) { return (synth(405, "Not allowed")); return (purge); if (req.method == "BAN") { if (!client.ip ~ invalidators) { return (synth(405, "Not allowed")); if (req.http.x-cache-tags) { ban("obj.http.x-host ~ " + req.http.x-host + " && obj.http.x-url ~ " + req.http.x-url + " && obj.http.content-type ~ " + req.http.x-content-type + " && obj.http.x-cache-tags ~ " + req.http.x-cache-tags ); else { ban("obj.http.x-host ~ " + req.http.x-host + " && obj.http.x-url ~ " + req.http.x-url + " && obj.http.content-type ~ " + req.http.x-content-type ); return (synth(200, "Banned")); sub vcl_backend_response { # Set ban-lurker friendly custom headers set beresp.http.x-url = bereq.url; set beresp.http.x-host = bereq.http.host; sub vcl_deliver { if (!resp.http.x-cache-debug) { unset resp.http.x-url; unset resp.http.x-host; if (obj.hits > 0) { set resp.http.x-cache = "HIT"; else { set resp.http.x-cache = "MISS"; Restart Varnish: $ /etc/init.d/varnish restart And now have a look at the headers on your website: $ curl -I mywebsite.com HTTP/ OK 1.2. Cookbook 39

44 #... Via: 1.1 varnish #... If you see the above Via header, then all is good and your are ready to go forward. Configuring Sulu Invalidation You will first need to ensure that the default soft cache has been disabled. Open the website front controller (app/website.php in the standard edition) and ensure that the following lines are commented out: // Uncomment this line if you want to use the "symfony" http // caching strategy. See // if (SYMFONY_ENV!= 'dev') { // require_once DIR. '/../app/websitecache.php'; // $kernel = new WebsiteCache($kernel); // Warning: If you do not comment out the above lines caching will not work as you will be using 2 caches. Now edit app/config.yml and change the proxy client from symfony to varnish and set the address of your varnish server (assuming that your Varnish server is on localhost and listening on port 80): sulu_http_cache: #... proxy_client: varnish: enabled: true servers: [ 'localhost:80' ] Now have another look at the headers from your website: $ curl -I sulu.lo HTTP/ OK Host: sulu.lo:6081 Cache-Control: max-age=1000, public, s-maxage=1000 Date: Fri, 16 Jan :46:58 GMT Content-Type: text/html; charset=utf-8 X-Reverse-Proxy-TTL: 2400 X-Sulu-Handlers: public, debug X-Sulu-Proxy-Client: varnish X-Sulu-Structure-Type: AnimalsPageCache X-Sulu-Structure-UUID: 26f b-4f98-a b830735d X-Sulu-Page-TTL: 2400 X-Debug-Token: f05a02 X-Debug-Token-Link: /_profiler/f05a02 X-Varnish: Age: 88 Via: 1.1 varnish-v4 X-Cache: HIT Content-Length: 9240 Connection: keep-alive Note: If you chose not to make Varnish listen on port 80, then use sulu.lo:6081 instead. 40 Chapter 1. What s in our documentation?

45 The meaning of all these headers will be explained in the HttpCacheBundle document. But for now you should see (providing your are in dev mode) the X-Sulu-Proxy-Client has a value of varnish. Optimal configuration To get the most out of the Varnish cache you should enable the tags cache handler and disable the paths handler. The tags handler will automatically ensure that any changes you make in the admin interface are immediately available on your website. See the HttpCacheBundle document for more information. The following is a full configuration example: sulu_http_cache: handlers: tags: enabled: true public: max_age: # one week shared_max_age: # one week use_page_ttl: true enabled: true debug: enabled: %kernel.debug% proxy_client: varnish: enabled: true servers: [ ' :80' ] Maintenance Mode When you need to deploy a new version of your project on a production environment it is often necessary to disable your sulu-application and inform your users about it. Sulu maintenance mode displays a simple holding page which can be easily customized. Create Maintenance Mode To create a maintenance page, you first need to create a maintenance.php file: $ cp app/maintenance.php.dist app/maintenance.php Then you need to set the environment variable SULU_MAINTENANCE to true. For example, in your.htaccess file (for apache) SetEnv SULU_MAINTENANCE true Configure Maintenance Mode Allowed IP addresses You may like to access your application while maintenance mode is active. Then you need to set the allowed IPs: 1.2. Cookbook 41

46 <?php $allowedips = array( ' ' ); Translations You can define translations for your template as follows: <?php $translations = array( 'en' => array( 'title' => 'Maintenance', 'heading' => 'The page is currently down for maintenance', 'description' => 'Sorry for any inconvenience caused. Please try again shortly.', ), ); Default locale By default, maintenance.php is automatically detecting your browsers language. If no translation for this language exists the default locale is being used. By default this is English: <?php define('default_locale', 'en'); Running Sulu on Heroku Heroku enables programmers to run their applications in the cloud, and makes it really easy to scale your application if it follows some rules. There is a Sulu cloud edition, which follows these rules. You will find a Deploy to Heroku button in the README.md file of the repository of the previously mentioned Sulu cloud edition. This button leads to a Heroku page for deploying your very own Sulu installation. Give the application a name and choose between Europe and United States as a region, whatever is closer to your actual destination. This choice will also influence the performance of your website. Unless you really want to, you should leave the SYMFONY_ENV environment variable to prod. Otherwise the buid process will fail, because Heroku installs the dependencies with composer install --no-dev. If you change the environment to dev or test Sulu wil try to load some Symfony bundles, which are not installed, and therefore lead to an error during the build procedure. The other environment variable you have to set is DOMAIN. Set it to whatever domain this installation should work on, e.g. sulu-cloud.herokuapp.com if you don t have your own DNS entry or to something like sulu.io. For more details about working with Heroku you should check out the Heroku Dev Center Securing your application Sulu is delivered with two different possiblities to protect parts of your application. The first is the permissions based on security contexts, which allow you to restrict access to entire parts of your application or Sulu. The permissions for this kind of security are managed on a roles level. In addition to that the localization for which these permissions are valid has to be defined on the assignment of the role to the user. 42 Chapter 1. What s in our documentation?

47 The second way is to protect the access on a per-object basis. These permissions are set on the specific object. The user still has to have the correct localizations assigned in order to gain access. This tutorial will show how to use Sulu s security functionality with your own application specific code. Protect content using a security context This section describes how to protect an entire part of your application (but not a specific object). Define your security context First of all you have to define the security context, which is represented by a simple string. This is done in the Admin class of your Bundle: <?php namespace Acme\Bundle\ExampleBundle\Admin; use Sulu\Bundle\AdminBundle\Admin\Admin; class AcmeExampleAdmin extends Admin { //... public function getsecuritycontexts() { return array( 'Sulu' => array( 'Acme' => array( 'sulu.acme.example' ) ); ); //... This information is defined in the getsecuritycontexts method, which should return an array. The first level describes the system to which the security context applies - this would either be Sulu (for stuff in the administration) or a different context that you have defined manually. The second level just defines the title for another separation used in the administration interface. The third and last level defines the name of the permissions themselves. This name follows a namespacing scheme based on the previously used names. Note: Since the Admin class is registered as a bundle, you can make use of different services to define the available security contexts. For example the SuluContentBundle uses a service to create an own security context for all available webspaces in the system. Protect your controller After defining a security context, you can use it to easily protect the actions of one of your controllers. All you have to do is to implement the SecuredControllerInterface telling the SuluSecuriyListener which security 1.2. Cookbook 43

48 context and locale to use for the permission check: <?php namespace Acme\Bundle\ExampleBundle\Controller; use FOS\RestBundle\Routing\ClassResourceInterface; use Sulu\Component\Security\SecuredControllerInterface; use Symfony\Component\HttpFoundation\Request; class ExampleController implements ClassResourceInterface, SecuredControllerInterface { public function cgetaction() { // code for your get action public function postaction() { // code for your post action //... public function getlocale(request $request) { return $request->get('locale'); public function getsecuritycontext() { return 'sulu.acme.example'; The getlocale method returns the locale, which is probably determined somehow by the request, and the getsecuritycontext method defines which security context is required to access this type of resource. The SuluSecurityListener appends the information on which type of permission (view, add, edit, delete,...) is required, and automatically takes care of the permission check and returns a page with a status code of 403 in case the permissions for the currently logged in user where not sufficient. Protecting specific objects For some parts of your application you might want to protect specific objects. This section will describe how this is done with the possibilities Sulu offers. Adding the permission tab to your form First of all you have to add the permission tab to your form to enable the user to set up the permissions accordingly. The permission tab presents a list of the available user roles and a few permission icons, which can be activated. Therefore the probably already existing ContentNavigationProvider has to be extended by the permission tab: <?php namespace Sulu\Bundle\MediaBundle\Admin; 44 Chapter 1. What s in our documentation?

49 use Sulu\Bundle\AdminBundle\Navigation\ContentNavigationItem; use Sulu\Bundle\AdminBundle\Navigation\ContentNavigationProviderInterface; use Sulu\Bundle\MediaBundle\Api\Collection; use Sulu\Component\Security\Authorization\SecurityCheckerInterface; class ContentNavigationProvider implements ContentNavigationProviderInterface { private $securitychecker; public function construct(securitycheckerinterface $securitychecker) { $this->securitychecker = $securitychecker; public function getnavigationitems(array $options = []) { // also add your other ContentNavigationItems here $navigation = []; $securitycontext = 'sulu.acme.example'; if ($this->securitychecker->haspermission($securitycontext, 'security')) { $permissions = new ContentNavigationItem('Permissions'); $permissions->setaction('permissions'); $permissions->setdisplay(['edit']); $permissions->setcomponent('permission-tab@sulusecurity'); $permissions->setcomponentoptions( [ 'display' => 'form', 'type' => Example::class, 'securitycontext' => $securitycontext, ] ); $navigation[] = $permissions; return $navigation; The Using tab navigation explains this code in more detail. The only important method call here is setcomponentoptions, the rest can stay widely the same over all bundles (of course you can change the other configuration as well as described in Using tab navigation). In setcomponentoptions the type of the object to secure and the required security context are passed. For the type it is a good idea to use the class name of the entity as shown in the example. The security context is required to check if the current user has the permission to change the security settings in the given context. After this addition the permission tab should already be visible in the edit form. Configure the controller The second part is to implement the SecuredObjectControllerInterface in the Controller handling the specific type of entities: 1.2. Cookbook 45

50 <?php namespace Acme\Bundle\ExampleBundle\Controller; use FOS\RestBundle\Routing\ClassResourceInterface; use Sulu\Component\Security\Authorization\AccessControl\SecuredObjectControllerInterface; use Sulu\Component\Security\SecuredControllerInterface; use Symfony\Component\HttpFoundation\Request; class ExampleController implements ClassResourceInterface, SecuredControllerInterface, SecuredObjectControllerInterface { public function cgetaction() { // code for your get action public function postaction() { // code for your post action //... public function getlocale(request $request) { return $request->get('locale'); public function getsecuritycontext() { return 'sulu.acme.example'; public function getsecuredclass() { return Example::class; public function getsecuredobjectid(request $request) { return $request->get('id'); The SecuredObjectControllerInterface required three different methods. The getlocale method is the same as in the SecuredControllerInterface, and the implementation can be shared. The getsecuredclass method has to return the same identifier for the type of object as used in the ContentNavigationProvider. Finally the getsecuredobjectid receives the request object, and has to return the id of the object from it. The rest of the work will be done by the SuluSecurityListener in the same way as for the check of the security contexts Using tab navigation It is very easy to build your own or to extend already existing tab navigations in Sulu. The general process of displaying such a tab navigation in the administration interface of Sulu covers the following steps: 46 Chapter 1. What s in our documentation?

51 1. Your JavaScript component sends a request to /admin/content-navigations?alias=acme, and might add more options as query parameters. 2. The server responds to this request based on so called ContentNavigationProviders, which are registered to listen to a certain alias, and the passed query parameters. 3. The content is returned and Sulu s JavaScript Tab component renders the delivered information for you as tabs. This article will describe how this can be achieved in a few simple steps. Create a content navigation provider If you want to create your own tab navigation, you have to build a provider for it first. A provider is just a simple service implementing the ContentNavigationProviderInterface containing a function named getnavigationitems. The task of this function is to return an array of ContentNavigationItems, the following lines show an example of this: <?php namespace Acme\Bundle\Example\Admin; use Sulu\Bundle\AdminBundle\Navigation\ContentNavigationProviderInterface; use Sulu\Bundle\AdminBundle\Navigation\ContentNavigationItem; class AcmeContentNavigationProvider implements ContentNavigationProviderInterface { pubilc function getnavigationitems(array $options = array()) { $item = new ContentNavigationItem('Item'); $item->setaction('item'); $item->setdisplay(array('edit')); $item->setcomponent('item-tab@acmeexample'); $item->setcomponentoptions(array()); return array($item); The getnavigationitems function takes an array with options. These options are all the query parameters that were passed via the HTTP request. You can base certain decisions on these options like if some navigation items should be created at all, or you can pass these options to the JavaScript components which will be started when selecting a specific tab. Note: Since this class will be registered as a service, you can inject any other service you want to help you decide which ContentNavigationItems you want to create. It is quite common to use SecurityChecker to check for certain privileges before creating an item. The ContentNavigationItem takes several arguments. The action will be appended to the URL in the administration interface. Display defines in which cases the tab is appearing (available options are new for forms creating a new entry and edit for forms editing already existing entries). Component sets the name of the aura component which should be started and ComponentOptions are the options which will be passed to this component Cookbook 47

52 Register the content provider as a service Afterwards you have to register your content navigation provider as a service in the dependency injection container. This is quite basic, but you have to add a tag named sulu.admin.content_navigation together with an alias, which will be used by a service to find all content navigation providers for the request sent from the javascript component. Note: You can also register multiple services with the same alias. The items will then be merged, this way it is very easy to extend existing content navigations. <?xml version="1.0" encoding="utf-8"?> <container xmlns=" xmlns:xsi=" xsi:schemalocation=" <service id="acme_example.content_navigation" class="acme\bundle\example\admin\acmecontentnavigat <tag name="sulu.admin.content_navigation" alias="acme"/> </service> </container> Custom error page With Sulu it is very easy to customize the error pages for your website users. You can define a template for each HTTP status code. Configuration The following code-block shows a default configuration for the exception templates. If you want to add an own exception for example 400 you can simply add it to the list. You can specify that for each theme. <theme> <key>default</key> <error-templates> <error-template default="true">clientwebsitebundle:views:error.html.twig</error-template> <error-template code="404">clientwebsitebundle:views:error404.html.twig</error-template> <error-template code="500">clientwebsitebundle:views:error500.html.twig</error-template> </error-templates> </theme> The ExceptionController uses the status-code of the response to determine which template is responsible for the exception. If no special template is defined it uses the default template. Twig-Template In the twig-template you can use your website master template to reuse your style. {% extends "ClientWebsiteBundle:views:master.html.twig" % {% block title %Error {{ status_code {% endblock % {% block content % <h1>error {{ status_code </h1> <p>{{ status_text </p> 48 Chapter 1. What s in our documentation?

53 <p>{{ exception.message </p> {% endblock % Warning: Be careful which variable you use in your master.html.twig. If you use variables which are not defined in the error-template, the error-page cannot be rendered. Following variables are usable inside the exception template. Name status_code status_text exception currentcontent urls request.webspacekey request.defaultlocale request.locale request.portalurl request.resourcelocatorprefix request.resourcelocator request.get request.post request.analyticskey Description http-status-code http-status-code message complete exception object repsonse content which were rendered bofore exception was thrown localized urls to start page (e.g. for language-switcher) key of the current webspace default locale of current portal current locale url of current portal prefix for resourcelocators of current portal current resourcelocator array of get parameter array of post parameter analytics key of current webspace Test it To test your error pages you can use following routes: {portal-prefix/_error/{statuscode Note: If you are not sure about your portal configuration you can get the routes with this app/webconsole router:debug grep _error command Examples: sulu.lo/ch._twig_error_test ANY ANY sulu.lo /ch/_error/{code.{_format sulu.lo/en._twig_error_test ANY ANY sulu.lo /en/_error/{code.{_format sulu.lo/fr._twig_error_test ANY ANY sulu.lo /fr/_error/{code.{_format sulu.lo/de._twig_error_test ANY ANY sulu.lo /de/_error/{code.{_format sulu.lo._twig_error_test ANY ANY sulu.lo /_error/{code.{_format Optimize for production usage If you want to use Sulu in production there are a few more optimizations you can do than just switching to the prod environment. The Symfony documentation already gives an introduction into deploying applications. Since Sulu is also a Symfony application all these tips also apply to deploying Sulu. This cookbook entry will show even more ways to optimize the performance of Sulu in a production environment. Enable doctrine caches The Symfony documentation already describes how to activate caching for the metadata, queries and results in its DoctrineBundle documentation. If you have APC installed and want to enable caching using APC you can just uncomment the following lines in app/config/admin/config_prod.yml and app/config/website/config_prod.yml: 1.2. Cookbook 49

54 doctrine: orm: metadata_cache_driver: apc result_cache_driver: apc query_cache_driver: apc In case you want to use other caching providers you should have a look at the DoctrineBundle documentation, where the configuration of other providers is explained Integrating custom filters When you want to enable custom filters for your bundle you have to follow the following steps. It s important to know that the filter component works with contexts. This means for example that the lists of contacts has the contacts context and everything concering the filters for the list will need this context. It should therefore be unique. Add the missing data types to the field descriptors The custom filter feature uses the field descriptors you ve already defined for your lists. To work as expected you should define the type of each column. If not defined the filter component will asume it s a string. The available data types are: string number / integer / float date / datetime boolean Add a context and configuration for new filters Add the filter configuration to e.g. app/config/admin/config.yml. The first parameter below contexts is the context mentioned above. The fields parameter defines the url where the fields api can be found. In the features the filter has to be enabled. sulu_resource: contexts: contact: fields: "/admin/api/contacts/fields" features: - "filters" Extend the js configuration in your bundle Extend the js configuration in your bundle with a config value for the bread- crumb and the route back to the list. The last part of the setting key is the context the filters component will use. Config.set('suluresource.filters.type.contacts', { breadcrumb: [ {title: 'navigation.contacts', {title: 'contact.contacts.title', link: 'contacts/contacts' ], routetolist: 'contacts/contacts' ); 50 Chapter 1. What s in our documentation?

55 Extend the list and toolbar initialization for the lists The toolbar should have at least two groups and one of them should have the id 2 because the filter button will be added in the one with id 2. Two additional parameters have to added at the end. The first one is the instance name of the datagrid and the second one is the selector for the container where the result of the filter (x entries match filter y) will be displayed. Therefore a div above the filter div should be added in the html. ); this.sandbox.sulu.initlisttoolbarandlist.call(this, 'contacts', '/admin/api/contacts/fields', { el: this.$find('#list-toolbar-container'), instancename: 'contacts', inheader: true, groups: [ { id: 1, align: 'left', { id: 2, align: 'right' ], { el: this.sandbox.dom.find('#people-list', this.$el), url: '/admin/api/contacts?flat=true', searchinstancename: 'contacts', searchfields: ['fullname'], resultkey: 'contacts', instancename: 'contacts', viewoptions: { table: { icons: [ { icon: 'pencil', column: 'firstname', align: 'left', callback: function(id) { this.sandbox.emit('sulu.contacts.contacts.load', id);.bind(this) ], highlightselected: true, fullwidth: true, 'contacts', '#people-list-info' <div id="people-list-info"></div> <div id="people-list"></div> 1.2. Cookbook 51

56 1.2.9 Extend Entities Sulu has a very easy way to extend and replace the internal entities. This feature is not implemented for each entity but it will be implemented for all soon. These entities are ready to extend: User Role Contact You can extend all of them in the same way. Therefor we explain it for User here. Create a Entity Create your own Entity for example in the ClientWebsiteBundle. You can use the doctrine:generate:entity command for that. Extend the generated Entity with the Sulu User class. <?php namespace Client\Bundle\WebsiteBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Sulu\Bundle\SecurityBundle\Entity\User as SuluUser; /** * User * */ class User extends SuluUser { /** string * type="string", length=255, nullable = true) */ private $myproperty; /** * Set myproperty * string $myproperty User */ public function setmyproperty($myproperty) { $this->myproperty = $myproperty; return $this; /** * Get myproperty * string 52 Chapter 1. What s in our documentation?

57 */ public function getmyproperty() { return $this->myproperty; Warning: Your Entity can have own properties, but they should have at least default values. Otherwise the normal features of Sulu could crash (like the sulu:security:user:create command). Configuration You can specify your new Entity and if it exists your Repository in the sulu_security configuration section. sulu_security: objects: user: model: Client\Bundle\WebsiteBundle\Entity\User repository: Sulu\Bundle\SecurityBundle\Entity\UserRepository For the Role entity: sulu_security: objects: role: model: repository: Sulu\Bundle\SecurityBundle\Entity\Role Sulu\Bundle\SecurityBundle\Entity\RoleRepository For the Contact entity: sulu_contact: objects: contact: model: repository: Sulu\Bundle\ContactBundle\Entity\Contact Sulu\Bundle\ContactBundle\Entity\ContactRepository Warning: If you override the entities you lose your old tables and data. You should provide a upgrade script Using Elasticsearch By default Sulu uses Zend Lucene for its search in the administration and on the website. But since Sulu uses the MassiveSearchBundle it supports the same range of different search implementations, including Elasticsearch. The MassiveSearchBundle Documentation describes how to setup Elasticsearch, the steps explained there also work in combination with Sulu DataProvider for SmartContent DataProviders are used to load data for SmartContent. It returns data filtered by a configuration array. This array can be configured with an overlay in the backend form. This configuration array includes following values: 1.2. Cookbook 53

58 Name datasource tags tagoperator categories categoryoperator Description Additional constraint - like page- folder. Multiple selection of tags, which a item should have. The item has any or all of the selected tags. Multiple selection of categories, which a item should have. The item has any or all of the selected categories. Tags (websitetags) and Categories (websitecategories) can also be injected by GET parameters from the website. This can be handled separately from the admin-selected. Also different operators (websitetagsoperator and website- CategoryOperator) are available. Additional features, which can be provided with a DataProvider: Name presentas page & pagesize limit Description Value can be used in the website for display options - like one or two column - these values can be freely configured by developers. Pagination of items. Maximum items for (if pagination is active) over all pages or overall. How to create a custom DataProvider? To create a custom data provider you simply have to create a service which implements the Interface DataProvider- Interface. This Interface provides functions to resolve the configured filters for the backend API with standardized objects and for the website with array and entity access. Additionally the DataProvider returns a configuration object to enable or disable features. There exists an abstraction layer for ORM DataProviders. This layer provides the implementation of basic DataProvider functionality and Database query. If you want to create a DataProvider for the ExampleEntity you have todo following steps. 1. Repository The repository has to implement the DataProviderRepositoryInterface and provide the findbyfilters function. If the default implementation is good enough, you can include the trait DataProviderRepositoryTrait, which, needs the functions createquerybuilder (is default in repositories) and appendjoins where you are able to configure eager loading for the entity. The rest of the functionality and Query generation is done in the Trait. <?php use Sulu\Component\SmartContent\Orm\DataProviderRepositoryInterface; use Sulu\Component\SmartContent\Orm\DataProviderRepositoryTrait; /** * Repository for the ExampleEntities. */ class ExampleRepository extends EntityRepository implements DataProviderRepositoryInterface { use DataProviderRepositoryTrait; /** * {@inheritdoc */ public function appendjoins(querybuilder $querybuilder, $alias, $locale) 54 Chapter 1. What s in our documentation?

59 { $querybuilder->addselect('type')->leftjoin($alias. '.type', 'type'); Note: Be sure that the returned entities has valid serialization configuration for JMSSerializer. There are following hooks to influence the query generation. These are functions which are optional to override in the repository. Name append(querybuilder $querybuilder, $alias, $locale, $options = []) appendtagsrelation(querybuilder $querybuilder, $alias) appendcategoriesrelation(querybuilder $querybuilder, $alias) appenddatasource($datasource, $includesubfolders, QueryBuilder $querybuilder, $alias) Description Additional select, where or joins can be added to the query to match given options. The options can be generated by the data-provider and can contain for example additional filter parameter. If your entity is not directly connected to the tags (entity.tags) you can append here all needed joins and return the path to the tag relation. Same as tags. If your dataprovider can handle datasources you can add the functionality to filter by the datasource here. 2. DataItem The DataItem will be used in the backend to display the filtered items. This class implements the Interface ItemInterface. <?php use Sulu\Component\SmartContent\ItemInterface; /** * Represents example item in example data provider. * */ class ExampleDataItem implements ItemInterface { /** Example */ private $entity; public function construct(example $entity) { $this->entity = $entity; /** * {@inheritdoc * */ 1.2. Cookbook 55

60 public function getid() { return $this->entity->getid(); /** * {@inheritdoc * */ public function gettitle() { return $this->entity->gettitle(); /** * {@inheritdoc * */ public function getimage() { return $this->entity->getimage(); /** * {@inheritdoc */ public function getresource() { return $this->entity; Note: If you return an image within the getimage function it will be displayed in the admin ui. You should be sure that the image is not bigger that 50x DataProvider Also the DataProvider is mostly abstracted by the SmartContent Component. The optimize in the configuration you can disable or enable the form-elements to avoid filtering for that values. <?php use JMS\Serializer\SerializerInterface; use Sulu\Component\SmartContent\Orm\BaseDataProvider; use Sulu\Component\SmartContent\Orm\DataProviderRepositoryInterface; use Symfony\Component\HttpFoundation\RequestStack; use Sulu\Component\SmartContent\ItemInterface; /** * Example DataProvider for SmartContent. */ class ExampleDataProvider extends BaseDataProvider { 56 Chapter 1. What s in our documentation?

61 /** RequestStack */ private $requeststack; public function construct(dataproviderrepositoryinterface $repository, SerializerInterface $ser { parent:: construct($repository, $serializer); $this->requeststack = $requeststack; $this->configuration = self::createconfigurationbuilder() ->enabletags() ->enablelimit() ->enablepagination() ->enablepresentas() ->getconfiguration(); /** * Decorates result as data item. * array $data * ItemInterface[] */ protected function decoratedataitems(array $data) { return array_map( function ($item) { return new ExampleDataItem($item);, $data ); /** * Returns additional options for query creation. * PropertyParameter[] $propertyparameter array $options * array */ protected function getoptions(array $propertyparameter, array $options = []) { $request = $this->requeststack->getcurrentrequest(); $result = [ 'type' => $request->get('type'), ]; return array_filter($result); 1.2. Cookbook 57

62 4. Service Definition Define a service with your Repository and DataProvider and add the tag sulu.smart_content.data_provider with a alias to your DataProvider service definition. <service id="sulu_example.example_repository" class="sulu\bundle\examplebundle\entity\examplereposito factory-method="getrepository" factory-service="doctrine"> <argument>%sulu_example.example.entity%</argument> </service> <service id="sulu_example.smart_content.data_provider.example" class="sulu\bundle\examplebundle\smart <argument type="service" id="sulu_example.example_repository"/> <argument type="service" id="serializer"/> <argument type="service" id="request_stack"/> <tag name="sulu.smart_content.data_provider" alias="example"/> </service> Afterwards you can use your new DataProvider within a normal SmartContent property. How to create a custom Datasource component? A Datasource component is a simple aura-component which returns some data. These data can be used in the DataProviderRepository::appendDatasource method. For example returns the Content-DataProvider the UUID of the page which should be used as the parent of result set. The following example is a simple (and not complete) example of a datasource component. If you need a full example please take a look at the components media-datasource@sulumedia or content-datasource@sulucontent. define(function() { 'use strict'; var defaults = { options: { url: null, resultkey: null, selected: null, selectcallback: function(item) {, templates: { skeleton: '' // TODO html skeleton to render component, /** * namespace for events {string */ eventnamespace = 'smart-content.datasource.'; return { defaults: defaults, events: { 58 Chapter 1. What s in our documentation?

63 , names: { setselected: { postfix: 'set-selected', type: 'on', namespace: eventnamespace /** * Initialize component */ initialize: function() { // merge options with defaults this.options = this.sandbox.util.extend(true, {, defaults, this.options); // current selected datasource this.selected = this.options.selected;, // render skeleton and start subcomponents this.render(); /** * Bind events to call select callback */ bindcustomevents: function() { // setter for selected this.events.setselected(this.setselected.bind(this));, /** * Set new selected and update UI. * {String selected can also be null. */ setselected: function(selected) { this.selected = selected;, // TODO update component with new selected datasource /** * These function should be called to propagate the result to smart-content component. * {String selected can also be null. */ emitselected: function(item) { this.selected = item.id; // identifier of item this.options.selectcallback( this.selected, // will be saved and used to generate the query item.path // will be displayed on the first slide );, /** * Render container for column-navigation */ 1.2. Cookbook 59

64 ); ; render: function() { this.$container = this.sandbox.dom.createelement( this.templates.skeleton() ); this.html(this.$container); To activate these datasource-component it has to be enabled in the DataProvider. <?php public function construct(dataproviderrepositoryinterface $repository, SerializerInterface $seriali { parent:: construct($repository, $serializer); $this->configuration = self::createconfigurationbuilder() ->enabletags() ->enablelimit() ->enablepagination() ->enablepresentas() ->enabledatasource( 'example@suludoc', [ 'url' => '/admin/api/example', 'resultkey' => 'examples', ] ) ->getconfiguration(); The component name and options will be used to initialize the component. this.options.url. Therefor you can use the url wil System-Collections System-Collections are special collections which are not editable, deletable or movable. Apart from that they can be used like all other collections. The System takes care of creating and upgrading them. Each bundle can request them, to save there images like avatar or logos in the contact section. Because of the usage of the configuration tree also the App itself can register system collection and use them. sulu_media: system_collections: # Prototype key: meta_title: [] collections: # Prototype key: meta_title: [] This structure will be used to create a Collection Structure like this: 60 Chapter 1. What s in our documentation?

65 System --> Sulu contact --> People --> Orginizations --> Client Website --> My own System-Collection To register own System-Collections you can prepend the configuration with your bundle extension: <?php class ClientWebsiteExtension extends Extension implements PrependExtensionInterface { /** * {@inheritdoc */ public function prepend(containerbuilder $container) { if ($container->hasextension('sulu_media')) { $container->prependextensionconfig( 'sulu_media', [ 'system_collections' => [ 'client_website' => [ 'meta_title' => ['en' => 'Client website', 'de' => 'Client Website'], 'collections' => [ 'uploads' => [ 'meta_title' => ['en' => 'My own System-Collection', 'de' => 'Mei ], ], ], ], ] ); /** * {@inheritdoc */ public function load(array $configs, ContainerBuilder $container) {... To use this new Collection you can use the sulu_media.system_collections.manager service. <?php // to get id of system collection $systemcollectionmanager->getsystemcollection('client_website.uploads'); // to determine if id is a system collection (e.g. validation) $systemcollectionmanager->issystemcollection(1); Note: The key of the system-collection consists of namespace.key. In this case namespace = client_website and key 1.2. Cookbook 61

66 = uploads Adding new Webspace To create a new webspace you have to create a new file within the app/resources/webspaces directory. The content of the file should be quite similar to the sulu_io.xml.dist file in this folder. Note: The key of the webspace has to be the same as the filename without the xml extension. To activate the webspace within sulu with a prod or stage environment you have to clear the cache with the command: app/console clear:cache -e <environment> To initiate the database for the new webspace run the command app/console sulu:phpcr:init && app/console sulu:webspaces:init. To allow users to see the new webspace you also have to set the permissions in the roles for the new webspace. After this few steps you are able to administrate and view your new webspace. It is possible to work through the recepies, altought most of the people will pick the ones, which are most similar to their own tasks. We re open to suggestions. 1.3 Reference In our reference we ll describe how to configure stuff and how to use existing things. You can find list of funcionality we put in Sulu and how you could use it. At the moment there are components, Content Types and Twig Extensions. The Reference aims to developers who already worked through the introdcution and know how Sulu works. What you can find in the Reference Content types As already described in Adding a template a template consists of multiple content types, which enable the user to manage content in a semantic way. The simplest template possible looks something like the this: <?xml version="1.0"?> <template xmlns=" xmlns:xsi=" xsi:schemalocation=" <key>default</key> <view>clientwebsitebundle:templates:default</view> <controller>suluwebsitebundle:default:index</controller> <cachelifetime>2400</cachelifetime> <meta> <title lang="en">default</title> </meta> <properties> <property name="title" type="text_line" mandatory="true"> 62 Chapter 1. What s in our documentation?

67 1.3. Reference 63

68 <meta> <title lang="en">title</title> </meta> <tag name="sulu.rlp.part"/> </property> <property name="url" type="resource_locator" mandatory="true"> <meta> <title lang="en">resourcelocator</title> </meta> <tag name="sulu.rlp"/> </property> </properties> </template> This chapter will describe which types you can insert within the properties tag. Every content type in the documentation comes with an example property tag to clarify the usage. This documentation also specifies the available parameters and tags for each content type: Category list Description Shows a list of all available categories. The user can select with a checkbox which ones to assign to the page. Categories can be managed in the settings section of Sulu. The selection will be saved as an array. Parameters No parameters available Example <property name="categories" type="category_list"> <meta> <title lang="en">category List</title> </meta> </property> Checkbox Description Shows a simple checkbox, the state of the checkbox will be saved as a boolean. Parameters No parameters available 64 Chapter 1. What s in our documentation?

69 Example <property name="available" type="checkbox"> <meta> <title lang="en">available</title> </meta> </property> Color Description Shows a text line with an attached color picker, the inserted content will be saved as simple string. Parameters No parameters available Example <property name="color" type="color"> <meta> <title lang="en">color</title> </meta> </property> Date Description Shows a text line with an attached date picker. The inserted content will be saved as a normalized string. Parameters No parameters available Example <property name="date" type="date"> <meta> <title lang="en">date</title> </meta> </property> 1.3. Reference 65

70 Description Shows a text line, the inserted content will be validated against a regex and saved as a simple string. Parameters No parameters available Example <property name=" " type=" "> <meta> <title lang="en"> </title> </meta> </property> Internal links Description Shows a list with the possibility to add links to other pages managed in Sulu. Additionally it populates all the fields defined in the template configuration to the HTML template. The content is stored as an array of references. Parameters Type Parameter properties collection Description Defines with which key which property of the linked page should be populated to the HTML template. Example <property name="links" type="internal_links"> <meta> <title lang="en">links</title> </meta> <params> <param name="properties" type="collection"> <param name="title" value="title"/> <param name="article" value="article"/> </param> </params> </property> 66 Chapter 1. What s in our documentation?

71 Location Description Adds the possibility to assign geographic information to a page. Can be used either with Google Maps and Open Street Maps. Parameters Parameter Type Description countries collection A collection of countries represented as string assigned to unique keys (usually the ISO code of the country) map- collection Defines the available map providers Providers default- string The preselected provider in the dropdown Provider geolocator- Name string The alias of the service, which should be used for geolocation Example <property name="location" type="location"> <meta> <title lang="en">location</title> </meta> </property> Media selection Description Shows a list with the possibility to assign some assets from the media section to a page. Also allows to define a position, which can be handled later in the template. Parameters Parameter Type Description types string A comma separated list of available asset types to assign. Each item in the list must be one of document, image, video or audio. collection defaultdisplayoption displayoptions string A collection of booleans, which defines to which positions the assets can be assigned (lefttop, top, righttop,...) Defines which of the displayoptions is the default one 1.3. Reference 67

72 Example <property name="images" type="media_selection"> <meta> <title lang="en">images</title> </meta> <params> <param name="types" value="image,video"/> <param name="displayoptions" type="collection"> <param name="lefttop" value="true"/> <param name="top" value="true"/> <param name="righttop" value="true"/> <param name="left" value="true"/> <param name="middle" value="false"/> <param name="right" value="true"/> <param name="leftbottom" value="true"/> <param name="bottom" value="true"/> <param name="rightbottom" value="true"/> </param> <param name="defaultdisplayoption" value="left"/> </params> </property> Contact selection Description Shows a list with the possibility to assign some people or organizations from the contact section to a page. Also allows to define a position, which can be handled later in the template. Parameters Parameter Type Description contact boolean Person tab should be visible or not. accounts boolean Organizations tab should be visible or not. Example <property name="contacts" type="contact"> <meta> <title lang="en">contacts</title> </meta> <params> <param name="contact" value="true"/> <param name="account" value="true"/> </params> </property> <ul property="contacts"> {% for contact in content.contacts % <li> 68 Chapter 1. What s in our documentation?

73 {{ contact.type == 'contact'? contact.fullname : contact.name ( {% for in contact. s % <a href="mailto:{{ . ">{{ . </a> {% if not loop.last % {% endif % {% endfor % ) </li> {% endfor % </ul> Password Description Shows a password input field, the inserted content will be saved as a simple string. Parameters No parameters available Example <property name="password" type="password"> <meta> <title lang="en">password</title> </meta> </property> Phone Description Shows a text line, the inserted content will be validated against a phone number regex and saved as a simple string. Parameters No parameters available Example <property name="phone" type="phone"> <meta> <title lang="en">phone number</title> </meta> </property> 1.3. Reference 69

74 Resource locator Description Shows a text line with a non-editable prefix, which represents the routes to this position in the content tree. The part of the current page can be edited in the available text line. Additionally there is a button with the URL history of the current page, where parts of the history can also be deleted or reactivated. Tags Tag sulu.rlp sulu.rlp.part Description The resource locator with this tag defines the URL to a specific page Fields marked with this tag are used to generate the URL for a specific page Parameters No parameters available Example <property name="title" type="text_line"> <tag name="sulu.rlp.part"/> </property> <property name="resource_locator" type="resource_locator"> <meta> <title lang="en">resource locator</title> </meta> <tag name="sulu.rlp"/> </property> Single internal link Description Shows a field, on which exactly one link to another page can be assigned. Parameters No parameters available Example <property name="link" type="single_internal_link"> <meta> <title lang="en">link</title> </meta> </property> 70 Chapter 1. What s in our documentation?

75 Smart content Description Shows a list of items, which depend on a configurable filter. Depending on the DataProvider you can define where the items come from (Datasource), what tags the filtered items must have, how they are sorted, and how many results you want to get. Additionally you can define some presentation types, so that the content manager can decide if the items should be displayed e.g. in one column or two columns. The filter is saved as a JSON string in the database. The DataProviders are backend modules which handle the selected filters and return the items which fit to this filters. There are some predefined ones but you can add your own DataProvider easily. How you can do this is described in DataProvider for SmartContent Parameters Parameter Type Description provider string DataProvider alias for content of SmartContent - Default content. max_per_page integer Limits the results per page. Omit this parameter to disable pagination. page_parameter string Defines the page number key to be used in the website query string. tags_parameter string Defines the tags key to be used in the website query string. This comma separated list of tag names will be combined (AND) with the selected tags from the backend. categories_parameter string Defines the categories key to be used in the website query string. This comma separated list of category ids will be combined (AND) with the selected tags from the backend. website_tags_operator string OR or AND to define how the tags will be combined in the query. website_categories_operator string OR or AND to define how the categories will be combined in the query. properties col- Defines the property names which will be exposed in the HTML template. lec- tion present_as collection A collection of strings, which can be configured for different presentation modes. If more than one element is given, the user can choose between the elements in this collection. The selected value is also passed to the HTML template. category_root string Root category (key) to display category-tree. display_options collection Hide form-elements (tags, categories, sorting, limit, presentas) can hide available elements for DataProvider. Return Value This values are available in the view variable in the twig templates Reference 71

76 Name Type Description datasource string Uuid of data-source includesubfolders bool Is TRUE if subfolders will be crawled categories string[] Selected categories categoryoperator string Operator which combines selected categories tags string[] Selected tags tagoperator string Operator which combines selected tags websitecategories string[] Selected categories over GET parameter websitecategoryoperator string Operator which combines GET parameter categories websitetags string[] Selected tags over GET parameter websitetagoperator string Operator which combines GET parameter tags sortby string Selected sort column sortmethod string Selected sort method - ASC or DESC presentas string selected present as value limitresult string Selected limit for result page int Current page number hasnextpage bool Is TRUE if another page exists The content values depends on the DataProvider. Note: You can determine content properties with the twig function dump. DataProvider These providers are predefined for Sulu-Entities. Content Pages Alias: content This provider filters content pages. You can choose a parent page as data source, whose child pages will be filtered by the DataProvider. Parameters Parameter Type Description properties collection Defines the property names which will be exposed in the HTML template. Note: properties can include structure properties or extension data: title - is a property of the structure excerpt.title - is a property of the excerpt structure extension with the name title For an example see Example for content DataProvider Contact - People Alias: contact This provider filters the contacts. Account - Organization This provider filters the accounts. Alias: account 72 Chapter 1. What s in our documentation?

77 Media Alias: media This provider filters the media. Parameters Parameter Type Description mimetype_parameter string name of mime-type GET parameter (default: mimetype) type_parameter string name of media-type GET parameter (default: type) Additionally the provider provides some additional filter for the website. With the PropertyParameter mimetype_parameter and type_parameter the name of the GET parameter can be specified. For example the MimeType can be filtered by adding?mimetype=application/pdf to the content URL. Same takes effect for?type=image with the media type (which is basically a group of mime-types). Example for content DataProvider Page template <property name="smart_content" type="smart_content"> <meta> <title lang="en">smart Content</title> </meta> <params> <param name="provider" value="content"/> <param name="max_per_page" value="5"/> <param name="page_parameter" value="p"/> <param name="properties" type="collection"> <param name="article" value="article"/> <param name="excerpt.title" value="excerpttitle"/> <param name="excerpt.tags" value="excerpttags"/> <param name="excerpt.images" value="excerptimages"/> </param> <param name="present_as" type="collection"> <param name="two"> <meta> <title lang="en">two columns</title> </meta> </param> <param name="one"> <meta> <title lang="en">one column</title> </meta> </param> </param> </params> </property> Twig template {% for page in content.pages % <div class="col-lg-{{ view.pages.presentas == 'two'? '6' : '12' "> <h2> <a href="{{ content_path(page.url) ">{{ page.title </a> </h2> <p> <i>{{ page.excerpttitle </i> <i>{{ page.excerpttags join(', ') </i> 1.3. Reference 73

78 </p> {% if page.excerptimages length > 0 % <img src="{{ page.excerptimages[0].thumbnails['50x50'] " alt="{{ page.excerptimages[0]. {% endif % {% autoescape false % {{ page.article {% endautoescape % </div> {% endfor % Snippet Description Shows a list with the possibility to assign an arbitrary amount of snippets. Snippets are small blocks managed in the global section, which can be reused on as many pages as necessary. The assigned snippets will be saved as an array of references. Parameters Parameter Type Description snippettype string The type of snippet to assign. Example <property name="snippets" type="snippet"> <meta> <title lang="en">snippets</title> </meta> <params> <param name="snippettype" value="animal"/> </params> </property> Tag list Description Shows a simple text line with an autocomplete feature for the available Tags in the system. Tags can be managed in the settings section of Sulu. The assigned tags will be saved as an array. Note: Tags which do not already exist will be created. Parameters No parameters available 74 Chapter 1. What s in our documentation?

79 Example <property name="tags" type="tag_list"> <meta> <title lang="en">tags</title> </meta> </property> Text area Description Shows a simple text area, the inserted content will be saved as simple string. Parameters No parameters available Example <property name="description" type="text_area"> <meta> <title lang="en">description</title> </meta> </property> Text editor Description Shows a rich text editor, capable of formatting text as well. The output of the editor will be stored as HTML in a string field. Parameters Parameter Type Description table booleanadds tools for creating tables to the text editor link booleanadds buttons for creating links to the text editor paste_from_word booleanadds a button to paste content from word to the text editor. If you add text via this button, some characters which could cause troubles are removed. height integer Sets the initialize height of the texteditor. max_height integer Sets the maximum height to which the texteditor can grow. Texteditor supports also all ckeditor config parameters in snakecase Reference 75

80 Example <property name="article" type="text_editor"> <meta> <title lang="en">article</title> </meta> <params> <param name="table" value="true"/> <param name="link" value="true"/> <param name="paste_from_word" value="true"/> <param name="height" value="100"/> <param name="max_height" value="200"/> <!-- CKEditor Parameters examples: --> <param name="extra_allowed_content" value="img(*)[*]; span(*)[*]; div(*)[*]; iframe(*)[*]; sc <param name="ui_color" value="#ffcc00"/> </params> </property> Text line Description Shows a simple text line, the inserted content will be saved as simple string. Parameters Parameter Type Description headline boolean If true the height and font size of the text line get increased. Example <property name="title" type="text_line"> <meta> <title lang="en">title</title> </meta> <params> <param name="headline" value="true"/> </params> </property> Time Description Shows a text line, the inserted content will be validated against a localized time string and saved as a simple string. Parameters No parameters available 76 Chapter 1. What s in our documentation?

81 Example <property name="time" type="time"> <meta> <title lang="en">time</title> </meta> </property> URL Description Shows a text line, the inserted content will be validated against an URL regex and saved as a simple string. Parameters Parameter Type Description defaults collection Default values for input (scheme and specificpart). schemes collection List of available schemes in dropdown and validation. Example <property name="url" type="url"> <meta> <title lang="en">url</title> </meta> <params> <param name="defaults" type="collection"> <param name="scheme" value=" <param name="specific_part" value=" </param> <param name="schemes" type="collection"> <param name=" <param name=" <param name="//"/> </param> </params> </property> Twig Extensions Sulu provides its own Twig functions and filters In addition to the standard set of Twig functions which you can use in website templates. CoreBundle Functions 1.3. Reference 77

82 sulu_breadcrumb Returns the breadcrumb for a given node UUID {{ sulu_breadcrumb(node.uuid) Arguments: uuid: string - UUID of page node for which to show the breadcrumb sulu_content_load Returns a Structure for the given UUID {% set page = sulu_content_load(' ') % Arguments: uuid: string - UUID of structure Returns: array uuid: UUID of page title: Title of page url: URL for page template: Template name of page changed: Changed date of page changer: User ID of changer created: Date of creation creator: User ID of creator nodetype: Type of node path: Path of page excerpt: Excerpt (if load-excerpt is true) sulu_content_load_parent Return the parent of the Structure with the given UUID {% set page = sulu_content_load_parent(' ') % Arguments: uuid: string - UUID of structure parent Returns: array uuid: UUID of page title: Title of page url: URL for page template: Template name of page changed: Changed date of page changer: User ID of changer created: Date of creation 78 Chapter 1. What s in our documentation?

83 creator: User ID of creator nodetype: Type of node path: Path of page excerpt: Excerpt (if load-excerpt is true) sulu_content_path Returns the absolute URL for the content at the given path <ul class="nav nav-justified"> {% for item in content.snippets[0].internallinks % <li> <a href="{{ sulu_content_path(item.url, item.webspacekey) " title="{{ item.title ">{{ </li> {% endfor % </ul> Arguments: url: string - Url to get path webspacekey string - If item is not in the same webspace as current content (optional) Returns: string - Absolute URL sulu_content_root_path Returns the absolute URL for the content root at the given path <ul class="nav nav-justified"> {% for item in content.snippets[0].internallinks % <li> <a href="{{ sulu_content_root_path(item.url, item.webspacekey) " title="{{ item.title </li> {% endfor % </ul> Arguments: url: string - Url to get path webspacekey string - If item is not in the same webspace as current content (optional) Returns: string - Absolute URL sulu_meta_alternate Note: This documentation is a incomplete. Note: This method is deprecated, use sulu_seo instead Return alternate links for the given URLs Arguments: urls: string - Urls Returns: Alternate links 1.3. Reference 79

84 sulu_meta_seo Note: This documentation is a incomplete. Note: This method is deprecated, use sulu_seo instead Return SEO metatags with fallbacks Arguments: extension: array content: array Returns: Seo fallbacks sulu_navigation_root_flat Returns navigation Page from root in a flat list data-structure. Arguments: context: string - optional: context to filter navigation depth: integer - optional: depth to load (1 - childs, 2 - childs and child of childs,...) loadexcerpt: boolean - optional: load data from excerpt tab Returns: array uuid: UUID of page title: Title of page url: URL for page template: Template name of page changed: Changed date of page changer: User ID of changer created: Date of creation creator: User ID of creator nodetype: Type of node path: Path of page excerpt: Excerpt (if load-excerpt is true) sulu_navigation_root_flat Returns navigation Page from root in a flat list data-structure. Arguments: context: string - optional: context to filter navigation depth: integer - optional: depth to load (1 - childs, 2 - childs and child of childs,...) loadexcerpt: boolean - optional: load data from excerpt tab Returns: 80 Chapter 1. What s in our documentation?

85 array uuid: UUID of page title: Title of page url: URL for page template: Template name of page changed: Changed date of page changer: User ID of changer created: Date of creation creator: User ID of creator nodetype: Type of node path: Path of page excerpt: Excerpt (if load-excerpt is true) sulu_navigation_root_tree Returns navigation Page from root in a tree data-structure. Arguments: context: string - optional: context to filter navigation depth: integer - optional: depth to load (1 - childs, 2 - childs and child of childs,...) loadexcerpt: boolean - optional: load data from excerpt tab Returns: array uuid: UUID of page title: Title of page url: URL for page template: Template name of page changed: Changed date of page changer: User ID of changer created: Date of creation creator: User ID of creator nodetype: Type of node path: Path of page excerpt: Excerpt (if load-excerpt is true) sulu_navigation_tree Returns navigation Page from root in a tree data-structure. Arguments: context: string - optional: context to filter navigation depth: integer - optional: depth to load (1 - childs, 2 - childs and child of childs,...) loadexcerpt: boolean - optional: load data from excerpt tab 1.3. Reference 81

86 Returns: array uuid: UUID of page title: Title of page url: URL for page template: Template name of page changed: Changed date of page changer: User ID of changer created: Date of creation creator: User ID of creator nodetype: Type of node path: Path of page excerpt: Excerpt (if load-excerpt is true) sulu_seo Returns all the SEO related HTML tags as one string, including: Title Description Keywords Alternate links Canonical tag {{ sulu_seo(extension.seo, content, urls, shadowbaselocale) Arguments: extension: array - The values of the SEO extension content: array - The values of the actual content urls: array - All urls in all localizations for this page shadowbaselocale: string - The locale the page shadows to, in case the page is a shadow page Returns: All HTML strings as a simple string sulu_sitemap Returns sitemap for given Webspace and Locale (or default is the current locale and webspace). Arguments: locale string - locale for determine sitemap (optional) webspacekey string - webspace for determine sitemap (optional) 82 Chapter 1. What s in our documentation?

87 sulu_sitemap_url Returns url for given Webspace and locale. Arguments; url string - The uuid of the current content locale string - optional: locale for determine url webspacekey string - optional: webspace for determine url Returns: Url for a gievn webspace and locale Filters sulu_util_multisort Allows arrays of arrays or objects to be sorted by any properties which are accessible via. the Symfony PropertyAccessor path(s). {% for content in content.smartcontent sulu_util_multisort('[title]', 'asc') % {#... # {% endfor % You can specify an array of paths to enable cascading sorting, for example {% for content in content.smartcontent sulu_util_multisort(['[title]', '[description]'], 'asc') % Arguments: path: Property path direction: Direction to sort, either ASC or DESC SnippetBundle sulu_snippet_load Returns content array for given uuid. Arguments: uuid: string - The uuid of requested content locale: string - optional: Locale to load snippet Returns: array uuid: UUID of page title: Title of page url: URL for page template: Template name of page changed: Changed date of page changer: User ID of changer created: Date of creation creator: User ID of creator 1.3. Reference 83

88 nodetype: Type of node path: Path of page excerpt: Excerpt (if load-excerpt is true) MediaBundle sulu_get_media_url Returns relative URL to the given media. {% set url = sulu_get_media_url(media, 'inline') % Configuration: Following configuration is optional and means, that the default dispositiontype is attachment for each file and only if the mimetypes of a file match application/pdf or image/jpeg it s the inline dispositiontype. If the default dispositiontype would be inline and some files should be attachment, than the configuration of mime_types_attachment should be filled and mime_types_inline should be empty. sulu_media: disposition_type: default: "attachment" mime_types_inline: ["application/pdf", "image/jpeg"] mime_types_attachment: [] Arguments: media: object - The media object dispositiontype: string - override default configuration ( inline, attachment ) (optional) Returns: string - Relative URL sulu_resolve_media Returns resolved media with needed properties for a given media object. {% set media = sulu_resolve_media(contact.medias[0], 'de') % <img src="{{ media.thumbnails['100x100'] " title="{{ media.title " /> Arguments: media: object - The media object. locale: string - Locale to resolve metadata. Returns: object - Object with all needed properties, like thumbnails, title, description and url. sulu_resolve_medias.rst Returns resolved medias with needed properties for a given media array. {% set medias = sulu_resolve_medias(contact.medias, 'de') % {% for media in medias % <img src="{{ media.thumbnails['100x100'] " title="{{ media.title " /> {% endfor % 84 Chapter 1. What s in our documentation?

89 Arguments: media: object[] - The media object. locale: string - Locale to resolve metadata. Returns: object[] - Object with all needed properties, like thumbnails, title, description and url. TagBundle sulu_tags Returns all tags in the system. <ul> <li><a href="{{ sulu_tag_url_clear() ">None</a></li> {% for tag in sulu_tags() % <li><a href="{{ sulu_tag_url(tag) ">{{ tag.name </a></li> {% endfor % </ul> Returns: array - array of serialized Tag instances sulu_tag_url Returns current URL with the given tag as GET parameter. Arguments: tag: array - Serialized Tag instance to determine value tagsparameter: string - optional tags : parameter name Returns: string - current URL with given tag in tags parameter sulu_tag_url_append Returns current URL and append given tag to GET parameter. Arguments: tag: array - Serialized Tag instance to determine value tagsparameter: string - optional tags : parameter name Returns: string - current URL with given tag in tags parameter sulu_tag_url_clear Returns current URL and clear the given GET parameter. Arguments: tagsparameter: string - optional tags : parameter name Returns: string - current URL removed tags parameter 1.3. Reference 85

90 CategoryBundle sulu_categories Returns all categories in the system. <ul> <li><a href="{{ sulu_category_url_clear() ">None</a></li> {% for category in sulu_categories() % <li id="{{ category.key "> <a href="{{ sulu_category_url(category) ">{{ category.name </a> </li> {% endfor % </ul> Returns: array - array of serialized Category instances sulu_category_url Returns current URL with the given category as GET parameter. Arguments: category: array - Serialized Category instance to determine value categoryparameter: string - optional category : parameter name Returns: string - current URL with given category in categories parameter sulu_category_url_append Returns current URL and append given category to GET parameter. Arguments: category: array - Serialized Category instance to determine value categoryparameter: string - optional category : parameter name Returns: string - current URL with given category in categories parameter sulu_category_url_clear Returns current URL and clear the given GET parameter. Arguments: categoryparameter: string - optional category : parameter name Returns: string - current URL removed category parameter Document Manager Sulu Document Manager The Sulu Document Manager is a layer which sits between the PHPCR repository and the application model. It provides a layer of domain abstraction on top of the raw PHPCR session, workspace, query manager, etc. 86 Chapter 1. What s in our documentation?

91 It is similar in concept to a typical ORM (for example Doctrine ORM) with some differences. The following is an example: <?php // find a document in a specific locale and set a new title $document = $documentmanager->find('/cmf/contents/foobar', 'de'); $document->settitle('hello'); // persist the document then flush the changes $documentmanager->persist($document); $documentmanager->flush(); If you are familiar with Doctrine this will seem very familiar. There are some differences however: Persist commits the chagnes to the node immediately, changes made to the document later on will not be taken into account on flush(). It is better to think of persist() as a function which prepares a snapshot of the current state of the document to be persisted. The document manager is localization aware by default. Some other things to note: The Document Manager is 100% event based. This makes it very extensible, all of the functionality is provided by Event Subscribers. Documents are defined with Behavior interfaces, which the event subscribers use to determine if and how the document should be handled. Using the Document Manager Finding documents Documents can be located using either their UUID or their path: <?php $document = $documentmanager->find('/path/to/document'); $document = $documentmanager->find('842e61c0-09ab-42a9-87c0-308ccc90e6f4'); To find a localized document: $germandocument = $documentmanager->find('842e61c0-09ab-42a9-87c0-308ccc90e6f4', 'de'); Additionally, options can be specified: <?php $foodocument = $documentmanager->find('842e61c0-09ab-42a9-87c0-308ccc90e6f4', 'de', array( 'my_option' => 'foobar', )); Persisting documents The Sulu Document Manager requires that you persist() documents and then flush the document manager. Note: The persist operation, unlike other document/object managers, takes a snapshot of the document in its current state and maps the data to the PHPCR node Reference 87

92 Changes made to the document after calling persist will not be taken in to account when flush is called. Below is a simple persist operation: <?php $document = new MyDocument(); $document->settitle(); $documentmanager->persist($document, 'fr', array( 'path' => '/path/to/persist/to', )); $documentmanager->flush(); This persists the document in the French language at the path. The path is given as an option. The path option comes from the ExplicitPathSubscriber subscriber. The amount of options available depends on which subscribers you have registered. See the Behaviors chapter for more information. The Path Builder The structure of the Sulu content repository is configurable. This means that if you hard code a path /cmf/sulu_io/contents then your code could break, as both the cmf and contents segments of this path are configurable. The path builder provides a way to elegantly compose content repository paths by passing an array of path segments: $pathbuilder = $container->get('sulu_document_manager.path_builder'); $path = $pathbuilder->build(array('%base%', 'sulu_io', '%content%', 'path/to/article'); The above code would produce the path /cmf/sulu_io/contents/path/to/article using the default configuration.k Path segments enclosed within % characters are resolved by the PathSegmentRegistry, which uses configuration to map path segment names to values. Other segments are interpreted literally. Creating Documents The Sulu Document Manager uses interfaces to determine how a document is handled. These interfaces are known as behaviors. Behaviors act upon documents. Note: It is equally possible to implement what is now the conventional mapping pattern using XML, YAML, annotation, etc. But for now only behavioral interfaces are supported. The Document <?php namespace Acme\Bundle\FooBundle\Document; use Sulu\Component\DocumentManager\Behavior\Mapping\NodeNameBehavior; use Sulu\Component\DocumentManager\Behavior\Mapping\PathBehavior; 88 Chapter 1. What s in our documentation?

93 use Sulu\Component\DocumentManager\Behavior\Mapping\UuidBehavior; class SomeDocument implements NodeNameBehavior, PathBehavior, UuidBehavior, { private $nodename; private $path; private $uuid; private $targetdocument; public function getnodename() { return $this->nodename; public function getpath() { return $this->path; public function getuuid() { return $this->uuid; The above document will have the nodes path, UUID and node name populated. The properties are mandatory and the behaviors will expect them to be there, if they are not then an exception will be thrown explaining which properties need to be added. Note: The behaviors will often use Reflection to set the value of an objects properties, bypassing any protection that property may have. Note: Because the Document Manager uses interfaces and does not depend on metadata mapping you can put your document anywhere you want without changing any configuration. Defining the alias and type In order for the document manager to recognize existing managed documents and persist new ones, you must add some mapping to your configuration. This configuration can be done in you applications config.yml file: sulu_document_manager: mapping: #... my_new_document: phpcr_type: acme:somedocument class: Acme\Bundle\FooBundle\Document\SomeDocument Above we define three things: 1.3. Reference 89

94 1. The alias of the document as my_new_document. This alias can be used instead of the long class name when managing the document. 2. A PHPCR type which will be used to map the document to the class name. 3. The class which should be managed. Data Fixtures The Sulu DocumentManager integration includes a fixture loader which allows you to load static data into your content repository. Getting Started Shown below is the simple data fixtures: <?php // YourBundle/DataFixtures/Document/SomeFixture.php namespace YourBundle\DataFixtures\Document; use Sulu\Bundle\DocumentManagerBundle\DataFixtures\DocumentFixtureInterface; class SomeFixture implements DocumentFixtureInterface { public function getorder() { return 10; public function load(documentmanager $documentmanager) { $document = $documentmanager->create('page'); //... $documentmanager->persist($document); $documentmanager->flush(); Note that: The class name MUST end with Fixture for it to be recognized The class MUST be placed in <your bundle>/datafixtures/document in order for it to be loaded automatically. You can now execute your data fixture using the sulu:document:fixtures:load command. $ php app/console sulu:document:fixtures:load By default this command will purge and re-initialize the workspace before loading all of the fixtures. Warning: Unless you use the append option, your workspace will be purged! Advanced Usage You can specify directories instead of having the command automatically find the fixtures: 90 Chapter 1. What s in our documentation?

95 $ php app/console sulu:document:fixtures:load --fixtures=/path/to/fixtures1 --fixtures=/path/to/fixtu You can also specify if fixturs should be appended (i.e. the repository will not be purged) and if the initializer should be executed. Append fixtures: $ php app/console sulu:document:fixtures:load --append Do not initialize: $ php app/console sulu:document:fixtures:load --no-initialize Using the Service Container If you need the service container you can implement the SymfonyComponentDependencyInjectionContainerAwareInterface: <?php // YourBundle/DataFixtures/Document/SomeFixture.php namespace YourBundle\DataFixtures\Document; use Sulu\Bundle\DocumentManagerBundle\DataFixtures\DocumentFixtureInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; class SomeFixture implements DocumentFixtureInterface implements ContainerAwareInterface { private $container; public function setcontainer(containerinterface $container = null) { $this->container = $container; Behaviors The document manager interacts with objects (documents) with event subscribers. The event subscribers use interfaces to determine if they should apply themselves to a document. These interfaces are known as Behaviors. This chapter will explain all of the behaviors which are available in Sulu. Each section will show, according to need, the behavior interface required to implement the behavior, the properties which you MUST implement and any options which will be available. Auditing Auditing subscribers record and provide access to details of when the document was modified and the user that modified it Reference 91

96 Blame Behavior: Sulu\Component\DocumentManager\Behavior\BlameBehavior This behavior will record the identifier of the user who created the object and when the document is updated, the user who updated it. The user identifier will be retrieved from the Symfony session, or can be explicitly specified with an option. If no user identifier is available, no action will be taken. Properties: $creator: The identifier of the user that created the object. $changer: The identifier the last user to have changed the object. Options: blame.user_id: Specify or override the identifier which will be recorded. Timestamp Behavior: Sulu\Component\DocumentManager\Behavior\Audit\TimestampBehavior Record the time when the object was created and the time when the object was updated. Properties: $created: The date the object was created. $changed: The data the object was changed. Mapping Mapping subscribers set and provide access to properties in the document. Children Behavior: Sulu\Component\DocumentManager\Behavior\Mapping\ChildrenBehavior Provides access from the document to the children of the document in the content tree. The property will be populated with a collection object. Note: Children documents are loaded lazily, so this behavior does not entail a performance penalty. Properties: $children: The children collection. Locale Behavior: Sulu\Component\DocumentManager\Behavior\Mapping\LocaleBehavior Provides access to the documents Locale at the time the object was hydrated according to the DocumentRegistry. Properties: $locale: The locale the document is currently loaded in. NodeName Behavior: Sulu\Component\DocumentManager\Behavior\Mapping\NodeNameBehavior Maps the PHPCR node name. Properties: $nodename: The locale the document is currently loaded in. 92 Chapter 1. What s in our documentation?

97 Parent Behavior: Sulu\Component\DocumentManager\Behavior\Mapping\ParentBehavior Map and assign the parent document through getparent and setparent methods. Unmanaged parent documents with a UUID will be returned UnknownDocument instances. Unmanaged parent documents with no UUID will not be hydrated (they will be NULL). Warning: This event currently incurs a performance penalty as it needs to eagerly load the parent PHPCR node. This could potentially have a noticable impact when loading a large number of nodes. Path Behavior: Sulu\Component\DocumentManager\Behavior\Mapping\PathBehavior Map the path of the document within the content repository. Properties: $path: The path to the document. Title Behavior: Sulu\Component\DocumentManager\Behavior\Mapping\TitleBehavior Map the title of the document. Properties: $title: Title of the document. Uuid Behavior: Sulu\Component\DocumentManager\Behavior\Mapping\UuidBehavior Map the UUID (Universally Unique Identifier) of the document. Properties: $uuid: The UUID of the document. Path Path subscribers affect the location of the document within the content repository. AliasFiling Behavior: Sulu\Component\DocumentManager\Behavior\Path\AliasFilingBehavior This is a filing behavior which will automatically place the document at given path as a child of a node named after the documents alias as defined in the configuraiton mapping. For example, if the base path is /cms/content and the document has an alias of article and the name my-article then the document will be stored at /cms/content/article/my-article. AutoName Behavior: Sulu\Component\DocumentManager\Behavior\Path\AutoNameBehavior The auto-name subscriber will automatically set the node name of the PHPCR node as a slugified version of its title (the document must also implement the TitleBehavior) Reference 93

98 Explicit Behavior: None. This behavior is depends entirely on options. This subscriber allows the path of the document to be set explicitly through the use of options. This subscriber requires no interfaces, it is available on all documents automatically. For example: <?php $documentmanager->persist($document, 'de', array( 'path' => '/path/to/document' )); Options: path: Absolute path to where the document should be stored. parent_path: Specify only the parent path (the node name could then be determined through another mechanism, e.g. the AutoName behavior. node_name: Specify only the node name auto_create: If any missing parent nodes should be automatically created. Sulu Specific The following behaviors are specific to Sulu. Content Behavior: Sulu\Component\Content\Document\Behavior\ContentBehavior Maps the structure content to the document. The content is mapped as a ContentContainer instance. Properties: $content: The content container. Extension Behavior: Sulu\Component\Content\Document\Behavior\ExtensionBehavior Sets and provides access to the extension data. LocalizedContent Behavior: Sulu\Component\Content\Document\Behavior\LocalizedContentBehavior Allows the document to potentially have different structure type for each locale. NavigationContext Behavior: Sulu\Component\Content\Document\Behavior\NavigationContextBehavior Enables the document to have navigation contexts assigned to it. Order Behavior: Sulu\Component\Content\Document\Behavior\OrderBehavior Documents implementing this behavior will have a sulu:order property added to the PHP node which will enable the document the order to remain constant in both the tree and in query results. Page Behavior: Sulu\Component\Content\Document\Behavior\PageBehavior Documents implementing this behavior will be treated as pages - that is they are expected to represent a single webpage with an associated route. This behavior extends the Webspace behavior. 94 Chapter 1. What s in our documentation?

99 RedirectType Behavior: Sulu\Component\Content\Document\Behavior\RedirectTypeBehavior Documents implementing this behavior are able to optionally redirect to either an internal or an external resource. ResourceSegmentBehavior Behavior: Sulu\Component\Content\Document\Behavior\ResourceSegmentBehavio Maps a resource segment which will be used when generating the URI for the document. Route Behavior: Sulu\Component\Content\Document\Behavior\RouteBehavior Documents implementing this behavior will act as routes. Routes are documents which are located at a path representing one of the URIs of a page document. The route contains a reference to the page. ShadowLocale Behavior: Sulu\Component\Content\Document\Behavior\ShadowLocaleBehavior The implementing document will have the possiblity to enable a shadow locale and load its content from a different locale within the same document. StructureTypeFiling Behavior: Sulu\Component\Content\Document\Behavior\StructureTypeFilingBehavio Implementing documents will be stored at a path depending on their structure type. Snippets implement this behavior. Webspace Behavior: Sulu\Component\Content\Document\Behavior\WebspaceBehavior Provides access to the documents webspace name. WorkflowStage Behavior: Sulu\Component\Content\Document\Behavior\WorkflowStageBehavior Documents implementing this interface can have a workflow stage applied to them. For example test and published are workflow stages. Debugging One of the disadvantages of an event based system is that tracking what happends and when it happens can be tricky. The Document Manager provides some tools to ameliorate this problem. Subscriber Debug Command It is often useful to know which subscribers are being called and the order in which they are called. If you are using Sulu, then this can be achieved via the following command: $./app/console sulu:document:subscriber:debug remove Class Method Prior Sulu\Bundle\SearchBundle\EventListener\ContentSubscriber handlepreremove 600 Sulu\Component\Content\Document\Subscriber\ContentRemoveSubscriber handleremove 550 Sulu\Component\DocumentManager\Subscriber\Phpcr\RemoveSubscriber handleremove 500 Sulu\Component\Content\Document\Subscriber\Compat\MapperRemoveSubscriber handlepreremove 500 Sulu\Component\DocumentManager\Subscriber\Core\RegistratorSubscriber handleremove 490 Sulu\Bundle\SearchBundle\EventListener\ContentSubscriber handlepostremove -100 Sulu\Component\Content\Document\Subscriber\Compat\MapperRemoveSubscriber handlepostremove Reference 95

100 Here we list all of the subscribers which will be executed when a remove event is fired. A full list of events can be retrived if you ommit the argument: $./app/console sulu:document:subscriber:debug Event persist hydrate remove refresh copy move create clear find reorder flush query.create query.create_builder query.execute configure_options Logging The Document Manager provides detailed logging about which subscribers are executed, the state of the event and the time taken by each event to be executed, for example: S\C\C\D\S\ExtensionSubscriber handlepersist n:/cmf/sulu_io/contents/test1 d S\C\C\D\S\WebspaceSubscriber handlepersist n:/cmf/sulu_io/contents/test1 d S\C\C\D\S\ContentSubscriber handlepersist n:/cmf/sulu_io/contents/test1 d S\C\C\D\S\NavigationContextSubscriber handlepersist n:/cmf/sulu_io/contents/test1 d S\C\C\D\S\RedirectTypeSubscriber handlepersist n:/cmf/sulu_io/contents/test1 d S\C\C\D\S\WorkflowStageSubscriber handlepersist n:/cmf/sulu_io/contents/test1 d S\C\C\D\S\OrderSubscriber handlepersist n:/cmf/sulu_io/contents/test1 d S\C\C\D\S\RouteSubscriber handlepersist n:/cmf/sulu_io/contents/test1 d S\C\D\S\B\A\BlameSubscriber handlepersist n:/cmf/sulu_io/contents/test1 d S\C\D\S\B\A\TimestampSubscriber handlepersist n:/cmf/sulu_io/contents/test1 d S\C\D\S\B\M\NodeNameSubscriber handlenodename n:/cmf/sulu_io/contents/test1 d S\C\D\S\B\M\UuidSubscriber handleuuid n:/cmf/sulu_io/contents/test1 d S\C\D\S\B\M\ParentSubscriber handlechangeparent n:/cmf/sulu_io/contents/test1 d Have a closer look: [1] [2] [3] [4] S\C\C\D\S\ExtensionSubscriber handlepersist n:/cmf/sulu_io/contents/test1 d: b01 1. The time taken by the subscriber, expressed as a fraction of a second. 2. The class name. The namespace is compressed to allow for greater readability. 3. The method which handled the event 4. Event details, retrieved by the events getdebugmessage method. The event details are context sensitive, the following lists all abbreviations: n: PHPCR Node path or UUID 96 Chapter 1. What s in our documentation?

101 d: Document path or UUID p: Parent node path or UUID l: Locale i: Identifier (used for find events) did: Destination ID (used in copy/move events) dnam: Destination name (used in copy/move events) after: If a node should be ordered after or not (only for reorder events) Warning: Logging will slow down your application drastically. It should only be enabled in development environments. Extending the Document Manager Where to put things? Any classes which relate to the documents or the document manager should first, by convention, be placed within a Document namespace. Documents themselves should be placed directly under this namespace and other types of class should be placed in sub namespaces with appropriate names. For example: src/bundle/mybundle/document/foodocument.php src/bundle/mybundle/document/initializer/fooinitializer.php src/bundle/mybundle/document/subscriber/foosubscriber.php Glossary A glossay is: A list of terms in a particular domain of knowledge with their definitions. This page aims to list all of the terminology used within Sulu both as a reference and as a guide to use when naming things in the code-base. Component Of a Structure a named set of Properties. Used by blocks.?? Document Documents are the domain representation of nodes from the PHPCR content repository. For example PageDocument, or SnippetDocument. The namespace used within components/bundles for all things relating to document the document manager component. Document type The short name for a class of document, for example page the name of the PageDocument class. Locale Represents a linguistic region, for example de, de_at, en or en_us. Localized Of a Property - the state of being localized, or capable of being translated. Metadata Literalaly data about data. Typically a data structure with information such as field mappings which should be applied to a different data structure. In the context of Sulu this applied to Structures, Properties and Documents. Non-localized Of a Property - the state of not being localized, not capable of being translated Reference 97

102 Path Always refers to the path of an object within the content repository, for example /cmf/sulu_io/contents/animals/dog is a path. Page A page is basic type of document. Pages are accessible directly with URLs and they represent pages of your website. Parameter In relation to Property and Structure items; a configuration parameter which relates to the configuration of the content type. Prefix The former part of a web facing URL which is defined by the portal, it is followed by the resource locator. The prefix may include the locale. Property This term refers to the items in a Structure. Property Type Property types are the way Sulu represents different types of content. For example, , text and smart_content are three examples of Sulu Property Types Resource locator The later part of a web facing URL belonging to some document, excluding the host and prefix segment. For example /articles/foo is a resource locator, however /de/articles/foo and are not. The resource locator will never include the locale. Segment As applying to URLs and Paths - a section of a path or URL, preseumably delimited by /. Shadow Of a document. A localized document can specify that it should be loaded in a different locale. The target locale is called the shadow locale. Workflow Stage The stage of the workflow, for example published and test are stages. Snippet Snippets are like pages except that they are not accessible directly with URLs. Snippets are typically aggregated within pages. Structure Structures represent dynamic content in Sulu. A structure is a collection of Properties. Structure type The name of a given structure, e.g. overview, hotel or article. Webspace In Sulu a webspace encapsulates all of the data of one or more domains which use the same data. Webspace Document The document at the root of the webspace tree the homepage. Have fun with our Reference. 1.4 Bundles The Sulu code is structured in Symfony Bundles. Some of them are more important to developers who work with Sulu than others. In this documentation we documented the most important ones. We documented the following bundles AdminBundle The AdminBundle contains important features for developing the User-Interface of bundles. It provides various hooks which can be used by Javascript-components in various bundles to reuse code or to just deal with different tasks more easily. Javascript-Hooks Javascript-hooks are just special-name-properties placed in the return-object of javascript-components. The Admin- Bundle recognizes the hooks and executes functionality, like rendering a header with tabs or just manipulating the column-layout. 98 Chapter 1. What s in our documentation?

103 1.4. Bundles 99

104 Layout With the layout-hook the three-column-layout (navigation, content, sidebar) can be manipulated Lets see an example: layout: { navigation: { collapsed: true, content: { width: 'fixed', topspace: false, leftspace: false, rightspace: true, sidebar: { width: 'max', url: '/admin/widget-groups/my-widget-group' This layout-property just needs to be placed in the return block of the javascript-component and the AdminBundle does the rest. List of all available options: Parameter Type Description navigation Object contains properties affecting the navigation-column navigation.collapsed Boolean If true the navigation transitions to collapsed state navigation.hidden Boolean If true the navigation gets hidden content Object contains properties affecting the content-column content.width String fixed to keep the column at a fixed width or max t column take the maximum of the available space content.leftspace Boolean If false the content-column has no padding on the left content.rightspace Boolean If false the content-column has no padding on the right content.topspace Boolean If false the content-column has no padding on the top sidebar Object Boolean Contains properties affecting the sidebar-column. If false the sidebar gets hidd sidebar.width String fixed to keep the column at a fixed width or max to make the column take t maximum of the available space sidebar.url String Url from which markup gets fetched and placed inside the sidebar extendexisting Boolean If true the passed configurations for navigation, column and sidebar won t be with the defaults. So the existing layout stays the same and only the explicitly properties take effect. Note: Either the sidebar-column or the content-column must have a fixed width. If the width of both columns is of type max the behaviour is not specified. The defaults of the layout-hook are: 100 Chapter 1. What s in our documentation?

105 layout: { extendexisting: false, navigation: { collapsed: false, hidden: false, content: { width: 'fixed', leftspace: true, rightspace: true, topspace: true, sidebar: false To get the default layout just write layout: {. Header The header-hook renders a header (the blue bar with the toolbar in it) into your component. Moreover it takes care of the tab-handling. Most often you ll find yourself defining a component which contains the header-hook and methods for manipulating the toolbar or other methods which implement behaviour which is the same over all tabs. The header-hook in such a component could look something like: header: { tabs: { url: 'url/to/tabsdata', toolbar: { languagechanger: true, buttons: { save: {, settings: { options: { dropdownitems: { delete: {, title: 'My title' What this hook does is essentially the following: It initializes the tabs with the data returned from the defined url. From then on you ll never have to worry about tabs again. The whole routing to and starting your tabs component is handled automatically if the data returned by tabs.url has the right format. It initializes the toolbar with the defined buttons. For information on how to configure buttons and even how to create your own buttons have look Sulu-Buttons. It injects the title into every tab (or into your current component if no tabs specified) 1.4. Bundles 101

106 Note: The header-hook can also be a function which returns the object seen in the example. Within this function you have access to things like this.options List of all available options: Parameter Type Description title String Function A title which gets injected into every tab-component or into the curren component if no tabs exist. If it s a function it must return a string. noback Boolean if true no back icon gets rendered tabs Object contains configuration-properties about the tabs tabs.url String url to load the tabs-data from tabs.data Object tabs-data. Either this option or the tabs.url option must be set whe with tabs. tabs.options Object an object which gets merged into the component-options of every tab-c tabs.container String Object a selector or a dom-object into which the tabs-components get rendere toolbar Object contains configuration-properties about the toolbar toolbar.buttons Object an object of sulu-buttons. For the documentation on sulu-buttons have Sulu-Buttons. toolbar.options Object an object of options to pass to the husky-toolbar-component toolbar.languagechangeject Boolean Ob- contains configuration-properties for the language-changer dropdown. to true renderes a dropdown with the system-locales and emits event callback toolbar.languagechanger.url String An url to load the items for the language-changer dropdown toolbar.languagechanger.preselected String the preselected language id toolbar.languagechanger.callbaction Func- a callback function which gets executed when the language-changer-dr gets changed Load-component-data As a front-end developer you ll often find yourself loading data at the beginning of your component startup and continuing only after the data has been loaded. The load-component-data-hook simplifies this task. Within the return-object of a javascript-component, you can specify a loadcomponentdata method where you load your data. This method must return a promise or your desired data straight away. If such a method is specified the AdminBundle delays the startup of your component and sets this.data with your laoded data (where this is the context of your component). So when your components initialize method gets called you can conveniently access your data via this.data and don t have to worry about asynchronicity. So the loadcomponentdata and initialize method of your component would look somthing like: /** * This method gets called by the AdminBundle */ loadcomponentdata: function() { var promise = $.Deffered(); $.ajax({ url: '/url-to-your-data', ).done(function(data) { //resolve promise. So your component can continue with the startup promise.resolve(data); 102 Chapter 1. What s in our documentation?

107 );, return promise; /** * When this method gets called this.data is already set with * your loaded data */ initialize: function() { // this.data is set with your data and can be used for whatever you want this.render(this.data); Defaults The default-hook merges and prepares the options, translations and templates automatically. This normalizes and centralize the functionality for default values in component. define(function () { 'use strict'; var defaults = { options: { instancename: 'example', items: [], translations: { examplebuttonlabel: 'example.button.label', exampleheader: 'example.header', templates: { skeleton: [ '<h1><%= translations.exampleheader %></h1>', '<button><%= translations.examplebuttonlabel %></button>' ].join('') ; return { defaults: defaults, initialize: function () {, ); ; render: function () { this.dom.html( this.templates.skeleton( {translations: this.translations ) ); 1.4. Bundles 103

108 Options The defaults.options will be merged with this.options from aura. Translations The defaults.translations will be merged with the this.options.translations to overwrite translations of the component and translated with globalize. Templates The defaults.templates will be merged with this.options.templates to overwrite templates of the component and prepared with _.template. Events The event-hook manages events and creates callable functions to throw or catch aura events. It encapsulate the createeventname function to build event-names with the this.events.namespace, this.options.instancename and postfix of the given events. define(['services/husky/util'], function (util) { 'use strict'; /** * Namespace for events. * {string */ var eventnamespace = 'smart-content.categories.'; return { defaults: { options: {instancename: 'example, events: { names: { initialized: {postfix: 'initialized', getdata: { postfix: 'get-data', type: 'on', namespace: eventnamespace, initialize: function () { this.loaddata().then(function (data) { this.data = data; ); // emit event this.events.initialized(data);, // getter for data this.events.getdata(function (callback) { callback(this.data);.bind(this)); 104 Chapter 1. What s in our documentation?

109 loaddata: function () { //... ); ; return util.deferred(); Note: The event-names will be build with this schema: <namespace>.[<instancename>.]<postfix>. Types The events-hook can handle different types of events. emit - default Uses this.sandbox.emit to emit an aura event. on Uses this.sandbox.on to add a event-listener to a aura event. once Uses this.sandbox.once to add a one-time event-listener to a aura event. Sticky-Toolbar The sticky-toolbar extension enables the datagrid list toolbar to stick under the header, when the page will be scrolled. To enable this extension call set the property stickytoolbar to a non false value. If this value is a number it will be used as the scroll-edge where the toolbar will snap-in. You need this for example if you use tabs in your component to compensate the height of the tabs container ( = 90 for the header and 50 for the tabs-container). { stickytoolbar: true // or a number like: 140 To reset the scroll-container if you rerender your component you can call the this.sandbox.stickytoolbar.reset() method. Sulu-Buttons The husky-toolbar-component needs to be passed data, which defines what buttons it should render or what happens when somebody clicks on a button. Essentially Sulu-Buttons are about passing buttons to the toolbar-component in an easier and more elegant way than just copying the same buttons all over the place. With Sulu-buttons you can define buttons in a specific place, extend other buttons and override properties really easily. Introduction The admin-bundle contains an aura-extension in which all default buttons are specified as well as methods to get buttons and add buttons to the pool of default buttons. An example for such a button is: { name: 'save', template: { icon: 'floppy-o', title: 'public.save', disabled: true, callback: function() { 1.4. Bundles 105

110 app.sandbox.emit('sulu.toolbar.save', 'edit'); As you can see a button gets registered with a name and a template, which is the actual button meeting the specifications of the husky-framework. The same holds for dropdown-items, for which also defaults are specified in the admin-bundle. For example: { name: 'delete', template: { title: 'public.delete', callback: function() { app.sandbox.emit('sulu.toolbar.delete'); Retrieve buttons The aura-extension in the admin-bundle extends every sandbox of a javascript-component with the method sulu.buttons.get. In your own component you can call this function like for example: var generatedbuttons = this.sandbox.sulu.buttons.get({ edit: {, save: { options: { callback: function() {//do something//, settings: { options: { dropdownitems: { delete: { ); The sulu.buttons.get method returns an array of buttons which meet the specification of the husky-framework. In our example this array contains the template of the edit-button, the template of the save -button but with the callback-property replaced with our own one and the template of the settings-button which has the template of the delete-dropdownitem as the only dropdown-item. If you want the settings-button two times in the same toolbar with - let s say - different dropdown-items you can make use of the parent property; var generatedbuttons = this.sandbox.sulu.buttons.get({ settings1: { parent: 'settings', options: { dropdownitems: { delete: { 106 Chapter 1. What s in our documentation?

111 , settings2: { parent: 'settings', options: { dropdownitems: { table: { ); Add your own buttons Additionally to the sulu.buttons.get method the aura-extension provides the following methods: sulu.buttons.add: takes a name and a button-template sulu.buttons.dropdownitems.add: takes a name and a dropdownitem-template sulu.buttons.push: takes an array of objects which all must contain a name and a template property sulu.buttons.dropdownitems.push: takes an array of objects which all must contain a name and a template property sulu.buttons.getapibutton: takes the name of a button-template and returns the actual template. Can be used to extend an existing button-template. So with this methods you can easily add your own buttons and dropdown-items to the pool. These buttons are then globally available via the sulu.buttons.get method. When adding your own button the preferable place to specify them is in a requirejs-component named sulu-buttons.js within the extensions-folder of your bundle. Adding the buttons and dropdown-items to the pool should then be done in the js/main.js file of your bundle in which the sulu-buttons.js file is required. If you want to specify your own button which extends another existing button you can do the following. In this example the settings button is extended with a custom title. var copyofsettings = app.sandbox.sulu.buttons.getapibutton('settings'); copyofsettings.title = 'My own title'; this.sandbox.sulu.buttons.add('my-settings-button', copyofsettings); Note: Don t overuse the possibility to extend an existing button and provide a new one. Extending and providing your own button should only be done if the same button comes up in multiple places. If you just need to overwrite some properties of a default button in a single-place just use the sulu.buttons.get method. Include custom css Sulu provides the package require-css to manage custom css. You can load css files in any require component with the prefix css!. You have to omit the file extension. require.config({ paths: { sulucontact: '../../sulucontact/js', sulucontactcss: '../../sulucontact/css' 1.4. Bundles 107

112 ); define(['css!sulucontactcss/main'], function(){); This will include the css file and manage multiple usages. If you want to load more than one css file simply add more entries in the array ContentBundle The SuluContentBundle is one of the most central parts of Sulu. It offers the content management functionality of Sulu, which is its most important part. Security Every page has its own permission tab, which is integrated like described in Securing your application. The settings placed in this tab has an influence on the UI of Sulu. The UI might also be adapted due to the permissions defined in Security Contexts (see the documentation at Security for more details). The form adapts to the permissions by changing its toolbar. The delete option in the edit dropdown is only available if the user has the delete permission on this page. The other toolbar items are only available if the user has the edit permission. The column navigation for the content is a bit more complicated. The entire tree is always visible, but the available funcationality is changing based on the permissions of the page. The delete permission is tied to the delete item in the option dropdown. The edit permission is required to move and sort the page in the content tree. For sorting the page the edit permission of all siblings and the parent page is also required. For copying a page the user has to have the view permission on the source page. In addition to that the icon appearing on hovering one of the items in the content tree depends on its permission. If the user is allowed to edit the page a pencil shows up, in case the user has only ther permission to view the page an eyes is shown instead. In case the user has no permission at all, there also will not appear any icon on hovering. ContentRepository The content-repository was developed to query the content raw-data. The developer can decide which properties will be loaded. The main goal of the repository is to centralize the core features ghost, shadow and internal links. These things will be handled full automatically. If you are using this repository. Usage There are two ways to use it. One in the front-end over an rest-api and one with a backend service. API The URL of the API is /admin/api/nodes or /admin/api/nodes/<uuid>. The mandatory parameters are: Name Example Description locale de Localization which will be used. webspace sulu_io Webspace from which content will be loaded. fields Comma separated list of properties. 108 Chapter 1. What s in our documentation?

113 Note: If the parameter fields is not set the content will be resolved with the slow legacy system (which is deprecated). You can specify following optional parameters: Name Default Description exclude-ghosts false If true ghost will be filtered. exclude-shadows false If true shadows will be filtered. Over the mapping you can specify which properties will be loaded by the repository (for example: title,order,article ). The list endpoint also accepts a parent parameter. If this parameter is set the given page will be used to query for children else the webspace root is default. The single endpoint also accepts a tree flag. If it is true all parents and siblings are returned else only the requested page will be returned. Service The id of the service is sulu_content.content_repository. The methods can be used as described in the phpdocs. The mapping variable contains information for the mapping process. Name hydrateshadow hydrateghost followinternallink properties Description if this is false no shadow pages will be returned. if this is false no ghost pages will be returned. if this is false the link will not be resolved. List of hydrated properties You can build this mapping over the mapping builder: $mapping = MappingBuilder::create() ->sethydrateghost() ->sethydrateshadow() ->addproperties(['title']) ->getmapping(); HttpCacheBundle The SuluHttpCache bundle provides tight integration between Sulu and HTTP caching proxies. Handlers All of the functionality of the Sulu HTTP cache implementation is encapsulated in handlers. Handlers are responsible primarily for handling the caching of Sulu Structure objects (e.g. Page and Snippet classes). Most handlers will need to talk to a HTTP proxy cache implementation. The cache implementations are provided by the FOSHttpCache component. Examples of handlers which do not need to talk to a cache implementation are the DebugHandler and the PublicHandler. Handler classes implement the HandlerInterface and are further specialized with three further interfaces: HandlerFlushInterface: This handler is capable of being flushed - this will normally be a proxy for ProxyClient#flush. HandlerInvalidateInterface: This handler can invalidate the cache. HandlerUpdateResponseInterface: This handler can update the response Bundles 109

114 Aggregate Handler Implements: flush, invalidate and update response. The aggregate handler is special as it aggregates other handlers so that you can apply multiple handlers at the same time. This is the default handler and by default it will aggregate all enabled handlers. Debug Handler Implements: update response. The debug handler simply adds debug information to your response: x-sulu-handler: The handlers which are enabled x-sulu-proxy-client: The name of the proxy client being used x-sulu-structure-type: The structure type for which the response is being returned x-sulu-structure-uuid: The UUID of the Structure x-sulu-page-ttl: Send the TTL (time to live) to the proxy client with the header X-Resverse-Proxy-TTL (which is defined as a constant in the Sulu\Component\HttpCache class). For example: x-sulu-handlers: paths, public, debug x-sulu-proxy-client: symfony x-sulu-structure-type: OverviewPageCache x-sulu-structure-uuid: 22a92d46-74ab-46cc-b47c-486b4b8a06a7 x-sulu-page-ttl: 2400 Paths Handler Implements: flush, invalidate and update response. The paths handler will invalidate all the URLs associated with the subject Structure when it is updated. For example, if a page is located at and then these two URLs will be purged in the cache, and their contents will be updated when they are next requested. Note: When using the paths handler you need to be aware that pages which reference the structure being invalidated will not be updated - for exmaple pages which aggregate the subject structure in a SmartContent content type. Public Handler Implements: update response. The public handler adds generic caching information to the response which will be consumed by the users web browser. For example a max-age time of 3600 will instruct the users browser to locally cache the page for one hour before requesting it from the server again. The following are example headers added by the public handler (the X-Reverse-Proxy header will normally be removed by the cache implementation): 110 Chapter 1. What s in our documentation?

115 Cache-Control: max-age=240, public, s-maxage=240 X-Reverse-Proxy-TTL: 2400 Tags Handler The tags handler is the most comprehensive cache invalidation strategy, it will invalidate both the URLs of the structure and the URLs of the pages which display references to the structure.. It must be used in conjunction with a proxy client which supports Banning. Currently this handler can only be used with Varnish. This handler works by sending all of the UUIDs of the structures which are contained in a page response to the proxy client. The proxy client can then store this information along with the cached HTML response. When you update any structure in the admin interface it will instruct the HTTP proxy to purge all the caches which have a reference to the UUID of the structure you have updated. Example header sent by the tags handler (which will be removed by varnish): X-Cache-Tags: structure-22a92d46-74ab-46cc-b47c-486b4b8a06a7 Proxy Clients Symfony Http Cache The Symfony HTTP cache is the default caching client for Sulu CMF. It is integrated directly into Sulu. It works by wrapping the kernel. You can find it in the website front controller web/website.php: // web/website.php //... // Comment this line if you want to use the "varnish" http // caching strategy. See if (SYMFONY_ENV!= 'dev') { require_once DIR. '/../app/websitecache.php'; $kernel = new WebsiteCache($kernel); It will need to be disabled when using varnish. Varnish The varnish proxy client is provided by the FOSHttpCache component. See Caching with Varnish for more information about setting up varnish. Default configuration # Default configuration for extension with alias: "sulu_http_cache" sulu_http_cache: default_handler: aggregate # Configuration for structure cache handlers handlers: 1.4. Bundles 111

116 aggregate: enabled: true # Handlers to aggregate, e.g. all or any of tags, path, public handlers: [] public: enabled: false max_age: 300 shared_max_age: 300 # Use the dynamic pages cache lifetime for reverse proxy server use_page_ttl: true paths: enabled: false tags: enabled: false debug: enabled: false proxy_client: symfony: enabled: false varnish: enabled: false # Addresses of the hosts Varnish is running on. May be hostname or ip, and with :port if servers: # Required # Prototype name: ~ # Default host name and optional path for path based invalidation. base_url: null MediaBundle The MediaBundle is responsible for the handling of all media assets in Sulu. It also offers functionality for resizing and scaling images automatically. Assets can be grouped in nestable collections for better organization. Security Separate permissions can be applied to every collection. These permissions also apply to the assets contained in the collection. So the view permission is required to see the collection itself in the navigation and its assets in any available view in the system. The add permission is needed to upload new assets and add new subcollections to a collection. With the edit permission the user is allowed to edit the title and other attributes of the collections and its containing assets, and finally the delete permission is required to delete assets and entire collections PersistenceBundle The Sulu Persistence bundle provides extensions for managing Doctrine entities and their repositories. 112 Chapter 1. What s in our documentation?

117 1.4.6 SearchBundle The SuluSearchBundle is mainly an integration of the MassiveSearchBundle into Sulu. There is also the MassiveSearchBundle Documentation explaining this Bundle in more detail. This documentation is also valid for using it with Sulu, although there are some extensions made by the SuluSearchBundle. It offers a controller to provide a web API to search through the system, adds more fields - like creator and changer - to the search documents and also handles the security provided by Sulu. But the most important thing is, that it also contains the UI for the administration interface. Configuration The configuration of this bundle contains some more metadata about each index created by the MassiveSearchBundle. There are two optional values, meaning both of them could be omitted: name: Can contain a name for the index, which will be used in the UI. Useful if the index represents something a non-translatable literal can describe. security_context: This setting is used to describe which security context (see SecurityBundle) the user has to have view permission in, in order to search through this index. So a sample configuration would look like this: sulu_search: indexes: contact: security_context: sulu.contacts.people The values under indexes, namely contact in this example, result from the index tag in the mapping configuration. The value of security_context indicates that the user has to have the permission to view the sulu.contacts.people security context to see result from the contact index. Note: It is also possible to use PrependExtensions or in more complicated cases to change the value of the sulu_search.indexes parameter in a CompilerPass. Actually that is what most of the Sulu bundles are doing to minimize the configuration effort of the application. That would be enough for the user to retrieve some search results, but a click on these results would not lead to the corresponding form. So the last missing step is to tell the system how to load this form when clicking on a search result. This has to be done in the main javascript entry point of the bundle, which is located at Resources/public/js/main.js. A line like the following has to be added to the initialize method: app.sandbox.urlmanager.seturl( 'contact', 'contacts/contacts/edit:<%= id %>/details' ); This line tells the urlmanager, which is responsible for creating the URLs for the search, how the entry from the search has to be resolved. The variables from the search document can also be used in the template, which is passed as the second argument. For more complex cases there are two more parameters in the seturl function, which are shown in the next example. sandbox.urlmanager.seturl( 'page', function(data) { return 'content/contents/<%= webspace %>/<%= locale %>/edit:<%= id %>/content';, function(data) { 1.4. Bundles 113

118 ); return { id: data.id, webspace: data.properties.webspace_key, url: data.url, locale: data.locale ;, function (key) { if (key.indexof('page_') === 0) { return 'page'; The first argument is again the name of the index, the second one a function, returning a string for the javascript template engine. The third is a handler returning a new object from the given data, which will passed to the template engine in combination with the string being returned from the second argument. Finally, the fourth argument is the key modifier, which takes the name of the index, and can modify it, before it is compared with the first argument from all seturl calls. This is especially useful if the ExpressionLanguage is used for the generation of the index name SecurityBundle The SuluSecurityBundle is responsible for protecting different data and areas of the application. Therefore it makes use and enhances the standard security mechanisms of Symfony. Structure Every Sulu user is linked to a specific Sulu contact from the SuluContactBundle. In addition to that a user can have some roles and groups assigned, whereby a group can consist of multiple other groups and roles. Every role has to be part of a certain system. Different systems can be registrated via the security contexts, which are explained later. These systems correspond to different applications handled by Sulu. So by default there is only the Sulu system. A user is only enabled to login into Sulu, if he has at least one role with the Sulu system assigned. Security contexts Every application can define its own security contexts, which will then be available in the list of security contexts, on which access can be granted or denied. Have a look at Securing your application to see an example. These contexts are used to control the access to different areas of the application, e.g. if the user is allowed to edit content at all. The following permissions are distinguished: VIEW ADD EDIT DELETE ARCHIVE LIVE SECURITY Permission to see data the given context Permission to add new data to the given context Permission to edit already existing data in the given context Permission to delete data in the given context Permission to archive data in the given context Permission to publish data in the given context Permission to grant or deny access on data in the given context All the permission values are encoded in a bitmask and saved in a permission object, which has a link to a role. This way it is easily possible to evaluate if a user has access to a security context by checking if one of his roles grants access. 114 Chapter 1. What s in our documentation?

119 Access Control Manager The AccessControlManager is reponsible to set permissions on specific objects. Since this is not totally decoupled from the entity being protected, there is the possibility to register multiple AccessControlProvider. This is simply a service implementing the AccessControlProviderInterface tagged with sulu.access_control. The task of this class is to save the permission information into the correct database. This is important, because otherwise it would not be possible to paginate lists considering permissions of these entities in an easy and performant way. There are already two implementations of the AccessControlProviderInterface, the PhpcrAccessControlProvider handling the permission storing for PHPCR and therefore for our content section, and the DoctrineAccessControlProvider, which can be used in combination with any Doctrine entity. The entity only has to implement the SecuredEntityInterface to signalize that it can be used with the DoctrineAccessControlProvider. Note: The AccessControlManager is used by some other components, especially by the PermissionController, which handles the requests from the reusable permission tab, and the SecurityContextVoter from Sulu. Checking security Sulu offers a SecurityChecker enabling the developer to easily check if a given SecurityCondition is granted for the currently logged in user. The security condition consists of the already mentioned security context, an object type and id for decoupling from real objects for performance reasons, and the locale to check the permission in. The SecurityChecker uses the Symfony AccessDecisionManager, which calls all security voters including the SecurityContextVoter. This voter will check if the user is allowed to perform the given action (the permissions already listed above) in the given context in the given locale. If the object type and id are also passed the permissions of the security contexts from the role might be overriden by the permissions from this specific object (which are handled by the previously mentioned AccessControlManager). When you get in touch with another bundle of Sulu, which is not documented in this place. Tell us. We ll provide the documentation. 1.5 Developer Guide Here s how we work at the Sulu team. We are really open to Pull Requests. It is also a aim to us to ensure code quality and guarantee some consistency in the project. So if you want to contribute to the Sulu project keep our developers guide in mind. Developers need to know: Contributing All contributions are welcome! We try and stand on the shoulders of giants, this means that we generally copy the existing coding and documentation standards of the Symfony project (with some minor differences) Developer Guide 115

120 116 Chapter 1. What s in our documentation?

Sulu 2.0 Documentation

Sulu 2.0 Documentation Sulu 2.0 Documentation Release 1.0 alpha Sulu Team Aug 01, 2017 Contents 1 The Book 1 1.1 Introduction............................................... 1 1.1.1 What is a Content Management Platform...........................

More information

Sulu 2.0 Documentation

Sulu 2.0 Documentation Sulu 2.0 Documentation Release 1.6 Sulu Team Sep 14, 2017 Contents 1 What s in our documentation? 3 1.1 The Book................................................. 3 1.2 Cookbook................................................

More information

C1 CMS User Guide Orckestra, Europe Nygårdsvej 16 DK-2100 Copenhagen Phone

C1 CMS User Guide Orckestra, Europe Nygårdsvej 16 DK-2100 Copenhagen Phone 2017-02-13 Orckestra, Europe Nygårdsvej 16 DK-2100 Copenhagen Phone +45 3915 7600 www.orckestra.com Content 1 INTRODUCTION... 4 1.1 Page-based systems versus item-based systems 4 1.2 Browser support 5

More information

HostPress.ca. User manual. July Version 1.0. Written by: Todd Munro. 1 P age

HostPress.ca. User manual. July Version 1.0. Written by: Todd Munro. 1 P age HostPress.ca User manual For your new WordPress website July 2010 Version 1.0 Written by: Todd Munro 1 P age Table of Contents Introduction page 3 Getting Ready page 3 Media, Pages & Posts page 3 7 Live

More information

JSN ImageShow Configuration Manual Introduction

JSN ImageShow Configuration Manual Introduction JSN ImageShow Configuration Manual Introduction JSN ImageShow is the gallery extension built for Joomla! Content Management System for developers, photographers, and publishers. You can choose to show

More information

Administrative Training Mura CMS Version 5.6

Administrative Training Mura CMS Version 5.6 Administrative Training Mura CMS Version 5.6 Published: March 9, 2012 Table of Contents Mura CMS Overview! 6 Dashboard!... 6 Site Manager!... 6 Drafts!... 6 Components!... 6 Categories!... 6 Content Collections:

More information

When you don t want to lose your site s existing look and feel, you re

When you don t want to lose your site s existing look and feel, you re Bonus Chapter 2 Hosting Your Site In This Chapter Hosting at home (page) Giving your site a test Using tags on a page When you don t want to lose your site s existing look and feel, you re short on time,

More information

TECHNICAL BRIEFING PIMCORE TECHNOLOGY BRIEFING DOCUMENT Pimcore s backend system is displayed and navigated as Documents, Assets and Objects that solves the challenges of digital transformation. Pimcore

More information

A Guide to Using WordPress + RAVEN5. v 1.4 Updated May 25, 2018

A Guide to Using WordPress + RAVEN5. v 1.4 Updated May 25, 2018 + v 1.4 Updated May 25, 2018 Table of Contents 1. Introduction...................................................................................3 2. Logging In.....................................................................................4

More information

JSN Dona Portfolio User's Guide

JSN Dona Portfolio User's Guide JSN Dona Portfolio User's Guide Getting Started Template Package Installation 1. Download the template installation package Log in JoomlaShine Customer Area to download the template package that you have

More information

Index. alt, 38, 57 class, 86, 88, 101, 107 href, 24, 51, 57 id, 86 88, 98 overview, 37. src, 37, 57. backend, WordPress, 146, 148

Index. alt, 38, 57 class, 86, 88, 101, 107 href, 24, 51, 57 id, 86 88, 98 overview, 37. src, 37, 57. backend, WordPress, 146, 148 Index Numbers & Symbols (angle brackets), in HTML, 47 : (colon), in CSS, 96 {} (curly brackets), in CSS, 75, 96. (dot), in CSS, 89, 102 # (hash mark), in CSS, 87 88, 99 % (percent) font size, in CSS,

More information

About the Tutorial. Audience. Prerequisites. Copyright & Disclaimer. Joomla

About the Tutorial. Audience. Prerequisites. Copyright & Disclaimer. Joomla About the Tutorial Joomla is an open source Content Management System (CMS), which is used to build websites and online applications. It is free and extendable which is separated into frontend templates

More information

SYMFONY2 WEB FRAMEWORK

SYMFONY2 WEB FRAMEWORK 1 5828 Foundations of Software Engineering Spring 2012 SYMFONY2 WEB FRAMEWORK By Mazin Hakeem Khaled Alanezi 2 Agenda Introduction What is a Framework? Why Use a Framework? What is Symfony2? Symfony2 from

More information

Developer Documentation. edirectory 11.2 Page Editor DevDocs

Developer Documentation. edirectory 11.2 Page Editor DevDocs Developer Documentation edirectory 11.2 Page Editor DevDocs 1 Introduction The all-new Widget-based, Front-End Page Editor is the new edirectory functionality available within the Site Manager to give

More information

MARKET RESPONSIVE PRESTASHOP THEME USER GUIDE

MARKET RESPONSIVE PRESTASHOP THEME USER GUIDE MARKET RESPONSIVE PRESTASHOP THEME USER GUIDE Version 1.0 Created by: arenathemes Page 1 Contents I. REQUIREMENTS & COMPATIBILITY... 3 II. INSTALLATION... 3 III. CONFIG AFTER INSTALLATION - THEME PACKAGE...

More information

Weebly 101. Make an Affordable, Professional Website in Less than an Hour

Weebly 101. Make an Affordable, Professional Website in Less than an Hour Weebly 101 Make an Affordable, Professional Website in Less than an Hour Text Copyright STARTUP UNIVERSITY All Rights Reserved No part of this document or the related files may be reproduced or transmitted

More information

Getting Started Guide

Getting Started Guide Getting Started Guide for education accounts Setup Manual Edition 7 Last updated: September 15th, 2016 Note: Click on File and select Make a copy to save this to your Google Drive, or select Print, to

More information

TangeloHub Documentation

TangeloHub Documentation TangeloHub Documentation Release None Kitware, Inc. September 21, 2015 Contents 1 User s Guide 3 1.1 Managing Data.............................................. 3 1.2 Running an Analysis...........................................

More information

Introduction to Git and GitHub for Writers Workbook February 23, 2019 Peter Gruenbaum

Introduction to Git and GitHub for Writers Workbook February 23, 2019 Peter Gruenbaum Introduction to Git and GitHub for Writers Workbook February 23, 2019 Peter Gruenbaum Table of Contents Preparation... 3 Exercise 1: Create a repository. Use the command line.... 4 Create a repository...

More information

Learn how to login to Sitefinity and what possible errors you can get if you do not have proper permissions.

Learn how to login to Sitefinity and what possible errors you can get if you do not have proper permissions. USER GUIDE This guide is intended for users of all levels of expertise. The guide describes in detail Sitefinity user interface - from logging to completing a project. Use it to learn how to create pages

More information

How to Build a Site Style. WebGUI LIVE!

How to Build a Site Style. WebGUI LIVE! How to Build a Site Style WebGUI LIVE! Where do we start? Create a design Turn it into HTML & graphics Introduce WebGUI Components Putting it all together A Closer Look Creating a Design The Big Question...

More information

VIVVO CMS Plug-in Manual

VIVVO CMS Plug-in Manual VIVVO CMS Plug-in Manual www.vivvo.net 1 TABLE OF CONTENTS INTRODUCTION...4 PLUGIN: CONTACT FORM BUILDER PLUG-IN...5 DESCRIPTION:...5 HOW TO INSTALL?...5 ACTIVATION:...5 ACCESS:...5 USER LEVEL:...5 ACTIONS:...6

More information

Committee Chair Manual for AIA SEATTLE S ONLINE MEMBER COMMUNICATION TOOL. Questions? Contact AIA Seattle s Communications team.

Committee Chair Manual for AIA SEATTLE S ONLINE MEMBER COMMUNICATION TOOL. Questions? Contact AIA Seattle s Communications team. Contents Access to edit aiaseattle.org... 1 Committee Hub Pages... 2 Hub Page Editor... 2 Main Content Block... 2 Featured Image... 3 Files... 3 Events... 5 Recurring Committee Meetings... 8 Posts... 8

More information

AGENT123. Full Q&A and Tutorials Table of Contents. Website IDX Agent Gallery Step-by-Step Tutorials

AGENT123. Full Q&A and Tutorials Table of Contents. Website IDX Agent Gallery Step-by-Step Tutorials AGENT123 Full Q&A and Tutorials Table of Contents Website IDX Agent Gallery Step-by-Step Tutorials WEBSITE General 1. How do I log into my website? 2. How do I change the Meta Tags on my website? 3. How

More information

DRESSSHOP RESPONSIVE PRESTASHOP THEME USER GUIDE

DRESSSHOP RESPONSIVE PRESTASHOP THEME USER GUIDE DRESSSHOP RESPONSIVE PRESTASHOP THEME USER GUIDE Version 1.0 Created by: arenathemes Page 1 Contents I. REQUIREMENTS & COMPATIBILITY... 3 II. INSTALLATION... 3 III. CONFIG AFTER INSTALLATION - THEME PACKAGE...

More information

How To Upload Your Newsletter

How To Upload Your Newsletter How To Upload Your Newsletter Using The WS_FTP Client Copyright 2005, DPW Enterprises All Rights Reserved Welcome, Hi, my name is Donna Warren. I m a certified Webmaster and have been teaching web design

More information

Introducing Thrive - The Ultimate In WordPress Blog Design & Growth

Introducing Thrive - The Ultimate In WordPress Blog Design & Growth Introducing Thrive - The Ultimate In WordPress Blog Design & Growth Module 1: Download 2 Okay, I know. The title of this download seems super selly. I have to apologize for that, but never before have

More information

WordPress Tutorial for Beginners with Step by Step PDF by Stratosphere Digital

WordPress Tutorial for Beginners with Step by Step PDF by Stratosphere Digital WordPress Tutorial for Beginners with Step by Step PDF by Stratosphere Digital This WordPress tutorial for beginners (find the PDF at the bottom of this post) will quickly introduce you to every core WordPress

More information

Lyna Framework Documentation

Lyna Framework Documentation Lyna Framework Documentation Release 0.1 Nicolas Bounoughaz June 12, 2015 Contents 1 Features 3 2 Contribute 5 3 Support 7 4 License 9 5 Get started 11 5.1 Installation................................................

More information

About the Tutorial. Audience. Prerequisites. Copyright & Disclaimer. Drupal

About the Tutorial. Audience. Prerequisites. Copyright & Disclaimer. Drupal About the Tutorial is a free and open source Content Management System (CMS) that allows organizing, managing and publishing your content. This reliable and secure CMS is built on PHP based environment

More information

Index COPYRIGHTED MATERIAL. Numerics

Index COPYRIGHTED MATERIAL. Numerics Numerics 2Checkout, 293 404 errors, 197 198 A HTML tag, 102 About page (Drupal Gardens), 253 Account Activation e-mail, 70 Account Blocked e-mail, 70 Account Canceled e-mail, 70 Account Cancellation

More information

Blue Form Builder extension for Magento 2

Blue Form Builder extension for Magento 2 Blue Form Builder extension for Magento 2 User Guide Version 1.0 Table of Contents I) Introduction......5 II) General Configurations....6 1) General Settings.....7 2) ReCaptcha... 8 III) Manage Forms......

More information

Frontend guide. Everything you need to know about HTML, CSS, JavaScript and DOM. Dejan V Čančarević

Frontend guide. Everything you need to know about HTML, CSS, JavaScript and DOM. Dejan V Čančarević Frontend guide Everything you need to know about HTML, CSS, JavaScript and DOM Dejan V Čančarević Today frontend is treated as a separate part of Web development and therefore frontend developer jobs are

More information

A new clients guide to: Activating a new Studio 3.0 Account Creating a Photo Album Starting a Project Submitting a Project Publishing Tips

A new clients guide to: Activating a new Studio 3.0 Account Creating a Photo Album Starting a Project Submitting a Project Publishing Tips Getting Started With Heritage Makers A Guide to the Heritage Studio 3.0 Drag and Drop Publishing System presented by Heritage Makers A new clients guide to: Activating a new Studio 3.0 Account Creating

More information

Unifer Documentation. Release V1.0. Matthew S

Unifer Documentation. Release V1.0. Matthew S Unifer Documentation Release V1.0 Matthew S July 28, 2014 Contents 1 Unifer Tutorial - Notes Web App 3 1.1 Setting up................................................. 3 1.2 Getting the Template...........................................

More information

End-User Reference Guide Troy University OU Campus Version 10

End-User Reference Guide Troy University OU Campus Version 10 End-User Reference Guide Troy University OU Campus Version 10 omniupdate.com Table of Contents Table of Contents... 2 Introduction... 3 Logging In... 4 Navigating in OU Campus... 6 Dashboard... 6 Content...

More information

How to Use WordPress

How to Use WordPress How to Use WordPress Introduction... 1 When to Use WordPress... 1 WordPress vs. WordPress.com... 1 WordPress... 1 WordPress.com... 2 Getting Started... 2 WordPress.com... 2 WordPress software... 3 Logging

More information

A Quick-Reference Guide. To access reddot: https://cms.hampshire.edu/cms

A Quick-Reference Guide. To access reddot: https://cms.hampshire.edu/cms Using RedDot A Quick-Reference Guide To access reddot: https://cms.hampshire.edu/cms For help: email reddot@hampshire.edu or visit http://www.hampshire.edu/computing/6433.htm Where is... Page 6 Page 8

More information

Internet: An international network of connected computers. The purpose of connecting computers together, of course, is to share information.

Internet: An international network of connected computers. The purpose of connecting computers together, of course, is to share information. Internet: An international network of connected computers. The purpose of connecting computers together, of course, is to share information. WWW: (World Wide Web) A way for information to be shared over

More information

0. Introduction On-demand. Manual Backups Full Backup Custom Backup Store Your Data Only Exclude Folders.

0. Introduction On-demand. Manual Backups Full Backup Custom Backup Store Your Data Only Exclude Folders. Backup & Restore 0. Introduction..2 1. On-demand. Manual Backups..3 1.1 Full Backup...3 1.2 Custom Backup 5 1.2.1 Store Your Data Only...5 1.2.2 Exclude Folders.6 1.3 Restore Your Backup..7 2. On Schedule.

More information

Welcome to Book Display Widgets

Welcome to Book Display Widgets Welcome to Book Display Widgets Book Display Widgets allow you to create virtual book displays on your website, where covers link to that item s record in your catalog. As a subscriber to Ebook Central

More information

SCHULICH MEDICINE & DENTISTRY Website Updates August 30, Administrative Web Editor Guide v6

SCHULICH MEDICINE & DENTISTRY Website Updates August 30, Administrative Web Editor Guide v6 SCHULICH MEDICINE & DENTISTRY Website Updates August 30, 2012 Administrative Web Editor Guide v6 Table of Contents Chapter 1 Web Anatomy... 1 1.1 What You Need To Know First... 1 1.2 Anatomy of a Home

More information

Working with the website editor...5. Editing page properties Creating a new page Adding and editing content records...

Working with the website editor...5. Editing page properties Creating a new page Adding and editing content records... About this guide...3 About the structure of web pages in typo3...4 The outer template...4 The page record...4 Page content records...4 Access to editing and publishing records...4 Working with the website

More information

About the Tutorial. Audience. Prerequisites. Copyright & Disclaimer. WordPress

About the Tutorial. Audience. Prerequisites. Copyright & Disclaimer. WordPress About the Tutorial WordPress is an open source Content Management System (CMS), which allows the users to build dynamic websites and blog. WordPress is the most popular blogging system on the web and allows

More information

Fixed Header edream Market

Fixed Header edream Market User s Manual Magento Extension Fixed Header edream Market www.edreamag.com support@edreamag.com Fixed Header for Magento MODERN, SIMPLE AND PROFESSIONAL edream Fixed Header is a unique extension that

More information

CMSilex Documentation

CMSilex Documentation CMSilex Documentation Release 0.1 Leigh Murray December 01, 2016 Contents 1 Introduction 3 2 Usage 5 2.1 Installation................................................ 5 2.2 Bootstrap.................................................

More information

HTML/CSS Lesson Plans

HTML/CSS Lesson Plans HTML/CSS Lesson Plans Course Outline 8 lessons x 1 hour Class size: 15-25 students Age: 10-12 years Requirements Computer for each student (or pair) and a classroom projector Pencil and paper Internet

More information

Blue Form Builder extension for Magento2

Blue Form Builder extension for Magento2 Blue Form Builder extension for Magento2 User Guide Version 1.0 Table of Contents I) Introduction.. 4 II) Installation 5 III) General Configurations...6 IV) Manage Forms.. 7 1) List of Forms 7 2) Add New

More information

Webshop Plus! v Pablo Software Solutions DB Technosystems

Webshop Plus! v Pablo Software Solutions DB Technosystems Webshop Plus! v.2.0 2009 Pablo Software Solutions http://www.wysiwygwebbuilder.com 2009 DB Technosystems http://www.dbtechnosystems.com Webshos Plus! V.2. is an evolution of the original webshop script

More information

Manual Html Image Src Url Path Not Working

Manual Html Image Src Url Path Not Working Manual Html Image Src Url Path Not Working _img src="file:///absolute/path/to/rails-app/public/image.png" alt="blah" /_. However i obviously want a relative path instead. Where is the relative path going.

More information

Ace Corporate Documentation

Ace Corporate Documentation Ace Corporate Documentation Introduction Welcome To Ace Corporate! We would like to thank you for donwloading Ace Corporate, Business WordPress theme. It is the lite version of Ace Corporate Pro. Before

More information

Introduction. The topics included in this guide are:

Introduction. The topics included in this guide are: Introduction Caorda Content is a powerful content management tool that allows you to update your web site through a standard Internet web browser. The purpose of this guide is to introduce you to Caorda

More information

CSCI 201 Lab 1 Environment Setup

CSCI 201 Lab 1 Environment Setup CSCI 201 Lab 1 Environment Setup "The journey of a thousand miles begins with one step." - Lao Tzu Introduction This lab document will go over the steps to install and set up Eclipse, which is a Java integrated

More information

Create-A-Page Design Documentation

Create-A-Page Design Documentation Create-A-Page Design Documentation Group 9 C r e a t e - A - P a g e This document contains a description of all development tools utilized by Create-A-Page, as well as sequence diagrams, the entity-relationship

More information

SEO Authority Score: 40.0%

SEO Authority Score: 40.0% SEO Authority Score: 40.0% The authority of a Web is defined by the external factors that affect its ranking in search engines. Improving the factors that determine the authority of a domain takes time

More information

BrandingUI (Basic, Advanced, Enterprise) Getting Started - Important First Steps

BrandingUI (Basic, Advanced, Enterprise) Getting Started - Important First Steps BrandingUI (Basic, Advanced, Enterprise) Getting Started - Important First Steps Step 1: Log into your BrandingUI Administrative site https:// yourclientid.brandingui.com/admin-signin.php Use the initial

More information

JSN Dona 2 Portfolio Configuration Manual

JSN Dona 2 Portfolio Configuration Manual JSN Dona 2 Portfolio Configuration Manual Getting Started The Sun Framework is automatically installed when you install JSN Shine or any JSN Template Gen.2 templates. In case manual installation is needed,

More information

A Quick Introduction to the Genesis Framework for WordPress. How to Install the Genesis Framework (and a Child Theme)

A Quick Introduction to the Genesis Framework for WordPress. How to Install the Genesis Framework (and a Child Theme) Table of Contents A Quick Introduction to the Genesis Framework for WordPress Introduction to the Genesis Framework... 5 1.1 What's a Framework?... 5 1.2 What's a Child Theme?... 5 1.3 Theme Files... 5

More information

Web logs (blogs. blogs) Feed support BLOGS) WEB LOGS (BLOGS

Web logs (blogs. blogs) Feed support BLOGS) WEB LOGS (BLOGS Web logs (blogs blogs) You can create your own personal Web logs (blogs) using IBM Lotus Notes. Using the blog template (dominoblog.ntf), you create a blog application, such as myblog.nsf, which you can

More information

Documentation English v1

Documentation English v1 Documentation English v1 Getting started Navigation menu Theme settings General Features Background Typography Banners Contact details Social Unique selling points Image Sizes Frequently asked questions

More information

All-In-One-Designer SEO Handbook

All-In-One-Designer SEO Handbook All-In-One-Designer SEO Handbook Introduction To increase the visibility of the e-store to potential buyers, there are some techniques that a website admin can implement through the admin panel to enhance

More information

This Tutorial is for Word 2007 but 2003 instructions are included in [brackets] after of each step.

This Tutorial is for Word 2007 but 2003 instructions are included in [brackets] after of each step. This Tutorial is for Word 2007 but 2003 instructions are included in [brackets] after of each step. Table of Contents Get Organized... 1 Create the Home Page... 1 Save the Home Page as a Word Document...

More information

One of the fundamental kinds of websites that SharePoint 2010 allows

One of the fundamental kinds of websites that SharePoint 2010 allows Chapter 1 Getting to Know Your Team Site In This Chapter Requesting a new team site and opening it in the browser Participating in a team site Changing your team site s home page One of the fundamental

More information

Speed Optimization PRO

Speed Optimization PRO Speed Optimization PRO Plugin for Joomla! This manual documents version 10.x of the Joomla! extension. https://www.aimy-extensions.com/joomla/speed-optimization.html 1 Introduction Aimy Speed Optimization

More information

World Journal of Engineering Research and Technology WJERT

World Journal of Engineering Research and Technology WJERT wjert, 2017, Vol. 3, Issue 2, 168-177 Original Article ISSN 2454-695X WJERT www.wjert.org SJIF Impact Factor: 4.326 ANALYSIS OF THE PERFORMANCE OF FEW WEBSITES OF THE GOVERNMENT OF BANGLADESH Nazmin Akter*,

More information

GeekLove. An Elegant WordPress Wedding Theme. Thanks for purchasing a theme from Codestag, you re awesome!

GeekLove. An Elegant WordPress Wedding Theme. Thanks for purchasing a theme from Codestag, you re awesome! GeekLove An Elegant WordPress Wedding Theme Thanks for purchasing a theme from Codestag, you re awesome! In this document we will cover the installation and use of this theme. If you have any questions

More information

It is written in plain language: no jargon, nor formality. Information gets across faster when it s written in words that our users actually use.

It is written in plain language: no jargon, nor formality. Information gets across faster when it s written in words that our users actually use. Web Style Guide A style guide for use for writing on Tufts Library Websites and LibGuides. Contents: 1. Web style guides for online content 2. LibGuides 2-specific style guide 3. Tisch s website-specific

More information

EMARSYS FOR MAGENTO 2

EMARSYS FOR MAGENTO 2 EMARSYS FOR MAGENTO 2 Integration Manual July 2017 Important Note: This PDF was uploaded in July, 2017 and will not be maintained. For the latest version of this manual, please visit our online help portal:

More information

Managing your content with the Adobe Experience Manager Template Editor. Gabriel Walt Product Manager twitter.com/gabrielwalt

Managing your content with the Adobe Experience Manager Template Editor. Gabriel Walt Product Manager twitter.com/gabrielwalt Managing your content with the Adobe Experience Manager Template Editor Gabriel Walt Product Manager twitter.com/gabrielwalt Table of Contents 1. Introduction 3 1.1 Overview 3 1.2 Prerequisites 3 2. Getting

More information

Nextcloud 13: How to Get Started and Why You Should

Nextcloud 13: How to Get Started and Why You Should Nextcloud 13: How to Get Started and Why You Should Nextcloud could be the first step toward replacing proprietary services like Dropbox and Skype. By Marco Fioretti In its simplest form, the Nextcloud

More information

Technical Intro Part 1

Technical Intro Part 1 Technical Intro Part 1 Learn how to create, manage, and publish content with users and groups Hannon Hill Corporation 950 East Paces Ferry Rd Suite 2440, 24 th Floor Atlanta, GA 30326 Tel: 800.407.3540

More information

JSN UniForm User Manual. Introduction. A simple contact form created by JSN UniForm. JSN UniForm is a Joomla form extension which helps you create

JSN UniForm User Manual. Introduction. A simple contact form created by JSN UniForm. JSN UniForm is a Joomla form extension which helps you create JSN UniForm User Manual Introduction A simple contact form created by JSN UniForm JSN UniForm is a Joomla form extension which helps you create forms quickly and easily - from normal forms to complex forms.

More information

RC Justified Gallery User guide for version 3.2.X. Last modified: 06/09/2016

RC Justified Gallery User guide for version 3.2.X. Last modified: 06/09/2016 RC Justified Gallery User guide for version 3.2.X. Last modified: 06/09/2016 This document may not be reproduced or redistributed without the permission of the copyright holder. It may not be posted on

More information

WHILE YOU RE GETTING ORGANIZED

WHILE YOU RE GETTING ORGANIZED CAMPTECH.CA WHILE YOU RE GETTING ORGANIZED 1. Go to camptech.ca/wordpress and download the PDF of slides. 2. If you have to leave early, please remember to fill out the (100% anonymous) feedback form on

More information

Things to note: Each week Xampp will need to be installed. Xampp is Windows software, similar software is available for Mac, called Mamp.

Things to note: Each week Xampp will need to be installed. Xampp is Windows software, similar software is available for Mac, called Mamp. Tutorial 8 Editor Brackets Goals Introduction to PHP and MySql. - Set up and configuration of Xampp - Learning Data flow Things to note: Each week Xampp will need to be installed. Xampp is Windows software,

More information

INTRODUCTION. This guide aims to help you make the most of your web presence. RETURN TO TOP eusa.ed.ac.uk/activities 1

INTRODUCTION. This guide aims to help you make the most of your web presence. RETURN TO TOP eusa.ed.ac.uk/activities 1 PROFILE GUIDANCE CONTENTS 01 Introduction 02 Editing your group s profile 03 Admin tools 04 Edit details 05 Tips for creating web content 06 Members 08 Memberships and groups 09 Messages 10 News 11 Writing

More information

Dynamic Product Options extension for Magento2. User Guide

Dynamic Product Options extension for Magento2. User Guide Dynamic Product Options extension for Magento2 User Guide version 2.0 Website: http://www.itoris.com Page 1 Contents 1. Introduction... 4 2. Installation... 5 2.1. System Requirements... 5 2.2. Installation...

More information

Welcome to Book Display Widgets

Welcome to Book Display Widgets Welcome to Book Display Widgets Book Display Widgets allow you to create virtual book displays on your website, where covers link to that item s record in your catalog. Bring your own lists of books, or

More information

Oceanica Theme Documentation

Oceanica Theme Documentation Oceanica Theme Documentation Updated on December 29, 2017 Installation Import sample data Import sample data from xml file. Import sample data from.sql file. Set up the front page Edit front page Site

More information

Static Webpage Development

Static Webpage Development Dear Student, Based upon your enquiry we are pleased to send you the course curriculum for PHP Given below is the brief description for the course you are looking for: - Static Webpage Development Introduction

More information

JSN Sun Framework User's Guide

JSN Sun Framework User's Guide JSN Sun Framework User's Guide Getting Started Layout Overview & Key concepts To start with layout configuration, Go to Extension Template JSN_template_default The first tab you see will be the Layout

More information

RESPONSIVE WEB DESIGN IN 24 HOURS, SAMS TEACH YOURSELF BY JENNIFER KYRNIN

RESPONSIVE WEB DESIGN IN 24 HOURS, SAMS TEACH YOURSELF BY JENNIFER KYRNIN RESPONSIVE WEB DESIGN IN 24 HOURS, SAMS TEACH YOURSELF BY JENNIFER KYRNIN DOWNLOAD EBOOK : RESPONSIVE WEB DESIGN IN 24 HOURS, SAMS TEACH Click link bellow and free register to download ebook: RESPONSIVE

More information

All India Council For Research & Training

All India Council For Research & Training WEB DEVELOPMENT & DESIGNING Are you looking for a master program in web that covers everything related to web? Then yes! You have landed up on the right page. Web Master Course is an advanced web designing,

More information

Client Side JavaScript and AJAX

Client Side JavaScript and AJAX Client Side JavaScript and AJAX Client side javascript is JavaScript that runs in the browsers of people using your site. So far all the JavaScript code we've written runs on our node.js server. This is

More information

ADMIN MANUAL OF Wordpress

ADMIN MANUAL OF Wordpress ADMIN MANUAL OF Wordpress By: - Pratap Singh 8800 93 45 56 Logging In to WordPress WordPress login screen Enter your username and password. If you have forgotten this information, use the Lost Your Password?

More information

The Ultimate Web Accessibility Checklist

The Ultimate Web Accessibility Checklist The Ultimate Web Accessibility Checklist Introduction Web Accessibility guidelines accepted through most of the world are based on the World Wide Web Consortium s (W3C) Web Content Accessibility Guidelines

More information

Who should use this manual. Signing into WordPress

Who should use this manual. Signing into WordPress WordPress Manual Table of Contents Who should use this manual... 3 Signing into WordPress... 3 The WordPress Dashboard and Left-Hand Navigation Menu... 4 Pages vs. Posts... 5 Adding & Editing Your Web

More information

How to Edit Your Website

How to Edit Your Website How to Edit Your Website A guide to using your Content Management System Overview 2 Accessing the CMS 2 Choosing Your Language 2 Resetting Your Password 3 Sites 4 Favorites 4 Pages 5 Creating Pages 5 Managing

More information

BrainCert Enterprise LMS. Learning Management System (LMS) documentation Administrator Guide Version 3.0

BrainCert Enterprise LMS. Learning Management System (LMS) documentation Administrator Guide Version 3.0 BrainCert Enterprise LMS Learning Management System (LMS) documentation Administrator Guide Version 3.0 1 P a g e Table of Contents... 3... 3... 4... 4... 5... 5... 6... 6... 8... 8... 9... 9... 10...

More information

1 Introduction. Table of Contents. Manual for

1 Introduction. Table of Contents. Manual for Manual for www.lornasixsmith.com Table of Contents 1Introduction...1 2Log in...2 3Users...2 4What is the difference between pages and posts?...2 5Adding Images to the Media Library...2 6Adding Text to

More information

USER MANUAL. SEO Hub TABLE OF CONTENTS. Version: 0.1.1

USER MANUAL. SEO Hub TABLE OF CONTENTS. Version: 0.1.1 USER MANUAL TABLE OF CONTENTS Introduction... 1 Benefits of SEO Hub... 1 Installation& Activation... 2 Installation Steps... 2 Extension Activation... 4 How it Works?... 5 Back End Configuration... 5 Points

More information

Classroom Blogging. Training wiki:

Classroom Blogging. Training wiki: Classroom Blogging Training wiki: http://technologyintegrationshthornt.pbworks.com/create-a-blog 1. Create a Google Account Navigate to http://www.google.com and sign up for a Google account. o Use your

More information

Vetstreet Web Builder Editor Tool User Guide v2.1. Web Builder. User Guide v2.1

Vetstreet Web Builder Editor Tool User Guide v2.1. Web Builder. User Guide v2.1 Web Builder User Guide v2.1 Contact your Account Manager at (888) 799-8387 or email support@vetstreet.com with questions. Page 1 Index... 1 The Editor Tool... 7 Forgot Your Username or Password?... 7 How

More information

Creating Post(s) In WordPress

Creating Post(s) In WordPress Creating Post(s) In WordPress Posts In WordPress: Here is what posts are in WordPress: Posts are regular blog entries i.e. dynamic content. When any Post(s) are published, they appear automatically in

More information

Edublogs. (WordPress) An Introductory Manual. Gail Desler

Edublogs. (WordPress) An Introductory Manual. Gail Desler Edublogs (WordPress) An Introductory Manual Gail Desler [Drawing on/updating/expanding tutorials and explanations from James Farmer, Mike Temple, Ewa McGrail, Lorelle, Joan Boan, Alice Mercer, Kate Olson,

More information

Sonatype CLM - Release Notes. Sonatype CLM - Release Notes

Sonatype CLM - Release Notes. Sonatype CLM - Release Notes Sonatype CLM - Release Notes i Sonatype CLM - Release Notes Sonatype CLM - Release Notes ii Contents 1 Introduction 1 2 Upgrade instructions 2 3 Sonatype CLM for Bamboo 3 4 Sonatype CLM 1.13 4 5 Sonatype

More information

Starting Your SD41 Wordpress Blog blogs.sd41.bc.ca

Starting Your SD41 Wordpress Blog blogs.sd41.bc.ca Starting Your SD41 Wordpress Blog blogs.sd41.bc.ca The web address to your blog starts with blogs.sd41.bc.ca/lastnamefirstinitial (eg. John Smith s blog is blogs.sd41.bc.ca/smithj) All work is done in

More information

JSN PageBuilder 2 User Manual

JSN PageBuilder 2 User Manual JSN PageBuilder 2 User Manual Introduction About JSN PageBuilder 2 JSN PageBuilder 2 is the latest innovation of Joomla PageBuilder with great improvements in terms of design, features, and user experience.

More information

Rocket Theme. User Guide

Rocket Theme. User Guide Rocket Theme User Guide This user guide explains all main features and tricks of multifunctional Rocket WordPress Theme. This information will make your work with the theme even easier and more effective.

More information

ENTANDO 4.3 IN SUMMARY

ENTANDO 4.3 IN SUMMARY RELEASE NOTE ENTANDO 4.3 IN SUMMARY Compelling user experiences are increasingly important to the success of digital transformation projects, as well as time to market and developer efficiency. This is

More information