php[architect] logo

Want to check out an issue? Sign up to receive a special offer.

WordPress 404 Plugin built on Bing Wrapper

Posted by on June 4, 2010

Update: We have added a link to a short youtube video on how to install the plugin. It explains each the options as well.

Over at my personal blog, I recently posted about the new Bing Search API wrapper I wrote for Microsoft. In the post, I said that I would talk about some of the uses of the wrapper. This post is the the first of two I have planned.

php|architect, The Accidental Businessman and Postcards From My Life are all three WordPress blogs. Personally, I have three others as well because it’s just so easy to setup and get running that I really have to have some serious requirements that absolutely cannot be met within WordPress to consider another option.

These days, being more of a market-teer than a code monkey, I worry about thinks like my site being “sticky”, people being able to find my site, and generally the things that programmers laugh at but are important to the rest of us that build out sites.

One of the things I’ve always hated about WordPress is the stock 404 error message. Out of the box, WordPress just tells users “I’m sorry, I can’t find what you are looking for.” Granted it is better than the stock Apache 404 page but it isn’t much more helpful. Having just finished working on the Bing Search Wrapper for PHP, the best use case I could think of for the wrapper was to solve this particular problem. This is how I helped Microsoft’s Interoperability team to put together the Bing 404 Plugin for WordPress.

Quick Start

Ok, if you are in a hurry you can either watch this video or follow the 4 steps below.

  1. Install the Bing 404 Plugin from the wordpres.org repository
  2. Get a Bing App ID
  3. Configure the plugin and give it your App Id
  4. Test it out by trying to go to an invalid URL on your blog.

All told, it should take you about 5 minutes, 2 if yo have the App Id already.

All the gory details

The goal of the plugin was to give useful 404 page. However, the definition of useful is different for different people. To be specific, I wanted to see if we could find what the user was looking for on the site and if not, then at the very least I wanted to suggest a few of the most popular articles on the blog. To further narrow the search, I wanted to be able to plug in “standard” search terms for which to search.

Abbreviated Workflow

Get the URL, strip off the domain. Everything else is considered the query.
If the url that led them to the 404 page is http://phparch.com/bing-rocks/ then I want to strip off http://phparch.com/ and be left with /bing-rocks/. Granted it is not very useful by itself but it gives us a hint at what the user was looking for.

Get the standard search terms.
Just in case the query string doesn’t return enough results (or any at all) we have the option of specifying some generic terms. In the case of phparch.com, we specify php, because that is what most people will be looking for here.

Run both queries, combine the arrays and pop off the top x results
In the setup, you can specify how many entries you want displayed on your page. If the query using the user’s original query string returns enough results, we use only those. However, if that doesn’t return enough to flesh out the entire x, the results of the second query to Bing, using the specified default keywords, will round out the list. Both queries honor the localized domain option so if you put in your domain name there, it will limit the results of both queries to results from your domain.

Code

Counting comments and all, the entire plugin (sans the API library) is 500+ lines. I am not going to paste them all in here but I will show the heart of the plugin and a couple of the bits of magic that allow it to work.

/**
 * perform the actual search
 *
 * This is the heart of the plugin. This function is called from the 404.php
 * template. No parameters are necessary. It returns the properly formatted
 * HTML to either display a list of potential links or an error message.
 *
 * @return string html to output.
 */
function bing404_search_bing() {
    include 'Msft/Exception.php';
    include 'Msft/Bing/Exception.php';
    include 'Msft/Bing/Search/Exception.php';
    include 'Msft/Bing/Search.php';

    /*
     * Create the Bing Search object.
     */
    $search = new Msft_Bing_Search( get_option( 'b4_apiKey' ) );
    $search->setWebCount( get_option( 'b4_count' ) );
    $search->setSource( 'Web' );
    $search->setAdult( get_option( 'b4_adult' ) );

    /*
     * If requested, make this a site specific search
     */
    if ( $localsite = get_option( 'b4_site' ) ) {
        $search->setSite( $localsite );
    }

    /*
     * If set, set the local market
     */
    $localMarket = get_option( 'b4_market' );
    if ( !empty( $localMarket ) && $localMarket != 'NONE' ) {
        $search->setMarket( $localMarket );
    }

    /*
     * Build the query to execute
     */
    $queryTerms = str_replace( '/', ' ', html_entity_decode( urldecode( $_SERVER['REQUEST_URI'] ) ) );
    $localQuery = get_option( 'b4_query' );

    /*
     * Try to pull the site-wide from cache. Otherwise, pull from bing
     */
    $cacheKey = md5( $localQuery );
    $raw      = wp_cache_get( $cacheKey );

    if ( $raw === false ) {
        $search->setQuery( $localQuery );
        $raw = $search->search();
        wp_cache_set( $cacheKey, $raw,'',86400 );
    }

    $siteResults = json_decode( $raw );

    /*
     * Try to pull the regular query from cache. Otherwise, pull from bing
     */
    $localQuery = trim( $queryTerms );
    $cacheKey   = md5( $localQuery );
    $raw        = wp_cache_get( $cacheKey );

    if ( $raw === false ) {
        $search->setQuery( $localQuery );
        $raw = $search->search();
        wp_cache_set( $cacheKey, $raw,'',86400 );
    }
    $results = json_decode( $raw );

    /*
     * Now merge the resultsets
     */
    $finalResults = bing404_merge_results( $results, $siteResults );

    /*
     * Finally, prepare the output
     */
    $output = '

    '; foreach ( $finalResults as $value ) { $output .= sprintf( '
  1. %s
  2. ', $value->Url, $value->Title ); } $output .= '
'; $bing404_dirname = WP_PLUGIN_URL . '/' . ( basename( dirname( __FILE__ ) ) ); switch ( get_option( 'b4_poweredByBing' ) ) { case 'Banner': $output .= '
'; break; case 'Text': $output .= '
Powered by Bing
'; break; case 'Off': break; } return $output;

A few of the code highlights:

  • Line 19 – Create the Bing search object.
  • Line 27 – If you have specified a local domain, localize the search to only that domain.
  • Line 42 – Get the query terms to search for. Note, 2 queries are actually made.
  • Line 48 – Execute the query pulling back the most popular items for the blog optionally using your specified query term.
  • Line 59 – Execute the query trying to find the page for which the user was actually looking

As I hope you can see, using the Bing Search wrapper makes this code very simple. The bulk of this method is simply parameter checking and setting defaults.

A bit of WordPress magic

Intercepting the 404 page on WordPress took a bit of digging. It turns out however to be simple, once you find the right hook.

/**
 * Register the 404 hook.
 *
 * Only register the 404 hook if the user wants to use our included template.
 */
if ( get_option( 'b4_useIncludedTemplate' ) ) {
    add_action( '404_template','bing404_use_included_template_hook' );
}

/**
 * include the standard template.
 *
 * If the user has opted to use the included template then include it for use.
 */
function bing404_use_included_template_hook() {
    include dirname( __FILE__ ). '/default-404.php';
    exit;
}

The plugin works in one of two ways.

  1. The plugin includes a 404 page. If you check the option, this will be the one that is used. This should work in 75%-80% of the cases and requires no code changes to get the plugin working.
  2. If you want to roll your own, include this line in your template’s 404.php.
    <?php if(function_exists('bing404_search_bing')) { echo bing404_search_bing(); } ?>

Either way works the same, a call is made to bing404_search_bing() and the results are displayed.

Conclusion

That is all there is to it. There are several other options for setting region localization, safe search and other options. All in all though, the Bing Search Wrapper allowed me to put this plugin together in a couple of hours. It took care of the details of the search and allowed me to worry about navigating the WordPress API minefield.


Cal Evans is a veteran of the browser wars. (BW-I, the big one) He has been programming for more years than he likes to remember but for the past [redacted] years he's been working strictly with PHP, MySQL and their friends. Cal regularly speaks at PHP users groups and conferences, writes articles and wanders the net looking for trouble to cause. He blogs on an "as he feels like it" basis at Postcards from my life.
Tags: , , ,
 

Responses and Pingbacks

[…] Evans has posted a tutorial on how to get started with the plugin on php|architect. His article discusses the details about how the plugin is […]

[…] Library for PHP project and was created in conjunction with PHP guru Cal Evans, who has posted a tutorial and details about the plugin on php | […]

Great work Cal! Thanks for posting these details as well.

Note: When I installed the plugin I was getting IO errors/file not found on three of the includes, I commented them out and it seems to work fine for me, not sure what functionality I’m missing though.

function bing404_searchBing()
{
/*
include ‘Msft/Exception.php’;
include ‘Msft/Bing/Exception.php’;
include ‘Msft/Bing/Search/Exception.php’;
*/
include ‘Msft/Bing/Search.php’;

Also,

Can you list the other values that are available in the $finalresults collection? I see Title and URL. Could you list any other values that are available? (for example, I’d love to get page description, or post date if those were avail in the results.)

Thanks again!

Caleb,

Strange, the Exception classes got left out of the final package. I am submitting a new package version 1.0.1 that should correct that. Sorry, not sure where it fell down. (Also not sure it installed on my blog from wordpress.org without error. will look into that too.)

I will dig up the other values for you and post them here.

=C=

[…] This plugin should work out-of-the-box with most themes using the included 404 template. You can also define your own to fine tune the look and feel to match your theme. Detailed tutorial on how to use the plugin is available here. […]

Cal – Thanks. I’m looking forward to the updates!

Caleb,

Version 1.0.1 is now in the WordPress.org repository and it’s fixed. Please re-try and tell me if it worked for you.

=C=

Cal –

Looks great. http://developingux.com/dependency-injection-solid (missing page)

I also noticed that the “Use the 404 template ” check box in the settings never stays checked for me, I’m not sure why that is.

Thanks again for putting this out there. I’m looking forward to digging in to the other values that are in the $finalresults collection.

BTW – I used the automatic update plugin and it picked up your update right ways. Very smooth process!

Caleb,

What version of WordPress are you using?

=C=

[…] Evans פרסם מדריך לשילוב התוסף לוורדפרס עבור עמוד 404 עם תוצאות מתוך Bing, […]

[…] WordPress 404 Plugin built on Bing Wrapper | php|architect (tags: php bing) […]

[…] post from the creator of the […]

Cal –

I’m using the latest (non-edge…) so I’m not on 3 yet. 😉
I use the automatic update plugin to keep my version up to date as often as I can… btw – I posted about my pimped out 404 here http://developingux.com/2010/06/05/bing-404-plugin-for-wordpress/

Thanks for all the work you’ve done of this!

[…] soffre il condizionamento di una palese operazione di marketing: sempre Cal Evans ne ha registrato uno screencast esplicativo che aiuta nell’installazione. Prescindendo dall’onnipresente logo di Bing, […]

[…] week Cal Evans announced the release of the Bing404 Plugin for WordPress, a plugin that takes advantage of the Bing Search Library for PHP released by the Interoperability […]

[…] wanted to show you this cool 404 page search plugin I found at the PHPArch […]

Awesome, got it working withing 5 minutes! I used the short version of the plugin, underneath that I placed the ‘select by month’ and ‘select by category’ lists.

[…] wanted to show you this cool 404 page search plugin I found at the PHPArch […]

thank you for the information,
This was helped,
spirit! ! ! ! !

[…] Update: The creator of this plug-in just added a quick start video… go check it out! […]

Thnx phparch team

Leave a comment

Use the form below to leave a comment: