Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

As some of you know, there's an Easter Egg hidden in the WordPress post revision system that will display a message from the movie The Matrix if you perform a specific action (if you don't know, I won't spoil the surprise ... poke around with post revisions and see if you can find it). I love Easter Eggs, and this one was a thrilling find when I stumbled upon it.

Some people, it seems, aren't really fans, though. I had a client recently discover this Easter Egg go into a panic attack because they thought someone had hacked their blog. They freaked out, flooded my inbox with panicked messages, and maxed out my voice mail quota with "please help!" messages.

This leads me to believe that some Easter Eggs should be turned off when WordPress is deployed in certain situations - i.e. for high-maintenance clients. Enter my idea for the first ever WordPress Answers code challenge.

The winner of this challenge will be awarded an extra 150 reputation points!!!

Let's see how skilled you all are at coding ... what would you recommend as the simplest way to remove this Easter Egg from WordPress without hacking core? In other words, using only action hooks, filters, and custom enqueued JavaScript, how would you remove the Matrix Easter Egg?

I'll select the "best" answer on October 31st based on:

  • The completeness of the answer (a description of the code + example code + screenshots if applicable)
  • The simplicity of the code (but remember, shorter isn't always better)
  • Full descriptions of how you would install the code on a client site

BTW, anyone who merely copy-pastes the solution I already posted on the WP-Hackers mailing list will be automatically disqualified. Let the games begin!

share|improve this question
4  
@EAMann You should have told your client "You take the blue pill and the story ends. You wake in your bed and believe whatever you want to believe." –  Chris_O Oct 25 '10 at 3:36
    
ah... i only read this on october 31st... –  edelwater Oct 31 '10 at 19:04
    
@edelwater: If you're lucky he'll be out all evening, collecting candy, and you still have some time left to write an answer! –  Jan Fabry Oct 31 '10 at 21:53
    
Actually I plan to be in all evening, distributing candy ... but I'll give you a couple more hours to post an answer :-) –  EAMann Nov 1 '10 at 0:48
    
How does the bounty get collected? :-) –  Denis de Bernardy Nov 2 '10 at 10:02

3 Answers 3

up vote 4 down vote accepted
+150

The following plugin dynamically hides the two offending radios using jQuery, and kills revision self-comparisons.

<?php
# Plugin Name: Pest Control
# Plugin URI: http://www.semiologic.com/
# Description: Kills the Easter Bunny
# Version: 1.0
# Author: Denis de Bernardy
# License: Public Domain

class PestControl {
    public static function bootstrap() {
        add_action('admin_head-revision.php', array(__CLASS__, 'mixomatosis'));
        add_action('load-revision.php', array(__CLASS__, 'plague'));
    }

    public static function mixomatosis() {
        echo <<<EOD
<script type="text/javascript">
// <![CDATA[
jQuery(document).ready(function($) {
    var mixomatosis = function() {
        var left = $(':radio[name=left]:checked').val(),
            right = $(':radio[name=right]:checked').val();
        $(':radio[name=left], :radio[name=right]').each(function() {
            var t = $(this);
            switch (true) {
                case t.attr('name') == 'left' && t.attr('value') == right:
                case t.attr('name') == 'right' && t.attr('value') == left:
                    t.css('display', 'none');
                    break;
                default:
                    t.css('display', '');
            }
        });
    };

    mixomatosis();
    $(':radio[name=left], :radio[name=right]').change(mixomatosis);
});
// ]]>
</script>
EOD;
    }

    public static function plague() {
        if ($_GET['action'] == 'diff' && $_GET['left'] == $_GET['right']) {
            wp_die("Can't compare a revision with itself.");
        }
    }
}

PestControl::bootstrap();
?>
share|improve this answer
    
The only warning I would preface this code with is that it requires PHP5 to work ... so if your site (or your client's site) is running on PHP4 for some reason, you'll have to adjust the code to work with the older version (or, preferably, just upgrade your server!!!). –  EAMann Nov 1 '10 at 13:13
    
Aye. It would be a matter of stripping the static keyword. :-) –  Denis de Bernardy Nov 1 '10 at 15:25

My solution works in two ways: it disables selection of two identical revisions by modifying the list-revisions Javascript file, and if by some means two identical revisions do get selected, it offers a real error message.

This screenshot gives you a quick overview of the error message, and the effect of the new Javascript. As you can see, it is no longer possible to select the same revision twice. If you want to see the effect you either have to disable the Javascript (comment out the add_action(('wp_default_scripts', ... line) or manually change the URL.

Comparison of the old and new revision screens

It is written as a plugin. For a multisite installation you could maybe drop it in mu-plugins, and let the initialization depend on a database configuration option. That way you can enable or disable it for different clients.

Comments on my plugin writing style are welcome, I tried to separate the code into three logical blocks.

Main plugin file. This file switches the list-revisions Javascript file with a "safer" version that prevents the selection of the same revision twice. It also checks the admin_action_diff action and shortcuts to an own page with an error message if the two revisions are equal. The new page is written in ui-identical.php to separate code and layout.

<?php
/*
Plugin Name: Myxomatosis
Plugin URI: http://www.monkeyman.be/
Description: Kill the Easter Bunny and his eggs!
Version: 1.0
Author: Jan Fabry
*/

class Myxomatosis
{
    function __construct()
    {
        add_action('admin_action_diff', array(&$this, 'checkEqualDiff'));
        add_action('wp_default_scripts', array(&$this, 'loadSafeListRevisions'), 20);
    }

    function checkEqualDiff()
    {
        global $left, $right;
        if (!array_key_exists('left', $_REQUEST) || !array_key_exists('right', $_REQUEST)) {
            return;
        }
        $left = absint($_REQUEST['left']);
        $right = absint($_REQUEST['right']);

        if (!$left || !$right || $left != $right) {
            // Nothing wrong, they are not equal
            return;
        }

        // They are equal. Set up globals so UI can be included
        // Which globals do I need here?
        global $title, $hook_suffix, $pagenow, $is_iphone, $current_screen, $user_identity, $post, $wp_locale;

        $post = get_post($left);
        if ($post->post_parent) {
            $post = get_post($post->post_parent);
        }

        require_once(plugin_dir_path(__FILE__) . 'ui-identical.php');
        exit();
    }

    function loadSafeListRevisions(&$scripts)
    {
        $scripts->remove('list-revisions');
        $scripts->add('list-revisions', plugin_dir_url(__FILE__) . 'safe-list-revisions.dev.js', null, '20101026' );
    }
}

$myxomatosis_instance = new Myxomatosis();

File ui-identical.php, in the plugin directory. This creates the page to show if the two revisions are the same. The revision list is shown again.

<?php
wp_enqueue_script('list-revisions');

$post_title = '<a href="' . get_edit_post_link() . '">' . get_the_title() . '</a>';
$h2 = sprintf( __( 'Compare Revisions of &#8220;%1$s&#8221;' ), $post_title );
$title = __( 'Revisions' );

require_once(ABSPATH . '/wp-admin/admin-header.php');
?>
<div class="wrap">
    <h2 class="long-header"><?php echo $h2; ?></h2>

    <div class="error"><p><?php _e( 'You selected two identical revisions' ); ?></p></div>

<h2><?php echo $title; ?></h2>

<?php

$args = array( 'format' => 'form-table', 'parent' => true, 'right' => $right, 'left' => $left );
if ( ! WP_POST_REVISIONS || !post_type_supports($post->post_type, 'revisions') )
    $args['type'] = 'autosave';

wp_list_post_revisions( $post, $args );
?>

</div>
<?php
require_once(ABSPATH . '/wp-admin/admin-footer.php');

File safe-list-revisions.dev.js, in the plugin directory. The logic is split up in two loops: one to read the current checked buttons, and one to hide and show the others. This is might simpler than the original version, and allows some tweaking in the middle.

(function(w) {
    var init = function() {
        var pr = document.getElementById('post-revisions'),
        var inputs = pr ? pr.getElementsByTagName('input') : [];
        if (inputs.length <= 2) {
            // Sanity check: if there is only one revision, hide nothing
            // Not that we should get here...
            return;
        }
        // For simplicity, only one click handler is registered on the whole #post-revisions table
        pr.onclick = function() {
            var i, checkCount = 0, side;
            var checkedIdx = {};
            for (i = 0; i < inputs.length; i++) {
                if (inputs[i].checked) {
                    side = inputs[i].getAttribute('name');
                    checkedIdx[side] = i;
                }
            }
            if (checkedIdx['left'] + 1 == checkedIdx['right']) {
                // The same revisions are checked
                // Move left down (or right up, if left is at the bottom)
                // There should always be at least two revisions (see sanity check above)
                if (checkedIdx['left'] + 2 < inputs.length) {
                    checkedIdx['left'] += 2;
                    inputs[checkedIdx['left']].checked = true;
                } else {
                    checkedIdx['right'] -= 2;
                    inputs[checkedIdx['right']].checked = true;
                }
            }
            if (checkedIdx['left'] < checkedIdx['right']) {
                // 'Old' is newer than 'New', so switch them
                // We sometimes get this - don't know why
                var origLeft = checkedIdx['left'];
                checkedIdx['left'] = checkedIdx['right'] - 1;
                checkedIdx['right'] = origLeft + 1;

                inputs[checkedIdx['left']].checked = true;
                inputs[checkedIdx['right']].checked = true;
            }
            // Loop again, hide what we should not see
            // 'left' buttons should be hidden until we see a checked 'right' button
            // 'right' buttons should be visible until we see a checked 'left' button
            for (i = 0; i < inputs.length; i++) {
                side = inputs[i].getAttribute('name');
                if ('left' == side) {
                    inputs[i].style.visibility = (i < checkedIdx['right'] ? 'hidden' : 'visible');
                } else if ('right' == side) {
                    inputs[i].style.visibility = (checkedIdx['left'] < i ? 'hidden' : 'visible');
                }
            }
        }
        pr.onclick();
    }
    if ( w && w.addEventListener )
        w.addEventListener('load', init, false);
    else if ( w && w.attachEvent )
        w.attachEvent('onload', init);
})(window);
share|improve this answer
    
For the record, this is also a fantastic solution! The fact that code would be split into two files rather than in one, simple drop-in was one of the largest reasons I went with the "answer" marked above. FWIW This solution looks to be more PHP4 compatible than the marked answer, so if you're on an update-restricted server or hosting plan, you should seriously look in to this option! –  EAMann Nov 2 '10 at 13:32

I adore how code goes extra mile to include easter egg in obfuscated and inflexible way. :(

I suck with admin area, so here is my code that spawned way more questions in my head than answered:

add_filter( 'get_edit_post_link', 'hijack_revision_easter_egg' );

function hijack_revision_easter_egg( $input ) {

    global $action, $left, $right;


    if( 'diff' != $action )
    return $input;

    if( $left == $right ) {

    $revision = wp_get_post_revision( $left );

    if( $revision->post_parent )
        wp_redirect ( site_url( "/wp-admin/revision.php?revision={$left}&action=view" ) );
    else
        wp_redirect( str_replace( 'amp;', '', $input ) );

    exit;
    }

    return $input;
}

No idea why encoded ampersand breaks redirect... Had no idea about admin_action_ hook that this should really use instead of messily hooking into harmless get_edit_post_link...

I tried to redirect to revision view, but that doesn't seem possible for latest revision.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.