Theming Tutorial

    Part 1: Theme Basics

    What should I know before making a custom theme?

    During the process of this article, we will be looking at the basic files and functions that are necessary to create a working Zenphoto theme, We'll use the basic theme as an example. We will not go into every single detail of the code because we assume that you have a good understanding of HTML and CSS. You should also have a basic understanding what PHP is and how PHP code is put into a webpage and communicates with the server and returns information back to the client. If you don't have this understanding we recommend to learn that first. Good resources are for example:

    For more detailed information on the Zenphoto template functions please visit our functions documentation and it's accompaning How To Read The Zenphoto Functions Guide article.

    What is a theme?

    In technical terms, it's a set of files that use markup language HTML (preferredly HTML5) and CSS and embedded PHP code to dynamically create the layout and style of your gallery. In other words, a theme is just a way to give your gallery a different look.

    Where are the theme files located?

    By default, when you first install Zenphoto, you have the "root" or main folder of Zenphoto, then in it you have four other folders named albums, cache, themes, and zp-core. The themes folder is where the default themes exist, where you should install new themes that you've downloaded, and where you will put all your new themes. Zenphoto comes with six themes: basic, garland, effervescence_plus, zenpage and zpmobile.

    Where do I find themes and how can I install a theme designed by someone else?

    You can find all known custom themes at our themes page, or from the theme creator's site.

    Usually, the distribution of a theme comes with instructions on how to install the theme. In case instructions are not supplied, here is a basic set of installation instructions for installing themes:

    1. Download the theme of your choice.
    2. Expand the zip archive to a local folder.
    3. Upload the extracted folder (keeping the underlying folder structure intact) to your /themes directory.
    4. Go into your admin > themes tab and activate your theme.
    5. View your gallery with the new theme in place!

    Note: Some themes have custom mods or things that need to be changed in addition to the normal theme installation. So take care to note in the theme distribution what these may be before you install.

    How does a theme work?

    Themes are done in a pretty straightforward way. They're just PHP files that use a set of theme functions (from zp-core/template-functions.php) to display the albums or images in any way. The current theme is selected in the admin themes panel. (Admin uses the file theme_description.php within the theme's folder as the source of its information about the theme.) The root index.php file then looks at the URL arguments (album, image, etc. or lack thereof) and decides whether to load the theme's index file, album page, or image page. Pretty simple.

    The already mentioned template functions generate predefined HTML output for your convenience. These are the functions that generally beginn with "print". You can style that via CSS to your needs. These function generate code that follows the XHTML 1.1 transitional standard for history reasons which is compatible with the current HTML5 standard.

    Of course for advanced users it is also possible to get the pure data to setup your own HTML output using custom functions for more flexibility. You can read an introduction on this later in this tutorial.

    Part 2: Making a Theme

    We will now look at the necessary theme pages and the basic structure of these files that Zenphoto needs to process a theme. Again, we won't discuss any functions (or any HTML or CSS styling) in detail and only provide basic examples of standard function whose names are pretty self explanatory. Optional plugin functions are not included.

    As already said it is up to you what HTML structure (besides the core one naturally) you use in your theme. So we just included the bare bones HTML page construct in the following examples. Look at the included standard themes for suggestions. None of the official themes does it (yet), but of course you can for example also use header.php or footer.php files to generalize those parts if your theme.

    You can then take this knowledge and use it to create your own theme. More info on specific functions can be found in our functions guide.

    Zenphoto themes don't require any special standard HTML or CSS setup. The standard template function currently do generate standard (X)HTML syntax. Generally we recommend to create your theme as HTML5. More advanced coders might also create their own functions. 

    Here is a diagram of the general structure including optional pages and support for the Zenpage CMS plugin:


    You can freely design and structure your theme as needed. It is recommended to look also at the included standard  themes, most notably the basic (gallery only) and zenpage theme (with news and pages) as they are the two most plain structured ones.

    However, there are some required basic files every theme must have (advanced, experienced theme coders may also leave this standard structure of course). We also provided example files of a bare bones theme on GitHub. These files are without any specific HTML structure to make it easier to learn the structure.

    We will discuss these files in the following sections.

    General required filter calls

    Each theme page (except themeoptions.php and theme_description.php) must include three standard filter calls as the Zenphoto template functions and many plugins may use them to insert special scripts or HTML:

    • zp_apply_filter('theme_head') – Best is to place this right before the theme's </head>. This way theme CSS does not accidentally override plugins that come with their own CSS like video players etc.
      Note: This filter also loads the jQuery base file. So if you put jQuery dependent scripts into your theme's head you need to do that after this call. Also a lot of standard functionality and plugins are jQuery based.
    • zp_apply_filter('theme_body_open'); – Place right after the <body> tag
    • zp_apply_filter('theme_body_close');  – Place right before the </body> tag

    Standard theme pages

    • theme_description.php (required): This is the description file which gives Zenphoto information about your theme. This information is displayed in the themes page of the Zenphoto admin backend. Older themes before Zenphoto 1.2 may use a theme.txt file for the same purpose.
    • theme.png/theme.gif/theme.jpg (required): It should be 150x150px at least and represent a screenshot of your theme. It is displayed on the themes tab on the Zenphoto backend.
    • index.php (required): The gallery index (home page) of a theme. It's read and displayed when someone visits your main gallery page. It usually prints the top level albums.
    • album.php (required): This page is displayed when someone clicks on an album link from your gallery page (index.php).  This page displays sub level albums of an album selected and/or the thumbnail overview of images within that album.
    • image.php (required): This page is displayed when someone clicks on a specific thumbnail picture on your album page (album.php). It then displays the single (sized) image.
    • search.php (recommended): It's actually nearly the same as the album.php since it does display albums and images as a result of a search. 

    You find examples on the demo theme repository:

    Adding the comments section

    You can add comments to album.php and image.php. Additionally also to Zenpage's pages.php and news.php (single news articles).

    Since Zenphoto 1.2.6 the comment handling code has been transfered to the comment_form plugin. All you need to do is to enable that plugin and put this code where you want the comment form and the comment display.

            if (function_exists('printCommentForm')) { ?>

    You can of course modify the look of the comment section via CSS. You could even make your own custom comment form by changing the file /zp-core/plugins/comment_form/comment_form.php and place it within /plugins/comment_form/comment_form.php.

    Part 3: Advanced Theme Functionality

    This part of our tutorial is about the more advanced functionalitly you can add to your theme.

    Static custom pages (optional)

    "Custom pages" are additional static pages (e.g. their content not directly managed via the backend) that do not display actual gallery stuff like albums or images. You can have multiple custom pages that are called with the url

    • zenphoto/index.php?p=<pagetitle> (non mod_rewrite)
    • zenphoto/page/<pagetitle> (mod_rewrite)

    In general a custom page is just like index.php but with the album loop removed. These pages can be used as an "about" or "references" page for example, but the content needs to be hardcoded and can not be adminstrated by Zenphoto. These page also know no hierachy. (Of course, you can create theme options to allow customization of these pages from the admin theme options tab.)

    You can use some of the more general theme functions as archive.php does. Official themes generally include the following custom pages but all are optional:

    • archive.phpThis theme pages displays a monthly archive of your gallery items.
    • 404.php: If your theme contains this script it will be invoked whenever a page not found condition is raised by Zenphoto. Creating a script of this name allows you to control the presentaton of the page not found error. 
    • password.php: Default password protection handling will check passwords in the image and album loops. If an album is password protected, no subalbums or images will be returned from the loops. Instead, a password form will be presented. You can create a password.php script in your theme folder. If such a script exists, it will be loaded in place of the target Zenphoto page. This allows you to completely control the presentation of the password protected content. Each of the distributed themes contains such a script.
    • slideshow.php: A page that displays a slideshow. The design is generic so that it works with all themes without design adjusting, just a black background with the image on it, but it's possible to make it look like your other theme pages. Related files that are required to run the slideshow are the slideshow.css and the slideshow-controls.png and the slideshow plugin must be installed and activated.
    • contact.php:This is an optional (static) custom theme page example to provide a simple contact form using the contact_form plugin.

    You find examples on the demo theme repository:

    Separation of the gallery and the index page

    You may wish to have an introductory page to your website but still keep the look and feel of the gallery for visitors viewing your images. This can easily be done by using the theme option custom index page. If you have an existing Zenphoto gallery the easiest way to accomplish this task is to rename your current theme index.php script to something else, say gallery.php. Create your new index.php script to introduce your site. Include on it a link to (assuming you named your old index file gallery.php and you installed Zenphoto in the folder zenphoto). Set the custom index page option to gallery and your are all set.


    Custom functions can be used to add additional functionality to your theme. Any custom function may be placed in a PHP file called functions.php which must be located in your theme folder. This file will then be loaded automatically on every theme page to make the custom functions available.

    Please also review the Developer coding guidelines on themes.


    Themes may create options that change the behavior or appearance of the theme. (All the distributed themes have options for these reasons.) Options are defined by PHP code in a file called themeoptions.php which is located in your theme folder. The file is optional, if you have no options you need not have themeoptions.php.

    You define the options in this code and make use of them in your theme by calling the function getOption() passing the option name. (It is a good idea to be sure any unique options you create have unique names so that they don't conflict with options some other theme builder might have made.)

    Some of the 'standard' theme options (as defined by the distributed themes) are: 'Allow_comments', 'Allow_search', and 'Theme_colors'. These are used in the distributed themes to enable comment forms, enable serach forms, and select a CSS for the theme. See the basic theme for examples.

    Themeoptions are a class of Zenphoto Plugin so reading about the plugin architecture might also be of some value.

    You find examples on the demo theme repository:

    Overriding options for special theme effects

    If your theme has special needs for some options it is possible to temporarily override the options as set in the Administrative back end. Cases where this might be useful are, for instance, to insure that the theme looks well balanced when there are multiple album thumbs or image thumbs in a row. The theme may then wish to change the albums per page option (images per page option) so that it is a multiple of the number that will fit in a row. (The standard themes all do this.)

    It would not be nice, however, for a theme to permanantly change the option as it would impact other themes that might get used. The setOption() function of Zenphoto has provided a means to temporarily change an option without updating the options database. There is a third parameter in the the setOption() function, $persistent, which is defaulted to true. Passing false to this parameter tells setOption() to change the value of the option in memory but not in the database.

    The duration for an option set non-persistent is the scope of the script from where it is set until the script ends. This means that each script that relies on the transient value of the option must set it.

    Special images

    Zenphoto has several special images that a theme can replace if it wished. These are:

    • imageDefault.png which is used for album thumbnails when there are no images in the album.
    • multimediaDefault.png which is the default image for video thumbnails.
    • err-passwordprotected.gif which is used (optionally) as a standin for the thumbnail of an album which is password protected and the viewer has not supplied the password.

    A theme can override the images that come with Zenphoto by placing a same named image in a folder named images within the theme folder.

    Separate theme translations (post 1.2)

    If you provide a theme as a third party, its translation is naturally not included with Zenphoto's general translation file. Zenphoto uses gettext for translations of literal strings on your theme.

    Please visit the translating tutorial for more detailed information on how to setup your theme for theme translations and how gettext translation works in general.

    Sophisticated theme functionality

    Zenphoto is actually not limited to the already described standard theme way. Beside the fact that all template functions have a "print" variant that prints a full convenient HTML setup there is also (nearly) always a "get" variant that just returns raw data (strings, objects, array etc.) to build customized functions for special needs.

    Zenphoto also provides an object orientated framework for advanced users with coding knowledge to do different and more sophisicated things that are bascially only limited by your abilities. See the object model framework tutorial and the functions documentation for more details.

    Different theme page layouts

    Sometimes you might want to use different layouts for certain albums etc. In that case you can use the multiple_layouts plugin.

    Extra database storage

    If your theme requires to store extra info you can use the general available table plugin_storage together with the object model. This table provdes this field setup to use:

    • id - int(11) unsigned (auto increment)
    • type - varchar(32)
    • aux - varchar(255)
    • data - text

    Since there is no fixed usage there are no wrapper functions. While you should generally only use the template functions or the object model elsewhere you have to use MySQL queries for this table.

    Using functionionalty from plugins/extensions

    The functionally of plugins does not and often cannot always enabled itself automatically Some plugins require additions and modifications to the theme like the Zenpage CMS plugin described in part 4 of this tutorial. Refer to the plugins instructions you most always find within the in-file comments or via  (for officially included ones).

    To not break your theme if a plugin is not enabled, you can use several ways for simple function calls.

    • Use the native PHP functions to check for existance like function_exists() or class_exists().
    • Use the native PHP function call_user_func() (@call_user_func() to supress errors) if still on older PHP prior PHP 8.
    • On Zenphoto 1.6+ use the new helper fucntion callUserFunction() that follows call_user_func() usage but is compatible with PHP 8+ not throwing fatal errors

    Part 4: Theming Zenpage

    Zenpage theme basics

    This part will give you only a basic overview how to setup your theme for the CMS plugin Zenpage. It will not explain every detail. For more about the functions in detail please visit the functions documentation and take a look at the included zenpage theme.

    Required theme pages

    Zenpage hooks on Zenphoto's custom page feature and therefore requires two new custom pages to be available within your theme folder: pages.php and news.php. The names can be changed if really required for a certain language but this is only recommended for more advanced users. You can read about it in the FAQs.

    Generally you can use all general Zenpage functions on all Zenphoto theme pages as you can in turn use all general Zenphoto functions on these two new pages. Although some functions are limited only to pages.php and news.php to work correctly.

    • pages.php: This theme page is the simplest of the both since it will only show one page at the time, so we start with it.
    • news.php: This page is a little more complicated because it shows either the single news article or the news loop. The general structure is single news articles or news loop.

    You find examples on the demo theme repository:

    Updates to standard theme pages required

    • Adding search results for Zenpage items on search.php: Adding search results to a search page is actually a little more complicated and may look a little confusing at first. Search results for Zenpage news articles and pages are not paginated and only shown on the first search results page. Since Zenpage is an optional plugin we need to make sure that we set Zenpage results to 0 if the plugin is not enabled to avoid errors.
    • Adding news archive support for Zenpage items on archive.php: This is actually quite simple by adding the additional function printNewsArchive() to the page.

    You find examples on the demo theme repository:

    News on index.php

    This option allows to turn the theme index.php into the first page of the news section (all further ones will be displayed on news.php). All you have to do to use this is to copy the complete next_news() loop to your index.php.

    So bascially you have to modify the theme's index.php like this:

    if (!extensionEnabled('zenpage') || ($_zp_gallery_page == 'gallery.php' || ($_zp_gallery_page == 'index.php' && !getOption("zenpage_zp_index_news")))) {
    // The standard next_album and next_image loops here
    } else {
    // the standard next_news loop from Zenpage here

    Showing Zenpage content on other theme pages

    You can use the get/printPageContent(), get/printExtraContent() and get/printCodeblock() functions to show published or unpublished pages' content, extracontent or codeblocks from elsewhere. More info about these functions' parameters on the functions documentation.

    If you need more fields like author or date, you probably should do this with the class object directly:

    $page = new ZenpagePage('<titlelink of the page to get>');

    Then you can call each field with getId(); ?> for example. Note that the title, content and extracontent fields support the multi-lingual feature, so that they need to be called like this:

    <?php $title = get_language_string($page->getTitle()); ?>

    Of course this works similar for news articles, too. For more info about the Zenpage object methods please see the the object model framework tutorial and the functions documentation.

    The CombiNews feature

    Note: The CombiNews feature has been removed in Zenphoto 1.4.6. While the functions still exists they should not be used anymore.

    This actually does not really need any special theming. Zenpage will just internally use the normal functions to show the lastest gallery items within the normal loop as if they were news articles. They are still independed.

    But you have some additional functions to use with them. For example there is:

    <?php is_GalleryNewsType(); ?>

    This will check if the entry is a news article or an image or a movie. More detailed info on the functions guide.

    Since images, movies or audio files do not have categories, but albums you can show this, too:

    <?php echo getNewsAlbumTitle(); ?>

    If the entry is an image etc it prints a link to the album it belongs to. If not it prints the list of the news article categories.

    If you are in CombiNews mode and within the next_news() loop, the global object variable $_zp_current_zenpage_news contains the object of the gallery object. So you can do basically everything here with the object model as if you were within the next_image or next_album loop (depends on your CombiNews option mode).

    Duplicating (cloning) a theme for customizations

    Zenphoto does not know child themes. To use an existing theme as a base to create your own you only have to follow these steps:

    1. Duplicate the folder of the theme chosen 
    2. Rename the folder of the new theme 
    3. Open the theme_description.php file and change the theme name.
    4. Open the theme's themeoptions.php file and change option definitions with the former theme name to your new one. Only change those with the theme name in it (For the Zenpage theme don't change any as they are connected with the Zenpage plugin and not the theme!). Example of the Garland theme
      1. Default option settings: setThemeOptionDefault('garland_caption_location', 'image'); (themeoptions class __construct)
      2. The option form definitions like: array(gettext('Theme personality') => array('key' => 'garland_personality', 'type' => OPTION_TYPE_SELECTOR,[....] (within themeoptions class getOptionsSupported).
    5. If you like to use the original theme's css file(s) you have to add their calls to the original theme manually on the theme files.

    Creative Commons LicenseThis text by is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

    Code examples are released under the GPL v2 or later license

    For questions and comments please use the forum or discuss on the social networks.

    Related items