Web Designer s Guide to panpage v4.0 Website Content Management System last updated 23 rd March 2014
Contents Why build your website with Panpage... 4 A word about fonts and names in this guide... 4 Installing Panpage... 5 Licensing... 5 Installing to a local XAMPP Server... 6 Installing to a Remote Server...10 First Tasks Checking & Securing...14 Panpage with an oven ready theme...18 Personalising your theme...19 Panpage with your own HTML & CSS...20 Building a complete working page...22 Streamlining: from Page Skeleton to Theme...33 Page, column and item styles...38 Providing page classes and templates...38 Adding column classes and styles...39 Adding item classes and styles...41 Styling: Items or Columns?...42 Layer based layouts...43 Mixed layouts...44 Item types...45 Std/Text Items...45 Folding Items...45 Ticker Items...46 Gallery Items...46 Thumb Items...48 Repeat Items...48 Raw/HTML Items...48 Application notes: Panpage How To s...49 Creating Fixed Pages...49 Placing content in more than one location...51 Protecting email links...51 Enquiry forms and form processing...52 Embedding content from other websites...57 Sitemaps...57 2
Configuration and theme files... 61 Configuration overview... 61 Configuration File... 62 Theme File... 65 Adding your Own Config Items... 68 Panpage Functions the API... 69 Panpage object model... 69 Site Functions... 69 Site Properties and Utility Functions... 74 Page Functions... 75 Utility Functions... 80 Page Properties... 81 Column Functions... 82 Column Utility Functions... 83 Column Properties... 83 Item Functions... 83 Item Utility Functions... 85 Item Properties... 85 3
Why build your website with Panpage Panpage was designed to be easy not only for website owners to make changes to their sites, but also for web designers to create Panpage websites in the first place. To that end you can use a ready-made Panpage theme or you can start with your own HTML and CSS and substitute a few lines of PHP code for certain blocks of HTML. You don t have to be a PHP programmer to use Panpage. Even if you choose not to use a ready-made theme you can copy and paste the PHP code without change into your web page files it s no more difficult than embedding a Google map or a YouTube video. (And you can still do both of those in a Panpage website too!) Once you have built a Panpage website around your own HTML & CSS you can take the next step and turn your design into a robust Panpage theme that you can use again. A word about fonts and names in this guide Just to make things clear (hopefully)... Fonts The descriptive part of this guide is set in Garamond a pleasant looking, easy to read, serif font. This paragraph is in Cambria. Code examples are shown in a mono-spaced font like this to make them stand out. Names In this guide... We means developers and designers at Abbeydale Web Ltd and we re probably giving examples of how we use Panpage. You means you and we presume you re a web designer or developer using, or thinking of using, Panpage to create content managed websites for your clients. Client means your client the owner of the website and probably the person who will be using Panpage to update the site. Visitor means anyone visiting your client s website and having no other interaction with Panpage. 4
Installing Panpage This section will get your Panpage installation up and running, either on a local development machine (localhost) or a live website. Licensing Panpage comes as a Zip file containing an image of the directory structure and all files needed to run the CMS. There is a very basic website and theme included in the package so you can check that everything is working before you start hacking it to pieces! Note that if you intend to install Panpage to a local XAMPP web server installation but haven t yet installed XAMPP, you should do so now, before downloading Panpage. You can get XAMPP from www.apachefriends.org or follow the link on the downloads page at www.panpage.com. When installing XAMPP take note of which version of Visual C/C++ was used to compile your copy of XAMPP. You ll need to install the ioncube loader compiled with the same version. The current version, XAMPP v1.8.3 at the time of writing, uses VC9, versions before 1.8 used VC6. The free download package is licensed for operation on localhost so you can run it on your development installation and experiment as long as you want. You only need to buy a license to run Panpage on a live site on the web. Panpage is licensed per domain and licenses can be purchased via the website at www.panpage.com, for 69 per domain. If you re going to use a live webserver then many of the remaining installation tasks will be done on the server so go to Installing to a Remote Server on page 10. If you re installing to a local XAMPP server read on 5
Installing to a local XAMPP Server Assuming you have a working XAMPP installation, including PHP and MySQL, these are the steps required to install and run Panpage... 1. Create a folder under the XAMPP document root (htdocs) called panpage then download and unpack the Panpage files into it 2. Install the ioncube loader 3. If you used our suggested folder names then you can run Panpage straightaway, otherwise you will have to edit the Panpage config file first. Note that the following local installation is seriously insecure and suitable only for development purposes! Download and unpack ioncube loader Download Panpage from www.panpage.com/download.php and unpack the files into a new folder called panpage under XAMPP s document root, ie. \xampp\htdocs\panpage. Panpage requires the ioncube loader to be installed into your XAMPP system and you can download this from www.ioncube.com/loaders.php. There are full installation instructions and an install wizard at ioncube but it does only half the job it copies the loader file into \xampp\php\ioncube but you still have to edit php.ini by hand. Manual installation is quite simple. Note that there are two versions of the ioncube loader for Windows compiled with VC9 and VC11. You should choose the same compiler version as your copy of XAMPP. If you installed the latest version of XAMPP (v1.8 or later) you should use the ioncube loader labelled, Windows VC9 (x86). 1. Copy the appropriate ioncube_loader_win_x.x.dll file to /xampp/php/ioncube (where x.x is your PHP version, eg 5.4). 2. Edit php.ini (found in /xampp/php) to add this line... zend_extension="c:\xampp\php\ioncube\ ioncube_loader_win_x.x.dll" (NB on one line and first zend extension in php.ini.) 3. Restart Apache to start using the loader. 6
MySQL Database Php.ini is located in \xampp\php and you should search it for zend_extension to make sure you insert the above entry before any other zend_extension entries. Stop then restart the Apache web server so you re using the modified php.ini. You can check that the ioncube loader is installed and working by pointing your browser to http://localhost/panpage/cms/_phpinfo.php. This will display an enormous panel of information about PHP and your XAMPP installation and you ll find an entry for the ioncube loader just at the bottom of the first panel If you see a line about the ioncube loader with its version number then it s installed and working. If not then carefully check you have entered the pathnames correctly and have the right version of the ioncube loader for your version of PHP and XAMPP. XAMPP includes the MySQL database server and creates a database user called root with all privileges and no password. Panpage will login to MySQL as user root and can do all the database work that s needed without further intervention. Panpage Configuration File If you went along with the folder names suggested above, ie you unzipped Panpage into \xampp\htdocs\panpage, you won t need to make any changes to the Panpage configuration file at least for now so skip to Run Panpage for the first time below. Otherwise read on The config file is in cms/cfg under the panpage folder and it s called pp_config.php. It s a PHP source file so open the file with your favourite text editor - NOT a word processor as we don t want formatting whatever you normally use to edit HTML and CSS should be fine. 7
First enter the database details... 1. Look for the line that starts $cfgpp[ dbdatabase ] = and set to your database name. In our example this will be... $cfgpp[ dbdatabase ] = cmsdb ; This is a PHP source file so don t lose the quotes or final semi-colon! 2. Set $cfgpp[ dbuser ] to your database username, eg... $cfgpp[ dbuser ] = cmsuser ; 3. Set $cfgpp[ dbpassword ] to cmsuser s password, eg $cfgpp[ dbpassword ] = LetMeIn ; 4. XAMPP locates the MySQL Server on the same machine as all the other components so the database server is localhost $cfgpp[ dbhost ] = localhost ; Next the folder details 5. Set $cfgpp[ SiteRoot ] equal to your folder name under the document root (including the leading slash), eg... $cfgpp[ SiteRoot ] = /panpage ; Note that we re in web server land here so it s forward slashes even on a windows machine. 6. Save the changes to the config file and Panpage is now ready to run. Run Panpage for the first time Run Panpage by pointing your web browser (preferably Firefox, Chrome or Safari) to... http://localhost/panpage/cms or whatever folder name you chose. 8
Panpage will discover that it has no database and will warn you that it is about to create a new database and tables for this website. Check the database name and location and, if they re what you expect, click yes and let it create the tables. (If they re not correct then you ll have to back up a step and check your config file entries again.) Panpage creates the database, the tables it needs and also creates a user called webmaster and an empty home page, index.php. (Again, if there are any problems Panpage will report them mostly they ll be down to config file errors so back up and check your config file entries.) You can now login to Panpage as user webmaster (with no password) and you re up and running. 9
Installing to a Remote Server The server for a Panpage website must support PHP v5 or later and MySQL v5 or later. The ioncube PHP loader (v3.1 or later) must also be installed. This is usually present already but if not then the tech support dept of most professional hosting providers will install it for you on request it s free after all from www.ioncube.com. Always ask for the latest version available from ioncube (4.4.1 at the time of writing). Beware of the following potential problems on commercial servers 1. PHP installed as an Apache module. Ideally PHP should be installed as a CGI or FastCGI module to have sufficient privileges on the server to create/edit/delete website page files. If PHP is running as an Apache module then Apache must have the mod_ruid module installed too. We have found this also allows Panpage to work correctly. 2. ioncube loader version 4.0.12. This version is buggy and ioncube replaced it with version 4.0.14 in Spring of 2012. At the time of writing (March 2014) CPanel is pushing out v4.4.1 as the current version but some servers may still be running v4.0.12. Panpage behaves erratically on v4.0.12 but works just fine on other versions. You can check both of the above by uploading the file _phpinfo.php to your server and pointing your browser to it. It s located in the cms folder of your Panpage download. Look for the Server API value in the first result panel (should be CGI/FastCGI) and the ioncube PHP Loader version in the Zend panel just below. Contact your host tech support to have either of these problems fixed. 10
Installing Panpage to a remote server involves the following tasks... 1. Unpack the Panpage download and purchase a license file for your domain. 2. Create a MySQL database and user on your web server. 3. Edit the Panpage config file with details of your web server and database 4. Upload the Panpage files to your server 5. Run Panpage Unpack the Panpage Files MySQL Database Create a folder on your hard disk to represent the root folder of your website and unpack the Panpage zip download into it. This process will create a number of subfolders too. Using Panpage on a live web server requires a license, a file called panpage.lic, dedicated to that domain. You should purchase the licence from www.panpage.com following the instructions there. All Panpage licenses include the domain localhost so you can run Panpage on a local development machine as well as on the live server. When you receive your new license file copy it into your website root folder in place of the default license file that came with the Panpage download. Note that the licence for Panpage v3 & v4 differs from earlier versions and if you are upgrading from Panpage v2 you will need a new, version 3/4 licence. These are free to those who have already purchased a v2 licence. Most commercial web hosts don t allow scripts to create databases so you ll most likely have to create one using the server s control panel. Login and create a MySQL database. On CPanel servers this will have a double barrelled name where the first part is the CPanel username. Let s say the domain is fredco.com. The CPanel username will probably be fredco, and the database could be called fredco_cms. You don t need to create any tables, Panpage can do that. Create a database user too, let s say fredco_webuser. Grant fredco_webuser at least the following rights in the fredco_cms database... SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER 11
ALTER is needed only to update the database should you update your copy of Panpage in the future. Panpage Configuration File Now you need to make some changes to Panpage s config file to fit it to your domain and server. The file is in the /cms/cfg folder (under the website root created above) and it s called pp_config.php. It s a PHP source file so you ll need a plain text editor to make changes. Windows Notepad or Mac Terminal will do at a pinch. First enter the database details... 1. Open cms/cfg/pp_config.php in your text editor. 2. Look for the line that starts $cfgpp[ dbdatabase ] = and set this equal to your database name. In our example this will be... $cfgpp[ dbdatabase ] = fredco_cms ; Remember that pp_config is a PHP source file so don t lose any quote marks or the final semi-colon! 3. Set $cfgpp[ dbuser ] to your database username, eg... $cfgpp[ dbuser ] = fredco_webuser ; 4. Set $cfgpp[ dbpassword ] to the above user s password, eg... $cfgpp[ dbpassword ] = LetMeIn ; 5. The database host on most, but not all, commercial webservers is localhost. If yours is not localhost you will need to change the database host name to suit your server $cfgpp[ dbhost ] = localhost ; Next enter the domain details... 1. Set $cfgpp[ TargetSiteBase ] = the fully qualified domain name of your website, eg... $cfgpp[ TargetSiteBase ] = http://www.fredco.com ; 2. Ensure the $cfgpp[ SiteRoot ] entry is an empty string ie... $cfgpp[ SiteRoot ] = ; there shouldn t even be a space between the two quote marks. 3. Save the changes to this config file and Panpage is now ready to upload. 12
Upload to the Server Run Panpage You ll need an FTP account on the server and an FTP Client on your computer to upload the Panpage files. There are a number of free FTP Clients available: FileZilla, CuteFTP and FTP Commander for example (Google for them). Login to the web server with your FTP client and upload everything in your website root folder and all subfolders to the document root on your server called public_html on most CPanel servers. Run Panpage on the web server by pointing your browser (preferably Firefox, Chrome or Safari) to the cms folder of your website, eg. http://www.fredco.com/cms. Panpage will discover that it has an empty database and will warn you that it is about to create new database tables for this website. Check the database name and location and, if they re what you expect, answer yes and let it create the tables. (If they re not correct then you ll have to back up a step and check your config file entries again. And don t forget to upload the config file to the web server again after you make changes it goes into the folder cms/cfg under the document root.) Panpage creates the tables it needs in the database and also creates a user, webmaster, and an empty home page, index.php. (Again, if there are any problems Panpage will report them mostly they ll be down to config file errors so back up and check your config file entries.) You can now login to Panpage as user webmaster (with no password) and you re up and running. Phew! 13
First Tasks Checking & Securing Before you leap into creating your website, it s worth taking a minute to make sure everything works and to secure your website by removing the installation files particularly the PHP file that creates the database tables. Checking Your Panpage Installation When you have logged in as webmaster you ll find yourself looking at the Panpage home page. This is basically a list of pages on your website and since you ve just installed the system there will be only one page the empty home page, index.php. It should look something like this... The menu on the left has a link: View Site. Click this and Panpage will open up the website it s managing in a new browser tab. For now this will be using the basic theme so it won t look very pretty but it will show that things are working Later you can beautify it with your own HTML & CSS or you can use a ready-made Panpage theme. 14
But enough of that for now. Let s go back to Panpage and take a quick tour... System Configuration... Click Site Config in the system menu on the left. This is where you set up configuration items that apply to the entire website - divided into 5 sections, opened and closed by the button at the top right of each section... Site Owner/Organisation name, email address, postal address and phone number. Site footer - common footer to every page on the site. Miscellaneous - drop menu and visitor email address items, Google Analytics ID and Verify tag. This section also contains any spare config items if enabled. Publishing - publish/unpublish the whole website and unpublished messages for site and pages. Privileges - who can edit what! 15
Backup... Click Backup in the system menu. This is where you will create (and possibly restore) backups of your website. You can also download backups from the server to your computer and upload them again if needed. There may be a backup already present. If so this contains a few pages of sample content that you can use to practice (or demonstrate) editing a website with Panpage. Click the Restore button,, to restore the backup and see the sample content in your site. User List Like the Page List this is a bit boring at present with only one user, webmaster. Shortly you ll use this section to create and edit users of the Panpage system. See the User Guide for details. User Guide This link downloads a PDF version of the Panpage User Guide. It s aimed at site owners rather than designers but you should have a look thru it if you re new to Panpage. 16
Securing Panpage If your website is on a live webserver READ THIS it s important As Panpage stands right now, your installation is vulnerable for two reasons 1. The file that creates the database tables is still present and this necessarily requires no username or password to run. If you re running on a live web server this is not a good thing! Now that you ve checked that everything is working you should remove this file. It s called _createdb.php and it s in the cms folder on your web server. Use your FTP client to delete it and do it now before you forget! 2. The one and only Panpage user, Webmaster, has no password. You should edit this user s details: ideally change the name and certainly enter a password. Don t forget to add an email address so that Panpage can send you a password reminder if you forget it. If you don t carry out the above actions your website will be wide open for anyone with a little Panpage knowledge to change or totally delete it! Secure it now! You might also like to remove the file containing the call to phpinfo(). It s not strictly a threat to your system but might give a hacker clues about your PHP installation. Use your FTP client to delete the file _phpinfo.php also in the cms folder. 17
Panpage with an oven ready theme This section shows how to customise your website by installing a theme from panpage.com. This is the quickest and easiest way to create a website with Panpage and doesn t require any PHP or Javascript coding skills at all even to create a website with image slideshows, folding items, video clips and embedded social media widgets. The basic Panpage download comes with a plain and simple website theme so you can check that everything is working. Everything that contributes to the appearance of the website is in a directory called theme, directly under the website root. To replace the basic theme 1. Delete the contents of the theme directory from your Panpage installation. 2. Download the theme of your choice from panpage.com. 3. Extract the contents of the zip into a folder on your computer. 4. Upload the files to the theme folder of your Panpage installation. Next time you open or refresh the website in your browser it will take on the appearance of the new theme. A theme consists of the following basic parts 1. A theme configuration file: pp_theme.php. This tells Panpage what page, column and item styles are in use, how to configure the navigation menu and, possibly, which of a number of alternative colour schemes or page layouts to use. Usually you won t need to change the theme file. 2. A file containing the PHP and HTML code to generate an empty page: pagecommon.php. You should never need to change pagecommon.php to use a ready-made theme. 3. One or more style sheet files. Usually there is at least a style sheet for the website appearance on a computer monitor: screen.css, but there may also be style sheets files for printing web pages, and for tablets or mobile phone displays. Often there will be supplementary style sheets for older versions of Internet Explorer too to work around various rendering bugs. 18
4. A collection of graphic fragments and other image files for backgrounds, buttons and icons. Themes generally come with a short user guide that tells you what styles are available for columns, layers and items and what the column or item widths are so you know what size images you can conveniently use. Personalising your theme Themes can generally be personalised by adding your own logo upload a file called logo.png to the theme folder or to the images folder. This should be at the correct size to fit your website banner and have a transparent background so that the banner colour scheme will show through. The png24 format works best. You may also be able to upload your own banner background graphics and/or other files. Some themes provide alternate colour schemes and, if any are available, they are usually selected by editing the theme file: pp_theme.php. This is the same format as the Panpage config file mentioned above and you can edit it with a text editor. Some themes also allow you to select either a column based layout or a layer based one. This too is selected in pp_theme.php. That s about all there is to a ready-made theme; you just need to compose your pages using appropriate columns and items and add content. The remainder of this Design Guide is concerned with using Panpage with your own HTML and CSS code and with generating new themes from scratch. 19
Panpage with your own HTML & CSS This section introduces the basics of creating a website with Panpage. It s a 10,000ft overview of the process but we ll get down to ground level soon. Designing for Panpage is just like designing for conventional fixed HTML and CSS. If you design graphically as a first stage and then convert the finished, client approved design into HTML & CSS, then adding Panpage to your workflow requires little more than replacing lines of fixed HTML with PHP function calls to Panpage. Working this way round, inserting Panpage calls into your HTML/CSS, makes the job easy. Panpage fits into your work rather than the other way round! Have a look at this sample of HTML - the <body> section of a simple webpage... <body> <div id="center"> <div id="banner"> <a href="index.php"><img id="title" src="images/title.png" /></a> <ul class= pp_navmain > <li><a href="index.htm">home</a></li>... <li><a href="contact.htm" >contact...</a></li> </ul> <div id="page"> <div id="colfullwidth"> <h1>web Design Sheffield</h1> <div class= colleft > <h2>website Packages</h2> <p>lots of content in here... </p> <div class= colright > <h2>portfolio</h2> <p>more content in another column here... </p> <! end of page --> <! end of site --> </body> The black sections are the same for every page in the website and form the page s structure hooks to hang your CSS on. The green section is page content and will be different for every page. Not completely different though the basic pattern of an area on the page containing columns of content is likely to be present in 20
many, if not all, of the pages. We can replace the green section of HTML with a call to Panpage s Render() function for that page... $page->render(); The blue section is also the same for each page and forms the navigation menu. However, it can t be fixed since it will change if we add new pages or delete or rename pages. We ll replace that too - with a call to Panpage s navigation menu function... $g_site->rendernavmain(); We end up with a sort of skeleton page with some fixed HTML and some PHP calls into Panpage... <body> <div id="center"> <div id="banner"> <a href="index.php"><img id="title" src="images/title.png" /></a> <?php $g_site->rendernavmain();?> <div id="page"> <?php $page->render();?> <! end of page --> <! end of site --> </body> The black parts, the fixed HTML, along with the CSS style sheet file(s), hold the site structure and design into which Panpage delivers the content. Your website files also need the.php extension rather than.htm or.html, so your web server will run the PHP code *. The above example page is obviously a VERY simple one but shows the principle of building a website with Panpage. In the next section we ll come right down to ground level and build a complete working web page along with its CSS and Panpage calls to deliver content. * If you re not familiar with PHP but are interested in how the above works... PHP programs run on the web server and whereas desktop computer programs produce output for the screen or printer, PHP produces output for your browser. It outputs lines of HTML which the webserver delivers to your browser just like lines from a simple HTML file. The PHP calls above output lines of HTML similar to those they replace but in which the content (the collection of headings, paragraphs, lists, tables, images etc) all comes from a database. A PHP file can contain a mixture of fixed HTML and PHP. The web server sends the HTML lines straight to your browser but executes the PHP code and sends the resulting HTML from that to the browser as well. The mixture is seamless when it reaches your browser so clicking View Source will show you just HTML as usual, but some of it has been generated by the PHP program code. 21
Building a complete working page An example can often answer lots of questions so this section will start from scratch and build a complete, if rather simple web page. Creating the HTML We ll assume you re starting with a localhost Panpage installation on your computer as described above but if you re working on a live web server the principle is the same. You ll just have to remember to upload your files to the server each time you edit them. Prepare the ground by deleting the current contents of the theme folder or rename it and create a new empty theme folder. Also delete index.php in the website root folder. We ll work towards something that looks like the Basic Theme so our new page will have a banner at the top, a horizontal nav menu below that, then the page content and a footer to round it all off. We ll look at the HTML first, then build the CSS to match and finally rip out the fixed content and replace it with Panpage calls. If you want to follow this section but not spend hours typing you can download the HTML and CSS code used here from www.panpage.com from the downloads page. Create an empty file in your text editor and add the head element first no big surprises in here... <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <title>content Management with Panpage </title> <meta name="description" content="panpage is so easy!" /> <meta name="keywords" content="content management system" /> <meta name="robots" content="index, follow" /> <link rel="stylesheet" href="theme/screen.css" type="text/css" /> </head> There s a DOCTYPE declaration to keep us out of quirks mode, HTML5 version here, followed by the <html> tag, <head> tag and the usual head section stuff. You can use an HTML4 or XHTML type declaration if you prefer, and add the usual viewport and other items Panpage doesn t really care about any of that. We ll place the CSS file, screen.css, in the theme folder. We normally put graphic files related to the website structure in there too, just to keep things tidy. There s often a lot more in the head section but remember this is just a simple example! 22
Next the body... <body > <div id='center'> <div id='banner'> <a href="index.htm"><img id='logo' src='images/logo.png' /></a> <h1>panpage Sample Website</h1> <ul class= pp_navmain > <li><a href="index.htm">home</a></li> <li><a href="about.htm">about</a></li> <li><a href="contact.htm">contact</a></li> </ul> <div id='page'> <div class='colleftof2'> <p>this is a simple sample website with a bit of text in the left column and a picture of the Dudh Kosi valley in the Himalayas on the right.</p> <div class='colrightof2'> <img src= images/himalayas.jpg /> <div id= pp_foot > <a href=http://www.panpage.com>powered by panpage</a> </body> </html> Your first question is probably, What s this <div id= center >? Its job is to center the page in the browser window while still allowing it to be a floating element. You ll see how it works when we add the CSS. We want the page to float because all the columns and items float inside it and, since the page often has a background colour, we want the page to grow to enclose all of its content. Just another cunning CSS trick but one that requires an extra <div> so not perfect! (Feel free to suggest a better way to center a floating page in the body.) Save the file as index.htm. You can point your browser at it to see what it looks like but it won t be very pretty it needs some CSS to beautify it. 23
Add the CSS Again this is simplified but will show how things work. Create a new, empty file in your text editor. We generally use Eric Meyer s CSS Reset code at the top of our style sheets to minimise cross browser inconsistencies and would recommend it to you Google that name and you ll find it. First the structural stuff: the body, site, banner, page and footer... body { text-align:center; background-color:#ccc; font: small arial, tahoma, sans-serif; } #center { width:960px; margin:12px auto; text-align:left; } #banner { float:left; clear:left; width:100%; height:130px; #page color:#fff; background-color:#999; } { float:left; clear:left; width:100%; min-height:300px; color:#666; background-color:#fff; } #pp_foot { float:left; clear:left; width:100%; padding:6px 0; color:#fff; background-color:#666; } The body has text-align:center; and #center sets the width of the website and uses auto for horizontal margins. This is the CSS way to center an element within another - #center is centered within the body. The other major page elements, the banner, page and footer, float within #center and have width:100%. This makes them floating elements so they will enclose child elements floating inside them, but they ll still be centered in the body. We ve given the page a min-height to stop empty pages looking silly. Next we ll style the columns: more or less as described earlier....colsingle {float:left; width:936px; margin:0 12px; clear:left;}.colleftof2 {float:left; width:456px; margin:0 12px; clear:left;}.colrightof2 {float:right; width:456px; margin:0 12px; }.colleftof3 {float:left; width:296px; margin:0 12px; clear:left;}.colmidof3 {float:left; width:296px; margin:0 12px; }.colrightof3 {float:right; width:296px; margin:0 12px; }.colleft2of3 {float:left; width:616px; margin:0 12px; clear:left;}.colright2of3 {float:right; width:616px; margin:0 12px; } Note that we ve included left and right two thirds width columns. Sometimes we also add quarter width columns, and matching threequarter widths, which can be mixed with half width columns in various arrangements. This usually calls for a colmidof2, which seems strange until you think about a quarter-half-quarter layout. These column styles are also entered into the Panpage theme file so that Panpage knows about them and can offer them as styling choices when you create or edit columns. More about that later. We won t consider item styling at this point let s get the structure of the pages finished and we ll maybe add some twiddly bits later. Next the navigation: Panpage gives the nav menu element a class, pp_navmain, so we can use that to style it... 24
.pp_navmain {float:left; width:100%; margin:0; padding:0; background-color:#666;}.pp_navmain li {float:left; list-style:none; margin:0; border-right:solid 1px #333;}.pp_navmain a {display:block; padding:6px 12px; text-decoration:none; color:#fff;}.pp_navmain a:hover {color:#28deff; background-color:#333;} The navigation menu bar will sit below the banner and be full width (100% of #center) with a dark grey background. It will be represented as an unordered list, <ul>, but the list items, <li>, will float within the list and have no bullets. Each menu item is a link anchor, <a>, within the list item and styling this display:block; means the anchor will have vertical padding as well as horizontal and will form the menu button the bit you click to choose that page. The result is a button whose whole area changes colour when you mouse over it (a:hover). If you re wondering why the nav menu has a class and not an id it s because it s possible, in theory at least, to have more than one nav menu on a page and two elements can t have the same id value. That s the important stuff but if you want to play along with this you ll need to fix up a few details to make this sample web page look right... #logo {float:left; border:none;} #banner h1 {font-size:48px; margin:24px 0 0 178px;} #pp_foot a {color:#999; text-decoration:none;} p {margin:9px 0 0 0;} Save the CSS file as screen.css in the theme folder. The end result, using the image files from the Panpage sample website, now looks something like this... Sample website HTML version 25
Adding Panpage Now that we have a working website design with proven CSS the next step is to replace the fixed HTML content with PHP calls to Panpage, and that s just a bit of copying and pasting. You can find all the common Panpage calls on www.panpage.com in paste-ready form. Starting with the head section, we need to add a few lines of initialization code at the top of the file and then replace the title, description and keywords tags with a Panpage call. In the following code samples, new code to be added is in blue and old code to be deleted is in red. Existing HTML code that we keep is in grey... <?php include_once( cms/cms_classes.php ); $spagename = basename($_server['php_self'], ".php"); $page = &cmsinit($spagename, isset($_get['qe']), isset($_get['prvw'])); if (!$page) die("error - Couldn't read page content!");?> <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <title>content Management with Panpage </title> <meta name="description" content="panpage is so easy!" /> <meta name="keywords" content="content management system" /> <?php $page->renderheadtags();?> <meta name="robots" content="index, follow" /> <link rel="stylesheet" href="theme/screen.css" type="text/css" /> </head> The Panpage initialisation code is pasted right at the top of the file, before the DOCTYPE declaration, while the RenderHeadTags() call replaces the title, meta description and meta keywords tags to bring these important SEO tags under CMS control. Moving on to the body section we ll replace the fixed HTML code for the navigation menu, the page content and the footer in the same way - giving us... <body > <div id='center'> <div id='banner'> <a href="index.php"><img id='logo' src='images/logo.png' /></a> <h1>panpage Sample Website</h1> <ul id='nav'> <li><a href="index.htm">home</a></li> <li><a href="about.htm">about</a></li> <li><a href="contact.htm">contact</a></li> </ul> <?php $g_site->rendernavmain();?> 26
<div id='page'> <div class='colleftof2'> <p>this is a simple sample website with a bit of text in the left column and a picture of the Dudh Kosi valley in the Himalayas on the right.</p> <div class='colrightof2'> <img src= images/himalayas.jpg /> <?php $page->render();?> <div id= pp_foot > <a href=http://www.panpage.com>powered by panpage</a> <?php $g_site->renderfooter();?> </body> </html> The navigation menu has been replaced by a call to RenderNavMain(), and the content and footer have been replaced with similar calls. Render() outputs the page content while RenderFoot() outputs the footer. Note that the RenderNavMain() function belongs to the site object rather than the page. This is because it works with data about ALL pages. The page-> functions, like Render() and RenderHeadTags() etc. all deal with data from just one page. The site object, like the page object, is created by the initialisation code at the beginning of each web page specifically by cms_classes.php in the first line of code. RenderFoot() is also a member of the site as the footer is common to all pages on the site. Now save the page file with the extension.php, ie. index.php. Don t try to view it just yet though. There s one more step first Telling Panpage about the columns: the theme file To keep things easy for users site owners Panpage needs to know about the column classes we ve created and offer them as choices when creating new columns. You do this by entering the column classes, and one or two other things, into the Panpage theme file. Create another empty text file and enter the following <?php $cfgpp['templatenames'] = array("std Page"); $cfgpp['templateclasses'] = array("standard"); $cfgpp['templatefileprefix'] = ""; $cfgpp['columnclasses'] = array("colsingle", "colleftof2", "colrightof2", "colleftof3", "colmidof3", "colrightof3", "colleft2of3", "colright2of3"); $cfgpp['columnnames'] = array("full Width", "Half Left", "Half Right", "Third Left", "Third Mid", "Third Right", "Two Thirds Left", "Two Thirds Right"); 27
$cfgpp['itemclasses'] = array("itemfullwidth"); $cfgpp['itemnames'] = array("full Width");?> Save this into the theme folder as pp_theme.php. If you re thinking that this is very similar to the Panpage config file, you re right. The theme file is effectively an extension to the config file that contains all the appearance related configuration items. Saving these into a file in the theme folder keeps all the appearance related stuff together and makes Panpage themes independent and self-contained. And finally, before starting Panpage, make a copy of the index.php you just created. Call it standard.php and save it in the theme folder. This will be a page template file that Panpage will use to create new page files. There s more about template files and the theme file later but now we re ready to look at the site again and to run Panpage and enter some content. Point your browser at the index.php file and check out the result. Note that you ll have to type in the http address, not just the filename, as PHP code needs to be executed by a webserver before it is sent to the browser. http://localhost/panpage/index.php (or something like www.fredco.com/index.php * if you re following this on a live webserver). Hopefully you ll see something like this Sample website, Panpage version Assuming you started with an empty database the home page will be empty. If you ve not even created the database yet then there won t even be a navigation menu! We ll fill in some content soon. * fredco.com was the example domain name we used earlier obviously you will use your own domain name here. We ve shown the full domain name and filename here just in case you still have an index.htm floating around. Most web servers, when given just the domain name, will serve up index.htm in preference to index.php if both are represent. 28
Entering content into Panpage More pages This process is described in detail in the Panpage User Guide but basically consists of the following steps... 1. Login to Panpage at the cms folder on your domain, eg. http://localhost/panpage/cms, or http://www.fredco.com/cms. 2. Click the Edit button for the home page 3. Enter a Page Title and Description in the Meta Tags section (to stop Panpage complaining). Anything will do try Just testing in both. 4. Add a column and change its class to Half Left 5. Add an item and enter some text use the text from the HTML page if you like. 6. Save the item and the column. 7. Add another column to the page and change its class to Half Right 8. Add an item and insert a picture ensuring it s no wider than 456px, the width of a Half Right column. 9. Save the item and column Now refresh the index.php page in your browser and you ll see the content you just added. The page file, index.php, you created above is a web page without any content and Panpage can use this as a template for creating new pages. If you didn t do it earlier, make a copy of index.php and save it the theme folder as standard.php. Now, in Panpage, create a new page. Again this is covered in the User Guide but consists of the following steps... 1. Navigate to the Panpage home page, the list of pages in your website. 2. Click the add button,, at the right of the page list heading. 3. In the Page section give the page a name (say about ) and a filename (or just accept the default) 4. Leave the Parent Page set to none-top level. 5. Open the Meta Tags section below, give the page a title and description and click the save button. Refresh the browser window showing the web site and you ll find another page in the navigation menu. Panpage has created a copy of the standard.php template file and saved it into the website root as about.php (or whatever filename 29
you gave). The fact that it actually creates this file is one of the reasons Panpage websites are search engine friendly and compatible with page based tools like Google Analytics. Child pages and drop-down navigation You can create as many pages as you like and Panpage will add them to the navigation menu, but beyond 6 or 7 pages this becomes unwieldy and you run out of space on the nav bar. The usual solution is to organise the website into sections each headed by a top level page and containing a number of child pages. The top level pages appear in the nav menu and the child pages appear in new menus that drop down from the main menu as you move the mouse over it (or touch it). This is VERY easy to do in Panpage but before you try it you ll need to add a few more lines to your CSS file to style the drop down menus. Panpage creates each drop down menu as another unordered list element within the navmain <li> item, and this, in turn, contains links in <li> elements representing the individual child pages. <ul class= pp_navmain > <li> <a href= index.php >home</a> </li> <li> <a href= about.php >about us</a> <ul class= pp_navdrop > <li> <a href= our-staff.php >our staff</a> </li> </ul> </li> </ul> Typical CSS for a drop menu looks like this... ul.pp_navdrop { position:absolute; display:none; margin:1px 0 0 0; padding:0; border-top:solid 1px #333; background-color:#666; }.pp_navdrop li { list-style:none; margin:0; border-bottom:solid 1px #333; }.pp_navdrop a { display:block; padding:6px 12px; text-decoration:none; color:#fff; }.pp_navdrop a:hover { color:#28deff; background-color:#000; } Again pp_navdrop is a class as there will often be more than one drop down menu within each navmain. It s initially invisible (because of display:none;) and is set to absolute positioning as Panpage will position it below the main menu item to which it belongs and make it visible when needed. 30
We ll also need to add a couple of lines to the PHP file too as we need some javascript to open and close the drop menus. This comes in two files in the cms directory and the first, pp_top.js, goes into the head section to make sure everything is ready when we need it further down the page. The pp_top script needs the jquery library too so we include that first...... <?php $page->renderheadtags();?> <meta name= robots content= index, follow /> <link rel= stylesheet href= screen.css type= text/css /> <script type= text/javascript src= cms/jquery-1.10.2.min.js ></script> <script type= text/javascript src= cms/pp_top.js ></script> </head> The drop menu HTML comes from the RenderNavMain() function so we don t need to do any more there. The second javascript file goes right at the bottom of the page, just before the closing </body> tag so it executes as the page finishes loading <?php $page->render();?> <?php $page->renderfooter();?> <script type= text/javascript src= cms/pp_btm.js ></script> </body> </html> RenderNavMain() outputs a <ul class= pp_navdrop > element for each drop menu and an <li> element for each item in each drop menu. Again you can compare the PHP source code with the browser s View Source output to see the exact HTML code that RenderNavMain() generates when there are child pages. You ll need to modify the about.php and standard.php files as well and add the javascript files to make sure the drop menus work correctly on every page. (This is one drawback of the very simple way we have created the template files with hard coded HTML. If you need to change the template then you have to change every page file in your site. There is a way round this though, as you ll see in Streamlining: from Page Skeleton below) Now you can go back into Panpage and create another web page. This time, in the Create New Page page, drop open the Parent Page box and choose about as the parent. Fill in a title and description to stop Panpage from moaning and save the new page. In fact to see the drop menus properly why not create a couple of pages with about as the parent. Open up the site again (or refresh it if it s still open in another browser tab) and mouse over the nav menu to see the drop menu open and close. 31
Panpage supports multiple level drop down menus so you can create pages whose parent page is also a child etc etc. Don t try this just yet tho we ll need a bit more CSS to make those work properly. Style Support for QuickEdit In QuickEdit, Panpage encloses each editable Item in a division of class pp_quickedit and it is important that this division should stand out when you mouse over it. It needs a style rule something like.pp_quickedit { display:block; cursor:crosshair; }.pp_quickedit:hover { color:#fc3; background-color:#630; background-image:none; } Add these two rules at the end of your style sheet. If you have styled any elements (eg. headings) with a foreground colour, you should also include specific selectors here to redefine their colour when inside a pp_quickedit div.pp_quickedit:hover,.pp_quickedit:hover h1,.pp_quickedit:hover h2 { background-color:#630; color:#fc3; background-image:none; } This will ensure that all your text looks the same when you mouse over it in quick edit. You now have the bones of a website that can accommodate dozens of pages and be organised in a logical, structured manner that s easy for visitors to navigate. The next step makes the site easier to maintain and also makes it compatible with other Panpage themes. 32
Streamlining: from Page Skeleton to Theme So far we ve created page files by removing fixed content from regular website HTML files, and while this is very quick and easy to understand, it has some drawbacks, particularly when we want to make structural or global changes to the site. We ll have to make such changes in every page file and in every template used to create new page files. Very tiresome! Since Panpage s skeleton pages are all PHP files we can use PHP to collect the common parts of every page into a single file. We ll replace much of the remaining fixed HTML in the page files with calls to PHP functions. Again, you don t have to be an expert PHP programmer to do this but a little knowledge of PHP won t go amiss! Replacing the Page Head Looking again at the <head> section of our skeleton page file <?php include_once( cms/cms_classes.php ); $spagename = basename($_server['php_self'], ".php"); $page = &cmsinit($spagename, isset($_get['qe']), isset($_get['prvw'])); if (!$page) die("error - Couldn't read page content!");?> <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <?php $page->renderheadtags();?> <meta name="robots" content="index, follow" /> <link rel="stylesheet" href="theme/screen.css" type="text/css" /> <script type= text/javascript src= cms/jquery-1.10.2.min.js ></script> <script type= text/javascript src= cms/pp_top.js ></script> </head> We have included the Panpage file, cms_classes.php which drags in a whole bunch of PHP code from within Panpage. We ll now use the same technique to include another PHP file. It will contain all the common parts of the page so we ll call it pagecommon.php and include it at the end of the initialisation code to give <?php if (!$page) die("error - Couldn't read page content!"); include_once( theme/pagecommon.php );?> Create a new file in your text editor and insert the following 33
<?php function WriteHead() {?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <?php $page->renderheadtags();?> <meta name="robots" content="index, follow" /> <link rel="stylesheet" href="theme/screen.css" type="text/css" /> <script type= text/javascript src= cms/jquery-1.10.2.min.js ></script> <script type= text/javascript src= cms/pp_top.js ></script> </head> <?php }?> Save pagecommon.php into the theme folder of your website. What we ve done here is to create a PHP function called WriteHead. Because PHP allows us to swap between PHP code and HTML, we can drop out of PHP as soon as the function starts (that s the?> bit) and just copy in the HTML from the head (the black bits above). Note that we ve also copied in the call to $page->renderheadtags() so we pop back into PHP for a line (that s the <?php..?> bit) and drop out again for the last few HTML tags. Now, having included pagecommon.php, we can replace all the remaining fixed HTML in the head section with a call to WriteHead(). The head section now becomes <?php include_once( cms/cms_classes.php ); $spagename = basename($_server['php_self'], ".php"); $page = &cmsinit($spagename, isset($_get['qe']), isset($_get['prvw'])); if (!$page) die("error - Couldn't read page content!"); include_once( theme/pagecommon.php ); WriteHead ();?> Naturally you can put a lot more into the head than we have shown here and you might include a viewport meta tag, a favicon or further <style> or <script> elements. 34
Replacing the Body We ll now do the same with the body of our skeleton page file. In pagecommon.php add an empty line or two at the bottom, just before the last?>, and then add function WriteBody () {?> <body > <div id='center'> <div id='banner'> <a href="index.php"><img id='logo' src='images/logo.png' /></a> <h1>panpage Sample Website</h1> <?php $g_site->rendernavmain();?> <div id='page'> <?php $page-render();?> <?php $page->renderfooter();?> <script type= text/javascript src= cms/pp_btm.js ></script> </body> </html> <?php } Again, the black bits are copied and pasted from the body of the page file. Save pagecommon.php again and modify the page file to use it <?php include_once( cms/cms_classes.php ); $spagename = basename($_server['php_self'], ".php"); $page = &cmsinit($spagename, isset($_get['qe']), isset($_get['prvw'])); if (!$page) die("error - Couldn't read page content!"); include_once( theme/pagecommon.php ); WriteHead(); WriteBody ();?> Now you can make site-wide changes to your pages just by changing pagecommon.php. We now have a very compact skeleton page file which is identical for every page and also can be used as a page template file for creating new pages. The only bit that changes from one page to another is the PHP variable, $spagename, which is the page s filename without the.php bit on the end. Thus the filename is what tells Panpage which page record to read from the database in order to render this page. To finish off and make our page files compatible with the other themes on the Panpage website we ll make one further change: we ll split WriteBody() into two parts, WriteBodyTop() and WriteBodyBottom() to give us the ultimate in flexibility. 35
In pagecommon.php change the WriteBody() function to WriteBodyTop() and then, in the function code, find the call to $page->render() and replace that line with just?> to end the function. WriteBodyTop() should now look something like this function WriteBodyTop() {?> <body > <div id='site'> <div id='banner'> <a href="index.php"><img id='logo' src='images/logo.png' /></a> <h1>panpage Sample Website</h1> <?php $g_site->rendernavmain();?> <div id='page'>?> Add a couple of empty lines after that and then add function WriteBodyBottom() {?> Finally, add a line or two at the bottom of pagcommon.php, just before the last?>, and then add function WriteBody() { global $page; WriteBodyTop(); $page->render(); WriteBodyBottom(); } Our page files can now call either WriteBody() or call the individual WriteBodyTop() and WriteBodyBottom() functions - if we need to create fixed pages for example, but for the most part we ll just call WriteBody(); To recap We ve taken out the common parts of each page and put them into a single php file called pagecommon.php. For flexibility we have divided up the common code into three php functions WriteHead() contains the DOCTYPE declaration, the opening <html> tag and the whole of the head section. WriteBodyTop() contains the body section up to, but not including the call to $page->render(). WriteBodyBottom() contains the remainder of the body section from just after the call to $page->render(). 36
WriteBody() combines the two body functions above and the call to $page->render(). 37
Page, column and item styles This section will build on the basic website we created above and add some easy to use features and styling. We ll be and adding more items to the theme file, pp_theme.php. To make updating a Panpage website as easy as possible for the site owner, you can supply it with built in styles for pages, columns and items that can be selected when creating or editing those elements. This section assumes some knowledge of CSS and describes how to create the class and id hooks within the Panpage generated HTML for styles to be attached. You ll also need to add some entries to the Panpage theme file, pp_theme.php, as described below. Columns and Items follow the same styling principals but pages are slightly different so we ll start with those. Providing page classes and templates When you create a new page in your Panpage website you are asked to select a page class and this also determines which template file Panpage will use to create the new page. The template is a skeleton page file just like the one we constructed above, with PHP calls to pagecommon.php and to Panpage itself. In creating the new page, Panpage makes a copy of the template file and gives it the filename you have chosen for your new page. Many website designs use only one page class (and hence one template) but different classes can result in pages that look and operate differently. They usually have a family resemblance but they don t have to. The page class appears as a class name for the <body> element, and template files can place other structural elements differently or give them different class or id names. All these class and id names will appear in the generated HTML for your web pages and you can use them to attach styles from your CSS style sheet file(s). Ultimately different page templates could include different pagecommon and CSS files for a completely different appearance and operation. Template files have a filename taken from the page class they represent and are saved in the theme folder. We generally prefix our template filenames with an underscore to make it obvious they are template files, but that s optional. So that Panpage knows about your page classes and template files and can present them by friendly, descriptive names, you must add the page classes to the theme file too. For example... $cfgpp[ TemplateClasses ] = array( standard, other ); $cfgpp[ TemplateNames ],= array( Std Page, Other Page ); $cfgpp[ TemplateFilePrefix ] = _ ; 38
The TemplateClasses line contains the page class names used in the website. The TemplateNames line contains friendly descriptive names in the same order and Panpage shows these as choices when you create a new page. Adding column classes and styles You can provide two collections of column classes for your website: mandatory structural classes and optional styling classes. Both result in class names being attached to your column divs. Mandatory structural classes When creating a new column in Panpage, you MUST assign it one class name from the drop down list of column classes. These are the structural classes: things like colsingle, colleftof2 etc. that define how the column fits into the page layout. When Panpage renders the column it will include the chosen class name in the column s div tag, for example... <div class= colleftof2 > Panpage will refer to these classes by friendly, descriptive names rather than the class names themselves. Insert your classes into the config file item $cfgpp[ ColumnClasses ] and put corresponding friendly names into $cfgpp[ ColumnNames ] $cfgpp[ ColumnClasses ] = array( colsingle, colleftof2, colrightof2, ); $cfgpp[ ColumnNames ] = array( Full Width (936), Half Left (456), Half Right (456), ); You must also provide CSS rules in your style sheet(s) for these classes. Typical styles might be....colsingle {float:left; width:936px; margin:0 12px; clear:left;}.colleftof2 {float:left; width:456px; margin:0 12px; clear:left;}.colrightof2 {float:right; width:456px; margin:0 12px; }......and more are shown in Building a complete working page above. It goes without saying that the class names you choose must comply with the rules for naming CSS classes in particular: no spaces! (If you do create a class with a space in its name it will appear to be two classes in the HTML class attribute as multiple class names are space separated which can be useful if you re trying to be clever!) Additional column styling classes As well as the mandatory, structural classes, you can also provide additional, styling classes for columns. These classes are optional in that you don t have to provide any, and also optional in that, even if you do provide them, the columns don t have to use them. They typically add visual styling to columns perhaps to create a column with a coloured background, or a fixed height column with a border 39
and scroll bar for a news panel or blog. They can also be used to display specific columns in different places on the page but more of that later. When Panpage renders the column it will include the chosen class name in the column s div tag, for example... <div class= colrightof2 framefixedhgt >... Again, in dialogs for the user, Panpage refers to these additional classes by friendly, descriptive names rather than the class names themselves, so you must insert your classes into the theme file, for example $cfgpp[ ColumnAddClasses ] = array( framefixedhgt, solidbox ); $cfgpp[ ColumnAddNames ] = array( Frame 500px, Grey Box ); You must also provide CSS rules in your style sheet(s) for these classes. Typical styles might be....framedfixedhgt {height:500px; overflow:auto; border:solid 2px black;}.solidbox {color:white; background-color:#666666; }... Note one further major difference between mandatory classes and optional classes: columns can only have one mandatory class but more than one additional class. Additional classes is a multiple selection drop-down-list so you select the first additional class by clicking it on the list and each extra class by holding down the [Ctrl] key while clicking it in the list. Splitting content using additional column classes You can also use additional column classes to tell the $page- >Render() function which columns to output. Some web page layouts require some of the content to appear in specific places like a sidebar or below the footer. You can choose which column(s) to output by passing them as an argument to $page->render(). For example $page->render( colsidebar ); will output only columns with the additional class colsidebar. You can reverse this by adding an exclamation mark as the first character of the argument... $page->render(!colsidebar ); will output all columns except those having the additional class colsidebar. Specifying more than one class ORs them together so $page->render( colsidebar, coltopbar ); will output columns with class colsidebar or coltopbar. This is commonly used with negation to output everything except the specified columns. You might output sidebar content in one 40
Render() call, topbar content in another, and everything else like this $page->render(!colsidebar, coltopbar ); Note that you need only one exclamation mark and it must be the first character in the argument. Adding item classes and styles In column based layouts, items don t usually have any styling attached to them. (But see Layer based layouts on page 43 for item styling in layer based layouts.) However, since we have these chunks of content it seems a shame to waste the opportunity to hang some CSS on them, so you can add styling classes to items just as you can to columns. In column based layouts there is usually only one mandatory item class: itemfullwidth $cfgpp[ ItemClasses ] = array( itemfullwidth ); $cfgpp[ ItemNames ] = array( Full Width ); And since there is only one possible class Panpage doesn t offer you the choice, it just uses the one and only class. Additional item classes work in exactly the same way as additional column classes: you add your class names and friendly names to the theme file lines $cfgpp[ ItemAddStyles ] and $cfgpp[ ItemAddNames ] respectively, and add the class styles to your style sheet(s). For example, you may want to add emphasis to some items by giving them a coloured background or a border, so you could create appropriate styles in your CSS.panelRed.panelBlue {background-color:#c02; padding:6px; color:#fff;} {background-color:#039; padding:6px; color:#fe0;} and add them to the theme file too so you can select them within Panpage $cfgpp[ ItemAddClasses ] = array( panelred, panelblue ); $cfgpp[ ItemAddNames ] = array( Red Panel, Blue Panel ); 41
Combining Column and Item classes You can combine item classes with column classes so that, for example, an item of class boxframed contained in a column of class colgreen may present an item with a green border. In such cases the column may not actually be styled to have a green background but that column class is used to style the child item with CSS descendant or child selectors - like this....colgreen,.colblue {}.colgreen.boxframed {border:solid 2px green;}.colblue.boxframed {border:solid 2px blue;} We have used similar techniques, along with page templates, to style different sections of a website in different colours, even styling drop down nav menus to match a page or section colour. Styling: Items or Columns? It s easy, when you first start to work with Panpage, to be confused about items and columns: their roles seem to overlap significantly and it can be difficult to decide to which your styling should be applied. Columns should be considered, first and foremost, to be structural elements, used to layout content on the page. In general the fewer the columns you can use to create a given layout, the more robust it is likely to be, and probably more understandable too. Consider a typical page layout (right) with a column of advert blocks at the right. This page could be laid out as... a quarter width column, floating right, containing four items for the adverts a three quarter column, clearing left, for the heading and intro text a quarter column clearing left for the picture description text a half mid column for the picture a three quarter column, clearing left, for the remaining text at the bottom of the page 42
Each advert block would be an individual item in the right column and styled to suit. It would be difficult to get this layout to work reliably if the right hand column were composed of four individual column elements each containing a single item. An even simpler layout would involve only two columns: a single three quarter column floating left for the text and photo, with the photo floating right within the text, and a single right floating column for the adverts. This would cope with different font sizes (on visitors machines) without the danger of gaps under the text or picture. A good rule of thumb is fewer columns, more items! The two column layout will work well above as long as the picture can be included in a Standard text item. If it s not a still picture but an embedded YouTube video clip for example, then the five column layout would be needed as videos can t reliably be embedded into a Standard Text item. The WYSIWYG HTML editor has a habit of messing with the embed code with disastrous results and it is far safer to put embedded video, Google maps etc, into a Raw/HTML item instead. Of course, you could put everything into Raw/HTML items but that would defeat the object of using a CMS! Layer based layouts So far we have discussed only column based layouts where each page is divided into vertical columns and items are the full width of the column that contains them. Items in one column are essentially independent of items in other columns - there is no easy way to make items in different columns line up with each other vertically. If your website design requires such alignment then you should use a layer based layout instead. In a column layout there are lots of different classes of column giving columns of different widths and positions. Items are always the full width of the column. A layer layout switches the roles. The columns (ie. layers) are always the full page width and there are lots of different item classes of different widths and positions. 43
Mixed layouts In the column layout on the left, items in the right column don t align with items in the left except right at the top of the columns. In the layer layout on the right the columns are all full width and each layer down the page starts a new column. Items align at the top of each column layer. By specifying two or more column classes but only one item class in the theme file you effectively have a column based layout. If you specify only one column but more than one item class you have a layer based layout. There is nothing to stop you specifying more than one of each and this can give you even more flexibility in your layout, but equally, more chance of a site owner breaking or abusing it!. 44
Item types This section shows how different item types work and how they can be styled. Check out the theme style sheet files from panpage.com for more examples. Basically Std/Text items contain normal, static text and images. The other item types call up some code as well as text and images, usually to add an animation to the item. Std/Text Items Folding Items Std/Text items contain only simple static content like paragraphs, lists, images, tables etc. You can style these just as you would in a fixed HTML website except that you can t rely on site owners to carefully craft inline styles, element IDs or classes into the HTML tags. However you can use additional column and items classes and CSS descendant selectors to style lists or tables in those elements. The site owner won t have to do anything more complex than select a column or item class from a drop down list. For example, a coloured panel might use a larger font size, a different colour, or a different list style to normal body text.itempanel { font-size: 1.2em; color: #fff; background-color: #c03; }.itempanel li { list-style: none; background-image: url(3d_bullet.png); } A folding item contains two further sub divisions, the fixed part and the folding part, and a piece of javascript code to slowly reduce the height of the folding part to zero <div class= pp_itemfold > <div class= pp_fixed > fixed content <div class= pp_fold > folding content To make this work the folding part needs to be styled so that it doesn t try to add scroll bars when not in the fully open state.pp_itemfold { cursor: pointer; }.pp_fold { overflow: hidden; } 45
Ticker Items Gallery Items Ticker items show content scrolling across the screen and use a small piece of javascript to move the content within the item bounds <div class="pp_itemtick"> <div class="pp_tick" onmouseover=..> <p>scrolling ticker text here</p> <script type="text/javascript"> javascript code </script> Tickers often have a different colour and background to the rest of the page as well as rules to ensure the scrolling works correctly.pp_itemtick {overflow: hidden; position: relative; color: #fff; background-color: #0b96b7;}.pp_Tick {white-space: nowrap; padding:6px 0;} The overflow: hidden and white-space: nowrap rules ensure the content doesn t try to wriggle out of the containing item and the position: relative rule allows the javascript code to position the content anywhere inside the item without fear of early versions of IE getting it wrong! Gallery items work by placing one image, whose opacity is reduced to zero, on top of another and slowly increasing the opacity of the top image and optionally reducing the opacity of the bottom one at the same time. Alternatively the top image can start off hidden to one side or above/below and slide into place while the previous image slides out. The HTML elements involved are <div class= pp_itemgallery > <div class= pp_galleryframe > <div class= pp_galleryslide > <img id= pp_gallerymainpic /> <img id= pp_galleryauxpic /> The following style rules are required #pp_galleryframe { position: relative; overflow: hidden; } #pp_galleryslide { position: relative; overflow: visible; } 46
Element pp_galleryslide is the immediate container for the images and the position: relative rule ensures that the gallery s javascript code can place the auxiliary image accurately over the top of the main image. Element pp_galleryframe is the container for the whole animated assembly and the overflow: hidden rule ensures that sliding transitions will not produce unwanted scroll bars! Note that any decorative styling such as padding or borders should be applied to pp_galleryframe rather than pp_galleryslide as some browsers (OK - earlier versions of IE!) get image position calculations wrong when any of the inner container elements have extra width as in padding and borders. This typically results in a jump as the image changes from one to the next. The position: relative rule on pp_galleryslide isolates it from further containers. A gallery can have overlay controls and markers so the visitor can stop and start it or choose a particular picture. These sit in a div of class pp_galleryoverlay which is positioned (absolute) directly over the top of pp_galleryframe. If the gallery has a caption then element for this is placed above or below the pp_galleryframe element <div class="pp_gallerycaption"> <p>caption text</p> <div id= pp_galleryframe > <div class="pp_gallerycaption"> <p>caption text</p> The following style rules are required < either here < or here.pp_gallerycaption { clear: both; text-align: center; } The clear: both and text-align: center rules ensure that the caption will center above or below the image. Margin and/or padding can be applied to the caption to tweak alignment. If you choose to have a caption on the left or right instead of centered then Panpage applies an inline float rule to pp_gallerycaption. The complete HTML structure of a gallery item can be seen most easily by examining the source HTML of a web page try some of the theme samples at panpage.com. You can also see the complete CSS for a gallery by examining the style sheet files of any of the themes at Panpage.com. 47
Thumb Items Repeat Items Thumb items display the thumbnail images, if present, for a gallery. In fact they contain nothing themselves and are simply linked to a gallery to display the thumbnails it contains. Thumbnails are separate from their gallery only to allow more flexibility in placing the thumbnails on the page. A typical arrangement is to place the thumbnail item immediately below the gallery item or in another column to the left or right of the gallery. See www.cmsdemo.co.uk/gallery.php for an example. Repeat items have no content of their own but display the content from another item. They have their own item class and additional classes and their own margins, padding and style line, but their content and any internal styling comes from the source item. Raw/HTML Items Although it is possible to edit the HTML of a Std/Text item via the WYSIWYG editor and even to place javascript within the item, the editor sometimes mangles your carefully crafted code when you edit it further or save the item. To ensure your code appears in your website exactly as you intended you can place it in a Raw/HTML item. Since there is no WYSIWYG editor and you have full control over the HTML code, you can place IDs, classes and inline styling wherever you like and further styling for the item is rarely needed. 48
Application notes: Panpage How To s Creating Fixed Pages Although Panpage allows your client to edit their own website, maybe not every page needs to be editable. Sometimes you may want to create pages that your client can t edit pages for processing forms for example. This is why we generally have split versions of WriteBody() to make it easier to create fixed pages. Included Fixed Page In the skeleton page files we created earlier we called a combined WriteBody() function in pagecommon which, in turn, called WriteBodyTop() and WriteBodyBottom() with a call to $page->render() in between. That s generally the most flexible approach, but if we call WriteBodyTop() and WriteBodyBottom() directly from the page file we can miss out the $page->render() call and replace it with fixed HTML (or PHP) content <?php include_once( cms/cms_classes.php ); session_start(); $spagename = basename($_server['php_self'], ".php"); $page = &cmsinit($spagename, isset($_get['qe']), isset($_get['prvw'])); if (!$page) die("error - Couldn't read page content!"); include_once( pagecommon.php ); WriteHead(); WriteBodyTop();?> <div class= colleftof2 > fixed HTML content <?php WriteBodyBottom();?> Recall that the last line of WriteBodyTop() outputs the opening <div id= page > tag and the first line of WriteBodyBottom() outputs the page element s closing tag. All you have to do is add the HTML that goes in between, the equivalent of Panpage s columns and items What we have created here is known as an included fixed page. Included because it still has a page record in the content database and this means Panpage knows about it and will include it in the site navigation. Create the page file initially by creating a page in Panpage and filling in its name, filename, parent page etc. You don t 49
need to create any columns or items tho. After creating the page you can edit the page file as above. Excluded Fixed Pages The other type of fixed page is known as an excluded fixed page because it does not appear in the navigation and needs no page record in the content database. Panpage knows nothing about an excluded fixed page usually its only link with the CMS is to call the $g_site functions so that it can display the site s navigation correctly. To create an excluded fixed page copy a skeleton page file and edit it to remove the initialisation code line that creates the $spagename variable, then call cmsinit() with a blank page name argument. <?php include_once( cms/cms_classes.php ); session_start(); $spagename = basename($_server['php_self'], ".php"); $page = &cmsinit(, isset($_get['qe']), isset($_get['prvw'])); if (!$page) die("error - Couldn't read page content!"); include_once( theme/pagecommon.php ); WriteHead(); WriteBodyTop();?> <div class= colleftof2 > <?php WriteBodyBottom();?> Remove the red line, edit the black line and add content as shown by the blue lines! The result will be a page that can use the Panpage site functions so it can display a navigation menu that will always be up to date, but will be otherwise be totally separate from the content management system. It won t appear in the navigation menu, and it won t appear in the site map XML or human readable. The only way you can reach such a page is to hard code a link to it in your page content or event handlers. Remember that any $page->... functions will return empty results. $page->renderheadtags(), for example, will return an empty <title></title> element and description and keywords meta tags with no content. Often pages like this are not required to be found by search engines but bear in mind that you may need to replace some or all of your pagecommon function calls with hard coded HTML again! 50
Alternatively, you can achieve a similar effect by creating an included fixed page and clearing the In Nav box on the Edit Page form. This will keep the page out of the navigation menu but it will still appear in any site map. Placing content in more than one location By default Panpage s page rendering function outputs all the columns in the page and this results in all the content appearing on one contiguous block on the page. However, Render() can accept an argument specifying which column or columns to output. See Render on page 76 for details but basically the argument specifies one or more additional column classes and Render() will output the columns with (or without) those classes. By creating additional column classes such as InSidebar or BelowFooter and placing calls to $page->rnder() at appropriate places in your page file, or in pagecommon.php, you can determine which columns will appear in different regions of the page. For an example checkout the Black Box theme. This specifies an additional column class of colbelowfoot (friendly name: Below Footer ) and the WriteBody() function in pagecommon.php calls $page->render() like this WriteBodyTop(); $page->render(!colbelowfoot ); WriteBodyBottom(); The argument,!colbelowfoot tells Render() to output only columns that DON T have the class colbelowfoot. The WriteBodyBottom() function contains another call to $page->render() that outputs only columns that DO that class $g_site->renderfoot($page->sfile); echo(" \n"); echo(" <div id='subfooter'>\n"); $page->render("colbelowfoot"); echo(" \n"); You can define as many regions on the page as you like in this way. Protecting email links As soon as you place an email address on to a website it becomes a target for harvesting by spammers who use the same technology as search engines to crawl the web and hunt down email addresses. You can usually get around this problem by not putting the email address on the page but instead placing a small piece of javascript on the page that creates the email address and mailto link right there in the visitor s browser. 51
Panpage includes a javascript function called nsmhere() which accepts the part of the email address before the @ as an argument and uses the website s domain name to create the remainder of the email address. You can call nsmhere() like this <script type= text/javascript > <!-- nsmhere( info, Enquiry from your website ); // --> </script> The function writes the following into the web page <a href= mailto:info@fredco.com >info@fredco.com</a> (using our example domain, fredco.com.) You can generally insert such a call into a Std/Text item using the HTML edit function. The item editor won t mangle it too too much tho it will usually add some [[CDATA ]] tags just so you know it s still there! Enquiry forms and form processing Most websites include an enquiry form as well as email and telephone links a form is easier for visitors who don t use an email client program like Outlook but rely instead on webmail or mobile phone. An enquiry form consists of 3 parts 1. the form itself an HTML form with appropriate input and textarea elements and some CSS styling. 2. some sort of validation code to ensure that the enquirer has filled in all the mandatory fields and has given feasible answers. 3. Processing code to convert the form response into an email and send it to you. Panpage oven-ready form The Panpage website, www.panpage.com, contains a complete tho minimal form, styling and processing code, oven-ready, for you to download and the javascript file, pp_top.js, contains validation code for this form. You can see an example of this at www.cmsdemo.co.uk and in fact on many Panpage based websites including www.panpage.com. HTML code 52
The subject line is optional and you can omit it from your form if you wish. The fields labelled in bold are mandatory: your visitor must fill in at least those fields and the validation code in pp_top.js will highlight any empty mandatory fields and refuse to send the enquiry until they are filled in. The full HTML code for the form can be seen and downloaded from panpage.com but consists basically of a number of input elements each with its own label element. The message box is a textarea element. Each mandatory field is labelled in bold characters. CSS Rules for styling The fields and labels are sized and styled by CSS code in screen.css in the theme folder and you can modify this to resize the elements to fit into a larger or smaller column if need be. form input[type="text"], form textarea {width:300px; font:13px "courier new", fixed;} form textarea {resize:none;} form input[type="text"].short {width:160px;} form input[type="text"].veryshort {width:120px;} form input#submit {margin:9px 0 9px 6.3em;} form label {float:left; width:6.0em; text-align:right; padding-right:6px;} form label.lblreq {font-weight:bold;} form label.lblerr {font-weight:bold; color:#cc0000;} The rules highlighted in red are the ones to change if you need to fit the form into a different column width. The class, lblerr, in the last line, is applied by the validation code in pp_top.js to labels of mandatory fields that the enquirer fails to fill in. Validation code The validation code in pp_top.js checks each mandatory field (ie. name, email or telephone number and message these are currently hard coded to be mandatory) to ensure that it has been filled in. You can see the full validation function by examining pp_top.js but basically it looks something like this 53
function bvalidateform(form) { // alert("validating form..."); var smsg = "Please fill in the boxes shown coloured."; var bvalid = true; // check message text... var elcaption = document.getelementbyid("lblmessage"); if (bisempty(form.smessage) ) { elcaption.classname = "lblerr"; form.smessage.focus(); smsg = "Please fill in the message box."; bvalid = false; } else elcaption.classname = "lblreq"; // more blocks like the above for message text if (!bvalid) alert(smsg); return bvalid; The function is hard coded assuming the name, email or phone number and message fields are mandatory. (Perhaps one day we ll get round to writing a more flexible one!) If you need to add further mandatory fields you must add more text blocks to the bvalidateform() function in pp_top.js. Processing code The job of the processing code is to convert the field data from the form into an email to send to the website owner (or whoever) and in the course of doing this it also checks the data to ensure that the enquirer is not trying to hijack the form or your mail server and is not just sending you a bunch of links to his porn or drug site! Panpage s processing code is in PHP and the following is necessarily little more than a quick tour to show you where to add sections for more fields if your form needs them. After some includes and a little HTML scene setting the processor gets incoming form data from the _POST variables into some local variables. If any $_POST vars are missing the corresponding local variable is still present but empty which saves headaches later. $sname = ""; if (isset($_post['sname'] ) && $_POST['sName']!= "") $sname = $_POST['sName']; $sphone = ""; if (isset($_post['sphone'] ) && $_POST['sPhone']!= "") $sphone = $_POST['sPhone']; 54
Add more blocks like this if you need more form variables Next we start to build an HTML email using a table (!!) to ensure that things line up nicely even in the poor HTML/CSS support available from many email clients $head = "<html>\n<head>\n". (isset($cfgpp['emailstyle'])? "<style>". $cfgpp['emailstyle']. "</style>\n" : ""). "</head>n<body>n<table cellspacing='0'>n"; $greet = "<tr><td colspan='2'>hello ". $g_site->sorgname. "</td></tr>\n"; $greet.= "<tr><td> </td></tr>\n"; $body = "<tr><td> </td></tr>\n"; $body.= "<tr><td>date: </td><td>". date('l d/m/y g:ia', time()). "</td></tr>\n"; Then we start to add the local data values but pass them thru a sanitizing function on the way SetUnsanitary(False); $body.= "<tr><td>name: </td><td>". ssanitize($sname, FORBID_ALL). "</td></tr>\n"; $body.= "<tr><td>phone: </td><td>". ssanitize($sphone, FORBID_ALL). "</td></tr>\n"; More about the sanitizer later but we re using it to remove any MIME codes intended to attack the mail server and to remove any inappropriate content such as email addresses or links where they re not wanted. We can also remove multiple links which are the hallmark of form attacks from drug and porn merchants (trying to post links to their websites presumably shakes head in despair for the human race!). If the sanitizer detects and unwanted content it sets a flag which we can test later and then decide how we re going to handle the message. The result is that we construct an email message containing all the POSTed form data but with unwelcome content replaced by a short explanation, eg. multiple links removed etc. We send that to the email address given in the Site Config. Section of Panpage. Finally we display a helpful acknowledgement to the enquirer telling him that his message has been sent or if not, why not. Sending the message by email PHP includes a function called mail() which sends an email message but this is increasingly being disabled on commercial hosting 55
accounts so Panpage directly addresses the server s SMTP mail server using a valid mail account. You need to enter the login credentials for this mail account in the Panpage config file. Form security Forms on websites are always subject to attack, either from bored students or from internet low-life pushing their nefarious wares. We ll never stop bored students and the sanitization function takes care of many problems but it s possible to write program code that will fire spoofed form data at our form processor and this can result in hundreds or thousands of messages per day. Seriously annoying and time consuming to deal with! Fortunately we can stop that dead with a simple addition to the form. We can ensure that our form processor only processes data from our own form and nobody else s, by generating a random value, or token, while the server is generating the enquiry form page. If we include that token in the form data via a hidden input element the form processor can check the token it receives with the server s original and process the form only if they match. Simples! Add the following code to your form (which will usually be in a Raw/HTML item so we can run PHP code) just after the opening <form> tag <?php $tok = md5(uniqid(rand(), false)); $_SESSION['token'] = $tok; echo("<input type='hidden' name='token' value='". $tok. "' />");?> The first line generates a random 32 hex digit (16 byte) token, the second saves it on the server and the third creates a hidden input field in the form and inserts the token. Then add this code to your form processor page just after the include cms_classes line (which calls session_start) if (!isset($_post['token'] )!isset($_session['token'] ) $_POST['token']!= $_SESSION['token'] ) die("error! Invalid submission."); unset($_session['token']); This code checks that the token is present ($_POST[ token ]), that a copy of the original ($_SESSION[ token ] ) exists, and that the two match. If any of these checks fails the form processor simply stops. If all checks succeed the form processor carries on as before but first deletes the original token to prevent multiple submissions. Sanitizer function The sanitizer accepts two arguments, a string to be tested and a value indicating what is acceptable content. It returns either the 56
input string or a string containing an explanation of what has been removed. outstring = ssanitize( instring, allow ); allow can take one of the following values ALLOW_ALL, FORBID_EMAIL, ALLOW_EMAIL, FORBID_LINKS, ALLOW_LINKS, FORBID_ALL Even ALLOW_ALL strips some types of content: MIME codes and multiple links (more than 3 links). ssanitize() sets a flag if it has to remove content and this can be tested by calling the function bisunsanitary(). ssanitize() never clears the flag so you can test multiple strings one after the other and check once at the end. This means that you must explicitly clear the flag before you use ssanitize the first time by calling SetUnsanitary(false). Check out the usage of ssanitize() in the form processing code at www.panpage.com. Embedding content from other websites Sitemaps Websites such as Youtube, Twitter, Facebook and Google Maps provide ready made code and HTML snippets to include on your own website. The best way to include these in a Panpage website is to paste them into a Raw/HTML item. If you try to paste them into a Std/Text item you ll generally find that the item editor will mangle the pasted code when you save the item. 1. Create a Raw/HTML item in a suitable width column and open it in the item editor. 2. Follow the instructions on the other site to generate the code and copy it to the clipboard. Ensure it is correctly sized to fit the column in your Panpage website. 3. Paste the code into the Raw/HTML item and save. That s it check out your web page and you should see the embedded item from the other site. There s more information with (fairly) up to date links to get code form the most popular websites. Panpage includes code for two types of sitemap: an XML sitemap for search engines and a visible sitemap for human visitors. 57
XML sitemap for search engines The file sitemap.php generates an XML sitemap directly from the Panpage content database. As soon as you add a new page or image to your website it appears in the sitemap too. The sitemap uses the sitemaps.org schema for the basic page information and Google s additions for images and videos, so it s compatible with the major search engines. By default the sitemap contains only page information but by setting the config entry $cfgpp[ SitemapImages ] to a non-zero value the sitemap will include image information too. The major search engines look by default for a sitemap file called sitemap.xml in the root of your website. By including a suitable entry in robots.txt you can use a different file, ie. sitemap.php Include the following line in robots.txt (in your website root) Sitemap: http://www.fredco.com/sitemap.php Obviously substitute your own website s domain name in place for fredco.com! The generated sitemap looks something like this <?xml version="1.0" encoding="utf-8"?> <urlset xmlns:xsi=http://www.w3.org/2001/xmlschema-instance xsi:schemalocation="http://www.sitemaps.org/s... xmlns=http://www.sitemaps.org/schemas/sitemap/0.9 xmlns:image=http://www.google.com/schemas/sitemap-image/1.1 < <url> <loc>http://www.panpage.com/index.php</loc> <lastmod>2012-11-09t17:33:25+00:00</lastmod> <priority>1.0</priority> <image:image> <image:loc>http://www... </image:loc> <image:title> stylish, informative</image:title> </image:image> <image:image> </image:image> </url> <url> <loc>http://www.panpage.com/easy-content-management.php</loc> <lastmod>2011-09-08t10:47:23+01:00</lastmod> <priority>1.0</priority> <image:image> </image:image> </url> </urlset> 58
The sitemap will include all published pages but not excluded fixed pages. Visible sitemap for human visitors The visible sitemap attempts to provide a picture of the website structure in terms of parent and child pages and a link to every page in the site. It looks something like this To create a visible sitemap start by creating a fixed page if an included fixed page then the sitemap will include itself, if an excluded page then it won t! In place of the call to $page->render() enter the following HTML code <div class= colfullwidth > <div class= itemfullwidth style="margin:24px 0 12px 24px;"> <h1>site Map</h1> <?php $g_site->rendersitemap();?> Note that the examples in this guide will put you at HTML level so the above code can go straight in but if you re using a theme from elsewhere you may be at PHP level in which case you should enclose the above in close and open PHP tags?>. <?php The background tree graphics make the site structure easier to see and come from a set of image files included in most themes and also available for download on www.panpage.com (see oven-ready- 59
resources visible-sitemap page). They need to go into the theme folder. The visible sitemap includes all pages except excluded fixed pages. 60
Configuration and theme files Panpage is configurable for domains and databases and for different website layouts. This section tells you about the configuration file, pp_config.php the theme file, pp_theme.php and the items the contain. Configuration overview Panpage is configured for a particular domain and database by means of the configuration file, pp_config.php which you ll find in the cms/cfg folder. Another file, called pp_theme.php and found in the theme folder, configures Panpage for the appearance and operation of your website. Keeping the two separate makes themes self contained and independent of the domain and database. These config files are PHP source files, so take care not to delete accidentally any brackets, quote marks and end of line semicolons, as this will prevent Panpage from running and prevent your web pages from displaying correctly - or at all! Each configuration option is an element in a PHP array called $cfgpp so lines in the config file look something like this $cfgpp[ SitemapImages ] = 1; Edit the part after the equals sign to change the config option but don t change the bit before. Some options are a single numeric value like the example above (which can be either 0 or something other than 0). Others are text strings which have to be in quotes $cfgpp[ dbdatabase ] = fredco_cms ; Some config options have multiple values represented as arrays within the $cfgpp array $cfgpp[ TemplateNames ] = array( Std Page, Home Page, Legal Page ); that was an array of text strings. The following is an array of numeric values $cfgpp['editorsize'] = array(80, 18); 61
Comments An array in PHP is a comma separated list enclosed in parentheses and prefixed by the word array. You can add or delete items from the array, even have an empty array. You can add comments to the config files by starting a line with two slashes, //. Panpage will ignore such lines. A common technique is to comment out config option by inserting two slashes at the beginning of the line to turn it into a comment, but be careful doing this as most config items need to be there, even if they re empty or set to the default value. Configuration File Domain details The configuration file, /cms/cfg/pp_config.php, configures Panpage to your domain, database and email and contains the following options and default values Document Root $cfgpp[ DocRoot ] = rtrim($_server['document_root'], '/'); This piece of PHP code retrieves the document root folder name from the data PHP holds about the server on which it is installed. The Document Root is the pathname of the folder, in the web server s file system, that contains the root folder of the server s web space. On CPanel servers you can see the document root folder in the PHP Variables section at the end of cms/_phpinfo.php. Site Root $cfgpp[ SiteRoot ] = ; Normally this will be just an empty string as most websites are located at the root of their domain. If the Panpage controlled website is not located at the root, but on a sub-folder, then set this item to the path from the Document Root to the website s root folder. Include a leading / but not a trailing one. For example, if your website is at www.fredco.co.uk/consumables then the site root would be $cfgpp[ SiteRoot ] = /consumables ; Website URL $cfgpp[ TargetSiteBase ] = http://www.fredco.com. $cfgpp[ SiteRoot ]; Simply the URL, or address of the website you re building. 62
Database Email account DO include the http:// bit and DON T put a slash on the end. This item appears below $cfgpp[ SiteRoot ] as that config item is usually appended here. Database Server / Host $cfgpp[ dbhost ] = localhost ; This is almost always set to localhost as the MySQL database holding the website content is almost always located on the web server. Some hosts (eg. GoDaddy) or very large websites with multiple servers have separate machines for database server and web server. Database Name $cfgpp[ dbdatabase ] = fredco_cms ; This is the name of the database in which Panpage will store website content and the name you chose when installing Panpage (above). Often this will be a double barrelled name with the first part being the site s username on the server and only the second part, here cms, being under your control. You must give the full name, both barrels, here. Database Username $cfgpp[ dbuser ] = fredco_webuser ; The name of the database user that you created when installing Panpage (above). Note that this is not a Panpage user but the name of the MySQL database user required to open the database within the Panpage program code. This is often a double barrelled name like that of the database. Database User Password $cfgpp[ dbpassword ] = LetMeIn ; The database user s password that you set up when installing Panpage. Panpage makes use of an SMTP email account to send messages from the site, eg from an enquiry form since many web servers restrict the use of the default PHP mail() function. $cfgpp['smtpserver'] = "mail.fredco.co.uk"; 63
Mail server name. Can be any mail server accessible on the internet. Doesn t have to be on this web server. $cfgpp['siteemail'] = "website@ fredco.co.uk "; This is where emails from the site appear to have come from. Must be a valid email account on the server specified above. $cfgpp['smtpuser'] = "website@fredco.co.uk"; $cfgpp['smtppassword'] = "LetMeIn"; Username and password to be used when logging in to the above mail server. $cfgpp['sendjunk'] = true; If set to 1 or true, Panpage will send on even messages it considers to be junk. Panpage includes a mail field sanitizer which checks for and removes things like multiple links and attempts to hijack the mail server with MIME code injection. $cfgpp['emailstyle'] = "body {font:12pt serif;} td {vertical-align:top;}"; A set of CSS style rules that are applied to messages emailed from the website. Webserver files and folders Image Folder $cfgpp [ImageFolder ] = images ; The folder, under TargetSiteBase, where user uploaded images are saved. No leading or trailing slashes here as this value is used from various folders within the Panpage installation so Panpage adds slashes when needed. Theme Folder $cfgpp [ThemeFolder ] = theme ; The folder, under TargetSiteBase, where theme files are saved. No leading or trailing slashes here as this value is used from various folders within the Panpage installation so Panpage adds slashes when needed. Website Backups $cfgpp [BackupPath ] = /cms/cfg/backup ; The folder, under TargetSiteBase, where backup files are saved. Leading slash needed. 64
Miscellaneous configuration items Theme File Show Images in Sitemap $cfgpp[ SitemapImages ] = 1; Panpage generates, on the fly, an XML sitemap for search engines which includes all pages in the website and may optionally include images as well. If you want search engines to find images on your site easily then set this item to 1, otherwise to 0 or comment it out. Editor Size $cfgpp[ EditorSize ] = array(80, 18); This is the size of the tinymce editor windows Panpage creates for you to edit your website content. Number of columns first followed by rows. Show Images in Sitemap $cfgpp[ Skins ] = array( Teal, Blue, Rust ); The skin colours each user can select for Panpage. Affects only Panpage screens and not the managed website. The first colour in the array is the one Panpage uses by default before you login. Spare Fields Panpage has a number of spare database fields which can be used for installation specific data: 4 floating point numeric fields (dspare1 dspare4), 4 integer numeric fields (nspare1 nspare4) and 4 text string (TEXT) fields (sspare1 sspare4). These config items specify which fields are to be used and what friendly names they should be known by. Eg. if you want to save an address in sspare1 and a code number in nspare1 you might enter $cfgpp[ SiteSpareFields ] = array( sspare1, nspare1 ); $cfgpp[ SiteSpareNames ] = array( Address, Pass code ); Any spare fields specified here can be edited in the Site Config section of Panpage. By default none of the spare fields are used. The theme file has the same format as the configuration file but contains options to determine the appearance of the managed website. The theme file is located in the theme folder and called pp_theme.php. 65
Older browsers noscript message $cfgpp['noscript'] = "You are seeing this message."; Very old browsers, or those that have had scripts disabled, will show this message and it should explain that your website uses scripts so visitors without script capability will be missing out. It appears that search engines read the noscript tag too nudge nudge, wink wink!!! Headings and footers $cfgpp['showemptyheading'] = 1; $cfgpp['showemptyfooter'] = 1; Normally Panpage will not bother to output empty elements but if your website has design elements in the heading and/or footer you should ensure here that even empty ones are displayed. 1 for true, 0 for false; Slideshow Galleries $cfgpp['gallerymaxcycles'] = 5; Slideshows stop after this many cycles and display the first image as a still from that point on. Set this value to 0 to make slideshows run forever (not recommended). $cfgpp['videocontrolextension'] = "gif"; If your galleries use video controls to start and stop the slideshow they will be represented as small graphic elements with this image type. Filenames are fixed: ctrlnext_x, ctrlprev_x, ctrlpause_x and ctrlplay_x, where x is 0 for the normal state control image and 1 for the hover state. These image files should be saved in the theme folder. Page classes and templates... These entries are used to tell Panpage what classes and template files are available when creating new pages. $cfgpp['templateclasses'] = array("standard"); Page class names as found in the CSS file(s). $cfgpp['templatenames'] = array("std Page"); Friendly names for the page classes $cfgpp['templatefileprefix'] = "_"; Prefix applied to class names to get template file pathnames. Template files are normally in the theme folder but you can include a folder path here, eg. templates/_ would direct Panpage to 66
consider files in theme/templates and beginning with an underscore to be page template files. Column classes $cfgpp['columnclasses'] = array("colfullwidth", "colleftof2", ); $cfgpp['columnnames'] = array("full Width (936)", "Half Left (456)", ); Arrays of column class names and equivalent friendly names. The classes appear in the website HTML and are used to style structural column elements while the friendly names are presented to Panpage users when they create or edit columns in the managed website. $cfgpp['columnstoclear'] = array("colfullwidth"); Older browsers, eg. Internet Explorer v6 and earlier, were not very good at handling CSS floating layouts and in particular at clearing earlier elements. This entry tells Panpage to output an additional clearing <div> element before these classes of column. The clearing div has class clear and is typically styled: float:none; clear:both;. Additional column classes $cfgpp['columnaddclasses'] = array(); $cfgpp['columnaddnames'] = array(); These list the additional, optional classes that you can apply to columns if required. Again the classes appear in the HTML and CSS while the friendly names are presented to the user. Additional classes have two main uses 1. To apply visual styling to columns or, by use of descendent selectors, elements inside the columns. 2. To output only a selection of the columns in the page, eg. some columns may appear in a sidebar, some in a footer and the remainder in the main content region. Item classes $cfgpp['itemclasses'] = array("itemfullwidth", "itemleftof2", ); $cfgpp['itemnames'] = array("full Width (936)", "Half Left (456)", ); Arrays of item class names and equivalent friendly names. The classes appear in the website HTML and are used to style structural item elements while the friendly names are presented to Panpage users when they create or edit items in the managed website. Additional item classes $cfgpp['itemaddclasses'] = array(); 67
$cfgpp['itemaddnames'] = array(); These list the additional, optional classes that you can apply to items if required. Again the classes appear in the HTML and CSS while the friendly names are presented to the user. Additional classes are used to apply visual styling to items or, by use of descendent selectors, elements inside the items. Navigation menu levels $cfgpp['maxmenulevel'] = 6; This is the maximum number of generations of drop down menus that can be created. In practice 2 or 3 generations is as much as most website visitors will cope with. Drop down menu indicator $cfgpp['marksubmenu'] = "..."; A character string specified here will be added to the end of a navigation menu item if it has children and a child menu will open up on mouse-over. Adding your Own Config Items The config and theme file items above are all used by the Panpage software. Some items are used when editing the website, some when displaying it too. But there s no reason why you shouldn t add items of your own for use in any software that you write yourself as part of the website. To use any of the confugration array items in your code you ll need to include the config file, /cms/cfg/pp_config.php and possibly the theme file, /theme/pp_theme.php as well. The config array is declared in the config file $cfgpp = array(); and used pretty well everywhere. You can add as many items as you want to $cfgpp just avoid using any of the item names that are already present! 68
Panpage Functions the API Panpage inserts content into a web page at the point where you call a Panpage function. This section looks at the functions that Panpage provides and how to use them. It s very much PHP developer oriented. Panpage object model Panpage considers a website to be a tree structure with a site object, $g_site, as the root (trunk?). $g_site is created when you call cmsinit() in your page file. The site object contains a tree of page objects. In fact it s an array of page objects each with a member variable indicating the index of its parent page and an array of indices of its child pages (if any). Each page object contains an array of column objects and each column contains an array of item objects. Each object also contains a number of functions, methods in object parlance, and these are referred to like this... $objectname->methodname That s a dash followed by a greater-than symbol (or right pointy bracket if you prefer). So the page object s Render() function is called like this... $page->render(); where $page is a page object. The descriptions below tell you what each function does, what it outputs and how to call it. In many cases you pass information into the function as one or more arguments. Site Functions RenderFoot We ll start at the top with the site object These functions work with data from the site as a whole rather than data for a specific page. This function outputs the site foot. RenderFoot accepts a single argument, the filename of the current page, eg. $page->sfile, which is used to return the user to the correct page after editing the site foot in QuickEdit mode. $g_site->renderfoot( $sfile = ); 69
RenderNavMain If the page filename is not supplied the site footer cannot be changed in QuickEdit mode. The footer will still appear and work as expected when viewing the site, and can still be edited via Site Config in the Panpage menu. This function outputs the following HTML... <div id= pp_sitefoot > What you typed into the site footer box In most cases you will not need to call $g_site->renderfoot() directly as it is called from $page->renderfooter() which outputs both page and site footer from one call. This function outputs the website s navigation menu $g_site->rendernavmain( $npageid = 0 ); RenderNavMain takes a single optional argument, the page ID (ie. record number) of the current page. It uses this argument to add the class pp_navthispage to the element that contains the navigation link pointing to the specified page. You can use this to style a link to the current page differently to the rest. RenderNavMain outputs the following HTML... <ul id= nav > <li>(link to a page and code for drop down menu if required)</li>... (repeated for as many top level pages as required) </ul> The <li> tag for the current page, as specified by $npageid, has an additional class <li class= pp_navthispage > </li> Note that the tags actually used are determined by the NavTags theme config item and you can create a nav menu using, for example, tables or definition lists, as well as unordered lists. This code, as well as links to the website s pages, includes javascript event handlers for the onmouseover, onmouseout and onclick events. If the navigation includes drop downs these functions will open and close the drop downs as the mouse moves over the navigation menu. You must include the javascript file, cms/pp_top.js, in the head section of every page if your site uses drop down menus. <script type= text/javascript src= cms/pp_to.js ></script> All Panpage themes include this file anyway. 70
RenderNavDrop RenderNavSub This function outputs drop down navigation menus $g_site->rendernavdrop( $npageid = 0 ); RenderNavDrop accepts an optional argument indicating the ID of the current page see RenderNavMain, above, for details. RenderNavDrop outputs the following HTML for each drop menu that your website requires... <ul class= navdrop > <li>(link to a page and code for further drop down menu if required)</li>... (repeated for each page in this drop menu) </ul> It then outputs some javascript code to define how the drop menus relate to each other and to the top level menu items... <script type= text/javascript > <!-- var arrmenu = new Array() arrmenu[0] = new CMenu('', 0); arrmenu[11] = new CMenu('about', 0);... (repeated for as many drop menus as are needed) // --> </script> Note that you only need to paste this line once into each page. It will output as many drop down menus as your website needs. You must include the javascript file, cms/pp_top.js, in the head section of every page if your site uses drop down menus <script type= text/javascript src= cms/pp_to.js ></script> All Panpage themes include this file anyway. This function renders a navigation menu of child pages as an independent sub-menu. $g_site->rendernavsub( $sfile, $npageid = 0 ); RenderNavSub() outputs the following HTML <ul class="pp_navsub" id="pp_navsub_pagename"> <li><a > </a></li> </ul> The sub-menu is single level, RenderNavSub() it does NOT create further drop down menus if any of the child pages itself has children. 71
RenderSitemap RenderOrgName This function displays a human readable site map of all published pages, including included fixed pages and pages that are marked not to appear in navigation. $g_site->rendersitemap(); This line outputs the following HTML... <table class='pp_sitemap' cellspacing='0'> <tr> <td> link to a page </td>... <tr>... </table> This table contains a row and a cell for each top level page and a cell for the children of each top level page. The child cell in turn contains further table with a cell for each child and a cell for its children in turn. It can get quite complex in a multi level website! Often the sitemap is the only content on the page. The sitemap requires some supporting graphic files to provide a visual representation of the tree structure of the site s pages. These are included in Panpage themes and can also be downloaded from panpage.com. This function outputs the organisation name as entered into Panpage s SiteConfig. $g_site->renderorgname( $slink =, $sprefix =, $ssuffix = ); RenderOrgName accepts three optional arguments, a link URL, a prefix and suffix added to the organisation name for display. This function outputs the following HTML <p class='pp_orgname'>prefix Organisation name Suffix</p> If link is given and is not empty this function will output the organisation name as a link <p class='pp_orgname'> Prefix <a href= LinkURL >Organisation name</a>suffix </p> If the link is external, ie. begins with http then the link target will be _blank and the link will open in a new tab or page in the browser. In practice there aren t any spaces between the prefix or suffix and the organisation name. If you want spaces you must include them in the prefix and suffix strings. 72
RenderOrgPhone This function works just like RenderOrgName() except that it outputs the organisation phone number rather than the organisation name $g_site->renderorgphone( $slink =, $sprefix =, $ssuffix = ); RenderOrgPhone accepts three optional arguments, a link URL, a prefix and suffix added to the phone number for display. <p class='pp_orgphone'>prefix Organisation phone no. Suffix</p> See RenderOrgName() for further details but note two differences 1. If the link argument is just tel: then the function outputs a phone call link like this <a href= tel:0114 234 5678 >0114 234 5678</a> Most mobile phones will offer to dial such a link when touched. 2. The phone number is entity encoded to make it more difficult to harvest by spammers. At the time of writing phone number harvesting is not a major problem but it could become one and this will afford some protection. RenderSiteName SplitEmail This function works just like RenderOrgName() except that it outputs the site name rather than the organisation name $g_site->rendersitename( $slink =, $sprefix =, $ssuffix = ); RenderSiteName outputs the following HTML <p class='pp_sitename'>prefix Organisation name Suffix</p> See RenderOrgName() for further details. This function splits an email address into a name, domain and top level or country domain code suitable for use in the nsm() javascript email function, and returns them as an array $arr = $g_site->splitemail( $semailaddr = ); will split the email address, info@panpage.com, into an array like this array( info, panpage, c ); The top level or country domain is represented by a one or two letter code suitable for the javascript function, nsm().com = c.org = o.co.uk = cu.org.uk = ou 73
Spare Data Fields.net = n.me.uk = mu.eu = e The results of SplitEmailAddress can be fed straight into nsm to give an email link protected from harvesting $arr = $g_site->splitemailaddress( info@panpage.com ); echo( <script type= text/javascript >\n ); echo( nsm(. $arr[0].,. $arr[1].,. $arr[2]., Enquiry from your website );\n ); echo( </script>\n ); Note that SplitEmailAddress() will use the organisation email address, as set in Site Config, if no email address is given. Panpage includes a number of spare data fields in the site object which can be configured for use by config values see Spare Fields on p65. You can set and get the values of these spare fields using the site functions bsetspare() and getspare() $g_site->bsetspare( $sindex, $Value ); This function sets the spare field named in $sindex to the value specified. For example $g_site->bsetspare( MobilePhone, 0797 777 7777 ); The field specified must have been set up in pp_config as described above. bsetspare returns true of the operation worked and false if it failed (eg. the named field doesn t exist). getspare( $sindex ) This is the opposite and returns the value of the named field, or null if it can t be found. The argument, $sindex, can be the friendly name or the field name of the required spare field. Site Properties and Utility Functions $g_site->arrpages $g_site->bqe Not normally needed unless you are doing something out of the ordinary... An array of page objects in this site. Member variable: true if the page is being viewed in quick edit mode (ie. being edited), false if viewed normally. 74
$g_site->bpreview Member variable: true if the page is being viewed in preview mode (ie. including unpublished pages), or in quick edit mode, false if viewed normally. $g_site->ngetmaxmenulevel() This function returns the maximum level of drop down menus in the site navigation. The top level nav menu is level zero, the first drop down is level 1 etc etc. $g_site->bhaschildpages() This function returns true if any of the pages in the website has child pages, false if none do. Page Functions The page functions operate on data from a single page at a time. Page Initialization Code One of the first things each page file has to do is create a page object and fill it with content data from the database. This happens in the initialisation code at the top of the page include_once( cms/cms_classes.php ); session_start(); $spagename = basename( $_SERVER[ 'PHP_SELF' ], ".php" ); $page = &cmsinit( $spagename, isset( $_GET['QE'] ), isset( $_GET['PrVw'] ) ); if (!$page ) die( "ERROR - Couldn't read page content!" ); These lines don t output anything unless something goes wrong. After they have executed successfully the $page object is ready to use. The first line, include-once..., loads the Panpage program code in preparation for running it. The third line derives a unique name for the page from its PHP filename (without the.php bit). cmsinit() is a global function: it creates the page object and reads data for that page from the content database. It also creates the global site object, $g_site. The first argument is the page s filename without the.php bit and this determines which page record cmsinit() reads from the database. The last two arguments tell cmsinit() if the page has been opened in QuickEdit or Preview mode. 75
RenderHeadTags RenderHeading The last two lines check that everything worked. They print an error message if something went wrong and the page didn t load correctly. $page->renderheadtags(); This function outputs the page title, meta description and meta keywords tags and is normally used in the <head> section of a web page <head> <meta http-equiv='content-type' content='text/html;charset=utf-8' /> <?php $page->renderheadtags();?> <meta name='robots' content='index, follow' /> RenderHeadTags() outputs the following HTML... <title>what you typed into the title box</title> <meta name= description content= What you typed into the description box /> <meta name= keywords content= What you typed into the keywords box /> It also outputs a generator meta tag to show that this is a Panpage website. This function outputs the page heading text (as entered in the page form) enclosed in a <div> with id= pageheading. $page->renderheading(); RenderHeading() takes no arguments and outputs the following HTML... <div id= pageheading > <h1>what you typed into the heading box</h1> Note that you only need this function if the page heading appears in a non-content part of the web page, above or within the banner for example. In most cases you re better to include <h1> headings within the page content. Render This function outputs page content. $page->render( $scolumnlist = ); Render() outputs the following HTML... <div class= column class(es) you selected id= name you gave this column > <div class item class(es) you selected id= name you gave this item > What you entered into this item... 76
... (repeated for as many items as this column contains)... (repeated for as many columns as this page contains) With no arguments Render outputs all columns and all items but you can give an argument to select which column(s) to render. This argument is a text string containing the name of an Additional Column Class. $page->render( colbelow ); In this case Render() will render only columns with the additional class colbelow. You can specify more than one class in the argument, space and/or comma separated, and Render will output every column with one or more of the specified classes. If the first character of the argument is an exclamation mark,!, the behaviour is reversed $page->render(!colbelow ); will render only columns that do NOT have the additional class colbelow. If you specifying two or more classes Render will output only columns that have none of the specified classes. A typical scenario is to render specific columns, in a sidebar and sub-footer for example, while rendering all other columns in the main content section. Eg $page->render(!colsidebar, colbelow ); RenderNoscript $page->rendernoscript(); This function outputs a <noscript> tag containing the page title and description <noscript> <h1>same as page title text</h1> <p>same as page description text</p> <p>noscript warning message from config file</p> </noscript> RenderNoscript outputs the page title and description, followed by a warning message that this page requires scripts to run properly, all inside a <noscript> tag. The <noscript> element is displayed by browsers that cannot run javascript or have had scripts disabled, and serves to warn visitors that they are not seeing the site as intended. The reason for including the page title and description is that search engines see the contents of <noscript> elements and so will see the <h1> element inside and attach further weight to the page title and description. The cynical amongst us believe that this is a grey hat SEO trick but since the noscript element is designed to inform users 77
RenderFoot RenderFooter of old or specialist browsers, political correctness means that search engines will continue to take note of it! The contents of the last <p> element come from $cfgpp[ Noscript ] as defined in the Panpage configuration file, pp_config.php. $page->renderfoot(); This function outputs the page s footer text using the following HTML... <div id= pp_pagefoot > What you typed into the page s footer box RenderFoot() takes no arguments. Panpage recognises two footer elements, one is common to the whole site and appears on every page, the other is individual to a specific page. The site foot is defined in the site config. section of Panpage while the page foot is defined in the Edit Page section. Sometimes both foot elements (both feet?) will be present so that perhaps one appears on the left of the footer, the other on the right. On other sites it may be more appropriate for the page footer, if present, to override the site footer. You rarely need to call $page->renderfoot() as it is called by the RenderFooter() function which outputs both parts of the footer in a single call. See below. This is the top level function to output the footer of a web page. $page->renderfooter($nmode = 0, $soverride =, $slastupdated = ); The function s default behaviour is to output the page footer if there is one, otherwise to output the site footer. You can change this behaviour as follows $nmode is a number that determines how RenderFooter() handles page and site (global) footers 0: Render page footer if present, otherwise render site footer (default) 1: Render Page footer then site footer 2: Render site footer then page footer $page->renderfooter(1) will output the following HTML... <div id= pp_foot > <div id= pp_pagefoot > This text is the page footer <div id= pp_sitefoot > This text is the site footer 78
$page->renderfooter() calls $page->renderfoot() and/or $g_site->renderfoot() as determined by $nmode. The second optional argument, $soverride, supplies a text string that, if present, will be used instead of the page s footer. This allows you to enter things like your byeline link in a way that cannot be removed from within Panpage. The third optional argument is an addition to the page footer that indicates the date this page was last updated. In fact the argument is a text string that, if present and not an empty string, is prepended to the update date and output on a line of its own at the end of the page footer For example RenderPageDate $page-renderfooter(2, powered by panpage, Last updated on ); might output the following HTML <div id= pp_foot > <div id= pp_sitefoot > This text is the site footer <div id= pp_pagefoot > last updated on 17/11/2012<br /> powered by panpage A date added to the page like this is often displayed by search engines and may help to convince searchers that this is an up-todate website. The format of the date is determined by the config file item, $cfgpp['dateformat']; This function outputs the page s last updated date. $page->renderpagedate( $sprefix ); inside a paragraph of id pp_pagedate. It takes an optional text string argument, $sprefix, which, if present, is output just before the date. Example $page->renderpagedate( Page last updated on ); might output the following HTML <p id='pp_pagedate'>page last updated on 25/10/2012</p> The format of the date is determined by the config file item, $cfgpp['dateformat']; 79
Utility Functions Mostly not needed unless you are doing something out of the ordinary... ncountchildren($bincunpublished = false, $binclnotinnav = false) Returns the number of child pages owned by this page. You can provide two optional arguments to specify whether (true) or not (false, default) the function includes unpublished pages and pages not in the navigation. arrgetchildren($binclunpublished = false, $binclnotinnav = false) ngetmenulevel() This function returns an array of page objects representing the children of $page. The pages are incomplete in that they contain no columns or items but they do contain all properties / member variables of the pages themselves (see below). These functions can be used, for example to create a submenu of child pages. if ($page->bhaschildren( $g_site->bpreview )) { $arrchildren = $page->arrgetchildren( $g_site->bpreview ); echo( <ul class= submenu >\n ); foreach ( $arrchildren as $p) echo ( <li><a href=. $p->sfile. >$p->sname</a></li>\n ); echo( </ul\n ); } The optional arguments, $binclunpublished and $binclnotinnav, tell arrgetchildren whether to include (true) or not (false, default if argument omitted) unpublished child pages and those not included in the navigation. Returns the menu level of the page. A main nav menu page is level 0, the first level of drop down nav menus contains pages at level 1 etc etc. pgetancestor($nlevel = 0) Returns a page object representing the ancestor (eg. parent, grandparent etc) of the page at the level specified. If no argument is given level 0 is assumed and the function return the top level ancestor 80
sgetpagedate() Returns the last updated date as a human readable text string. The format of the date is determined by the config file item, $cfgpp['dateformat']; bisfirst($binclunpublished = false, $binclnotinnavigation = false) Returns true if this page is the first child of its parent page, false if not. Optional arguments determine whether (true) or not (false) unpublished pages and those not in the navigation should be counted. bislast($binclunpublished = false, $binclnotinnavigation = false) TimeStamp() Returns true if this page is the last child of its parent page, false if not. Optional arguments determine whether (true) or not (false) unpublished pages and those not in the navigation should be counted. Changes the page s last updated date. Accepts an optional argument which should be a Unix timestamp value (seconds since 00:00. 1/1/1970). With no argument the current time/date is used. Page Properties $page->sclass These are pieces of data which Panpage holds for each page in the website. All should be considered as READ-ONLY unless otherwise indicated below. The class name of the page chosen when the page was created or edited. This determines which template was used to create the page file and often determines which of a number of alternative layouts or colour schemes is used. $page->arrcolumns $page->sfile An array of column objects owned by this page. The filename for this page. $page->nlastupdated The time and date when the page was last updated in Panpage. It is in PHP s timestamp format, ie. the number of seconds since the 81
$page->sname beginning of the Unix epoch (1/1/1970). Use $page->sgetpagedate() or PHP functions such as localtime() and date() to render as a human readable time date string. The name of the page as it appears in the navigation menu. Column Functions You ll rarely need to use the member functions of a column object as Panpage websites normally render columns by calling the page rendering function, $page->render(). However you can, if you need to, render columns individually by calling the column rendering function. Render This function outputs HTML for the items in a single column $col->render (); Render outputs the following HTML... <div class= column class(es) you selected id= col_columnname > <div class item class(es) you selected id= item_itemname > Content you entered into this item...... (repeated for as many items as this column contains) The page rendering function calls this function once for each column on the page (after first checking the page has been published) like this... <?php if ($page->bpublish $g_site->bpreview) { foreach ( $page->arrcolumns as $col ) { $col->render(); } }?> Say you ve used the first column on the page as a content managed banner and need to render it separately from the remaining columns. Rendering a single column is easy as long as you know its order on the page which gives its index (0 based) in the page s column array. The following code renders the first column and then the remaining columns later 82
<?php $page->arrcolumns[0]->render(); // render 1 st column $ncols = count( $page->arrcolumns ); for ( $i = 1; $i < $ncols; $i++ ) { $page->arrcolumns[ $i ]->Render(); }?> There is very little you can do this way that can t be done more easily using $page->render() with additional column classes. See Render on p76. Column Utility Functions $col->bisfirst() $col->bislast() Returns true of the column is the first in its parent page s array of columns, otherwise returns false. Returns true of the column is the last in its parent page s array of columns, otherwise returns false. Column Properties $col->arritems $col->npageid These are pieces of data which Panpage holds for each column in the website. All should be considered as READ-ONLY unless otherwise indicated below. An array of item objects belonging to this column. The database record ID of the page that owns this column. Item Functions Like columns, items are normally handled by the page render function so you ll only need to use item functions on their own if you re rendering a page in some special way. Render This function outputs a single item and its contents... 83
sgetfirstheading $item->render (); This function outputs the following HTML... <a name= name you gave this item ></a> <div class= item class(es) you selected id= item_itemname > Content you entered into this item... Obviously there s a bit more to it than that and the function outputs content for different types of item: Standard, Folding, Ticker, Gallery, Thumbnail, Repeat and Raw/HTML. The first line, the <a...> tag, appears if you gave the item a name and serves as a link target allowing you to link directly to this item, not just to the page it appears on. The column rendering function calls this function once for each item in the column like this... <?php foreach ( $col->arritems as $item ) { $item->render(); }?> $item->sgetfirstheading($nmaxlen = 0); Returns the text of the first heading element (of any level) in the item. This can be used to create an excerpt from the item, eg. as a link on another page. If nmaxlen is zero or not preset the function will return the entire heading. If nmaxlen is given and is greater than zero the function will return at most nmaxlen characters from the heading. If the heading contains more than nmaxlen characters the return string will contain nmaxlen 3 characters suffixed with three dots:. sgetfirstparagraph $item->sgetfirstheading($nmaxlen = 0); Returns the text of the first body paragraph (HTML <p> </p> element) in the item. This can be used to create an excerpt from the item, eg. as a link on another page. If nmaxlen is zero or not preset the function will return the entire paragraph text. If nmaxlen is given and is greater than zero the function will return at most nmaxlen characters from the pragraph. If the paragraph 84
contains more than nmaxlen characters the return string will contain nmaxlen 3 characters suffixed with three dots:. Item Utility Functions $item->bisfirst() $item->bislast() Returns true of the item is the first item in its parent column s array of items, otherwise returns false. Returns true of the item is the last item in its parent column s array of items, otherwise returns false. Item Properties $item->ncolumnid $item->ntype Database record ID of the column that owns this item. What type of item this is possible values are ITEM_TEXT ITEM_GALLERY ITEM_THUMBS ITEM_HTML ITEM_FOLD ITEM_REPEAT ITEM_TICKER 85