【Permalink Redirect】ylsy_permalink_redirect.phpのソースコード

<?php
/*
 * Plugin Name: Permalink Redirect
 * Plugin URI: http://scott.yang.id.au/code/permalink-redirect/
 * Description: Permalink Redirect ensures that pages and entries are always accessed via the permalink. Otherwise, a 301 redirect will be issued.
 * Version: 2.0.5
 * Author: Scott Yang
 * Author URI: http://scott.yang.id.au/
 */
class YLSY_PermalinkRedirect {
    function admin_menu() {
        add_options_page('Permalink Redirect Manager', 'Permalink Redirect', 5,
            'permalink-redirect', array($this, 'admin_page'));
    }

    function admin_page() {
        global $wp_version;

        // If we are updating, we will flush all the rewrite rules to force the 
        // old structure to be added.
        if (isset($_GET['updated']) ||
            isset($_GET['settings-updated'])) {
            $this->regenerate_rules();
        }

        $options = array('feedburner', 'feedburnerbrand', 'hostname', 
            'oldstruct', 'skip', 'newpath');
        $optionvars = array();
        foreach ($options as $option) {
            $$option = get_option("permalink_redirect_$option");
            if (!$$option) {
                $$option = ($option == 'feedburnerbrand') ? 
                    'feeds.feedburner.com' : '';
            }
            if ($wp_version < '2' && !$$option) {
                add_option("permalink_redirect_$option", $$option);
            }
            $optionvars[] = "permalink_redirect_$option";
        }

        $home = parse_url(get_option('home'));
?>
<div class="wrap">
    <h2>Permalink Redirect Manager</h2>
    <form action="options.php" method="post">
        <fieldset class="options">
            <legend>Paths to be skipped</legend>
            <p>Separate each entry with a new line. Matched with regular expression.</p>
            <textarea name="permalink_redirect_skip" style="width:98%;" rows="5"><?php echo htmlspecialchars($skip); ?></textarea>

            <legend style="padding-top:20px">Path pairs to redirect from and to</legend>
            <p>Separate each entry with a new line. Each line is [from]<spaces>[to].</p>
            <textarea name="permalink_redirect_newpath" style="width:98%;" rows="5"><?php echo htmlspecialchars($newpath); ?></textarea>
            <table class="optiontable" style="padding-top:20px">
                <tr valign="top">
                    <th scope="row">Old Permalink Structures:</th> 
                    <td><textarea name="permalink_redirect_oldstruct" id="permalink_redirect_oldstruct" style="width:98%" rows="3"><?php echo htmlspecialchars($oldstruct); ?></textarea><br/><small><a href="http://codex.wordpress.org/Using_Permalinks">Available tags</a>. One Permalink Structure per line. Current permalink structure: <a href="#" onclick="document.getElementById('permalink_redirect_oldstruct').value = '<?php echo htmlspecialchars(get_option('permalink_structure')); ?>';return false;"><code><?php echo htmlspecialchars(get_option('permalink_structure')); ?></code></a></small></td>
                </tr>
                <tr>
                    <th scope="row">FeedBurner Redirect:</th> 
                    <td>http://<input name="permalink_redirect_feedburnerbrand" type="text" id="permalink_redirect_feedburnerbrand" value="<?php print htmlspecialchars($feedburnerbrand); ?>" size="20"/>/<input name="permalink_redirect_feedburner" type="text" id="permalink_redirect_feedburner" value="<?php echo htmlspecialchars($feedburner) ?>" size="20" /></td> 
                </tr> 
                <tr>
                    <th scope="row">Hostname Redirect:</th> 
                    <td><input name="permalink_redirect_hostname" type="checkbox" id="permalink_redirect_hostname" value="1"<?php if ($hostname) { ?> checked="checked"<?php } ?>/> Redirect if hostname is not <code><?php echo htmlspecialchars($home['host']); ?></code>.</td> 
                </tr>
            </table>
        </fieldset>
        <p class="submit">
            <input type="submit" name="Submit" value="<?php _e('Update Options') ?> »" />
            <input type="hidden" name="action" value="update" />
            <input type="hidden" name="page_options" value="<?php echo join(',', $optionvars); ?>"/>
            <?php if (function_exists('wp_nonce_field')) { wp_nonce_field('update-options'); } ?>
        </p>
    </form>
</div>
<?php
    }

    function check_hostname() {
        if (! get_option('permalink_redirect_hostname')) {
            return false;
        }
        $requested = $_SERVER['HTTP_HOST'];
        $home = parse_url(get_option('home'));
        return $requested != $home['host'];
    }

    function execute() {
        global $wp_query;
        $this->execute2($wp_query);
    }

    function execute2($query, $testold=true) {
        $req_uri = $_SERVER['REQUEST_URI'];

        if ($query->is_trackback || 
            $query->is_search || 
            $query->is_comments_popup ||
            $query->is_robots ||
            $this->is_skip($req_uri))
        {
            return;
        }

        $this->redirect_newpath($req_uri);
        $this->redirect_feedburner($query);

        if ($query->is_404) {
            if ($testold) {
                $this->redirect_old_permalink($req_uri);
            }
            return;
        }

        if (($req_uri = @parse_url($_SERVER['REQUEST_URI'])) === false) {
            return;
        }

        $req_path = $req_uri['path'];
        $new_uri = $this->guess_permalink($query);
        if (!$new_uri) {
            return;
        }
        $permalink = @parse_url($new_uri);

        // WP2.1: If a static page has been set as the front-page, we'll get 
        // empty string here.
        if (!$permalink['path']) {
            $permalink['path'] = '/';
        }
        if (($req_path != $permalink['path']) || $this->check_hostname()) {
            wp_redirect($new_uri, 301);
        }
    }

    function guess_permalink($query) {
        $haspost = count($query->posts) > 0;
        $has_ut = function_exists('user_trailingslashit');

        if (get_query_var('m')) {
            // Handling special case with '?m=yyyymmddHHMMSS'
            // Since there is no code for producing the archive links for
            // is_time, we will give up and not trying any redirection.
            $m = preg_replace('/[^0-9]/', '', get_query_var('m'));
            switch (strlen($m)) {
                case 4: // Yearly
                    $link = get_year_link($m);
                    break;
                case 6: // Monthly
                    $link = get_month_link(substr($m, 0, 4), substr($m, 4, 2));
                    break;
                case 8: // Daily
                    $link = get_day_link(substr($m, 0, 4), substr($m, 4, 2),
                                         substr($m, 6, 2));
                    break;
                default:
                    return false;
            }
        } elseif (($query->is_single || $query->is_page) && $haspost) {
            $post = $query->posts[0];
            $link = get_permalink($post->ID);
            $page = get_query_var('page');
            if ($page && $page > 1) {
                $link = trailingslashit($link) . "$page";
                if ($has_ut) {
                    $link = user_trailingslashit($link, 'paged');
                } else {
                    $link .= '/';
                }
            }
            // WP2.2: In WordPress 2.2+ is_home() returns false and is_page() 
            // returns true if front page is a static page.
            if ($query->is_page && ('page' == get_option('show_on_front')) && 
                $post->ID == get_option('page_on_front'))
            {
                $link = trailingslashit($link);
            }
        } elseif ($query->is_author && $haspost) {
            global $wp_version;
            if ($wp_version >= '2') {
                $author = get_userdata(get_query_var('author'));
                if ($author === false)
                    return false;
                if (function_exists('get_author_posts_url')) {
                    $link = get_author_posts_url($author->ID,
                        $author->user_nicename);
                } else {
                    $link = get_author_link(false, $author->ID,
                        $author->user_nicename);
                }
                // XXX: get_author_link seems to always return one with 
                // trailing slash. We have to call user_trailingslashit to 
                // make it right.
                if ($has_ut) {
                    $link = user_trailingslashit($link);
                }
            } else {
                // XXX: get_author_link() bug in WP 1.5.1.2
                //      s/author_nicename/user_nicename/
                global $cache_userdata;
                $userid = get_query_var('author');
                $link = get_author_link(false, $userid,
                    $cache_userdata[$userid]->user_nicename);
            }
        } elseif ($query->is_category && $haspost) {
            $link = get_category_link(get_query_var('cat'));
        } elseif ($query->is_tag && $haspost) {
            $link = get_tag_link(get_query_var('tag_id'));
        } elseif ($query->is_day && $haspost) {
            $link = get_day_link(get_query_var('year'),
                                 get_query_var('monthnum'),
                                 get_query_var('day'));
        } elseif ($query->is_month && $haspost) {
            $link = get_month_link(get_query_var('year'),
                                   get_query_var('monthnum'));
        } elseif ($query->is_year && $haspost) {
            $link = get_year_link(get_query_var('year'));
        } elseif ($query->is_home) {
            // WP2.1: Handling "Posts page" option. In WordPress 2.1 is_home() 
            // returns true and is_page() returns false if home page has been 
            // set to a page, and we are getting the permalink of that page 
            // here.
            if ((get_option('show_on_front') == 'page') &&
                ($pageid = get_option('page_for_posts'))) 
            {
                $link = trailingslashit(get_permalink($pageid));
            } else {
                $link = trailingslashit(get_option('home'));
            }
        } else {
            return false;
        }

        if ($query->is_paged) {
            $paged = get_query_var('paged');
            if ($paged) {
                $link = trailingslashit($link) . "page/$paged";
                if ($has_ut) {
                    $link = user_trailingslashit($link, 'paged');
                } else {
                    $link .= '/';
                }
            }
        }

        if ($query->is_feed) {
            $link = trailingslashit($link) . 'feed';
            if ($has_ut) {
                $link = user_trailingslashit($link, 'feed');
            } else {
                $link .= '/';
            }

        }

        return $link;
    }

    function is_feedburner() {
        return strncmp('FeedBurner/', $_SERVER['HTTP_USER_AGENT'], 11) == 0;
    }

    function is_skip($path) {
        $permalink_redirect_skip = get_option('permalink_redirect_skip');
        $permalink_redirect_skip = explode("\n", $permalink_redirect_skip);

        // Apply 'permalink_redirect_skip' filter so other plugins can
        // customise the skip behaviour. (Denis de Bernardy @ 2006-04-23)
        $permalink_redirect_skip = apply_filters('permalink_redirect_skip', 
            $permalink_redirect_skip);

        foreach ($permalink_redirect_skip as $skip) {
            $skip = trim($skip);
            if ($skip && ereg($skip, $path))
                return true;
        }

        return false;
    }

    function redirect_feedburner($query) {
        // Check whether we need to do redirect for FeedBurner.
        // NOTE this might not always get executed. For feeds,
        // WP::send_headers() might send back a 304 before template_redirect
        // action can be called.
        global $withcomments;

        if ($query->is_feed && !$query->is_archive && !$withcomments) {
            if (($feedburner = get_option('permalink_redirect_feedburner')) &&
                (strncmp('FeedBurner/', $_SERVER['HTTP_USER_AGENT'], 11) != 0))
            {
                $brand = get_option('permalink_redirect_feedburnerbrand');
                $brand = $brand ? $brand : 'feeds.feedburner.com';
                wp_redirect("http://$brand/$feedburner", 302);
            }
        }
    }

    // Static page redirect contributed by Sergey Menshikov.
    function redirect_newpath($path) {
        if ($newpathlist = get_option('permalink_redirect_newpath')) {
            $newpathlist = explode("\n", $newpathlist);
            foreach ($newpathlist as $newpath) {
                $pair = preg_split('/\s+/', trim($newpath));
                if ($pair[0] == $path) {
                    wp_redirect($pair[1], 301);
                }
            }
        }
    }

    /**
     * Called when the main execute function gets a 404 to check against old 
     * permalink structures and perform redirect if an old post can be 
     * matched.
     */
    function redirect_old_permalink($req_uri) {
        global $wp_query, $wp_rewrite;
        global $wp_version;

        $rules = get_option('permalink_redirect_rules');
        if (!$rules) {
            return;
        }

        // Backing up the rewrite object for you, imperative programmers!
        $wp_rewrite_old = $wp_rewrite;

        // Unsetting the globals. Argh! Evil global variables!
        foreach ($wp_query->query_vars as $key => $val) {
            unset($GLOBALS[$key]);
        }

        // Going through the rules.
        foreach ($rules as $rules2) {
            $wp2 = new WP();
            $wp_rewrite = new YLSY_Rewrite();
            $wp_rewrite->index = $wp_rewrite_old->index;
            $wp_rewrite->rules = $rules2;

            $wp2->parse_request();
            if (isset($wp2->query_vars['error']) && 
                ($wp2->query_vars['error'] == 404)) 
            {
                continue;
            }
            $query = new WP_Query();
            if ($wp_version >= '2.1') {
                $posts = $query->query($wp2->query_vars);
            } else {
                $wp2->build_query_string();
                $posts = $query->query($wp2->query_string);
            }
            if (count($posts) > 0) {
                $wp_rewrite = $wp_rewrite_old;
                $this->execute2($query, false);
                return;
            }
        }

        // Restoring global variables. We don't bother to reset the other 
        // variables as we are going to do a 404 anyway.
        $wp_rewrite = $wp_rewrite_old;
    }

    /**
     * This function is called after someone saved the old permalink 
     * structure. It will create cached version of rewrite rules from the 
     * old structure.
     */
    function regenerate_rules() {
        global $wp_rewrite;
        $oldstruct = get_option('permalink_redirect_oldstruct');
        if ($oldstruct) {
            $rules = array();
            $oldstruct = explode("\n", $oldstruct);
            foreach ($oldstruct as $item) {
                $rules2 = $wp_rewrite->generate_rewrite_rule(trim($item), 
                    false, false, false, true);
                $rules3 = array();
                foreach ($rules2 as $match => $query) {
                    $query = preg_replace('/\$(\d+)/', '\$matches[\1]', $query);
                    $rules3[$match] = $query;
                }
                $rules[] = $rules3;
            }
            update_option('permalink_redirect_rules', $rules);
        } else {
            delete_option('permalink_redirect_rules');
        }
    }
}

/**
 * I am a dummy class to simulate the WP_Rewite class, but only has one 
 * method implemented.
 */
class YLSY_Rewrite {
    function wp_rewrite_rules() {
        return $this->rules;
    }
}

if (!function_exists('wp_redirect')) {
    function wp_redirect($location, $status=302) {
        global $is_IIS;

        $location = apply_filters('wp_redirect', $location, $status);
        $status = apply_filters('wp_redirect_status', $status, $location);

        if (!$location)
            return false;

        if (function_exists('wp_sanitize_redirect')) {
            $location = wp_sanitize_redirect($location);
        }

        if ($is_IIS) {
            header("Refresh: 0;url=$location");
        } else {
            status_header($status);
            header("Location: $location");
        }
    }
}


$_permalink_redirect = new YLSY_PermalinkRedirect();
add_action('admin_menu', array($_permalink_redirect, 'admin_menu'));
add_action('template_redirect', array($_permalink_redirect, 'execute'));

コメント

コメントする