. */ // don't load directly - exit if add_action or plugins_url functions do not exist if ( ! defined( 'ABSPATH' ) || ! function_exists( 'add_action' ) || ! function_exists( 'plugins_url' ) ) { die(); } if ( ! class_exists( 'AA_G404' ) ) : /** * Defines whether ISCLOG class for custom logging exists * * This can not be defined elsewhere * * @since 5.0.1 * @var bool */ define( 'AA_G404_HAS_ISCLOG', (bool) ( defined( 'ISC_DEBUG' ) && ISC_DEBUG && class_exists( 'ISCLOG' ) ) ); /** * Defines whether debugging is enabled or not. * * This can be defined in wp-config.php which overwrites it here. * * @since 5.0.1 * @var bool */ ! defined( 'AA_G404_DEBUG' ) && define( 'AA_G404_DEBUG', AA_G404_HAS_ISCLOG ); /** * Defines whether to debug start and stop of functions * * This can be defined in wp-config.php which overwrites it here. * * @since 5.0.1 * @var bool */ ! defined( 'AA_G404_DEBUG_FUNCTIONS' ) && define( 'AA_G404_DEBUG_FUNCTIONS', AA_G404_HAS_ISCLOG ); /** * Defines whether to debug * * This can not be defined elsewhere and requires ISCLOG and AA_G404_DEBUG_FUNCTIONS==true * * @since 5.0.1 * @var bool */ define( 'AA_G404D_F', (bool) ( AA_G404_HAS_ISCLOG && AA_G404_DEBUG_FUNCTIONS ) ); /** * Defines whether to debug * * This can not be defined elsewhere and requires ISCLOG and AA_G404_DEBUG==true * * @since 5.0.1 * @var bool */ define( 'AA_G404D', (bool) ( AA_G404_HAS_ISCLOG && AA_G404_DEBUG ) ); /** * AA_G404 * * @package WordPress * @author AskApache * @version 4.10 * @copyright Copyright (C) www.askapache.com * @access public * @link http://googlesystem.blogspot.com/2008/02/google-toolbar-and-404-error-pages.html */ class AA_G404 { // an array of options and values var $options = array(); // array to hold plugin information var $plugin = array(); // array to hold the css and html var $code = array( 'css' => '', 'html' => '', ); /** * Loads the options into the class vars. * Adds this plugins 'load' function to the 'load-plugin' hook. * * @return void */ function init() { AA_G404D_F && ISCLOG::ti(); // load $this->plugin, $this->options $this->load_options(); if ( is_admin() ) { // sorry, gotta force a reset if ( ! isset( $this->options['cse_id'] ) ) { $this->reset_options(); } // add options page add_action( 'admin_menu', array( &$this, 'admin_menu' ) ); // add load add_action( "load-{$this->plugin['hook']}", array( &$this, 'load' ) ); } else { // hook 404_template to show our 404 template, but only if enabled if ( ( '1' === $this->options['enabled'] ) ) { add_filter( '404_template', array( &$this, 'get_404_template' ), 2000, 1 ); } } AA_G404D_F && ISCLOG::ti(); } /** * The load function executed by the load-plugin hook. Passes control of request handling to the 'handle_post' function. * Adds the meta-boxes and the contextual help. * Enqueues the neccessary js and css files for plugin adminstration. * * @return void */ function load() { AA_G404D_F && ISCLOG::ti(); AA_G404D && ISCLOG::tw( ( is_404() ? 'is_404: TRUE' : ' is_404: FALSE' ) ); // load code $this->load_code(); // add contextual help add_action( "admin_head-{$this->plugin['hook']}", array( &$this, 'add_help' ) ); // enqueue css - wp_enqueue_style( $handle, $src = false, $deps = array(), $ver = false, $media = 'all' ) wp_enqueue_style( $this->plugin['pagenice'], plugins_url( 'f/admin.css', __FILE__ ), array( 'wp-jquery-ui-dialog' ), $this->plugin['version'], 'all' ); // enqueue javascript - wp_enqueue_script( $handle, $src = false, $deps = array(), $ver = false, $in_footer = false ) wp_enqueue_script( $this->plugin['pagenice'], plugins_url( 'f/admin.js', __FILE__ ), array( 'jquery', 'jquery-ui-dialog', 'jquery-ui-tabs', 'jquery-ui-progressbar', 'postbox' ), $this->plugin['version'], true ); // parse and handle post requests to plugin if ( 'POST' === $_SERVER['REQUEST_METHOD'] ) { $this->handle_post(); } AA_G404D && ISCLOG::tw( ( is_404() ? 'is_404: TRUE' : ' is_404: FALSE' ) ); AA_G404D_F && ISCLOG::ti(); } /** * The main function that lets this plugin handle errors instead of WP's builtin error handling. * * @param string $template The template file * * @return string absolute path of php template */ function get_404_template( $template ) { AA_G404D_F && ISCLOG::ti(); AA_G404D && ISCLOG::tw( ( is_404() ? 'is_404: TRUE' : ' is_404: FALSE' ) ); // load code $this->load_code(); // construct handler class global $AA_G404_Handler; if ( ! is_object( $AA_G404_Handler ) ) { AA_G404D && ISCLOG::tw( 'AA_G404_Handler NOT AN OBJECT' ); $AA_G404_Handler = aa_g404_get_handler_object(); } // Now handle the incoming request with AA_G404_Handler::handle_it $AA_G404_Handler->handle_it(); // Loads the 404 error template specified by the 404_handler option if ( file_exists( $this->options['404_handler'] ) ) { AA_G404D && ISCLOG::tw( 'loading: ' . $this->options['404_handler'] ); AA_G404D_F && ISCLOG::ti(); return $this->options['404_handler']; } // return for the template_redirect AA_G404D && ISCLOG::tw( ( is_404() ? 'is_404: TRUE' : ' is_404: FALSE' ) ); AA_G404D_F && ISCLOG::ti(); return $template; } /** * currently code is not saved across upgrades due to a potential security issue * * @return void */ function upgrade_settings() { AA_G404D_F && ISCLOG::ti(); // upgrade plugin settings $this->plugin = $this->get_plugin_data( true ); // current code $code = get_option( 'askapache_google_404_code' ); // code base64_decoded $codeb64 = ( ( $code !== false && strlen( $code ) > 2 ) ? base64_decode( $code ) : '' ); // if 46 empty $codeb64_len = strlen( $codeb64 ); if ( substr( $codeb64, 0, 2 ) === 'a:' ) { AA_G404D && ISCLOG::tw( 'code looks to be uncompressed: ' . $codeb64 ); $code = base64_encode( gzdeflate( $codeb64, 1 ) ); if ( strlen( $code ) > 46 ) { AA_G404D && ISCLOG::tw( 'saving askapache_google_404_code: ' . $code ); $this->code = $code; update_option( 'askapache_google_404_code', $code ); } } else { AA_G404D && ISCLOG::tw( 'code is compressed: ' . $codeb64_len ); $this->code = unserialize( gzinflate( $codeb64 ) ); } // first check $code is valid if ( $code === false || strlen( $code ) < 20 ) { AA_G404D && ISCLOG::epx( array( 'code === false', $code ) ); // set code to defaults $this->code = $this->get_default_code(); } elseif ( @unserialize( $codeb64 ) !== false ) { AA_G404D && ISCLOG::tw( 'IS OLD VERSION' ); $old_code = unserialize( $codeb64 ); $new_code_compressed = base64_encode( gzdeflate( serialize( $old_code ), 1 ) ); $new_code_uncompressed = unserialize( gzinflate( base64_decode( $new_code_compressed ) ) ); if ( $new_code_uncompressed === $old_code ) { AA_G404D && ISCLOG::tw( 'SWITCHING TO NEW VERSION' ); $this->code = $old_code; delete_option( 'askapache_google_404_code' ); add_option( 'askapache_google_404_code', $new_code_compressed, '', 'no' ); } else { AA_G404D && ISCLOG::tw( 'NOT SWITCHING TO NEW VERSION' ); } } else { AA_G404D && ISCLOG::tw( 'NEW VERSION ALREADY' ); $this->code = $code; } // default options $default_options = $this->get_default_options(); // current options $options = get_option( 'askapache_google_404_options' ); // first check $options is valid or set to defaults if ( $options === false || ! is_array( $options ) ) { AA_G404D && ISCLOG::epx( 'options === false or not array!' ); $options = $default_options; } else { // the default_options keys $default_options_keys = array_keys( $default_options ); sort( $default_options_keys ); // keys to current options $options_keys = array_keys( $options ); sort( $options_keys ); if ( $default_options_keys != $options_keys ) { AA_G404D && ISCLOG::epx( 'default_options_keys != options_keys' ); foreach ( $options as $k => $v ) { AA_G404D && ISCLOG::tw( "{$k} => {$v}" ); if ( array_key_exists( $k, $default_options ) ) { AA_G404D && ISCLOG::epx( "{$k} => {$v}" ); $default_options[ $k ] = $v; } } // no set the options to the newly updated default_options $options = $default_options; } } // get legacy analytics_key and save to options if ( ! array_key_exists( 'analytics_key', $options ) || empty( $options['analytics_key'] ) ) { AA_G404D && ISCLOG::tw( 'searching for analytics_key' ); $analytics_key = get_option( 'aa_google_404_analytics_key' ); // UA-732153-7 $options['analytics_key'] = ( $analytics_key !== false && strlen( $analytics_key ) > 3 ) ? $analytics_key : ''; } // update 404_handler in case of __DIR__ changed if ( strpos( $options['404_handler'], 'plugins/askapache-google-404/404.php' ) !== false ) { $options['404_handler'] = __DIR__ . '/404.php'; } // now set this->options to newly created options $this->options = $options; // ------------------------------------------------------------------------------------------------------ // delete these unused options delete_option( 'aa_google_404_api_key' ); delete_option( 'aa_google_404_adsense_key' ); delete_option( 'aa_google_404_analytics_key' ); // Save all these variables to database $this->save_options(); AA_G404D_F && ISCLOG::ti(); } /** * Loads this->code * * @return void */ function load_code() { AA_G404D_F && ISCLOG::ti(); // get code $code = get_option( 'askapache_google_404_code' ); // code decoded $code_decoded = ( $code !== false ) ? base64_decode( $code ) : ''; // if 46 empty $code_decoded_len = strlen( $code_decoded ); if ( $code_decoded_len === 46 ) { AA_G404D && ISCLOG::tw( 'code is empty! Getting and saving default code' ); // original code that comes with plugin $this->code = $this->get_default_code(); $this->save_options(); AA_G404D_F && ISCLOG::ti(); return; } // check if code is serialized already, indicating it is not using the newer compression if ( substr( $code_decoded, 0, 2 ) === 'a:' ) { AA_G404D && ISCLOG::tw( 'code looks to be uncompressed: ' . $code_decoded ); $code = base64_encode( gzdeflate( $code_decoded, 1 ) ); if ( strlen( $code ) > 4 ) { $this->code = $code; update_option( 'askapache_google_404_code', $code ); } } else { AA_G404D && ISCLOG::tw( 'code is compressed: ' . $code_decoded_len ); $this->code = unserialize( gzinflate( $code_decoded ) ); //AA_G404D && ISCLOG::epx( $this->code ); } AA_G404D_F && ISCLOG::ti(); } /** * Loads options named by opts array into correspondingly named class vars * * @return void */ function load_options() { AA_G404D_F && ISCLOG::ti(); // get options $this->options = get_option( 'askapache_google_404_options' ); // first try get_option, then parse this __FILE__ $this->plugin = $this->get_plugin_data(); AA_G404D_F && ISCLOG::ti(); } /** * Saves options from class vars passed in by opts array and the adsense key and api key * * @return void */ function save_options() { AA_G404D_F && ISCLOG::ti(); // save options update_option( 'askapache_google_404_options', $this->options ); // save plugin update_option( 'askapache_google_404_plugin', $this->plugin ); // save code if ( ! empty( $this->code ) && is_array( $this->code ) && array_key_exists( 'css', $this->code ) ) { //$code = base64_encode( serialize( $this->code ) ); $code = base64_encode( gzdeflate( serialize( $this->code ), 1 ) ); if ( strlen( $code ) > 46 ) { AA_G404D && ISCLOG::tw( "saving askapache_google_404_code as: {$code}" ); update_option( 'askapache_google_404_code', $code ); } else { AA_G404D && ISCLOG::tw( "NOT saving askapache_google_404_code as: {$code}" ); } } else { AA_G404D && ISCLOG::tw( 'this->code is empty! not saving' ); } AA_G404D_F && ISCLOG::ti(); } /** * this plugin has to protect the code as it is displayed live on error pages, a prime target for malicious crackers and spammers * can someone help me add the proper code to make sure everything is escaped correctly? * * @return void */ function handle_post() { AA_G404D_F && ISCLOG::ti(); // if current user does not have manage_options rights, then DIE if ( ! current_user_can( 'manage_options' ) ) { wp_die( __( 'You do not have sufficient permissions to manage options for this site.' ) ); } // verify nonce, if not verified, then DIE if ( isset( $_POST[ "_{$this->plugin['nonce']}" ] ) ) { wp_verify_nonce( $_POST[ "_{$this->plugin['nonce']}" ], $this->plugin['nonce'] ) || wp_die( __( 'ERROR: Incorrect Form Submission, please try again.' ) ); } elseif ( isset( $_POST['ag4_action_reset'] ) ) { wp_verify_nonce( $_POST['ag4_action_reset'], 'ag4_action_reset_nonce' ) || wp_die( __( 'ERROR: Incorrect Form Submission, please try again.' ) ); } // resets options to default values if ( isset( $_POST['ag4_action_reset'] ) ) { $this->reset_options(); return; } // load up the current options from the database $this->load_options(); // process absolute integer options foreach ( array( 'recent_num', 'tag_cloud_num' ) as $k ) { $this->options[ $k ] = ( ( isset( $_POST[ "ag4_{$k}" ] ) ) ? absint( $_POST[ "ag4_{$k}" ] ) : absint( $this->options[ $k ] ) ); } // process options of type string foreach ( array( 'cse_id', 'analytics_key', 'robots_tag', '404_handler' ) as $k ) { $this->options[ $k ] = ( ( isset( $_POST[ "ag4_{$k}" ] ) && ! empty( $_POST[ "ag4_{$k}" ] ) ) ? $_POST[ "ag4_{$k}" ] : $this->options[ $k ] ); } // process on ('1' ) or off ('0' ) options $on_off_options = array( 'enabled', 'robots_meta', 'recent_posts', 'tag_cloud', 'analytics_log', ); foreach ( $on_off_options as $k ) { $this->options[ $k ] = ( ( ! isset( $_POST[ "ag4_{$k}" ] ) ) ? '0' : '1' ); } // TODO: Nothing :) foreach ( array( 'analytics_url' ) as $k ) { if ( isset( $_POST[ "ag4_{$k}" ] ) ) { $this->options[ $k ] = stripslashes( $_POST[ "ag4_{$k}" ] ); } } // process incoming unfiltered code foreach ( array( 'css', 'html' ) as $k ) { if ( isset( $_POST[ "ag4_{$k}" ] ) && strlen( $_POST[ "ag4_{$k}" ] ) > 10 ) { $this->code[ $k ] = stripslashes( $_POST[ "ag4_{$k}" ] ); } } // Save code and options arrays to database $this->save_options(); AA_G404D_F && ISCLOG::ti(); } /** * Gets and sets the default values for the plugin options, then saves them * * @return void */ function reset_options() { AA_G404D_F && ISCLOG::ti(); // get all the plugin array data $this->plugin = $this->get_plugin_data( true ); // original code that comes with plugin $this->code = $this->get_default_code(); // get default options $this->options = $this->get_default_options(); // Save all these variables to database $this->save_options(); AA_G404D_F && ISCLOG::ti(); } /** * Gets the default $this->options * * @return array Array of options */ function get_default_options() { AA_G404D_F && ISCLOG::ti(); $handler = file_exists( TEMPLATEPATH . '/404.php' ) ? TEMPLATEPATH . '/404.php' : __DIR__ . '/404.php'; $ga = isset( $this->options['analytics_key'], $this->options['analytics_key'][5] ) ? $this->options['analytics_key'] : ''; $cse = isset( $this->options['cse_id'], $this->options['cse_id'][15] ) ? $this->options['cse_id'] : 'partner-pub-4356884677303281:hcqlgw-sn16'; // default options $options = array( 'cse_id' => $cse, // partner-pub-4356884677303281:hcqlgw-sn16 'analytics_key' => $ga, // UA-732153-7 'analytics_url' => '"/404/?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer', 'enabled' => '1', // 404 error handling is ON by default 'analytics_log' => '1', // 'robots_meta' => '1', // adding noindex,follow robot meta tag to error pages is ON by default 'robots_tag' => 'noindex,follow', // the value of the robot meta on error pages 'recent_posts' => '1', // showing recent posts on error pages is ON by default 'recent_num' => 6, // number of recent posts to show 'tag_cloud' => '1', // showing a tag cloud on error pages is ON by default 'tag_cloud_num' => 30, // number tags used to create cloud '404_handler' => $handler, // the file location of 404 template ); AA_G404D_F && ISCLOG::ti(); return $options; } /** * Gets the default code for css and html * * @return array original_code with 3 keys */ function get_default_code() { AA_G404D_F && ISCLOG::ti(); $original_code = array( 'css' => '#g404ajax {width:99%;overflow:hidden;margin-left:2px;}' . "\n" . '#g404ajax .gsc-control-cse,' . "\n" . '#g404ajax .gsc-webResult.gsc-result,' . "\n" . '#g404ajax .gsc-results .gsc-imageResult,' . "\n" . '#g404ajax .cse .gsc-webResult.gsc-result,' . "\n" . '#g404ajax .gsc-imageResult-column,' . "\n" . '#g404ajax .gsc-imageResult-classic {border:0};', 'html' => '
For super-advanced users, or those with access and knowledge of Apache .htaccess/httpd.conf files';
$help .= ' you should check that your error pages are correctly returning a 404 Not Found';
$help .= ' HTTP Header and not a 200 OK Header which appears to be the default for many WP installs, this plugin attempts to fix this using PHP, but the best way I have found';
$help .= ' is to add the following to your .htaccess file.
ErrorDocument 404 /index.php?error=404' . "\n" . 'Redirect 404 /index.php?error=404'; $help .= '
You can check your headers by requesting a bad url on your site using my online tool Advanced HTTP Headers.
'; $help .= 'The goal of this plugin is to boost your sites SEO by telling search engines to ignore your error pages, with the focus on human users to increase people staying on your site and being'; $help .= ' able to find what they were originally looking for on your site. Because I am obsessed with fast web pages, many various speed/efficiency improvements are also on the horizon.
'; $help .= 'Another feature that I am using with beta versions of this plugin, is tracking information for you to go over at your leisure, to fix recurring problems. The information is collected'; $help .= ' is the requested url that wasnt found, the referring url that contains the invalid link.
'; $help .= 'The reason I didnt include it in this release is because for sites like AskApache with a very high volume of traffic (and thus 404 requests) this feature can create a bottleneck and '; $help .= 'slow down or freeze a blog if thousands of 404 errors are being requested and saved to the database. This could also very quickly be used by malicious entities as a Denial of Service '; $help .= 'attack. So I am figuring out and putting into place limits.. like once a specific requested url resulting in a not found error has been requested 100x in a day, an email is sent to the '; $help .= 'blog administrator. But to prevent Email DoS and similar problems with the number and interval of emails allowed by your email provider other considerations on limits need to be examined.
'; $help .= 'Please visit AskApache.com or send me an email at webmaster@askapache.com
options[ $id ], false ) . ' />';
echo "
";
echo "
";
echo "
options[ $id ] ) ? $this->options[ $id ] : '' ) . "' />
Expect:',
422 => 'The server understands the media type of the request entity, but was unable to process the contained instructions.',
423 => 'The requested resource is currently locked. The lock must be released or proper identification given before the method can be applied.',
424 => 'The method could not be performed on the resource because the requested action depended on another action and that other action failed.',
426 => 'The requested resource can only be retrieved using SSL. Either upgrade your client, or try requesting the page using https://',
501 => '%M% to %U% not supported.',
502 => 'The proxy server received an invalid response from an upstream server.',
503 => 'The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.',
504 => 'The proxy server did not receive a timely response from the upstream server.',
506 => 'A variant for the requested resource %U% is itself a negotiable resource. This indicates a configuration error.',
507 => 'The method could not be performed. There is insufficient free space left in your storage allocation.',
510 => 'A mandatory extension policy in the request is not accepted by the server for this resource.',
);
$this->msg = ( array_key_exists( $this->sc, $asc ) ? str_replace( array( '%U%', '%M%' ), array( $this->uri, $this->req_method ), $asc[ $this->sc ] ) : 'Error' );
unset( $asc );
}
// send headers
@header( "{$this->protocol} {$this->sc} {$this->reason}", 1, $this->sc );
@header( "Status: {$this->sc} {$this->reason}", 1, $this->sc );
// Always close connections
@header( 'Connection: close', 1 );
if ( in_array( $this->sc, array( 400, 403, 405 ), true ) || $this->sc > 499 ) {
// Method Not Allowed
if ( $this->sc === 405 ) {
@header( 'Allow: GET,HEAD,POST,OPTIONS,TRACE', 1, 405 );
}
echo "\n\n" . esc_html( $this->msg ) . "
\n
' . wp_tag_cloud( array( 'echo' => false ) ) . '
' : '' ); $sr = array( '%error_title%' => $this->sc . ' ' . $this->reason, '%recent_posts%' => $recent, '%google%' => $google, '%tag_cloud%' => $tag_cloud, ); echo str_replace( array_keys( $sr ), array_values( $sr ), $AA_G404->code['html'] ); AA_G404D_F && ISCLOG::ti(); } /** * Output code in the header * @return void */ function output_head() { AA_G404D_F && ISCLOG::ti(); global $AA_G404; if ( ! is_object( $AA_G404 ) ) { AA_G404D && ISCLOG::tw( 'AA_G404 NOT AN OBJECT' ); $AA_G404 = aa_g404_get_object(); } if ( $AA_G404->options['analytics_log'] === '1' ) : ?> options['robots_meta'] === '1' ) { echo '' . "\n"; } ?> output(); AA_G404D_F && ISCLOG::ti(); } /** * A super efficient way to add the AA_G404->init() function to wordpress actions on init. * * @return void */ function aa_g404_init() { AA_G404D_F && ISCLOG::ti(); global $AA_G404; if ( ! is_object( $AA_G404 ) ) { AA_G404D && ISCLOG::tw( 'AA_G404 NOT AN OBJECT' ); $AA_G404 = aa_g404_get_object(); } $AA_G404->init(); AA_G404D_F && ISCLOG::ti(); } add_action( 'init', 'aa_g404_init', 0 ); endif; // ! function_exists( 'aa_google_404' ) if ( is_admin() ) : /** * Run on Activation * * @return void */ function aa_g404_activate() { AA_G404D_F && ISCLOG::ti(); global $AA_G404; if ( ! is_object( $AA_G404 ) ) { AA_G404D && ISCLOG::tw( 'AA_G404 NOT AN OBJECT' ); $AA_G404 = aa_g404_get_object(); } $AA_G404->upgrade_settings(); AA_G404D_F && ISCLOG::ti(); } register_activation_hook( __FILE__, 'aa_g404_activate' ); /** * Deactivate * * @return void */ function aa_g404_deactivate() { AA_G404D_F && ISCLOG::ti(); // delete plugin option delete_option( 'askapache_google_404_plugin' ); AA_G404D_F && ISCLOG::ti(); } register_deactivation_hook( __FILE__, 'aa_g404_deactivate' ); /** * Uninstallation * * @return void */ function aa_g404_uninstall() { AA_G404D_F && ISCLOG::ti(); // delete options delete_option( 'askapache_google_404_plugin' ); delete_option( 'askapache_google_404_code' ); delete_option( 'askapache_google_404_options' ); delete_option( 'askapache_google_404_orig_code' ); delete_option( 'askapache_google_404_iframe_one_time' ); delete_option( 'aa_google_404_api_key' ); delete_option( 'aa_google_404_cse_id' ); delete_option( 'aa_google_404_analytics_key' ); AA_G404D_F && ISCLOG::ti(); } register_uninstall_hook( __FILE__, 'aa_g404_uninstall' ); /** * Add options link to plugin listing in backend * * @return void */ function aa_g404_plugin_action_links( $l ) { return array_merge( array( 'Settings' ), $l ); } add_filter( 'plugin_action_links_askapache-google-404/askapache-google-404.php', 'aa_g404_plugin_action_links' ); /** * JS to add to plugin-specific footer * * @return void */ function aa_g404_admin_footer_settings_page() { AA_G404D_F && ISCLOG::ti(); ?>