Share this page     submit to reddit   
   

How does Pyplate work?

Pyplate is a set of Python scripts that can be installed on a web server to serve pages to web browsers. Pyplate uses templates to ensure that pages have a consistent layout and style, and it uses an SQL database to store information about each page. When the server receives a request from a web browser, it passes the request to one of Pyplate's scripts, index.py in /usr/lib/cgi-bin/. This script looks up the requested URL in the database to see which page has been requested. Pyplate builds pages on demand using information from the database, HTML templates, and posts stored in Pyplate's content directory.

The code for the HTML template is stored in several files in Pyplate's template directory. These files contain a few lines of HTML that are embedded in each page in places like the banner, footer and sidebar. Styling is applied by embedding a CSS file in the head section of the page.

Pyplate uses several layouts in layouts.py in /usr/lib/cgi-bin/. These layouts are strings that tell Pyplate how each page should be arranged. Layouts contain a mixture of HTML, and variable fields which can be filled in with HTML code generated by Pyplate, or code from template files. Posts are stored in HTML files in Pyplate's content directory. When a page is generated, posts from the content directory are embedded in the page along with the template.

Finally the newly assembled page is sent back to the browser that requested it.

Themes, Layouts and Templates

Themes are stored in /usr/share/pyplate/themes. Each theme consists of a folder named after the theme. The folder contains a file called theme.css and a file called layouts.py. The CSS file contains all the styling information for the theme. Colours, visual effects and fonts are all defined in the CSS file.

Layouts.py contains strings of HTML defined as Python variables. Each string represents a layout for a type of page or part of a page. There is a layout for pages in the admin section, a layout for pages with individual posts, a layout for pages with several posts (pages showing all the posts in a category) and a layout for uncategorized pages. Layouts.py also contains layouts for the sidebar and the page header.

In Pyplate's database, each record has a field for the layout that should be used to display that page. When a page is generated, a function named getlayout is called, and the layout name from the database is passed to it as an argument. For each layout, there's a section of code in getLayout that formats the layout string.

For example, a theme's post_layout string may be defined in layouts.py as follows:

post_layout=""" <body> {banner} {navbar} <div id="container"> {bannerad} <div id="midpage"> {sidebar} {post_header} {breadcrumbs} {posts} {section_menu} {comments} </div><!-- midpage --> </div><!-- end_container --> {footer} <script src="/js/jquery-1.7.2.min.js"></script> <script src="/js/lightbox.min.js"></script> </body> </html> """

The strings contained in braces are fields that will be replaced when the layout is formatted. In getLayout, the post_layout string can be formatted like this:

if layout == "post_layout": return post_layout.format( banner=pyplate.getFile(pyplate.getCMSRoot() + "/template/banner.html"), navbar=pyplate.getFile(pyplate.getCMSRoot() + "/template/navbar.html"), sidebar=pyplate.getSidebar(), post_header=pyplate.getFile(pyplate.getCMSRoot() + "/template/post_header.html"), breadcrumbs=pyplate.get_breadcrumbs(dbase, page.posts[0]), posts=page.doPosts(dbase), section_menu=pyplate.get_category_menu(dbase, page.category), comments=pyplate.getFile(pyplate.getCMSRoot() + "/template/comments.html"), footer=pyplate.getFile(pyplate.getCMSRoot() + "/template/footer.html"))

The formatted layout string is returned to index.py, and then printed to the user's browser. Some fields are filled in with the contents of files from the template directory, such as the banner, navbar and footer. Other parts of the page are generated using the Pyplate API, such as the sidebar, breadcrumbs, and the posts for that page.

The code in the layout string and getLayout can be customized to change the way pages are formatted.

Symbolic links

When pyplate needs to access the current theme's CSS file, it uses a symbolic link in the web server's root directory called default_theme.css. This link points to the CSS file in the current theme. There is also a symbolic link for the current themes' layouts file in /usr/lib/cgi-bin/layouts.py. So if the current theme is named Edge, the symbolic link in /var/www/default_theme.css points to /usr/share/pyplate/themes/Edge/theme.css, and the link in /usr/lib/cgi-bin/layouts.py will point to /usr/share/pyplate/themes/Edge/layouts.py.

The template directory

In most web sites, there are some page components that are the same across the entire site. These page components usually include the banner, footer, sharing widgets, and parts of the sidebar. The code for these page components is stored in HTML files in /usr/share/pyplate/template. The templates for the banner, navbar and footer can be edited in the Site Setting's page in Pyplate's Admin area.

How does Pyplate store content?

Pyplate's content directory contains a directory structure that mirrors the site's category structure. Every time a category is created, a corresponding directory is created in the content directory tree, and in the web root directory.

Posts are stored as HTML files in the appropriate dirctory in the content directory tree. These files only contain the HTML code for each post, without any of the code for the rest of the page. When a page is served dynamically, Pyplate builds a page and embeds the contents of one or more post files in the page.

When a page is requested by a user, the domain name is stripped from the requested URL, leaving a relative path. For example, a request for a page at http://example.com/foo/bar/bletch.html gives a relative path of /foo/bar/bletch.html. Pyplate uses the relative path and translates it to an absolute path by appending it to /usr/share/pyplate/content. The file containing the post can be found at /usr/share/pyplate/content/foo/bar/bletch.html.

The Web Root Directory

When Pyplate is installed, Apache's default web root directory, /var/www, is moved to /var/www2. In it's place, the Pyplate installation script creates a file system link from /var/www to /usr/share/pyplate/webroot. Files and directories in Pyplate's webroot directory can be accessed via /var/www.

Cached Pages

Dynamically generating every page, every time it is served, puts an unnecessary load on the CPU. It's better to generate pages in advance and cache them as static HTML files. Cached pages are stored in the web server's root directory so that they can be served without the CMS executing. This significantly decreases page load time and increases the number of concurrent users that a web server can handle.

The site's category structure is also mirrored in the web root directory. When a page is cached, an HTML file is created in the appropriate place in the web root directory. When a page at http://example.com/foo/bar/bletch.html is cached, the complete page will be stored in /var/www/foo/bar/bletch.html.

Clearing the Cache

when you add pages or make changes to your site, you must clear the cache and rebuild it. Cached pages aren't automatically updated when you make changes to your site, so if you to modify a page that's been cached, you need to go to the admin area and click on the "Clear Cache" button. When you've finished making changes to your site, click on the "Build Cache" button to rebuild the page cache.

Post pages and category pages

The example above shows how individual posts are stored, displayed and cached. As well as handling pages that contain individual posts, Pyplate also needs to handle pages that correspond to entire categories. Category pages display all the posts in one category in a single page. These pages correspond to a directory in Pyplate's content directory. To continue using the example above, if a user visits http://example.com/foo/bar/, Pyplate creates a page containing all the posts in /usr/share/pyplate/content/foo/bar/.

When a category page is cached, it is saved in the corresponding place in the web root directory in a file named dir.html. When the page at http://example.com/foo/bar/ is cached, it will be stored in /var/www/foo/bar/dir.html. The web server must be configured to serve dir.html when users request a page that corresponds to a category.

Sidebar Caching

Generating the sidebar every time a page is served would be too time consuming, so the sidebar is cached automatically. The sidebar is cached independently of the rest of the site. Any time a page is requested, Pyplate will check to see if the sidebar has been saved in the template directory. If not, the sidebar will be generated and saved. The next time a page is requested, the sidebar will already exist, so the page load time and the load on the server will both be reduced.

The sidebar file is deleted when the page cache is emptied. It is also deleted when pages or categories are added, modified or deleted.

Uncategorized Pages

Some pages don't need to be displayed in a site's navigation system, such as pages with terms and conditions or a privacy policy. These kinds of pages can be omitted from site navigation by creating them in the 'General' category. This isn't a real category; it's a dummy category that tells Pyplate that a particular page doesn't need to be included in the category hierarchy. The posts for uncategorized pages are stored in /usr/share/pyplate/content.

Pyplate's Database

Pyplate doesn't store content in the database. Instead content is stored in files in /usr/share/pyplate/content/. The database contains meta data about each page, and information about where each post is stored in /usr/share/pyplate/content/.

When a page is added to a site, a new record is created in the database's pages table. Each record contains the following fields:

FieldDescription
paththe relative path of the page
titlethe title of a post
categorythe category that the post belongs to expressed as a relative path
layoutthe name of the layout that should be used to format the page
descriptiona meta description of what the page is about
tagstags relevant to the page
statusthe status of a page (deleted or published)
pubdatea timestamp of when the page was created
updatea timestamp of when the page was updated

When a new category is added a record is created in the categories table. The categories table has the following fields:

FieldDescription
titlethe title of the category
slugthe text that will be used to represent the category in URLs
paththe relative path of the category
layoutthe name of the layout that should be used to format the page
descriptiona meta description of what the category is about
tagstags relevant to the category
parentthe category that contains this category
placethe position of this category when the contents of the parent category are listed
statusthe status of a category (deleted or published)
pubdatea timestamp of when the category was created
updatea timestamp of when the category was updated

The code to manage the database is in /usr/lib/cgi-bin/db.py. This code handles SQL queries for the database.

Storing relative paths in the database

Pyplate is built on the principle of translating web URLs to local paths. Pyplate uses relative paths extensively as they can easily be translated in to web URLs or file system paths. The relative path of a file or category can be obtained from a URL by removing the domain name. For example, removing the domain name from the following URL will leave the relative path: http://raspberrywebserver.com/linux-basics/bash/bash-basics.html

In this case the relative path is /linux-basics/bash/bash-basics.html. In the filesystem, paths are relative to /usr/share/pyplate/content, so this post can be found in /usr/share/pyplate/content/linux-basics/bash/bash-basics.html.

Site Navigation

Effective site navigation helps users find their way around a site. It means people are more likely to find what they're looking for on your site, and will spend more time browsing on it. Most site navigation features are generated by the Pyplate API.

The Navigation Bar

The navigation bar is the menu along the top of the page. It can be created in two different ways (whichever way it is created, CSS styling is used to make the list appear horizontal). It can be generated by calling get_navbar from pyplate.py, a function which generates an HTML list of links to all the top level categories. For example, if a site has categories named 'a', 'b', and a subcategory named 'c' contained in 'a', then the navigation bar will contain links to the home directory, 'a' and 'b'. 'C' won't appear in this menu because it's a subdirectory. The generated code would look like this:

<div class="navbar"> <ul class="navmenu"> <li><a href="/">Home</a></li> <li><a href="/a/">A</a></li> <li><a href="/b/">B</a></li> </ul> </div>

Users who want a customized navigation bar can write the HTML code by hand in the Site Settings page in the admin area. This is useful when you want to include extra links in your navigation bar. This site uses a hand written navigation bar in order to include the link to the forum. The forum isn't a category in the Pyplate database, so it wouldn't appear in code generated by get_navbar.

In the HTML layouts in layouts.py, each page layout has a {navbar} field, which is substituded for another string when format() is called in get_layout. If you want to use a hand written navigation bar, the navbar field should be set by using getFile to access the navbar file in the template directory:

navbar=pyplate.getFile(pyplate.getCMSRoot() + "/template/navbar.html"),

If you'd rather use a navigation bar that just contains a list of links to top-level categories, then the navbar feld should be set like this:

navbar=pyplate.get_navbar(database),

The Sidebar

The sidebar contains the main site navigation menu, which lists all categories and posts. The sidebar is generated by a call to pyplate.get_sidebar. The menu is generated by calling pyplate.get_menu, a function that prints categroy names wrapped in h2 tags, and prints the titles of posts in each category as an item in an unordered list. Categories displayed in the order specified in the position field in each category record.

In the default theme, the sidebar just contains the site menu. If you look at the right hand column on this site, you can see that there are several other panels in the sidebar. The HTML for each file is stored in a file in the template durectory. The sidebar layout in the theme's layout.py needs to be modified to include extra panels. Pyplate.getFile is used in getLayout to fill in the sidebar panels.

Generating the HTML code for the sidebar can be quite CPU intensive because Pyplate needs to execute quite a lot of code to generate the navigation menu. Instead of generating the sidebar every time a page is generated, the sidebar is cached in the template directory. The sidebar file is deleted when the cache is cleared. If the sidebar file can't be found when Pyplate generates a page, it will be generated and cached for future use.

The sidebar file in the template folder should not be edited manually as it will be deleted when the cache is cleared, and modifications will be lost.

Category Menu

Pyplate.get_category_menu is a lot like the pyplate.get_menu function that's used to generate the site menu. The main difference is that pyplate.get_category_menu only displays the contents of the current category and its subcategories. This makes it easy for people to see what other pages are in the same category. When people finish reading an article on a web site, they often look around the bottom of the article to see if there's anything else to read on the site, so it's common to use this feature underneath the main content on a page.

Breadcrumbs

Breadcrumbs are a list of links, usually near the top of a page, that make it easier for users to see where the page they are viewing fits into the hierarchy of your site's categories. Breadcrumbs also make it easy for users to get to higher level categories. The HTML code for breadcrumbs is generated by pyplate.get_breadcrumbs.

Follow me