WordPress Child Page Menus

Whilst helping Michelle set up Kids Puzzles and Games I came across the need for the menus in the various sections to show child pages when in a section home page, and peer pages when viewing any content in a section.

The site structure is along the lines of:

  • Home page
    • Section home page
      • Section page
      • Another section page
    • Another section homepage
      • Etc

So in the Colouring Sheets section the menu will show types of colouring sheets, and when viewing a colouring sheet page you will also see types of colouring sheets. For an added twist, as the page titles repeat the name of the section they are in I needed to remove that repetition when displayed in a menu – e.g. Dinosaur Colouring Sheets is the title of a page in the Colouring Sheets section.

Example menu

My PHP isn’t great, and it took me a little while to find examples to put together to make the answer but this seems to do the trick. I’m sharing it in case you need to do something similar.

 <?php
 // get the title of the parent page
 $parent_title = get_the_title($post->post_parent);
 // get formatted array of child pages but don't echo them
 $child_pages = wp_list_pages('title_li=&child_of=2&echo=0');
 // replace any mention of the parent page title with an empty string
 $child_pages = str_replace($parent_title,'',$child_pages);
 // and now output the menu
 echo $child_pages;
 ?>

You’ll notice I’ve hard coded the page ID of the parent page – I can do this because each section has it’s own template. I know that $post->post_parent will give the ID of the parent page, but I needed that to be fixed for the section heading and for the section content (which is a child page of the section heading). Feel free to let me know if there is an easier way of doing this I’m all for keeping code simple.

Updated 17th April to remove extra semi-colons added by editing this post on the iPhone WordPress app!

Coding away from the keyboard

Whilst working on a program to automatically generate mazes, I realised that most of my spare time for this kind of thing is either when watching TV, or when I’m away from home, such as on the park and ride bus to and from work. As I was looking to solve the problem using JavaScript/HTML there is no compiler involved, so some kind of editor app for my phone would be ideal. Sure enough there are several in the App Store, I settled on Expresso HTML, well because it looks nice, has some useful shortcuts to characters such as “<", has a handy inbuilt browser to preview my efforts – oh and it's free.

20120115-162704.jpg
Coding on the go is fairly tough going, the virtual keyboard obscures half of the screen and doesn’t allow tabs (double space indentation!), but it is easy to switch between preview and editor mode, and you can work on multiple files. Ideal for small projects and experimenting on the go – it was enough to get my maze generator finished and working, details of how I got on to follow in a future post. If it had an in-built FTP client it would be great for making for emergency corrections.

Creating mazes

My wife creates printable activity sheets for children, and the subject of how to create mazes came up. Hand drawing leaves too many chances for mistakes, so we settled on using a spreadsheet – draw a grid, use the table eraser to make paths:

20120108-104933.jpg

Now this works fine, but being a developer I can’t help thinking there must be a way to programmatically generate these based on some parameters. Sure enough, solutions already exist, but this is a puzzle I’d like to solve on my own.

Over the next few posts I’m going to record my progress and my various attempts at creating a solution.

20120108-104920.jpg

Infinite scrolling with an ASP.net webform, jQuery, and a little bit of code

Infinite scrolling presents your content as one long page – as you read (scroll) toward the bottom of the content some more loads in below automatically (and hopefully seamlessly). This allows your site visitor to focus on content without being distracted by enforced navigation concepts such as paging. It also means you only serve as much content as the user wants to see, which is espacially useful in today’s increasingly mobile world. Twitter and Facebook are good examples of sites that do this well.

This post aims to give a hopefully simple example of how to achieve this using the following basic ingredients:

  • ASP.net/C# 4.0 (I’m using Visual Web Developer Express)
  • An ASP.net webform
  • A ScriptMethod
  • jQuery and a bit of JavaScript
  • Some data – in this case a list of pretend blog posts

How it works

The webform will display the first ten blog posts. When the user scrolls to the bottom of the page some JavaScript will call a method to return the next ten items. These are then appended to the bottom of the page. When the user scrolls to the bottom of that the process repeats until there are no blog posts left.

This is simplified for us by the use of a ScriptMethod, which is like a WebMethod in a web service, except you place it in a normal ASPX page as a static method decorated with the ScriptMethod attribute (code example below). ASP.net then kindly provides a nice JavaScript proxy for us to call this with one line of code. I’m then using jQuery to simplify the process of adding the resulting array of BlogPost items to the page.

Blog Post Repository

First things first, we need some data to display and so I have created a static class BlogPostRepository which provides access to a list of made up BlogPost items:


public class BlogPost
{
	public string Title { get; set; }
	public string Summary { get; set; }

	public BlogPost(string title, string summary)
	{
		Title = title;
		Summary = summary;
	}
}

public static class BlogPostRepository
{
	static List<BlogPost> posts;

	static BlogPostRepository()
	{
		posts = new List<BlogPost>();

		for (int i = 1; i <= 200; i++)
		{
			posts.Add(new BlogPost(string.Format("Post number {0}", i),
				string.Format("Discover my thoughts on the number {0}.", i)));
		}
	}

	public static List<BlogPost> GetPosts(int startAt, int howMany)
	{
		return (from p in posts
			select p).Skip(startAt).Take(howMany).ToList();
	}
}

The code behind page

The code behind for the web page is straightforward – bind the first ten posts to a ListView control during Page_Load, and the ScriptMethod GetPosts will return additional blog posts to the page on request:

protected void Page_Load(object sender, EventArgs e)
{
	if (!IsPostBack)
	{
		lvItems.DataSource = BlogPostRepository.GetPosts(0, 10);
		lvItems.DataBind();
	}
}

[System.Web.Services.WebMethod()]
[System.Web.Script.Services.ScriptMethod()]
public static List<BlogPost> GetPosts(int startAt, int howMany)
{
	return BlogPostRepository.GetPosts(startAt, howMany);
}

Note that GetPosts is decorated as a WebMethod and also a ScriptMethod. It also needs to be static.

The mark up

The key to making Script Methods work is the <asp:ScriptManager> which needs to have EnablePageMethods set to “true”:

<asp:ScriptManager runat="server" ID="ScriptManager1" EnablePageMethods="true">
</asp:ScriptManager>

This ensures that the necessary JavaScript helper methods are available.

Next up is a ListView control which I really like because of the control it offers over the output in your page. This takes care of the initial output of blog posts:

<asp:ListView runat="server" ID="lvItems">
	<LayoutTemplate>
		<div id="container">
			<asp:PlaceHolder ID="itemPlaceholder" runat="server"></asp:PlaceHolder>
		</div>
	</LayoutTemplate>
	<ItemTemplate>
		<div class="post">
			<h2>
				<%# Eval("Title") %></h2>
			<p>
				<%# Eval("Summary") %></p>
		</div>
	</ItemTemplate>
	<AlternatingItemTemplate>
		<div class="post shade">
			<h2>
				<h2>
					<%# Eval("Title") %></h2>
				<p>
					<%# Eval("Summary") %></p>
		</div>
	</AlternatingItemTemplate>
</asp:ListView>       

You will notice that each blog post has a container DIV with a class of “post”, and that they are all held within a container DIV with an ID of “container”. Alternate posts have a shaded background thanks to some CSS and the additional “shade” class. The next thing is to add the JavaScript:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
    $(window).scroll(function () {
        if ($(window).scrollTop() == $(document).height() - $(window).height()) {
            GetPosts();
        }
    });
});

function GetPosts() {
    var howMany = 10;
    var startAt = $(".post").size();
    PageMethods.GetPosts(startAt, howMany, OnGetPostsComplete);
}

function OnGetPostsComplete(posts) {
    for (var i = 0; i < posts.length; i++) {
        var shade = (i % 2) != 0 ? " shade" : "";
        $("#container").last().append("<div class=\"post" + shade + "\"><h2>" +
                            posts[i].Title + "</h2><p>" +
                            posts[i].Summary + "</p></div>");
    }
}
</script>

Lets look at the script above. First I use jQuery to attach a function to the scroll event of the window. This will fire whenever the user scrolls to the bottom of the page, and simply calls the GetPosts method.

GetPosts uses jQuery to get a count of items in the page with the class “post”. This will equal the number of blog posts output so far. I can then call a JavaScript method provided for us by ASP.net because the GetPosts method in our code behind is decorated as a ScriptMethod. So PageMethods.GetPosts takes the same parameters as the C# code, plus in addition the name of the method to call when the asynchronous web call has completed – i.e. when we have the results of the call, in this case OnGetPostsComplete

OnGetPostsComplete takes the array of BlogPost items returned by the ScriptMethod and appends them to the end of the items already in the container DIV which holds all of the blog post DIVs. For effect I’m adding the “shade” class to alternate post items which I have defined in CSS to give them a different background colour.

What next

I haven’t tried this with a database as a data source so speeds will vary. When using the in-memory repository there was hardly a noticable delay at all in the new items being displayed. You might want to add an AJAX style “spinner” graphic to show when loading is occurring. This can easily be achieved using a hidden DIV and the jQuery toggle() method, e.g. $("#loading").toggle();. Toggle it on in GetPosts, and off again in OnGetPostsComplete.

HexaClock

20120121-070519.jpg

A little while back a friend of mine Anthony Casey decided to make an iOS friendly HTML5/CSS3 based clock similar to the Flash based The Colour Clock. This is a digital clock where the background colour changes with every second of the day. You can view the completed HexaClock here, though you will need a HTML5 browser (no Internet Explorer 8 or below I’m afraid).

Anthony is a whizz with all things HTML/CSS, and asked me if I could help out by coming up with some JavaScript to make the clock change colour and tell the time.

Figuring out which colour to show

First things first, how do I make every second of the day a different colour? As we know the current time of day is made up of three parts, hours (0-23), minutes (0-59) and seconds (0-59). Luckily for us colours on the web are also made up of three parts, combinations of red, green and blue (known as RGB). The amount of each colour to use is a value between 0 and 255, e.g. 255 red is solid red, 0 red is no red at all, and 128 red is a dark maroon type colour. Using this knowledge we can create colours and shades, for example:

Red – R:255 G:0 B:0
White – R:255 G:255 B:255
Black – R:0 G:0 B:0
Yellow – R:255 G:255 B:0
Purple – R:195 G:48 B:255

It’s kind of like the opposite of mixing paint – here mix lots of each colour and you end up with white instead of a mucky browny black colour. There are plenty of sites out there that explain RGB colours in more detail.

How much of each colour to use

The amount of red to use maps to the hour of the day, green to the minute in the hour, and blue to the second in the minute. Using the actual value of hour, minute and second would result in lots of dark colours as we would never get a number higher than 59, so instead we will figure it out as a proportion of 255:

Red = (hour / 24) * 255
Green = (minute / 60) * 255
Blue = (second / 60) * 255

Making it tick

With the colour problem sorted the next step is to make the clock update every second. I created a “tick” function to show the current time and the appropriate background colour. To make it update once a second the JavaScript setTimeout function was used to call “tick” again after 1000 milliseconds.

Web browsers prefer their colour values represented in hexadecimal so the numbers need converting first. After first looking at writing a small decimal to hex conversion function I realised there was no need as I could use a nice feature of JavaScript to specify which number base to use when converting a number to a string, e.g. 15.toString(16) = “f”. This should actually be “0f” so the fix2 function tidies up any one digit hex values.

Here is the full code:

function hexClock(bodyId, clockId) { this.body = document.getElementById(bodyId); this.clock = document.getElementById(clockId); this.running = false; this.fix2 = function (n) { return (n < 10) ? "0" + n : "" + n; } this.tick = function () { if (!this.running) return; var now = new Date(); var h = now.getHours(); var m = now.getMinutes(); var s = now.getSeconds(); var hexH = Math.round((h/24) * 255).toString(16); var hexM = Math.round((m/60) * 255).toString(16); var hexS = Math.round((s/60) * 255).toString(16); this.body.style.backgroundColor = "#" + this.fix2(hexH) + this.fix2(hexM) + this.fix2(hexS); this.clock.innerHTML = this.fix2(h) + ":" + this.fix2(m) + ":" + this.fix2(s); setTimeout(function(me) { me.tick(); }, 1000, this); } this.start = function () { this.running = true; this.tick(); } this.stop = function () { this.running = false; } } // this bit runs when the page loads function init() { var clock = new hexClock("body", "clock"); clock.start(); }

Probably not the best bit of JavaScript that you will ever see but it does the job. At some point I might rewrite it using the Prototype approach.