SHARE
TWEET

Smart 404 Wordpress Plugin FIXED TO NEVER SHOW A 404 ERROR

Fastmover Nov 15th, 2011 280 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?php
  2. /*
  3. Plugin Name: Smart 404
  4. Plugin URI: http://atastypixel.com/blog/wordpress/plugins/smart-404/
  5. Description: Rescue your viewers from site errors!  When content cannot be found, Smart 404 will use the current URL to attempt to find matching content, and redirect to it automatically. Smart 404 also supplies template tags which provide a list of suggestions, for use on a 404.php template page if matching content can't be immediately discovered.
  6. Version: 0.5
  7. Author: Michael Tyson
  8. Author URI: http://atastypixel.com/blog/
  9. */
  10.  
  11. /*  Copyright 2008 Michael Tyson <mike@tyson.id.au>
  12.  
  13.     This program is free software; you can redistribute it and/or modify
  14.     it under the terms of the GNU General Public License as published by
  15.     the Free Software Foundation; either version 2 of the License, or
  16.     (at your option) any later version.
  17.  
  18.     This program is distributed in the hope that it will be useful,
  19.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.     GNU General Public License for more details.
  22.  
  23.     You should have received a copy of the GNU General Public License
  24.     along with this program; if not, write to the Free Software
  25.     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  26. */
  27.  
  28.  
  29. /**
  30.  * Main action handler
  31.  *
  32.  * @package Smart404
  33.  * @since 0.1
  34.  *
  35.  * Searches through posts to see if any matches the REQUEST_URI.
  36.  * Also searches tags
  37.  */
  38. function smart404_redirect() {
  39.         if ( !is_404() )
  40.                 return;
  41.        
  42.         // Extract any GET parameters from URL
  43.         $get_params = "";
  44.         if ( preg_match("@/?(\?.*)@", $_SERVER["REQUEST_URI"], $matches) ) {
  45.             $get_params = $matches[1];
  46.         }
  47.        
  48.         // Extract search term from URL
  49.         $patterns_array = array();
  50.         if ( ( $patterns = trim( get_option('ignored_patterns' ) ) ) ) {
  51.                 $patterns_array = explode( '\n', $patterns );
  52.         }
  53.        
  54.         $patterns_array[] = "/(trackback|feed|(comment-)?page-?[0-9]*)/?$";
  55.         $patterns_array[] = "\.(html|php)$";
  56.         $patterns_array[] = "/?\?.*";
  57.         $patterns_array = array_map(create_function('$a', '$sep = (strpos($a, "@") === false ? "@" : "%"); return $sep.trim($a).$sep."i";'), $patterns_array);
  58.        
  59.         $search = preg_replace( $patterns_array, "", urldecode( $_SERVER["REQUEST_URI"] ) );
  60.         $search = basename(trim($search));
  61.         $search = str_replace("_", "-", $search);
  62.         $search = trim(preg_replace( $patterns_array, "", $search));
  63.        
  64.         if ( !$search ) return;
  65.        
  66.         $search_words = trim(preg_replace( "@[_-]@", " ", $search));
  67.         $GLOBALS["__smart404"]["search_words"] = explode(" ", $search_words);
  68.     $GLOBALS["__smart404"]["suggestions"] = array();
  69.  
  70.     $search_groups = (array)get_option( 'also_search' );
  71.     if ( !$search_groups ) $search_groups = array("posts","pages","tags","categories");
  72.    
  73.     // Search twice: First looking for exact title match (high priority), then for a general search
  74.     foreach ( $search_groups as $group ) {
  75.         switch ( $group ) {
  76.             case "posts":
  77.                 // Search for posts with exact name, redirect if one found
  78.                     $posts = get_posts( array( "name" => $search, "post_type" => "post" ) );
  79.                         if ( count( $posts ) == 1 ) {
  80.                                 wp_redirect( get_permalink( $posts[0]->ID ) . $get_params, 301 );
  81.                                 exit();
  82.                         }
  83.                 break;
  84.                
  85.             case "pages":
  86.                 // Search pages
  87.                 $posts = get_posts( array( "name" => $search, "post_type" => "page" ) );
  88.                         if ( count( $posts ) == 1 ) {
  89.                                 wp_redirect( get_permalink( $posts[0]->ID ) . $get_params, 301 );
  90.                                 exit();
  91.                         }
  92.                         break;
  93.                        
  94.                 case "tags":
  95.                     // Search tags
  96.                         $tags = get_tags( array ( "name__like" => $search ) );
  97.                         if ( count($tags) == 1) {
  98.                                 wp_redirect(get_tag_link($tags[0]->term_id) . $get_params, 301);
  99.                                 exit();
  100.                         }
  101.                         break;
  102.                        
  103.             case "categories":
  104.                 // Search categories
  105.                         $categories = get_categories( array ( "name__like" => $search ) );
  106.                         if ( count($categories) == 1) {
  107.                                 wp_redirect(get_category_link($categories[0]->term_id) . $get_params, 301);
  108.                                 exit();
  109.                         }
  110.                         break;
  111.         }
  112.     }
  113.    
  114.     // Now perform general search
  115.     foreach ( $search_groups as $group ) {
  116.         switch ( $group ) {
  117.             case "posts":
  118.                 $posts = smart404_search($search, "post");
  119.                         if ( count( $posts ) == 1 ) {
  120.                                 wp_redirect( get_permalink( $posts[0]->ID ) . $get_params, 301 );
  121.                                 exit();
  122.                         }
  123.  
  124.                         $GLOBALS["__smart404"]["suggestions"] = array_merge ( (array)$GLOBALS["__smart404"]["suggestions"], $posts );
  125.                 break;
  126.                
  127.             case "pages":
  128.                 $posts = smart404_search($search, "page");
  129.                         if ( count( $posts ) == 1 ) {
  130.                                 wp_redirect( get_permalink( $posts[0]->ID ) . $get_params, 301 );
  131.                                 exit();
  132.                         }
  133.  
  134.                         $GLOBALS["__smart404"]["suggestions"] = array_merge ( (array)$GLOBALS["__smart404"]["suggestions"], $posts );
  135.                         break;
  136.             /* Added by Fastmover 11/08/2011 */
  137.             default:
  138.                 $posts = smart404_default_result();
  139.                 wp_redirect( get_permalink( $posts[0]->ID ), 301 );
  140.                 exit();
  141.                 break;
  142.         }
  143.     }
  144. }
  145.  
  146.  
  147. /**
  148.  * Helper function for searching
  149.  *
  150.  * @package Smart404
  151.  * @since 0.5
  152.  * @param   query   Search query
  153.  * @param   type    Entity type (page or post)
  154.  * @return  Array of results
  155.  */
  156. function smart404_search($search, $type) {
  157.     $search_words = trim(preg_replace( "@[_-]@", " ", $search));
  158.         $posts = get_posts( array( "s" => $search_words, "post_type" => $type ) );
  159.         if ( count( $posts ) > 1 ) {
  160.             // See if search phrase exists in title, and prioritise any single match
  161.             $titlematches = array();
  162.             foreach ( $posts as $post ) {
  163.                 if ( strpos(strtolower($post->post_title), strtolower($search_words)) !== false ) {
  164.                     $titlematches[] = $post;
  165.                 }
  166.             }
  167.             if ( count($titlematches) == 1 ) {
  168.                 return $titlematches;
  169.             }
  170.         }
  171.        
  172.         return $posts;
  173. }
  174. /* Added by Fastmover 11/08/2011 */
  175. function smart404_default_result() {
  176.     $posts = get_posts( array( 'numberposts' => 1, 'order'=> 'DESC' ) );
  177.     return $posts;
  178. }
  179.  
  180. /**
  181.  * Filter to keep the inbuilt 404 handlers at bay
  182.  *
  183.  * @package Smart404
  184.  * @since 0.3
  185.  *
  186.  */
  187. function smart404_redirect_canonical_filter($redirect, $request) {
  188.        
  189.         if ( is_404() ) {
  190.                 // 404s are our domain now - keep redirect_canonical out of it!
  191.                 return false;
  192.         }
  193.        
  194.         // redirect_canonical is good to go
  195.         return $redirect;
  196. }
  197.  
  198. /**
  199.  * Set up administration
  200.  *
  201.  * @package Smart404
  202.  * @since 0.1
  203.  */
  204. function smart404_setup_admin() {
  205.         add_options_page( 'Smart 404', 'Smart 404', 5, __FILE__, 'smart404_options_page' );
  206.         wp_enqueue_script('jquery-ui-sortable');
  207. }
  208.  
  209. /**
  210.  * Options page
  211.  *
  212.  * @package Smart404
  213.  * @since 0.1
  214.  */
  215. function smart404_options_page() {
  216.         ?>
  217.         <div class="wrap">
  218.         <h2>Smart 404</h2>
  219.        
  220.         <form method="post" action="options.php">
  221.         <?php wp_nonce_field('update-options'); ?>
  222.        
  223.         <table class="form-table">
  224.        
  225.         <tr valign="top">
  226.                 <th scope="row"><?php _e('Search:') ?><br/><small><?php _e('(Drag up/down to change priority)') ?></small></th>
  227.                 <td>
  228.                 <ul id="also_search_group">
  229.                     <?php foreach ( array_unique(array_merge((array)get_option('also_search'), array('posts','pages','tags','categories'))) as $group ) : ?>
  230.                         <li><input type="checkbox" name="also_search[]" value="<?php echo $group ?>" <?php echo (in_array($group, (array)get_option('also_search')) ? "checked" : ""); ?> /> <?php _e(ucwords($group)) ?></li>
  231.                     <?php endforeach; ?>
  232.                 </ul>
  233.                 </div>
  234.                 </td>
  235.         </tr>
  236.        
  237.         <script type="text/javascript">
  238.     jQuery(document).ready(function() {
  239.         jQuery('#also_search_group').sortable();
  240.         jQuery('#also_search_group').disableSelection();
  241.     });
  242.         </script>
  243.        
  244.         <tr valign="top">
  245.                 <th scope="row"><?php _e('Ignored patterns:') ?></th>
  246.                 <td>
  247.                         <textarea name="ignored_patterns" cols="44" rows="5"><?php echo htmlspecialchars(get_option('ignored_patterns')); ?></textarea><br />
  248.                         <?php _e("One term per line to ignore while searching. Regular expressions are permitted."); ?>
  249.                 </td>
  250.         </tr>
  251.        
  252.         </table>
  253.        
  254.         <input type="hidden" name="action" value="update" />
  255.         <input type="hidden" name="page_options" value="also_search,ignored_patterns" />
  256.        
  257.         <p class="submit">
  258.         <input type="submit" name="Submit" value="<?php _e('Save Changes') ?>" />
  259.         </p>
  260.        
  261.         </form>
  262.         </div>
  263.         <?php
  264. }
  265.  
  266. /**
  267.  * Template tag to determine if there any suggested posts
  268.  *
  269.  * @package Smart404
  270.  * @since 0.1
  271.  *
  272.  * @return      boolean True if there are some suggestions, false otherwise
  273.  */
  274. function smart404_has_suggestions() {
  275.         return ( isset ( $GLOBALS["__smart404"]["suggestions"] ) && is_array( $GLOBALS["__smart404"]["suggestions"] ) && count( $GLOBALS["__smart404"]["suggestions"] ) > 0 );
  276. }
  277.  
  278. /**
  279.  * Template tag to obtain suggested posts
  280.  *
  281.  * @package Smart404
  282.  * @since 0.1
  283.  *
  284.  * @return      array   Array of posts
  285.  */
  286. function smart404_get_suggestions() {
  287.         return $GLOBALS["__smart404"]["suggestions"];
  288. }
  289.  
  290. /**
  291.  * Template tag to render HTML list of suggestions
  292.  *
  293.  * @package Smart404
  294.  * @since 0.1
  295.  *
  296.  * @param       format  string  How to display the items: flat (just links, separated by line-breaks), list (li items)
  297.  * @return      boolean True if some suggestions were rendered, false otherwise
  298.  */
  299. function smart404_suggestions($format = 'flat') {
  300.         if ( !isset ( $GLOBALS["__smart404"]["suggestions"] ) || !is_array( $GLOBALS["__smart404"]["suggestions"] ) || count( $GLOBALS["__smart404"]["suggestions"] ) == 0 )
  301.                 return false;
  302.        
  303.         echo '<div id="smart404_suggestions">';
  304.         if ( $format == 'list' )
  305.                 echo '<ul>';
  306.                
  307.         foreach ( (array) $GLOBALS["__smart404"]["suggestions"] as $post ) {
  308.                 if ( $format == "list" )
  309.                         echo '<li>';
  310.                        
  311.                 ?>
  312.                 <a href="<?php echo get_permalink($post->ID); ?>"><?php echo $post->post_title; ?></a>
  313.                 <?php
  314.                
  315.                 if ( $format == "list" )
  316.                         echo '</li>';
  317.                 else if ( $format == "flat" )
  318.                         echo '<br />';
  319.         }
  320.        
  321.         if ( $format == 'list ')
  322.                 echo '</ul>';
  323.                
  324.         echo '</div>';
  325.        
  326.         return true;
  327. }
  328.  
  329. /**
  330.  * Template tag to initiate 'The Loop' with suggested posts
  331.  *
  332.  * @package Smart404
  333.  * @since 0.1
  334.  *
  335.  * @return      boolean True if there are some posts to loop over, false otherwise
  336.  */
  337. function smart404_loop() {
  338.         if ( !isset ( $GLOBALS["__smart404"]["suggestions"] ) || !is_array( $GLOBALS["__smart404"]["suggestions"] ) || count( $GLOBALS["__smart404"]["suggestions"] ) == 0 ) {
  339.                 return false;
  340.         }
  341.        
  342.         $postids = array_map(create_function('$a', 'return $a->ID;'), $GLOBALS["__smart404"]["suggestions"]);
  343.        
  344.         query_posts( array( "post__in" => $postids ) );
  345.         return have_posts();
  346. }
  347.  
  348. /**
  349.  * Template tag to retrieve array of search terms used
  350.  *
  351.  * @package Smart 404
  352.  * @since 0.4
  353.  *
  354.  * @return Array of search terms
  355.  */
  356. function smart404_get_search_terms() {
  357.     return $GLOBALS["__smart404"]["search_words"];
  358. }
  359.  
  360. // Set up plugin
  361.  
  362. add_action( 'template_redirect', 'smart404_redirect' );
  363. add_filter( 'redirect_canonical', 'smart404_redirect_canonical_filter', 10, 2 );
  364. add_action( 'admin_menu', 'smart404_setup_admin' );
  365. add_option( 'also_search', array ( 'posts', 'pages', 'tags', 'categories' ) );
  366. add_option( 'ignored_patterns', '' );
  367.  
  368. ?>
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top