FreeBSD Programming Primer – Part 6

In the sixth part of our series on programming, we will design a basic menu navigation system and style it with CSS.


So far in this series, we have focused on adding and displaying standard HTML pages which have been pulled from our database. We are now going to shift directions and start to look at the user interface of the CMS itself. Traditionally, menu links were hard coded into pages, which not only made long-term maintenance time-consuming but also error-prone. By leveraging the power of a database back end, we can easily extract the title and section of pages we want to display and if desired, include or exclude that content from the menu. For flexibility, we will also include the facility to add disparate links to other sites, etc. Many sites now use multi-level menus which are driven by a combination of SQL, Javascript / Jquery and CSS. Later on in the series, we will look at using Jquery to add this functionality, but for now we will concentrate on a block navigation menu that is displayed alongside the main content.

The SQL

To demonstrate, let’s spin up a MySQL session and take a look at our content. At the shell prompt, login to MySQL and run some queries. By using the UNION keyword, we can combine the output of both SELECT statements into one result. This would be fine if we had a small site with not much content, but as the site grows, the menu would become unmanageable in size. We could build the interface with a dropdown and filter by section, but we would just be postponing the inevitable. An additional improvement would be to use a combination of a content type filter and a pager with the MySQL LIMIT keyword, restricting the display to a certain number of items.  This would help in the final design and theming of the site, as we will know exactly how much browser real estate would be occupied by the menu itself even if the content expanded rapidly.

The remaining issues are how to add disparate links and whether we want to display the content in the menu at all. For example, we might have an error page that only is displayed when the content is not found. While it would be useful to store this in the database, displaying it in the menu would be rather pointless. The question is where to store this data? We could have a separate menu table, with the ID of each page and a numeric flag (0, 1) to represent do not display in the navigation menu or include in the menu. We would then have to maintain 2 tables when content is added and removed. This could be easily accomplished using MySQL triggers.  Alternatively, we could store the page status in the relevant content tables (e.g. news, pages) with a flag (0,1,2) to represent “do not publish”, “publish but do not show in menu”, and “publish andshow in menu”. Both designs have their good and bad points from the implementation and data integrity viewpoint, but for the sake of simplicity, I will use the latter for our navigation menu.

In the meantime, we have an FAQ definition in our file content.inc but we do not have any table data for it. We will now manually create the table and add 10 random FAQ entries (Listing 3-5). This will result in a new FAQ table with our status field. However, the ID field is not set to auto increment, so we need to change this (Listing 4). Now insert the data (10 entries) – replacing the title, heading and status (0, 1 or 2) as appropriate. We need to repeat the structural amendments for our news and pages tables as well (Listing 6). Let’s check what data we now have in the three tables.. As we can see, the news and pages will not be published or displayed in the menu. Change this so the news items are not in the menu but published, but the pages are (Listing 8). Let us check in a browser if FAQ 1, 2 and 3 are displayed. Visit http://yourserverip/faq/1 and you should get an error message “No template”. To rectify this, create a faqs_template.inc file in /usr/home/dev/ data/templates with the following content (Listing 9).

Bug alert! If you visit http://yourserverip/faq/1 you will find the page is not rendering correctly..  You will receive an error message: Notice: Undefined index: heading in /usr/home/dev/data/templates/faqs_template.inc on line 23. If you want to try and  diagnose the problem, have a look at core.inc and skip the next code listing. The problem lies in the following code snippet. To fix it, change as follows.

If you visit http://yourserverip/faq/1, you will find the page is still not rendering correctly (Figure 2). The reason for this is that the the global CSS doesn’t know about our FAQ content type yet, so we need to modify global.css as follows (Listing 12). You may have to refresh or clear your browser cache to pick this up. This should result in thecorrectly rendered content in (Figure 3). However, if we visit http://yourserverip/faq/2 , we will see an FAQ page even though the status is 0. Modify core.inc as follows to fix this (Listing 13). This should now give a “No data” message. If you are still experiencing problems, ensure that the content.inc file is as follows.

Building our menu
How can we remember the filter value selected for the content type? As HTTP is stateless, we could pass the parameter to each page. This would get complex very quickly with multiple menus. A better solution would be to write a cookie to the visitors browser when the content type is filtered. To do this we will use Javascript, and specifically a suite of Jquerylibraries. Download jquery-1.10.2.min.js and jquery.cookie.js from the Jquery website. Place these files in the Javascript folder, then modify our source code as follows. When you visit http://youripaddress/faq/1, you should see a page similar to Figure 4. Clicking on the FAQ, News or Page button will raise a Javascript dialogue box.

In the next part
We will tie the onclick event to writing a local cookie, and extracting the links for the MySQL table. We will also look at using the Jquery library to build a multi-part menu.

About the Author
Rob Somerville has been passionate about technology since his early teens. A keen advocate of open systems since the mid-eighties, he has worked in many corporate sectors including finance, automotive, airlines, government and media in a variety of roles from technical support, system administrator, developer, systems integrator and IT manager. He has moved on from CP/M and nixie tubes but keeps a soldering iron handy just in case.

This article was re-published with the permission of BSD Magazine.  To Learn More about iXsystem’s commitment to open source check us out here:   https://www.ixsystems.com/about-ix/

Join iX Newsletter

iXsystems values privacy for all visitors. Learn more about how we use cookies and how you can control them by reading our Privacy Policy.
π