How To: Fixing CakePHP Broken GET Query Strings

After getting familiar with CakePHP 2.x for a little while, writing an application, I had a need to perform an AJAX action  using the query string of an HTTP GET request. I’ve done it countless times using straight PHP, ASP.Net, even custom constructed requests from C# desktop applications.  How difficult could it be? After all, the idea behind these PHP frameworks is to take all the heavy lifting out of writing your code, right? I set out writing the AJAX links to construct my query string using CakePHP’s JsHelper.

I started out by writing a simple query string with a single key/value and then retrieving it with some AJAX. It worked perfectly! Then I added a few more key/value pairs to the string and that’s when things went down hill. Apparently, I stumbled on to bug in the way CakePHP handles and encodes URL Query strings. Funny thing is, this bug was discovered and fixed in a previous version of the framework, but some how found it’s way into the code base again in version 2.x. Research revealed a number of work-arounds and hacks, most included editing a core file or two. I, however, did not want to have to resort to messing with core files of the framework, because they would likely be overwritten again after a version update or upgrade, leaving me back where I started. Instead I decided to “repair” the parts of the query string that CakePHP broke.

Continue reading “How To: Fixing CakePHP Broken GET Query Strings”

WordPress: Use Custom Fields To Add Keyword Metadata to Your Posts

Keywords at edwardstafford.com
Keywords for edwardstafford.com

One of the short-comings with using WordPress is that it does not provide an easy, built-in way to include metadata for your web page descriptions and keywords (and rightfully so). Why Not? The reason is simply that WordPress cannot read your mind. I know it’s hard to believe when you consider what you can do with wordpress, but it’s true. The issue with Description and Keyword page metadata is that, to be truely effective, it should be created to  describe the content found on each individual page. It’s how search engines like google determine how to categorize and index each page. Now, there are some SEO “experts” who will argue that this information is not very relevant anymore, and I do agree with that for the most part, but there are still SEO benefits to including this metadata vs. not including it at all.

I’ve been giving this some thought lately and developed a couple ideas of how to add these features into a wordpress site without too much difficulty. A bulb went off in a moment clarity when I started to think about using the Custom Fields to store page specific metadata. I was even naive enough to think I was on to something new (should have known better) but as I started researching some ideas, I realized there were others already doing similar things. Oh well, a minor detail. I took my own approach to the idea anyway, if for no other reason than a learning exercise. Ultimately, this could be added as a premium feature to any custom theme using a couple hooks and some custom theme options magic.

Continue reading “WordPress: Use Custom Fields To Add Keyword Metadata to Your Posts”

YouTube API Hack: Link Your Videos Directly to Your YouTube Channel

Wait! Your a Hacker?

Hack ItFirst of all, my use of the word “Hack” is not the version popularized by the media. It is used here in the context of using a tool (YouTube API) to accomplish a task that was not originally part of the tool’s design. By using some creative thinking and little trial and error, I was able to accomplish a desired result, and overcome a limitation of the API.

Ready, Set, GO!!

While working on a recent project I came across a mildly irritating limitation of the YouTube API. The thing is, I wanted to display a list of recently added YouTube video thumbnails to a web site that link back to the videos in the YouTube users channel.  Easy! right?

Not So Fast!

Here’s the thing. The channel feed returned by the API does include the link back to the YouTube Video, BUT it sends the visitor to the usual standard public YouTube page with the video embeded and NOT to the Channel of the YouTube member who uploaded it.

For most, this would be fine. But I wanted to be able to preserve a connection and identity between the web site and the YouTube Channel.

Unfortunately, the YouTube API does not provide a direct way to do this [link videos back directly to the YouTube Channel instead of the standard YouTube page]. So what’s a developer to do? … Come up with a hack, of course!! (even if is is a small one)..

First A Note:

This solution uses the Simplepie PHP Code Library to grab the Channel RSS feed

The Code:

<?php

require_once(‘php/simplepie.inc’);

$feed = new SimplePie(‘http://gdata.youtube.com/feeds/api/users/[user name]/uploads’);

$feed->handle_content_type();

$YT_PlayerPage = “http://www.youtube.com/user/[user name]#play/uploads/”;

$YT_VideoNumber = 0;
$ShowMax = 4;

foreach ($feed->get_items() as $item)
{

if ($enclosure = $item->get_enclosure())
{

$YT_VidID = substr(strstr($item->get_permalink(), ‘v=’), 2, 11);

echo ‘<a href=”‘ . $YT_PlayerPage . $YT_VideoNumber . “/” . $YT_VidID . ‘”title=”‘ . $item->get_title() . ‘”> <img src=”‘ . $enclosure->get_thumbnail() . ‘”/></a>’;

}
if($YT_VideoNumber == $ShowMax) break;
$YT_VideoNumber++;
}
?>

Tiptoe Through the Tulips (or walking through the code)

There you have it. A small block of PHP code and we have the result we’re looking for. Now let’s take a look at each line in the code.

require_once(‘php/simplepie.inc’);

This line does nothing more than call/include the Simplepie Library. The one thing you may need to change here is the location of the library. I stored it in a directory at the root of my web called “php”. So depending where you store your copy of the library, you may need to change this.

$feed = new SimplePie(‘http://gdata.youtube.com/feeds/api/users/[user name]/uploads’);

The next line creates a new feed and stores it as $feed. Pretty creative.. huh? Whats happening here is simplepie is grabing the rss feed for the YouTube Channel’s Uploaded videos.

An important note to make here is that the URI for the RSS passed to SimplePie is not the same as the RSS URI that you would use to subscribe to the channel’s RSS feed to use with your RSS reader. You will also need to replace [user name] in the URI with the YouTube user name for the channel you want to pull videos from.

The Standard RSS Subscription URI looks like this:
http://gdata.youtube.com/feeds/base/users/[user name]/uploads

While the URI used by the API to grab the RSS looks like this:
http://gdata.youtube.com/feeds/api/users/[user name]/uploads

Notice the difference indicated in bold text (“base” vs “api”). You will need to be sure you use “API” version of the URI. You can get this by copying the public RSS URI and simply changing “base” to “api”.

At the next line we have:

$feed->handle_content_type();

This just makes sure the content is being served out to the browser properly.

The next three lines contain three variables I’ve added: $YT_PlayerPage, $YT_VideoNumber and $ShowMax

$YT_PlayerPage = “http://www.youtube.com/user/[user name]#play/uploads/”;

This is the first part of the key to getting YouTube links to point directly to the Channel page. This variable holds the base Channel player URI and is used to construct a complete video link. The completed URI link also includes a counter reference and the unique 11 character video ID. To get the URI for the channel player page, visit the YouTube Channel you’re grabing the video feed from and click on a video link. The complete URI for that video will appear in the browser’s address bar. Simply copy that URI and eliminate everything following the backslash “/” after “uploads” (indicated in red)

http://www.youtube.com/user/[user name]#play/uploads/#/xxxxxxxxxxx

$YT_VideoNumber = 0;

The links on the YouTube Channel page contain a counter in the URI and increases by +1 with each link. This is the second part of the key in constructing the direct Channel links. This counter was a portion of the link that was removed in $YT_PlayerPage. I’m not completely clear on what the purpose of the counter is and in my experimenting with this, it did not seem to make a difference what the counter value was as long as the video ID followed it. But since it is the format that is used on YouTube’s Channel pages, I’ve figured it would be best to recreate the same thing here. Besides, we are going to use that value later in the code. I’ve set the initial value of the variable to 0 (zero) because the counter is zero based. (0, 1, 2 … )

$ShowMax = 4;

The next line contains the $ShowMax variable. This is used to set a limit to the number video links I wanted to display on the page. BUT, there is a trick you need to be aware of here. We are using the $YT_VideoNumber to get the counter number for the current video in the Loop (the loop will be described in the next section). But because $YT_VideoNumber is zero based, we need to compensate for that in the $ShowMax Variable and offset the limit by -1. In other words, to limit the display to 5 items, we need to set $ShowMax to 4 because we are including 0 as the first item (0 1 2 3 4) for a total of 5 items. Got it?… good!

foreach ($feed->get_items() as $item)
{

These lines start/open the Loop getting each item in the feed. This is where the code will “loop” through each item (video) in the feed and extract the information I wanted for each video.

if ($enclosure = $item->get_enclosure())
{

This line sets a conditional variable ($enclosure) to check if the current item in the loop contains enclosure data provided by MRSS (Multimedia RSS) that might be provided with the feed. YouTube feeds do support and provide MRSS enclosure data and we need to be able to pull it from the feed. The get_enclosure() method is part of the SimplePie Library and makes getting access to this data pretty easy.

$YT_VidID = substr(strstr($item->get_permalink(), ‘v=’), 2, 11);

This line is the final [and probably most important] part of the key to constructing the Channel video link.  It’s also the most confusing part at first sight. I mentioned earlier that a video link is provided with the feed that will direct the viewer to a the standard public YouTube page for viewing. This link contains the video ID that we need. The bad news is that the API as far as I could see does not allow a direct or easy way to get the ID for each video [please correct me if I’m wrong here]. The good news is that the ID can be extracted from the link provided with the feed, and that’s exactly what this line does.

$item->get_permalink() returns the URI / video  that would direct a visitor to the standard YouTube page. The URI is similar to:
http://www.youtube.com/watch?v=xxxxxxxxxxx

v=xxxxxxxxxxx of the URI contains the video ID and needs to be extracted.

substr(strstr($item->get_permalink(), ‘v=’), 2, 11) isolates and extracts the video ID and then stores the ID in the $YT_VidID variable.

Lets have a closer look.
We need to find the position in the URI string where the video ID starts and then extract it.

The video ID is passed in the URI as in query string paramater “v”.  I used the PHP strstr() method to match and find the position of “v=”. This will create a new string eliminating everything in front “v=” so we are left with “v=xxxxxxxxxxx”.

If you look close, you’ll notice that strstr($item->get_permalink(), ‘v=’) and therefore the resulting string, is actually used as the string argument in the substr() method used to isolate the video ID.

The second argument, “2” tells the substr method to offset the beginning of the string by two characters. This is to eliminate the “v” and “=” characters and moves the substring start position to the character after the “=” which is the first character of the Video ID.

The third argument, 11, tells the substr method to isolate the next eleven characters from the start position, leaving us with the full video ID “xxxxxxxxxxx”.

In experimenting and playing with this, I found that all YouTube video IDs are 11 characters long. I limited the substring to 11 instead of allowing it to extend to the end of the URI because, if for some reason additional string data was passed with the URI after the video ID, it would be included as part of  the extracted string and the result would be an invalid ID.

After all that, I had the golden nugget of an isolated video ID which is now stored in the $YT_VidID variable. The hard part is DONE!! (really, it wasn’t that hard).

echo ‘<a href=”‘ . $YT_PlayerPage . $YT_VideoNumber . “/” . $YT_VidID . ‘”title=”‘ . $item->get_title() . ‘”> <img src=”‘ . $enclosure->get_thumbnail() . ‘”/></a>’;

The three key pieces needed to construct the direct Channel URIs are now available and the links can be put together. This line, still contained in our loop, constructs the link for each video item in the feed and outputs the HTML markup that will be included in the rendered page. To construct the link, join the three key pieces (the variables) like so:

$YT_PlayerPage . $YT_VideoNumber . “/” . $YT_VidID

$YT_PlayerPage = The base URI.
$YT_VideoNumber = The video counter
include a “/” character
$YT_VidID = The video ID

The output should look like:
http://www.youtube.com/user/[user name]#play/uploads/#/xxxxxxxxxxx

Include this string as the value of the href of an HTML <a> tag.
‘<a href=”‘ . $YT_PlayerPage . $YT_VideoNumber . “/” . $YT_VidID . ‘
Next add a “title” attribute to the <a> tag and set the value to $item->get_title().
“title=”‘ . $item->get_title() . ‘”>
This will create a hover text that shows the title of the video when the cursor hovers over the link.

Next, include the link content (text or image to act as the visible link). In my sample, I’ve used a thumbnail of each video.
<img src=”‘ . $enclosure->get_thumbnail() . ‘”/>
Note that again I’m extracting the enclosure data included with MRSS as part of the RSS feed to get the thumbnail image for each video.

Finally add the closing </a> tag to complete.

But wait … There’s more!!

}

The next line is nothing more than a closing bracket that closes and completes the conditional statement that checks for the enclosure data.

if($YT_VideoNumber == $ShowMax) break;

Remember the $ShowMax variable? This is where it comes into play. We are using the $YT_VideoNumber variable that was added to hold the counter for the current video and comparing it to the $ShowMax variable used to limit the number of videos the page will display. With each iteration of the loop, the code extracts the information for each video item and increments the counter by +1. The counter actually serves two purposes in the code. First,  to be used in constructing the video URI and second, to control the point at which the loop is to be exited. Why?.. If our video feed has 100 items and we only want to display 5 of them, then it does not make any sense to continue stepping through the loop to read the remaining items. So after we get what we want, we exit the loop to save resources.

What’s happening here is this:
If the current $YT_VideoNumber variable value for the current iteration of the loop matches the value of the $ShowMax variable, then “break” (exit) out of the loop and we’re done.

$YT_VideoNumber++;

BUT, if the values of these variables does not match, then the next line increments the $YT_VideoNumber by +1 and continues to the next iteration of the loop.

}

And Finally, there is the closing bracket of the loop which also brings us to the end of the code block.

So that’s it. This code will render a set of YouTube video thumbnails in a web page that will link directly back to the video on the YouTube member’s channel page where ever it is included. But don’t stop there. Have a look at the other methods available in the YouTube API and SimplePie Library for additional information and data you can extract and use, add your own CSS and markup to the the output to change the layout, appearance, function … whatever you want.

I hope you found this useful. If you have any thoughts, improvements or comments to share, please post in the comments section here.

And if you do use this in your own projects, I’d really appreciate a comment in your code, a shoutout or link back to this post.

Happy coding!!!