Quintic
WordPress Integration
Post type: post

WordPress Integration

Just a few notes on the integration, which is not going well, or at least taking a lot longer than I had anticiapted. I realised that the BLIKI functionality would be a challenge and needed to be implemented as a plugin, not part of the theme. That’s all OK. On the Theme side though I was expecting things to be a bit more straightforward. What do I need:

  • Have two types of ‘Pages’ – Site-pages (Inital page, About, Privacy, Contact, …..) and Content Pages
  • Ability to assign a background image to Front-page and Site pages (Site pages defined as Pages with a category of ‘site’, and expected to be pages like, About, Contact us, ‘Privacy Policy’ etc.)
  • For non site pages, which I expect to be topic specific, technical pages, I wanted a ToC sidebar.
  • Drop down menus for Pages and Blogs
  • Allow images for Menu Items (Which is possible with a plug-in)

Each of the above provides its own challenge. To make the choice of background image user definable I needed to add options to the Appearance. (OK no big thing, just a learning experience). For the ToC, thats a bigger issue, and the solutions out there seem to implement it as a plugin not part of a theme, which I think is actually wrong. Displaying a ToC is about interpreting the information, so I would say it is presentation not functionality. That though is really a matter of opinion, the real issue is how to implement it. What I need to do is:

  • Peruse the content looking for ‘Content Elements’ (say <h1>, <h2>, <h3>…).
  • Insert an anchor point at the ‘Content Elements’ that the ToC can link to. The anchor points inserted at presentation time, not saved away. And , of course the anchor point Ids must be unique
  • Retain the set of ContentElements, their descriptions and anchor points for publishing in the sidebar.

Just the first of those is a pain. PHP is very lack when it comes to iterating. Everything seems geared towards arrays, and returning an array of results as opposed to steping through a sequence. I can use regex to match all headers, but augmenting the headers with anchor points is another matter. I looked into XPATH, and they do have an iterator, but it doesn’t work on the DOM, it works on an object generated from the DOM. So its fine for extracting information, but no good for injecting or transforming. And I am not going down the road of XSLT (assuming PHP even has support for XSLT)

Started using the DOMDocument class. Seems a reasonable way forward to generating the Table Of Contents. What I found whilst playing around was interesting though. I used loadHTML to load a test string into a DOMDocument object. I then extracted the first node, checked that it was an HTML node and then tried recursing down through the childNodes of the HTML node… only there were no child nodes.

So I then went on to recurse through all the child nodes of the DOMDocument, and to my surprise there were two HTML nodes, one empty, the other containing the expected child nodes. Reason: The function loadHTML will ensure that the document loaded is correct HTML. That will include:

  • Ensuring that the document has a !DOCTYPE element.
  • Ensuring that the contents are encapsulated in a <html> element.

It is the first item in the above list that was responsible for generating the HTML element with no children.

I now have:

  • Left and Right sidebars for single pages
  • Table Of Contents widget
  • ToC Widget assigned to page-left sidebar.

There are(at least) two ways of implementatibng the Sidebar with ToC. The first is to ‘hard-code’ the ToC into the sidebar. What this means is that you can guarantee that the ToC is in the sidebar, and that only the ToC is in the sidebar, and for the Techincal Pages, this is exactly what I want.

However, a more fleixble approach is to use what are known as Dynamic Sidebars. These are sidebars that the administrator can load with whatever widgets she/he decides. To go down this route I needed to:

  • Define the ToC as a Widget and register it as such in the functions.php file.
  • Register the Sidebar-Page-Left as a sidebar
  • As a courtesy to my users, preload Sidebar-Page-Left with the ToC widget (provided there were no widgets already assigned.)

What did surprise me and took a while to fully understand and work through is that Page Loading Life-Cycle. For the ToC I need to locate the various <hn> elements and add a child <a name=”xxxx” /> to the <hn> element. That being the anchor point to which the ToC will link.

To add the anchor points I wrote a content filter function that is presented with the page’s content and can the return a filtered version of the content. Sounds good. Problem is, the content filter is not fired when the page is loaded but when the content is rendered, which is AFTER the left-sidebar has been displayed. This meant I needed to implement my own Content Filtering process, by getting hold of the $POST object, and operarting on its $Content property. It works, but it feels a little dirty.

Oh and one last piece of information. I mentioned above that I use the DOMDocument object. On Windows you do need to include the statement

use \DOMDocument;

That needs to be included in the php file before referencing the DOMDocument. (Though I am assuming that you could use a fully qualified name of\DOMDocument instead if you really wanted to.)

One last thing is a recognition of https://two-wrongs.com/draw-a-tree-structure-with-only-css.html which is where I came up with the CSS to produce the context line with the tree ToC.

Site-page Background Image

I have added the customize controls to upload a background image for the Site-Pages. Works reasonably well with the front-page template file. Do need to get the sizing correct.

Am going to create a ToDo List to detail what I have left to do and to keep track of what I have achieved.

I have the background working for Front Page and as a faded image on other site-pages. I also have the text on the site-pages coming to the fore. Site-Pages implemented by allowing Categories with pages, and then creating a ‘category-site-page’, which displays the faded image as a background. This allows the user to decide which pages she/he wants to use the site-page template by adding that category to the pages.

That’s the good news. The bad news is:

  • Cannot use the DOMDocument to insert the anchor points for the Table of Contents. The DOMDocument class will accept a non-complete snippet of HTML in loadHTML, but it will add a <DOCTYPE> and <html> elements if they are missing. So the content, once updated is top and tailed with these elements, which, of course we do not want and cannot have. I could concievably remove them afterwards, but that feels dirty.
  • The ToC parsing and the insertion of the anchor points are two separate passes of the page’s content. ie. We have one pass to determine the Headers, and another to insert the anchor points, as the insertion can ONLY take place during ‘content’ filtering.

Slight change of mind from above. There is no way round the second issue listed, that of the ToC parsing and the insertion of the anchor points via the ‘content filtering’ mechanism. Content filtering is only executed on rendering the content, which is happening after I am attempting to construct the ToC. So they have to be two independent runs.

As to how I am going to insert the anchor points. I did want to insert an <a name=’xxxx’ /> element immediately after the ToC elements (usually <h1> / <h2>…). Problem is using the DOMDocument, there is no mechanism to insert that specifically. All I can do is add a child node. Not good enough. I tried using DOMXpath, which does have the level of control that I need, but there does not appear to be a mechanism for retrieving the modified DOMDocument from the DOMXpath.

Instead I have decided to use the id of the ToC elements as the anchor points. If the ToC element does not have an id, then I will construct one using the same mechanism as I was going to use to construct the name for the anchor points.

The issue about the result from the DOMDocument being top and tailed with extra info, that I am resolving by prefixing and suffixing the content with made up html elements, and then retrieving just the snippet between these elements.

Good news all the above is up and working. I do need to increase the width of the sidebars, but code wise I believe we are complete.

Next is creating drop down menus from the header.

Creating Drop Down Menus

This took a bit of investigating. WordPress already allows indented menus. the Menu Customization UI provides the facility for heirarchical menus. However, the standard menu rendering does not honour the heirarchy. Instead all you get in a normal list. Plus I am after something a bit different.

  • A set of menus, horizontally aligned, with Pages and Posts drop down being dynamic, ie new published pages / posts are automatically added, deleted Pages / Posts are automatically removed.

I have now develpoed a php function to do the above. Before I can incorporate it into a Q5 Theme I need to work out the itegration with the Menu Customization UI, but the good news is, I believe I now have everything I need to move my site to a fully integrated WordPress installation.

Table Of Contents – Again

Slight problem with the Table of Contents. When you jump to point that requires the page to scroll you loose the ToC, as it is still at the top of the page. You can get round this by making the ToC’s position attribute fixed. The problem with that approach is that the ToC no longer participates in the page layout. The effect is that the ToC sidebar registers as zero size, and the main content overides it.

Solved this by actually rendering the ToC twice. Once visible but with position fixed. The second time with position; relative but hidden.

Time to Deploy

I now have the header menu developed, with drop down menus implemented in CSS. (see below) The styling is not quite what I want, not bad, but not what I want. main thing is the content and functionality is there. Which means its time to delpoy.

I know a number of you have been commenting on the lack of images / pictures / imagination when it comes to the site. Well so far what I have been doing is keeping a diary. Once deployed I should be in a postion to make the content visually more interesting. For the moment though, a couple of notes on the latest WordPress functions.

The Header drop down menus look like this:

The Blogs and Techincal drop downs are populated on the fly from the set of Posts / Pages in the site. (The pages drop down excludes pages that have been flagged as ‘site-pages’. So, for example, Home and About do not appear in that drop down.). The menu is presently hard-coded into the header.php. I need to work out how to configure the Customize feature to allow functions to be inserted into a menu .

The population of the drop downs is undertaken by the following function:

	function q5_dropdown_posts( $args = '' ) {
				$defaults = array(
			'selected'              => FALSE,
			'pagination'            => FALSE,
			'posts_per_page'        => - 1,
			'post_status'           => 'publish',
			'cache_results'         => TRUE,
			'cache_post_meta_cache' => TRUE,
			'echo'                  => 1,
			'select_name'           => 'post_id',
			'id'                    => '',
			'class'                 => '',
			'show'                  => '',
			'show_callback'         => NULL,
			'show_option_all'       => NULL,
			'show_option_none'      => NULL,
			'option_none_value'     => '',
			'multi'                 => FALSE,
			'value_field'           => 'ID',
			'order'                 => 'ASC',
			'orderby'               => 'post_title',
			'empty_title'			=> 'No Posts ',
			'filter_callback'		=> '',
			'ul_class'              => 'q5_dropdown',
			'li_header_class'       => 'q5_dropdown_title',
			'li_class'              => 'q5_dropdown_entry',
			'a_class'				=> 'q5_dropdown_anchor',
		);

		$r = wp_parse_args( $args, $defaults );
		
		// get required posts, filtered where necessary.
		if ($r['filter_callback'] != null)
		{
			add_action('pre_get_posts', $r['filter_callback']);
		}
		$posts  = new WP_Query( $r );
		
		if ($r['filter_callback'] != null)
		{
			remove_action('pre_get_posts', $r['filter_callback']);
		}
		
		$output = $r['empty_title'];

		if( $posts->have_posts() ) {

			$li_header = $r['li_header_class'] == null ? '<li>' : '<li class="' . $r['li_header_class'] . '"><a href="#">';
			$output = $li_header . $r['menu_title'] . " »</a>";
			$output .= $r['ul_class'] == null ? '<ul>' : '<ul class="' . $r['ul_class'] . '">';
			
			$a = $r['a_class'] == null ? '<a href="' : '<a class="' . $r['a_class'] . '" href="';
			$li =  $r['li_class'] == null ? '<li>' : '<li class="' . $r['li_class'] . '">';

			$posts = $posts->posts;
			foreach ($posts as $post)
			{ 
				$link = get_permalink($post->ID);
				if ($link == null)
				{
					$link = get_page_link($post->ID);
				}
				$output .=  $li . $a . $link . '">' . $post->post_title . '</a></li>';
			}
			$output .= '</ul></li>';
		}
		
		wp_reset_postdata();
		
		return $output;
	}
}

With the following CSS style code giving us the behaviour we need. (Which in itself is interesting, because CSS should be about styling, and JavaScript / PHP / … controlling behaviour. However these days CSS is so powerful that a great deal of behaviour can be defined without resorting to programming languages.)

ul#q5-HeaderNavigation {
    margin:0px auto;
    position:relative;
    float:left;
    border-left:1px solid #c4dbe7;
    border-right:1px solid #c4dbe7;
}
 
ul#q5-HeaderNavigation li {
    display:inline;
    font-size:12px;
    font-weight:bold;
    margin:0;
    padding:0;
    float:left;
    position:relative;
    border-top:1px solid #c4dbe7;
    border-bottom:2px solid #c4dbe7;
}
 
ul#q5-HeaderNavigation li a {
    padding:10px 25px;
    color:#616161;
    text-shadow:1px 1px 0px #fff;
    text-decoration:none;
    display:inline-block;
    border-right:1px solid #fff;
    border-left:1px solid #C2C2C2;
    border-top:1px solid #fff;
    background: #f5f5f5;
 
    -webkit-transition:color 0.2s linear, background 0.2s linear;
    -moz-transition:color 0.2s linear, background 0.2s linear;
    -o-transition:color 0.2s linear, background 0.2s linear;
    transition:color 0.2s linear, background 0.2s linear;
}
 
ul#q5-HeaderNavigation li a:hover {
    background:#f8f8f8;
    color:#282828;
}
 
ul#q5-HeaderNavigation li a.first {
    border-left: 0 none;
}
 
ul#navigation li a.last {
    border-right: 0 none;
}
 
ul#q5-HeaderNavigation li:hover > a {
    background:#fff;
}
/* Drop-Down Navigation */
ul#q5-HeaderNavigation li:hover > ul
{
/*these 2 styles are very important,
being the ones which make the drop-down to appear on hover */
    visibility:visible;
    opacity:1;
}
 
ul#q5-HeaderNavigation ul, ul#q5-HeaderNavigation ul li ul {
    list-style: none;
    margin: 0;
    padding: 0;
/*the next 2 styles are very important,
being the ones which make the drop-down to stay hidden */
    visibility:hidden;
    opacity:0;
    position: absolute;
    z-index: 99999;
    width:180px;
    background:#f8f8f8;
    box-shadow:1px 1px 3px #ccc;
/* css3 transitions for smooth hover effect */
    -webkit-transition:opacity 0.2s linear, visibility 0.2s linear;
    -moz-transition:opacity 0.2s linear, visibility 0.2s linear;
    -o-transition:opacity 0.2s linear, visibility 0.2s linear;
    transition:opacity 0.2s linear, visibility 0.2s linear;
}
 
ul#q5-HeaderNavigation ul {
    top: 43px;
    left: 1px;
}
 
ul#q5-HeaderNavigation ul li ul {
    top: 0;
    left: 181px; /* strong related to width:180px; from above */
}
 
ul#q5-HeaderNavigation ul li {
    clear:both;
    width:100%;
    border:0 none;
    border-bottom:1px solid #c9c9c9;
}
 
ul#q5-HeaderNavigation ul li a {
    background:none;
    padding:7px 15px;
    color:#616161;
    text-shadow:1px 1px 0px #fff;
    text-decoration:none;
    display:inline-block;
    border:0 none;
    float:left;
    clear:both;
    width:150px;
}

Deployed

Have restrurcture the WordPress web site. Previously it was located in directory “blogs” below the main site. I took a punt and copied the whole of “blogs” up a level and then created a soft link called “blogs” to the main site. I was hopeful that this would work and that any absolute paths would be honoured, but I would not have been surprised to have hit problems. However it worked fine. No issues encountered (yet).

I then:

  • Copied over the Q5 theme from my dev area.
  • Switched off debuging.
  • Switched theme to Q5
  • Tested

The result was surprisingly good. The original ‘site-pages’ were not available, obvioulsy, because they were not in WordPress, but everything else seemed to work fine.

Deployed Oopses

There were a couple of issues – not surpringly. In fact I was surprised how everything did seem to come together simply by moving the WordPress stuff up to the main site directory and replacing the original WordPress directory by a soft-link back to the main site directory.

Issues:

  • Not being able to login to the admin page. UserName and Password were correct and recognised, but I was simply returned each time to the login page
  • Index.php redirected to Index.php?home, which in turn redirected to Index.php, which meant No First Page.
  • Index.html was redirecting to Index.php correctly, but because of previous item was then stuck in a re-direct loop.

All the above was caused by the ReWrite instructions in the .htaccess file, and indeed if you read the notes about the ReWrite flags at http://httpd.apache.org/docs/current/rewrite/flags.html

it tells you to be careful about creating loops, as a triggered ReWrite rule can cause the ReWrite rules to be re-parsed for the re-written url.

Site Styling

I now have the Site Front page looking almost identical to the original Quintic Front Page. Header menus are working as I want them with drop downs for Blogs and Pages, and styled as per my requirements.

Central menu of ICONs for the technical pages is in place, and again styled as per my requirements. Did require a bit of slight of hand to get the styling as I want, because WordPress seems intent on using vertical lists for menus. However once you realise that the ID of the ul Menu element will be ‘menu-[menu name in lower case, with dashes replacing spaces]’ then you can construct CSS styles to override WordPress’s styles.

Just want to construct the footer menu, and then we should be good. All integrated. Good Job Daddy Raccoon.