From ba599f58e4d43005732659b946bf6f13beaa7607 Mon Sep 17 00:00:00 2001 From: JasWSInc Date: Fri, 23 May 2014 20:09:50 -0800 Subject: [PATCH 01/18] Reformat, https://github.com/WebSharks/wp-redirects/issues --- wp-redirects/wp-redirects.php | 470 +++++++++++++++++----------------- 1 file changed, 235 insertions(+), 235 deletions(-) diff --git a/wp-redirects/wp-redirects.php b/wp-redirects/wp-redirects.php index 19a02b2..eff32d7 100644 --- a/wp-redirects/wp-redirects.php +++ b/wp-redirects/wp-redirects.php @@ -22,301 +22,301 @@ class wp_redirects // WP Redirects; from anywhere — to anywhere. public static $roles_edit_caps = array(); // WP Roles; as array. public static function init() // Initialize WP Redirects. - { - load_plugin_textdomain('wp-redirects'); + { + load_plugin_textdomain('wp-redirects'); - if(WP_REDIRECT_ROLES_ALL_CAPS) // Specific Roles? - wp_redirects::$roles_all_caps = // Convert these to an array. - preg_split('/[\s;,]+/', WP_REDIRECT_ROLES_ALL_CAPS, NULL, PREG_SPLIT_NO_EMPTY); - wp_redirects::$roles_all_caps = apply_filters('wp_redirect_roles_all_caps', wp_redirects::$roles_all_caps); + if(WP_REDIRECT_ROLES_ALL_CAPS) // Specific Roles? + wp_redirects::$roles_all_caps = // Convert these to an array. + preg_split('/[\s;,]+/', WP_REDIRECT_ROLES_ALL_CAPS, NULL, PREG_SPLIT_NO_EMPTY); + wp_redirects::$roles_all_caps = apply_filters('wp_redirect_roles_all_caps', wp_redirects::$roles_all_caps); - if(WP_REDIRECT_ROLES_EDIT_CAPS) // Specific Roles? - wp_redirects::$roles_edit_caps = // Convert these to an array. - preg_split('/[\s;,]+/', WP_REDIRECT_ROLES_EDIT_CAPS, NULL, PREG_SPLIT_NO_EMPTY); - wp_redirects::$roles_edit_caps = apply_filters('wp_redirect_roles_edit_caps', wp_redirects::$roles_edit_caps); + if(WP_REDIRECT_ROLES_EDIT_CAPS) // Specific Roles? + wp_redirects::$roles_edit_caps = // Convert these to an array. + preg_split('/[\s;,]+/', WP_REDIRECT_ROLES_EDIT_CAPS, NULL, PREG_SPLIT_NO_EMPTY); + wp_redirects::$roles_edit_caps = apply_filters('wp_redirect_roles_edit_caps', wp_redirects::$roles_edit_caps); - wp_redirects::register(); + wp_redirects::register(); - wp_redirects::redirect_uri_patterns(); - add_action('wp', 'wp_redirects::redirect_redirects', 1); + wp_redirects::redirect_uri_patterns(); + add_action('wp', 'wp_redirects::redirect_redirects', 1); - add_action('add_meta_boxes_'.($post_type = 'redirect'), 'wp_redirects::meta_boxes'); - add_action('save_post', 'wp_redirects::meta_boxes_save'); - } + add_action('add_meta_boxes_'.($post_type = 'redirect'), 'wp_redirects::meta_boxes'); + add_action('save_post', 'wp_redirects::meta_boxes_save'); + } public static function register() - { - $post_type_args = array - ( - 'public' => TRUE, 'exclude_from_search' => TRUE, - 'map_meta_cap' => TRUE, 'capability_type' => array('redirect', 'redirects'), - 'rewrite' => array('slug' => 'r', 'with_front' => FALSE), - 'supports' => array('title', 'author', 'revisions') - ); - $post_type_args['labels'] = array - ( - 'name' => __('Redirects', 'wp-redirects'), - 'singular_name' => __('Redirect', 'wp-redirects'), - 'add_new' => __('Add Redirect', 'wp-redirects'), - 'add_new_item' => __('Add New Redirect', 'wp-redirects'), - 'edit_item' => __('Edit Redirect', 'wp-redirects'), - 'new_item' => __('New Redirect', 'wp-redirects'), - 'all_items' => __('All Redirects', 'wp-redirects'), - 'view_item' => __('View Redirect', 'wp-redirects'), - 'search_items' => __('Search Redirects', 'wp-redirects'), - 'not_found' => __('No Redirects found', 'wp-redirects'), - 'not_found_in_trash' => __('No Redirects found in Trash', 'wp-redirects') - ); - register_post_type('redirect', $post_type_args); - - $taxonomy_args = array // Categories. - ( - 'public' => TRUE, 'show_admin_column' => TRUE, - 'hierarchical' => TRUE, // This will use category labels. - 'rewrite' => array('slug' => 'redirect-category', 'with_front' => FALSE), - 'capabilities' => array('assign_terms' => 'edit_redirects', - 'edit_terms' => 'edit_redirects', - 'manage_terms' => 'edit_others_redirects', - 'delete_terms' => 'delete_others_redirects') - ); - register_taxonomy('redirect_category', array('redirect'), $taxonomy_args); - } + { + $post_type_args = array + ( + 'public' => TRUE, 'exclude_from_search' => TRUE, + 'map_meta_cap' => TRUE, 'capability_type' => array('redirect', 'redirects'), + 'rewrite' => array('slug' => 'r', 'with_front' => FALSE), + 'supports' => array('title', 'author', 'revisions') + ); + $post_type_args['labels'] = array + ( + 'name' => __('Redirects', 'wp-redirects'), + 'singular_name' => __('Redirect', 'wp-redirects'), + 'add_new' => __('Add Redirect', 'wp-redirects'), + 'add_new_item' => __('Add New Redirect', 'wp-redirects'), + 'edit_item' => __('Edit Redirect', 'wp-redirects'), + 'new_item' => __('New Redirect', 'wp-redirects'), + 'all_items' => __('All Redirects', 'wp-redirects'), + 'view_item' => __('View Redirect', 'wp-redirects'), + 'search_items' => __('Search Redirects', 'wp-redirects'), + 'not_found' => __('No Redirects found', 'wp-redirects'), + 'not_found_in_trash' => __('No Redirects found in Trash', 'wp-redirects') + ); + register_post_type('redirect', $post_type_args); + + $taxonomy_args = array // Categories. + ( + 'public' => TRUE, 'show_admin_column' => TRUE, + 'hierarchical' => TRUE, // This will use category labels. + 'rewrite' => array('slug' => 'redirect-category', 'with_front' => FALSE), + 'capabilities' => array('assign_terms' => 'edit_redirects', + 'edit_terms' => 'edit_redirects', + 'manage_terms' => 'edit_others_redirects', + 'delete_terms' => 'delete_others_redirects') + ); + register_taxonomy('redirect_category', array('redirect'), $taxonomy_args); + } public static function caps($action) - { - $all_caps = array // The ability to manage (all caps). - ( - 'edit_redirects', - 'edit_others_redirects', - 'edit_published_redirects', - 'edit_private_redirects', - - 'publish_redirects', - - 'delete_redirects', - 'delete_private_redirects', - 'delete_published_redirects', - 'delete_others_redirects', - - 'read_private_redirects' - ); - if($action === 'deactivate') // All on deactivate. - $_roles = array_keys($GLOBALS['wp_roles']->roles); - else $_roles = wp_redirects::$roles_all_caps; - - foreach($_roles as $_role) if(is_object($_role = get_role($_role))) - foreach($all_caps as $_cap) switch($action) - { - case 'activate': - $_role->add_cap($_cap); - break; - - case 'deactivate': - $_role->remove_cap($_cap); - break; - } - unset($_roles, $_role, $_cap); // Housekeeping. - - $edit_caps = array // The ability to edit/publish/delete. - ( - 'edit_redirects', - 'edit_published_redirects', - - 'publish_redirects', - - 'delete_redirects', - 'delete_published_redirects' - ); - if($action === 'deactivate') // All on deactivate. - $_roles = array_keys($GLOBALS['wp_roles']->roles); - else $_roles = wp_redirects::$roles_edit_caps; - - foreach($_roles as $_role) if(is_object($_role = get_role($_role))) - foreach((($action === 'deactivate') ? $all_caps : $edit_caps) as $_cap) switch($action) - { - case 'activate': - $_role->add_cap($_cap); - break; - - case 'deactivate': - $_role->remove_cap($_cap); - break; - } - unset($_roles, $_role, $_cap); // Housekeeping. - } + { + $all_caps = array // The ability to manage (all caps). + ( + 'edit_redirects', + 'edit_others_redirects', + 'edit_published_redirects', + 'edit_private_redirects', + + 'publish_redirects', + + 'delete_redirects', + 'delete_private_redirects', + 'delete_published_redirects', + 'delete_others_redirects', + + 'read_private_redirects' + ); + if($action === 'deactivate') // All on deactivate. + $_roles = array_keys($GLOBALS['wp_roles']->roles); + else $_roles = wp_redirects::$roles_all_caps; + + foreach($_roles as $_role) if(is_object($_role = get_role($_role))) + foreach($all_caps as $_cap) switch($action) + { + case 'activate': + $_role->add_cap($_cap); + break; + + case 'deactivate': + $_role->remove_cap($_cap); + break; + } + unset($_roles, $_role, $_cap); // Housekeeping. + + $edit_caps = array // The ability to edit/publish/delete. + ( + 'edit_redirects', + 'edit_published_redirects', + + 'publish_redirects', + + 'delete_redirects', + 'delete_published_redirects' + ); + if($action === 'deactivate') // All on deactivate. + $_roles = array_keys($GLOBALS['wp_roles']->roles); + else $_roles = wp_redirects::$roles_edit_caps; + + foreach($_roles as $_role) if(is_object($_role = get_role($_role))) + foreach((($action === 'deactivate') ? $all_caps : $edit_caps) as $_cap) switch($action) + { + case 'activate': + $_role->add_cap($_cap); + break; + + case 'deactivate': + $_role->remove_cap($_cap); + break; + } + unset($_roles, $_role, $_cap); // Housekeeping. + } public static function redirect_redirects() - { - if(!($is_singular_redirect = is_singular('redirect'))) - return; // Nothing to do in this case. + { + if(!($is_singular_redirect = is_singular('redirect'))) + return; // Nothing to do in this case. - $to = (string)get_post_meta(get_the_ID(), 'wp_redirect_to', TRUE); - $to = preg_replace_callback('/%%\\\$([^\[]+?)(.+?)%%/i', 'wp_redirects::_url_e_gprcs_value', $to); - $to = preg_replace('/%%(.+?)%%/i', '', $to); // Ditch any remaining replacement codes. + $to = (string)get_post_meta(get_the_ID(), 'wp_redirect_to', TRUE); + $to = preg_replace_callback('/%%\\\$([^\[]+?)(.+?)%%/i', 'wp_redirects::_url_e_gprcs_value', $to); + $to = preg_replace('/%%(.+?)%%/i', '', $to); // Ditch any remaining replacement codes. - $to = // Cleanup any double slashes left over by replacement codes. - wp_redirects::trim(preg_replace('/(?get_results( + "SELECT `post_id`, `meta_value` AS `pattern`". // Meta value is pattern (possibly a regex pattern). + " FROM `".wp_redirects::wpdb()->postmeta."` WHERE `meta_key` = 'wp_redirect_from_uri_pattern' AND `meta_value` != ''". + " AND `post_id` IN(SELECT `ID` FROM `".wp_redirects::wpdb()->posts."`". // Every `redirect` ID. + " WHERE `post_type` = 'redirect' AND `post_status` = 'publish')"); + if(!is_array($patterns) || !$patterns) return; // Nothing to do in this case. + + foreach($patterns as $_pattern) // Iterate all redirection patterns. { - $patterns = // URI patterns. - wp_redirects::wpdb()->get_results( - "SELECT `post_id`, `meta_value` AS `pattern`". // Meta value is pattern (possibly a regex pattern). - " FROM `".wp_redirects::wpdb()->postmeta."` WHERE `meta_key` = 'wp_redirect_from_uri_pattern' AND `meta_value` != ''". - " AND `post_id` IN(SELECT `ID` FROM `".wp_redirects::wpdb()->posts."`". // Every `redirect` ID. - " WHERE `post_type` = 'redirect' AND `post_status` = 'publish')"); - if(!is_array($patterns) || !$patterns) return; // Nothing to do in this case. - - foreach($patterns as $_pattern) // Iterate all redirection patterns. - { - $_pattern_matches = $_is_regex = $_is_regex_matches = FALSE; // Initialize. - $_is_regex = (stripos($_pattern->pattern, 'regex:') === 0) ? TRUE : FALSE; + $_pattern_matches = $_is_regex = $_is_regex_matches = FALSE; // Initialize. + $_is_regex = (stripos($_pattern->pattern, 'regex:') === 0) ? TRUE : FALSE; - if(!$_is_regex && trim($_pattern->pattern, '/') === trim($_SERVER['REQUEST_URI'], '/')) - $_pattern_matches = TRUE; // Exact match in this case (after trimming). + if(!$_is_regex && trim($_pattern->pattern, '/') === trim($_SERVER['REQUEST_URI'], '/')) + $_pattern_matches = TRUE; // Exact match in this case (after trimming). - else if($_is_regex && @preg_match(trim(preg_replace('/^regex\:/i', '', $_pattern->pattern)), - $_SERVER['REQUEST_URI'], $_is_regex_matches) - ) $_pattern_matches = TRUE; // A matching regular expression. + else if($_is_regex && @preg_match(trim(preg_replace('/^regex\:/i', '', $_pattern->pattern)), + $_SERVER['REQUEST_URI'], $_is_regex_matches) + ) $_pattern_matches = TRUE; // A matching regular expression. - else continue; // Nothing to do in this case; NOT a matching pattern. + else continue; // Nothing to do in this case; NOT a matching pattern. - if(!($_to = (string)get_post_meta($_pattern->post_id, 'wp_redirect_to', TRUE))) - continue; // Stop here if there is nothing to redirect to. + if(!($_to = (string)get_post_meta($_pattern->post_id, 'wp_redirect_to', TRUE))) + continue; // Stop here if there is nothing to redirect to. - $_to = (($_is_regex && $_is_regex_matches) // Regex replacement codes for captured groups. - ? preg_replace_callback('/%%([0-9]+)%%/i', function ($m) use ($_is_regex_matches) - { - return urlencode((string)@$_is_regex_matches[$m[1]]); - }, $_to) : $_to); - $_to = preg_replace_callback('/%%\\\$([^\[]+?)(.+?)%%/i', 'wp_redirects::_url_e_gprcs_value', $_to); - $_to = preg_replace('/%%(.+?)%%/i', '', $_to); // Ditch any remaining replacement codes. + $_to = (($_is_regex && $_is_regex_matches) // Regex replacement codes for captured groups. + ? preg_replace_callback('/%%([0-9]+)%%/i', function ($m) use ($_is_regex_matches) + { + return urlencode((string)@$_is_regex_matches[$m[1]]); + }, $_to) : $_to); + $_to = preg_replace_callback('/%%\\\$([^\[]+?)(.+?)%%/i', 'wp_redirects::_url_e_gprcs_value', $_to); + $_to = preg_replace('/%%(.+?)%%/i', '', $_to); // Ditch any remaining replacement codes. - if(!empty($_GET) && get_post_meta($_pattern->post_id, 'wp_redirect_to_w_query_vars', TRUE)) - $_to = add_query_arg(urlencode_deep(wp_redirects::trim_strip_deep($_GET)), $_to); + if(!empty($_GET) && get_post_meta($_pattern->post_id, 'wp_redirect_to_w_query_vars', TRUE)) + $_to = add_query_arg(urlencode_deep(wp_redirects::trim_strip_deep($_GET)), $_to); - $_to = // Cleanup any double slashes left over by replacement codes. - wp_redirects::trim(preg_replace('/(?post_id, 'wp_redirect_status', TRUE))) ? (integer)$_status : 301; + $_status = (is_numeric($_status = get_post_meta($_pattern->post_id, 'wp_redirect_status', TRUE))) ? (integer)$_status : 301; - wp_redirect($_to, $_status).exit(); // Redirection URL w/ a possible custom status code. - } - unset($_pattern, $_is_regex, $_pattern_matches, $_is_regex_matches, $_to, $_status); // Housekeeping. + wp_redirect($_to, $_status).exit(); // Redirection URL w/ a possible custom status code. } + unset($_pattern, $_is_regex, $_pattern_matches, $_is_regex_matches, $_to, $_status); // Housekeeping. + } public static function _url_e_gprcs_value($m) - { - if(isset($m[1], $m[2]) && in_array(($gprcs = strtoupper($m[1])), array('_GET', '_POST', '_REQUEST', '_COOKIE', '_SESSION'), TRUE)) - if(strlen($element_w_brackets = $m[2]) && preg_match('/^(?:(?:\[(["\'])[a-z0-9 \._\-]+?\\1\])|(?:\[[0-9]+\]))+$/i', $element_w_brackets)) - eval('$value = urlencode(trim(stripslashes((string)@$'.$gprcs.$element_w_brackets.')));'); + { + if(isset($m[1], $m[2]) && in_array(($gprcs = strtoupper($m[1])), array('_GET', '_POST', '_REQUEST', '_COOKIE', '_SESSION'), TRUE)) + if(strlen($element_w_brackets = $m[2]) && preg_match('/^(?:(?:\[(["\'])[a-z0-9 \._\-]+?\\1\])|(?:\[[0-9]+\]))+$/i', $element_w_brackets)) + eval('$value = urlencode(trim(stripslashes((string)@$'.$gprcs.$element_w_brackets.')));'); - return (!empty($value)) ? $value : ''; // Default to empty string. - } + return (!empty($value)) ? $value : ''; // Default to empty string. + } public static function meta_boxes() - { - add_meta_box('wp-redirect', __('Redirect Configuration', 'wp-redirects'), // One meta box (for now). - 'wp_redirects::redirect_meta_box', 'redirect', 'normal', 'high'); - } + { + add_meta_box('wp-redirect', __('Redirect Configuration', 'wp-redirects'), // One meta box (for now). + 'wp_redirects::redirect_meta_box', 'redirect', 'normal', 'high'); + } public static function redirect_meta_box($post) - { - if(!is_object($post) || empty($post->ID) || !($post_id = $post->ID)) - return; // No can-do. Should NOT happen; but just in case. + { + if(!is_object($post) || empty($post->ID) || !($post_id = $post->ID)) + return; // No can-do. Should NOT happen; but just in case. - echo '
'."\n"; - echo '
'."\n"; - echo __('This is optional. It defaults to a value of 301 for redirection.', 'wp-redirects')."\n"; + echo '
'."\n"; + echo '
'."\n"; + echo __('This is optional. It defaults to a value of 301 for redirection.', 'wp-redirects')."\n"; - echo '
'."\n"; + echo '
'."\n"; - echo '
'."\n"; - echo '
'."\n"; - echo ' [?]'."\n"; + echo '
'."\n"; + echo '
'."\n"; + echo ' [?]'."\n"; - echo '
'."\n"; + echo '
'."\n"; - echo '
'."\n"; - echo '
'."\n"; - echo __('This is optional. By default, redirection simply occurs from the Permalink for this Redirection.', 'wp-redirects').'

'."\n"; - echo __('Redirecting from additional locations: This can be accomplished here with a pattern. By default, a pattern supplied here is caSe sensitive, using one exact comparison against $_SERVER[\'REQUEST_URI\']. However, it is possible to precede your pattern with: regex: to enable advanced regular expression pattern matching. Example: regex: /pattern/i. It is also possible to use regex Replacement Codes in your Redirection URL above, referencing any parenthesized subpatterns. For example: %%0%%, %%1%%, %%2%%.', 'wp-redirects')."\n"; + echo '
'."\n"; + echo '
'."\n"; + echo __('This is optional. By default, redirection simply occurs from the Permalink for this Redirection.', 'wp-redirects').'

'."\n"; + echo __('Redirecting from additional locations: This can be accomplished here with a pattern. By default, a pattern supplied here is caSe sensitive, using one exact comparison against $_SERVER[\'REQUEST_URI\']. However, it is possible to precede your pattern with: regex: to enable advanced regular expression pattern matching. Example: regex: /pattern/i. It is also possible to use regex Replacement Codes in your Redirection URL above, referencing any parenthesized subpatterns. For example: %%0%%, %%1%%, %%2%%.', 'wp-redirects')."\n"; - wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); - } + wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); + } public static function meta_boxes_save($post_id) - { - if(is_numeric($post_id) && (!defined('DOING_AUTOSAVE') || !DOING_AUTOSAVE) && ($_p = wp_redirects::trim_strip_deep($_POST))) - if(!empty($_p['wp_redirect_meta_boxes']) && wp_verify_nonce($_p['wp_redirect_meta_boxes'], 'wp-redirect-meta-boxes')) - if(!empty($_p['post_type']) && $_p['post_type'] === 'redirect' && current_user_can('edit_redirect', $post_id)) - { - if(isset($_p['wp_redirect_status'])) - update_post_meta($post_id, 'wp_redirect_status', (string)$_p['wp_redirect_status']); - - if(isset($_p['wp_redirect_to'])) - update_post_meta($post_id, 'wp_redirect_to', (string)$_p['wp_redirect_to']); - - if(isset($_p)) // A checkbox may (or may NOT) be set; we update in either case. - update_post_meta($post_id, 'wp_redirect_to_w_query_vars', (int)@$_p['wp_redirect_to_w_query_vars']); - - if(isset($_p['wp_redirect_from_uri_pattern'])) - update_post_meta($post_id, 'wp_redirect_from_uri_pattern', addslashes((string)$_p['wp_redirect_from_uri_pattern'])); - } - } + { + if(is_numeric($post_id) && (!defined('DOING_AUTOSAVE') || !DOING_AUTOSAVE) && ($_p = wp_redirects::trim_strip_deep($_POST))) + if(!empty($_p['wp_redirect_meta_boxes']) && wp_verify_nonce($_p['wp_redirect_meta_boxes'], 'wp-redirect-meta-boxes')) + if(!empty($_p['post_type']) && $_p['post_type'] === 'redirect' && current_user_can('edit_redirect', $post_id)) + { + if(isset($_p['wp_redirect_status'])) + update_post_meta($post_id, 'wp_redirect_status', (string)$_p['wp_redirect_status']); + + if(isset($_p['wp_redirect_to'])) + update_post_meta($post_id, 'wp_redirect_to', (string)$_p['wp_redirect_to']); + + if(isset($_p)) // A checkbox may (or may NOT) be set; we update in either case. + update_post_meta($post_id, 'wp_redirect_to_w_query_vars', (int)@$_p['wp_redirect_to_w_query_vars']); + + if(isset($_p['wp_redirect_from_uri_pattern'])) + update_post_meta($post_id, 'wp_redirect_from_uri_pattern', addslashes((string)$_p['wp_redirect_from_uri_pattern'])); + } + } public static function trim($value, $chars = NULL, $extra_chars = NULL) - { - return wp_redirects::trim_deep($value, $chars, $extra_chars); - } + { + return wp_redirects::trim_deep($value, $chars, $extra_chars); + } public static function trim_deep($value, $chars = NULL, $extra_chars = NULL) - { - $chars = (is_string($chars)) ? $chars : " \r\n\t\0\x0B"; - $chars = (is_string($extra_chars)) ? $chars.$extra_chars : $chars; + { + $chars = (is_string($chars)) ? $chars : " \r\n\t\0\x0B"; + $chars = (is_string($extra_chars)) ? $chars.$extra_chars : $chars; - if(is_array($value) || is_object($value)) // Deeply. - { - foreach($value as &$_value) - $_value = wp_redirects::trim_deep($_value, $chars); - unset($_value); // Housekeeping. + if(is_array($value) || is_object($value)) // Deeply. + { + foreach($value as &$_value) + $_value = wp_redirects::trim_deep($_value, $chars); + unset($_value); // Housekeeping. - return $value; - } - return trim((string)$value, $chars); + return $value; } + return trim((string)$value, $chars); + } public static function trim_strip_deep($value, $chars = NULL, $extra_chars = NULL) - { - return wp_redirects::trim_deep(stripslashes_deep($value), $chars, $extra_chars); - } + { + return wp_redirects::trim_deep(stripslashes_deep($value), $chars, $extra_chars); + } public static function activate() - { - wp_redirects::init(); - wp_redirects::caps('activate'); - flush_rewrite_rules(); - } + { + wp_redirects::init(); + wp_redirects::caps('activate'); + flush_rewrite_rules(); + } public static function deactivate() - { - wp_redirects::caps('deactivate'); - flush_rewrite_rules(); - } + { + wp_redirects::caps('deactivate'); + flush_rewrite_rules(); + } /** @return \wpdb */ public static function wpdb() - { - return $GLOBALS['wpdb']; - } + { + return $GLOBALS['wpdb']; + } } add_action('init', 'wp_redirects::init', 1); From 1f793953ae3eeb9f93438d6fc3acd29b3b709589 Mon Sep 17 00:00:00 2001 From: JasWSInc Date: Sat, 24 May 2014 22:42:28 -0800 Subject: [PATCH 02/18] Bug fix; $_GET should be passed through when requested by config. --- wp-redirects/wp-redirects.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/wp-redirects/wp-redirects.php b/wp-redirects/wp-redirects.php index eff32d7..4e06275 100644 --- a/wp-redirects/wp-redirects.php +++ b/wp-redirects/wp-redirects.php @@ -150,14 +150,19 @@ public static function redirect_redirects() if(!($is_singular_redirect = is_singular('redirect'))) return; // Nothing to do in this case. - $to = (string)get_post_meta(get_the_ID(), 'wp_redirect_to', TRUE); + $redirect_id = get_the_ID(); // Pull this one time only. + + $to = (string)get_post_meta($redirect_id, 'wp_redirect_to', TRUE); $to = preg_replace_callback('/%%\\\$([^\[]+?)(.+?)%%/i', 'wp_redirects::_url_e_gprcs_value', $to); $to = preg_replace('/%%(.+?)%%/i', '', $to); // Ditch any remaining replacement codes. $to = // Cleanup any double slashes left over by replacement codes. wp_redirects::trim(preg_replace('/(?post_id, 'wp_redirect_to_w_query_vars', TRUE)) - $_to = add_query_arg(urlencode_deep(wp_redirects::trim_strip_deep($_GET)), $_to); - $_to = // Cleanup any double slashes left over by replacement codes. wp_redirects::trim(preg_replace('/(?post_id, 'wp_redirect_to_w_query_vars', TRUE)) + $_to = add_query_arg(urlencode_deep(wp_redirects::trim_strip_deep($_GET)), $_to); + $_status = (is_numeric($_status = get_post_meta($_pattern->post_id, 'wp_redirect_status', TRUE))) ? (integer)$_status : 301; wp_redirect($_to, $_status).exit(); // Redirection URL w/ a possible custom status code. From 231eb769edc3798aad4e684f88942f2684688b5e Mon Sep 17 00:00:00 2001 From: JasWSInc Date: Mon, 11 Aug 2014 06:43:48 -0800 Subject: [PATCH 03/18] Adding Floobits-related files. Updating README. --- .floo | 3 +++ .flooignore | 6 ++++++ README.md | 4 ++++ 3 files changed, 13 insertions(+) create mode 100644 .floo create mode 100644 .flooignore diff --git a/.floo b/.floo new file mode 100644 index 0000000..c9fc70a --- /dev/null +++ b/.floo @@ -0,0 +1,3 @@ +{ + "url": "https://floobits.com/jaswsinc/wp-redirects" +} \ No newline at end of file diff --git a/.flooignore b/.flooignore new file mode 100644 index 0000000..ed824d3 --- /dev/null +++ b/.flooignore @@ -0,0 +1,6 @@ +extern +node_modules +tmp +vendor +.idea/workspace.xml +.idea/misc.xml diff --git a/README.md b/README.md index 240cdf6..d47eef3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ ## WordPress® Redirects Redirects (a new Post Type) for WordPress®. + +--- + +This project is now on Floobits too! [Watch us code](https://floobits.com/jaswsinc/wp-redirects/redirect) in real-time :-) Floobits status From ad859b87b1cac333186027f3cbc656580e40128a Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Thu, 11 Sep 2014 00:57:27 -0400 Subject: [PATCH 04/18] Keep track of redirect hits and last access time --- wp-redirects/admin-style.css | 2 + wp-redirects/wp-redirects.php | 111 +++++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 wp-redirects/admin-style.css diff --git a/wp-redirects/admin-style.css b/wp-redirects/admin-style.css new file mode 100644 index 0000000..9ebb9f0 --- /dev/null +++ b/wp-redirects/admin-style.css @@ -0,0 +1,2 @@ +.column-hits { width: 75px; } +.column-last_access { width: 150px; } \ No newline at end of file diff --git a/wp-redirects/wp-redirects.php b/wp-redirects/wp-redirects.php index 4e06275..5356303 100644 --- a/wp-redirects/wp-redirects.php +++ b/wp-redirects/wp-redirects.php @@ -18,7 +18,9 @@ class wp_redirects // WP Redirects; from anywhere — to anywhere. { + public static $roles_all_caps = array(); // WP Roles; as array. + public static $roles_edit_caps = array(); // WP Roles; as array. public static function init() // Initialize WP Redirects. @@ -42,6 +44,12 @@ public static function init() // Initialize WP Redirects. add_action('add_meta_boxes_'.($post_type = 'redirect'), 'wp_redirects::meta_boxes'); add_action('save_post', 'wp_redirects::meta_boxes_save'); + + add_action('manage_redirect_posts_custom_column', 'wp_redirects::show_admin_column_value', 10, 2); + add_action('pre_get_posts', 'wp_redirects::admin_column_orderby', 10, 1); + add_action('admin_enqueue_scripts', 'wp_redirects::load_custom_wp_admin_style'); + add_filter('manage_redirect_posts_columns', 'wp_redirects::add_admin_columns', 10, 1); + add_filter('manage_edit-redirect_sortable_columns', 'wp_redirects::register_sortable_admin_columns', 10, 1); } public static function register() @@ -165,7 +173,16 @@ public static function redirect_redirects() $status = (is_numeric($status = get_post_meta($redirect_id, 'wp_redirect_status', TRUE))) ? (integer)$status : 301; if($to && $status) // Redirection URL w/ a possible custom status code. + { + // Update hit counter for this redirect + $redirect_hits = (int)get_post_meta(get_the_ID(), 'wp_redirect_hits', TRUE) + 1; + update_post_meta(get_the_ID(), 'wp_redirect_hits', $redirect_hits); + + // Update last access time for this redirect + update_post_meta(get_the_ID(), 'wp_redirect_last_access', time()); + wp_redirect($to, $status).exit(); // It's a good day in Eureka :-) + } wp_redirect(home_url('/'), 301).exit(); // Default redirection (ALWAYS redirect). } @@ -213,6 +230,13 @@ public static function redirect_uri_patterns() $_status = (is_numeric($_status = get_post_meta($_pattern->post_id, 'wp_redirect_status', TRUE))) ? (integer)$_status : 301; + // Update hit counter for this redirect + $redirect_hits = (int)get_post_meta(get_the_ID(), 'wp_redirect_hits', TRUE) + 1; + update_post_meta(get_the_ID(), 'wp_redirect_hits', $redirect_hits); + + // Update last access time for this redirect + update_post_meta(get_the_ID(), 'wp_redirect_last_access', time()); + wp_redirect($_to, $_status).exit(); // Redirection URL w/ a possible custom status code. } unset($_pattern, $_is_regex, $_pattern_matches, $_is_regex_matches, $_to, $_status); // Housekeeping. @@ -229,8 +253,9 @@ public static function _url_e_gprcs_value($m) public static function meta_boxes() { - add_meta_box('wp-redirect', __('Redirect Configuration', 'wp-redirects'), // One meta box (for now). + add_meta_box('wp-redirect', __('Redirect Configuration', 'wp-redirects'), 'wp_redirects::redirect_meta_box', 'redirect', 'normal', 'high'); + add_meta_box('wp-redirect-stats', __('Redirection Statistics', 'wp-redirects'), 'wp_redirects::redirect_stats_meta_box', 'redirect', 'normal', 'high'); } public static function redirect_meta_box($post) @@ -258,6 +283,20 @@ public static function redirect_meta_box($post) wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); } + public static function redirect_stats_meta_box($post) + { + if(is_object($post) && !empty($post->ID) && ($post_id = $post->ID)) + { + echo __('Total Hits:', 'wp-redirects').' '.((get_post_meta($post_id, 'wp_redirect_hits', TRUE)) ? esc_attr(get_post_meta($post_id, 'wp_redirect_hits', TRUE)) : '0').' (reset)
'."\n"; + echo '
'."\n"; + echo ''; + + echo '
'."\n"; + + wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); + } + } + public static function meta_boxes_save($post_id) { if(is_numeric($post_id) && (!defined('DOING_AUTOSAVE') || !DOING_AUTOSAVE) && ($_p = wp_redirects::trim_strip_deep($_POST))) @@ -275,6 +314,12 @@ public static function meta_boxes_save($post_id) if(isset($_p['wp_redirect_from_uri_pattern'])) update_post_meta($post_id, 'wp_redirect_from_uri_pattern', addslashes((string)$_p['wp_redirect_from_uri_pattern'])); + + if(isset($_p['wp_redirect_hits'])) + update_post_meta($post_id, 'wp_redirect_hits', (int)$_p['wp_redirect_hits']); + + if(isset($_p['wp_redirect_last_access'])) + update_post_meta($post_id, 'wp_redirect_last_access', (int)$_p['wp_redirect_last_access']); } } @@ -322,6 +367,70 @@ public static function wpdb() { return $GLOBALS['wpdb']; } + + public static function add_admin_columns($columns) + { + return array_merge($columns, + array('hits' => __('Hits'), + 'last_access' => __('Last Access'))); + } + + public static function show_admin_column_value($column, $post_id) + { + switch($column) + { + case 'hits': + echo get_post_meta($post_id, 'wp_redirect_hits', TRUE); + break; + + case 'last_access': + if(get_post_meta($post_id, 'wp_redirect_last_access', TRUE) == '0') + { + echo __('Never', 'wp-redirects'); + } + elseif(get_post_meta($post_id, 'wp_redirect_last_access', TRUE)) + { + echo date(get_option('date_format'), get_post_meta($post_id, 'wp_redirect_last_access', TRUE)); + } + + break; + } + } + + public static function register_sortable_admin_columns($columns) + { + $columns['hits'] = 'hit'; + $columns['last_access'] = 'last_access'; + + return $columns; + } + + public static function admin_column_orderby($query) + { + if(!is_admin()) + return; + + $orderby = $query->get('orderby'); + + if('hit' == $orderby) + { + $query->set('meta_key', 'wp_redirect_hits'); + $query->set('orderby', 'meta_value_num'); + } + elseif('last_access' == $orderby) + { + $query->set('meta_key', 'wp_redirect_last_access'); + $query->set('orderby', 'meta_value_num'); + } + } + + public static function load_custom_wp_admin_style($hook) + { + if('edit.php' != $hook) // only load this style on the Edit posts admin screen + return; + wp_register_style('wp_redirects_wp_admin_css', plugin_dir_url(__FILE__).'admin-style.css', FALSE, '1.0.0'); + wp_enqueue_style('wp_redirects_wp_admin_css'); + } } add_action('init', 'wp_redirects::init', 1); From 0a769a252391d62c8269e7a70adee073971c4234 Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Thu, 11 Sep 2014 02:23:45 -0400 Subject: [PATCH 05/18] Refactor plugin to use WebSharks plugin format --- .../{ => client-s/css}/admin-style.css | 0 wp-redirects/wp-redirects.inc.php | 559 ++++++++++++++++++ wp-redirects/wp-redirects.php | 429 +------------- 3 files changed, 567 insertions(+), 421 deletions(-) rename wp-redirects/{ => client-s/css}/admin-style.css (100%) create mode 100644 wp-redirects/wp-redirects.inc.php diff --git a/wp-redirects/admin-style.css b/wp-redirects/client-s/css/admin-style.css similarity index 100% rename from wp-redirects/admin-style.css rename to wp-redirects/client-s/css/admin-style.css diff --git a/wp-redirects/wp-redirects.inc.php b/wp-redirects/wp-redirects.inc.php new file mode 100644 index 0000000..c2e1828 --- /dev/null +++ b/wp-redirects/wp-redirects.inc.php @@ -0,0 +1,559 @@ +file = preg_replace('/\.inc\.php$/', '.php', __FILE__); + $this->text_domain = str_replace('_', '-', __NAMESPACE__); + + add_action('after_setup_theme', array($this, 'setup')); + register_activation_hook($this->file, array($this, 'activate')); + register_deactivation_hook($this->file, array($this, 'deactivate')); + } + + public function setup() + { + do_action('before__'.__METHOD__, get_defined_vars()); + + load_plugin_textdomain($this->text_domain); + + $this->default_options = array( // Default options. + 'version' => $this->version + ); // Default options are merged with those defined by the site owner. + $options = (is_array($options = get_option(__NAMESPACE__.'_options'))) ? $options : array(); + $this->default_options = apply_filters(__METHOD__.'__default_options', $this->default_options, get_defined_vars()); + $this->options = array_merge($this->default_options, $options); // This considers old options also. + $this->options = apply_filters(__METHOD__.'__options', $this->options, get_defined_vars()); + + $this->cap = apply_filters(__METHOD__.'__cap', 'activate_plugins'); + + if(WP_REDIRECT_ROLES_ALL_CAPS) // Specific Roles? + $this->roles_all_caps = // Convert these to an array. + preg_split('/[\s;,]+/', WP_REDIRECT_ROLES_ALL_CAPS, NULL, PREG_SPLIT_NO_EMPTY); + $this->roles_all_caps = apply_filters('wp_redirect_roles_all_caps', $this->roles_all_caps); + + if(WP_REDIRECT_ROLES_EDIT_CAPS) // Specific Roles? + $this->roles_edit_caps = // Convert these to an array. + preg_split('/[\s;,]+/', WP_REDIRECT_ROLES_EDIT_CAPS, NULL, PREG_SPLIT_NO_EMPTY); + $this->roles_edit_caps = apply_filters('wp_redirect_roles_edit_caps', $this->roles_edit_caps); + + add_action('wp_loaded', array($this, 'actions')); + + $this->register(); + + $this->redirect_uri_patterns(); + add_action('wp', 'wp_redirects\plugin::redirect_redirects', 1); + + add_action('add_meta_boxes_'.($post_type = 'redirect'), 'wp_redirects\plugin::meta_boxes'); + add_action('save_post', 'wp_redirects\plugin::meta_boxes_save'); + + add_action('manage_redirect_posts_custom_column', 'wp_redirects\plugin::show_admin_column_value', 10, 2); + add_action('pre_get_posts', 'wp_redirects\plugin::admin_column_orderby', 10, 1); + add_filter('manage_redirect_posts_columns', 'wp_redirects\plugin::add_admin_columns', 10, 1); + add_filter('manage_edit-redirect_sortable_columns', 'wp_redirects\plugin::register_sortable_admin_columns', 10, 1); + + add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_styles')); + + add_action('admin_init', array($this, 'check_version')); + add_action('all_admin_notices', array($this, 'all_admin_notices')); + add_action('all_admin_notices', array($this, 'all_admin_errors')); + + do_action('after__'.__METHOD__, get_defined_vars()); + do_action(__METHOD__.'_complete', get_defined_vars()); + } + + public function register() + { + $post_type_args = array + ( + 'public' => TRUE, 'exclude_from_search' => TRUE, + 'map_meta_cap' => TRUE, 'capability_type' => array('redirect', 'redirects'), + 'rewrite' => array('slug' => 'r', 'with_front' => FALSE), + 'supports' => array('title', 'author', 'revisions') + ); + $post_type_args['labels'] = array + ( + 'name' => __('Redirects', 'wp-redirects'), + 'singular_name' => __('Redirect', 'wp-redirects'), + 'add_new' => __('Add Redirect', 'wp-redirects'), + 'add_new_item' => __('Add New Redirect', 'wp-redirects'), + 'edit_item' => __('Edit Redirect', 'wp-redirects'), + 'new_item' => __('New Redirect', 'wp-redirects'), + 'all_items' => __('All Redirects', 'wp-redirects'), + 'view_item' => __('View Redirect', 'wp-redirects'), + 'search_items' => __('Search Redirects', 'wp-redirects'), + 'not_found' => __('No Redirects found', 'wp-redirects'), + 'not_found_in_trash' => __('No Redirects found in Trash', 'wp-redirects') + ); + register_post_type('redirect', $post_type_args); + + $taxonomy_args = array // Categories. + ( + 'public' => TRUE, 'show_admin_column' => TRUE, + 'hierarchical' => TRUE, // This will use category labels. + 'rewrite' => array('slug' => 'redirect-category', 'with_front' => FALSE), + 'capabilities' => array('assign_terms' => 'edit_redirects', + 'edit_terms' => 'edit_redirects', + 'manage_terms' => 'edit_others_redirects', + 'delete_terms' => 'delete_others_redirects') + ); + register_taxonomy('redirect_category', array('redirect'), $taxonomy_args); + } + + public function url($file = '', $scheme = '') + { + static $plugin_directory; // Static cache. + + if(!isset($plugin_directory)) // Not cached yet? + $plugin_directory = rtrim(plugin_dir_url($this->file), '/'); + + $url = $plugin_directory.(string)$file; + + if($scheme) // A specific URL scheme? + $url = set_url_scheme($url, (string)$scheme); + + return apply_filters(__METHOD__, $url, get_defined_vars()); + } + + public function caps($action) + { + $all_caps = array // The ability to manage (all caps). + ( + 'edit_redirects', + 'edit_others_redirects', + 'edit_published_redirects', + 'edit_private_redirects', + + 'publish_redirects', + + 'delete_redirects', + 'delete_private_redirects', + 'delete_published_redirects', + 'delete_others_redirects', + + 'read_private_redirects' + ); + if($action === 'deactivate') // All on deactivate. + $_roles = array_keys($GLOBALS['wp_roles']->roles); + else $_roles = $this->roles_all_caps; + + foreach($_roles as $_role) if(is_object($_role = get_role($_role))) + foreach($all_caps as $_cap) switch($action) + { + case 'activate': + $_role->add_cap($_cap); + break; + + case 'deactivate': + $_role->remove_cap($_cap); + break; + } + unset($_roles, $_role, $_cap); // Housekeeping. + + $edit_caps = array // The ability to edit/publish/delete. + ( + 'edit_redirects', + 'edit_published_redirects', + + 'publish_redirects', + + 'delete_redirects', + 'delete_published_redirects' + ); + if($action === 'deactivate') // All on deactivate. + $_roles = array_keys($GLOBALS['wp_roles']->roles); + else $_roles = $this->roles_edit_caps; + + foreach($_roles as $_role) if(is_object($_role = get_role($_role))) + foreach((($action === 'deactivate') ? $all_caps : $edit_caps) as $_cap) switch($action) + { + case 'activate': + $_role->add_cap($_cap); + break; + + case 'deactivate': + $_role->remove_cap($_cap); + break; + } + unset($_roles, $_role, $_cap); // Housekeeping. + } + + public static function redirect_redirects() + { + if(!($is_singular_redirect = is_singular('redirect'))) + return; // Nothing to do in this case. + + $redirect_id = get_the_ID(); // Pull this one time only. + + $to = (string)get_post_meta($redirect_id, 'wp_redirect_to', TRUE); + $to = preg_replace_callback('/%%\\\$([^\[]+?)(.+?)%%/i', 'wp_redirects\plugin::_url_e_gprcs_value', $to); + $to = preg_replace('/%%(.+?)%%/i', '', $to); // Ditch any remaining replacement codes. + + $to = // Cleanup any double slashes left over by replacement codes. + plugin::trim(preg_replace('/(?wpdb()->get_results( + "SELECT `post_id`, `meta_value` AS `pattern`". // Meta value is pattern (possibly a regex pattern). + " FROM `".$this->wpdb()->postmeta."` WHERE `meta_key` = 'wp_redirect_from_uri_pattern' AND `meta_value` != ''". + " AND `post_id` IN(SELECT `ID` FROM `".$this->wpdb()->posts."`". // Every `redirect` ID. + " WHERE `post_type` = 'redirect' AND `post_status` = 'publish')"); + if(!is_array($patterns) || !$patterns) return; // Nothing to do in this case. + + foreach($patterns as $_pattern) // Iterate all redirection patterns. + { + $_pattern_matches = $_is_regex = $_is_regex_matches = FALSE; // Initialize. + $_is_regex = (stripos($_pattern->pattern, 'regex:') === 0) ? TRUE : FALSE; + + if(!$_is_regex && trim($_pattern->pattern, '/') === trim($_SERVER['REQUEST_URI'], '/')) + $_pattern_matches = TRUE; // Exact match in this case (after trimming). + + else if($_is_regex && @preg_match(trim(preg_replace('/^regex\:/i', '', $_pattern->pattern)), + $_SERVER['REQUEST_URI'], $_is_regex_matches) + ) $_pattern_matches = TRUE; // A matching regular expression. + + else continue; // Nothing to do in this case; NOT a matching pattern. + + if(!($_to = (string)get_post_meta($_pattern->post_id, 'wp_redirect_to', TRUE))) + continue; // Stop here if there is nothing to redirect to. + + $_to = (($_is_regex && $_is_regex_matches) // Regex replacement codes for captured groups. + ? preg_replace_callback('/%%([0-9]+)%%/i', function ($m) use ($_is_regex_matches) + { + return urlencode((string)@$_is_regex_matches[$m[1]]); + }, $_to) : $_to); + $_to = preg_replace_callback('/%%\\\$([^\[]+?)(.+?)%%/i', 'wp_redirects\plugin::_url_e_gprcs_value', $_to); + $_to = preg_replace('/%%(.+?)%%/i', '', $_to); // Ditch any remaining replacement codes. + + $_to = // Cleanup any double slashes left over by replacement codes. + plugin::trim(preg_replace('/(?post_id, 'wp_redirect_to_w_query_vars', TRUE)) + $_to = add_query_arg(urlencode_deep(plugin::trim_strip_deep($_GET)), $_to); + + $_status = (is_numeric($_status = get_post_meta($_pattern->post_id, 'wp_redirect_status', TRUE))) ? (integer)$_status : 301; + + // Update hit counter for this redirect + $redirect_hits = (int)get_post_meta(get_the_ID(), 'wp_redirect_hits', TRUE) + 1; + update_post_meta(get_the_ID(), 'wp_redirect_hits', $redirect_hits); + + // Update last access time for this redirect + update_post_meta(get_the_ID(), 'wp_redirect_last_access', time()); + + wp_redirect($_to, $_status).exit(); // Redirection URL w/ a possible custom status code. + } + unset($_pattern, $_is_regex, $_pattern_matches, $_is_regex_matches, $_to, $_status); // Housekeeping. + } + + public static function _url_e_gprcs_value($m) + { + if(isset($m[1], $m[2]) && in_array(($gprcs = strtoupper($m[1])), array('_GET', '_POST', '_REQUEST', '_COOKIE', '_SESSION'), TRUE)) + if(strlen($element_w_brackets = $m[2]) && preg_match('/^(?:(?:\[(["\'])[a-z0-9 \._\-]+?\\1\])|(?:\[[0-9]+\]))+$/i', $element_w_brackets)) + eval('$value = urlencode(trim(stripslashes((string)@$'.$gprcs.$element_w_brackets.')));'); + + return (!empty($value)) ? $value : ''; // Default to empty string. + } + + public static function meta_boxes() + { + add_meta_box('wp-redirect', __('Redirect Configuration', 'wp-redirects'), + 'wp_redirects\plugin::redirect_meta_box', 'redirect', 'normal', 'high'); + add_meta_box('wp-redirect-stats', __('Redirection Statistics', 'wp-redirects'), 'wp_redirects\plugin::redirect_stats_meta_box', 'redirect', 'normal', 'high'); + } + + public static function redirect_meta_box($post) + { + if(!is_object($post) || empty($post->ID) || !($post_id = $post->ID)) + return; // No can-do. Should NOT happen; but just in case. + + echo '
'."\n"; + echo '
'."\n"; + echo __('This is optional. It defaults to a value of 301 for redirection.', 'wp-redirects')."\n"; + + echo '
'."\n"; + + echo '
'."\n"; + echo '
'."\n"; + echo ' [?]'."\n"; + + echo '
'."\n"; + + echo '
'."\n"; + echo '
'."\n"; + echo __('This is optional. By default, redirection simply occurs from the Permalink for this Redirection.', 'wp-redirects').'

'."\n"; + echo __('Redirecting from additional locations: This can be accomplished here with a pattern. By default, a pattern supplied here is caSe sensitive, using one exact comparison against $_SERVER[\'REQUEST_URI\']. However, it is possible to precede your pattern with: regex: to enable advanced regular expression pattern matching. Example: regex: /pattern/i. It is also possible to use regex Replacement Codes in your Redirection URL above, referencing any parenthesized subpatterns. For example: %%0%%, %%1%%, %%2%%.', 'wp-redirects')."\n"; + + wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); + } + + public static function redirect_stats_meta_box($post) + { + if(is_object($post) && !empty($post->ID) && ($post_id = $post->ID)) + { + echo __('Total Hits:', 'wp-redirects').' '.((get_post_meta($post_id, 'wp_redirect_hits', TRUE)) ? esc_attr(get_post_meta($post_id, 'wp_redirect_hits', TRUE)) : '0').' (reset)
'."\n"; + echo '
'."\n"; + echo ''; + + echo '
'."\n"; + + wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); + } + } + + public static function meta_boxes_save($post_id) + { + if(is_numeric($post_id) && (!defined('DOING_AUTOSAVE') || !DOING_AUTOSAVE) && ($_p = plugin::trim_strip_deep($_POST))) + if(!empty($_p['wp_redirect_meta_boxes']) && wp_verify_nonce($_p['wp_redirect_meta_boxes'], 'wp-redirect-meta-boxes')) + if(!empty($_p['post_type']) && $_p['post_type'] === 'redirect' && current_user_can('edit_redirect', $post_id)) + { + if(isset($_p['wp_redirect_status'])) + update_post_meta($post_id, 'wp_redirect_status', (string)$_p['wp_redirect_status']); + + if(isset($_p['wp_redirect_to'])) + update_post_meta($post_id, 'wp_redirect_to', (string)$_p['wp_redirect_to']); + + if(isset($_p)) // A checkbox may (or may NOT) be set; we update in either case. + update_post_meta($post_id, 'wp_redirect_to_w_query_vars', (int)@$_p['wp_redirect_to_w_query_vars']); + + if(isset($_p['wp_redirect_from_uri_pattern'])) + update_post_meta($post_id, 'wp_redirect_from_uri_pattern', addslashes((string)$_p['wp_redirect_from_uri_pattern'])); + + if(isset($_p['wp_redirect_hits'])) + update_post_meta($post_id, 'wp_redirect_hits', (int)$_p['wp_redirect_hits']); + + if(isset($_p['wp_redirect_last_access'])) + update_post_meta($post_id, 'wp_redirect_last_access', (int)$_p['wp_redirect_last_access']); + } + } + + public static function trim($value, $chars = NULL, $extra_chars = NULL) + { + return plugin::trim_deep($value, $chars, $extra_chars); + } + + public static function trim_deep($value, $chars = NULL, $extra_chars = NULL) + { + $chars = (is_string($chars)) ? $chars : " \r\n\t\0\x0B"; + $chars = (is_string($extra_chars)) ? $chars.$extra_chars : $chars; + + if(is_array($value) || is_object($value)) // Deeply. + { + foreach($value as &$_value) + $_value = plugin::trim_deep($_value, $chars); + unset($_value); // Housekeeping. + + return $value; + } + return trim((string)$value, $chars); + } + + public static function trim_strip_deep($value, $chars = NULL, $extra_chars = NULL) + { + return plugin::trim_deep(stripslashes_deep($value), $chars, $extra_chars); + } + + /** @return \wpdb */ + public function wpdb() + { + return $GLOBALS['wpdb']; + } + + public static function add_admin_columns($columns) + { + return array_merge($columns, + array('hits' => __('Hits'), + 'last_access' => __('Last Access'))); + } + + public static function show_admin_column_value($column, $post_id) + { + switch($column) + { + case 'hits': + echo get_post_meta($post_id, 'wp_redirect_hits', TRUE); + break; + + case 'last_access': + if(get_post_meta($post_id, 'wp_redirect_last_access', TRUE) == '0') + { + echo __('Never', 'wp-redirects'); + } + elseif(get_post_meta($post_id, 'wp_redirect_last_access', TRUE)) + { + echo date(get_option('date_format'), get_post_meta($post_id, 'wp_redirect_last_access', TRUE)); + } + + break; + } + } + + public static function register_sortable_admin_columns($columns) + { + $columns['hits'] = 'hit'; + $columns['last_access'] = 'last_access'; + + return $columns; + } + + public static function admin_column_orderby($query) + { + if(!is_admin()) + return; + + $orderby = $query->get('orderby'); + + if('hit' == $orderby) + { + $query->set('meta_key', 'wp_redirect_hits'); + $query->set('orderby', 'meta_value_num'); + } + elseif('last_access' == $orderby) + { + $query->set('meta_key', 'wp_redirect_last_access'); + $query->set('orderby', 'meta_value_num'); + } + } + + public function activate() + { + $this->setup(); // Setup routines. + $this->caps('activate'); + flush_rewrite_rules(); + } + + public function check_version() + { + if(version_compare($this->options['version'], $this->version, '>=')) + return; // Nothing to do in this case. + + $this->options['version'] = $this->version; + update_option(__NAMESPACE__.'_options', $this->options); + + $notices = (is_array($notices = get_option(__NAMESPACE__.'_notices'))) ? $notices : array(); + $notices[] = __('WP Redirects: detected a new version of itself. Recompiling w/ latest version... all done :-)', $this->text_domain); + update_option(__NAMESPACE__.'_notices', $notices); + } + + public function deactivate() + { + + delete_option(__NAMESPACE__.'_options'); + delete_option(__NAMESPACE__.'_notices'); + delete_option(__NAMESPACE__.'_errors'); + $this->caps('deactivate'); + flush_rewrite_rules(); + } + + public function actions() + { + if(empty($_REQUEST[__NAMESPACE__])) return; + + require_once dirname(__FILE__).'/includes/actions.php'; + } + + public function enqueue_admin_styles($hook) + { + if('edit.php' != $hook) // only load this style on the Edit posts admin screen + return; + + $deps = array(); // Plugin dependencies. + + wp_enqueue_style(__NAMESPACE__, $this->url('/client-s/css/admin-style.css'), $deps, $this->version, 'all'); + } + + public function all_admin_notices() + { + $notices = (is_array($notices = get_option(__NAMESPACE__.'_notices'))) ? $notices : array(); + if($notices) delete_option(__NAMESPACE__.'_notices'); // Process one-time only. + + $notices = array_unique($notices); // Don't show dupes. + + if(current_user_can($this->cap)) foreach($notices as $_notice) + echo apply_filters(__METHOD__.'__notice', '

'.$_notice.'

', get_defined_vars()); + unset($_notice); // Housekeeping. + } + + public function all_admin_errors() + { + $errors = (is_array($errors = get_option(__NAMESPACE__.'_errors'))) ? $errors : array(); + if($errors) delete_option(__NAMESPACE__.'_errors'); // Process one-time only. + + $errors = array_unique($errors); // Don't show dupes. + + if(current_user_can($this->cap)) foreach($errors as $_error) + echo apply_filters(__METHOD__.'__error', '

'.$_error.'

', get_defined_vars()); + unset($_error); // Housekeeping. + } + } + + /** + * @return plugin Class instance. + */ + function plugin() // Easy reference. + { + return $GLOBALS[__NAMESPACE__]; + } + + $GLOBALS[__NAMESPACE__] = new plugin(); // New plugin instance. + } + else add_action('all_admin_notices', function () // Do NOT load in this case. + { + echo '

'. // Running multiple versions of this plugin at same time. + __('You appear to be running another instance of WP-Redirects. Please disable the other instance before enabling this one.', + str_replace('_', '-', __NAMESPACE__)).'

'; + }); +} \ No newline at end of file diff --git a/wp-redirects/wp-redirects.php b/wp-redirects/wp-redirects.php index 5356303..0d28439 100644 --- a/wp-redirects/wp-redirects.php +++ b/wp-redirects/wp-redirects.php @@ -1,11 +1,11 @@ TRUE, 'exclude_from_search' => TRUE, - 'map_meta_cap' => TRUE, 'capability_type' => array('redirect', 'redirects'), - 'rewrite' => array('slug' => 'r', 'with_front' => FALSE), - 'supports' => array('title', 'author', 'revisions') - ); - $post_type_args['labels'] = array - ( - 'name' => __('Redirects', 'wp-redirects'), - 'singular_name' => __('Redirect', 'wp-redirects'), - 'add_new' => __('Add Redirect', 'wp-redirects'), - 'add_new_item' => __('Add New Redirect', 'wp-redirects'), - 'edit_item' => __('Edit Redirect', 'wp-redirects'), - 'new_item' => __('New Redirect', 'wp-redirects'), - 'all_items' => __('All Redirects', 'wp-redirects'), - 'view_item' => __('View Redirect', 'wp-redirects'), - 'search_items' => __('Search Redirects', 'wp-redirects'), - 'not_found' => __('No Redirects found', 'wp-redirects'), - 'not_found_in_trash' => __('No Redirects found in Trash', 'wp-redirects') - ); - register_post_type('redirect', $post_type_args); - - $taxonomy_args = array // Categories. - ( - 'public' => TRUE, 'show_admin_column' => TRUE, - 'hierarchical' => TRUE, // This will use category labels. - 'rewrite' => array('slug' => 'redirect-category', 'with_front' => FALSE), - 'capabilities' => array('assign_terms' => 'edit_redirects', - 'edit_terms' => 'edit_redirects', - 'manage_terms' => 'edit_others_redirects', - 'delete_terms' => 'delete_others_redirects') - ); - register_taxonomy('redirect_category', array('redirect'), $taxonomy_args); - } - - public static function caps($action) - { - $all_caps = array // The ability to manage (all caps). - ( - 'edit_redirects', - 'edit_others_redirects', - 'edit_published_redirects', - 'edit_private_redirects', - - 'publish_redirects', - - 'delete_redirects', - 'delete_private_redirects', - 'delete_published_redirects', - 'delete_others_redirects', - - 'read_private_redirects' - ); - if($action === 'deactivate') // All on deactivate. - $_roles = array_keys($GLOBALS['wp_roles']->roles); - else $_roles = wp_redirects::$roles_all_caps; - - foreach($_roles as $_role) if(is_object($_role = get_role($_role))) - foreach($all_caps as $_cap) switch($action) - { - case 'activate': - $_role->add_cap($_cap); - break; - - case 'deactivate': - $_role->remove_cap($_cap); - break; - } - unset($_roles, $_role, $_cap); // Housekeeping. - - $edit_caps = array // The ability to edit/publish/delete. - ( - 'edit_redirects', - 'edit_published_redirects', - - 'publish_redirects', - - 'delete_redirects', - 'delete_published_redirects' - ); - if($action === 'deactivate') // All on deactivate. - $_roles = array_keys($GLOBALS['wp_roles']->roles); - else $_roles = wp_redirects::$roles_edit_caps; - - foreach($_roles as $_role) if(is_object($_role = get_role($_role))) - foreach((($action === 'deactivate') ? $all_caps : $edit_caps) as $_cap) switch($action) - { - case 'activate': - $_role->add_cap($_cap); - break; - - case 'deactivate': - $_role->remove_cap($_cap); - break; - } - unset($_roles, $_role, $_cap); // Housekeeping. - } - - public static function redirect_redirects() - { - if(!($is_singular_redirect = is_singular('redirect'))) - return; // Nothing to do in this case. - - $redirect_id = get_the_ID(); // Pull this one time only. - - $to = (string)get_post_meta($redirect_id, 'wp_redirect_to', TRUE); - $to = preg_replace_callback('/%%\\\$([^\[]+?)(.+?)%%/i', 'wp_redirects::_url_e_gprcs_value', $to); - $to = preg_replace('/%%(.+?)%%/i', '', $to); // Ditch any remaining replacement codes. - - $to = // Cleanup any double slashes left over by replacement codes. - wp_redirects::trim(preg_replace('/(?get_results( - "SELECT `post_id`, `meta_value` AS `pattern`". // Meta value is pattern (possibly a regex pattern). - " FROM `".wp_redirects::wpdb()->postmeta."` WHERE `meta_key` = 'wp_redirect_from_uri_pattern' AND `meta_value` != ''". - " AND `post_id` IN(SELECT `ID` FROM `".wp_redirects::wpdb()->posts."`". // Every `redirect` ID. - " WHERE `post_type` = 'redirect' AND `post_status` = 'publish')"); - if(!is_array($patterns) || !$patterns) return; // Nothing to do in this case. - - foreach($patterns as $_pattern) // Iterate all redirection patterns. - { - $_pattern_matches = $_is_regex = $_is_regex_matches = FALSE; // Initialize. - $_is_regex = (stripos($_pattern->pattern, 'regex:') === 0) ? TRUE : FALSE; - - if(!$_is_regex && trim($_pattern->pattern, '/') === trim($_SERVER['REQUEST_URI'], '/')) - $_pattern_matches = TRUE; // Exact match in this case (after trimming). - - else if($_is_regex && @preg_match(trim(preg_replace('/^regex\:/i', '', $_pattern->pattern)), - $_SERVER['REQUEST_URI'], $_is_regex_matches) - ) $_pattern_matches = TRUE; // A matching regular expression. - - else continue; // Nothing to do in this case; NOT a matching pattern. - - if(!($_to = (string)get_post_meta($_pattern->post_id, 'wp_redirect_to', TRUE))) - continue; // Stop here if there is nothing to redirect to. - - $_to = (($_is_regex && $_is_regex_matches) // Regex replacement codes for captured groups. - ? preg_replace_callback('/%%([0-9]+)%%/i', function ($m) use ($_is_regex_matches) - { - return urlencode((string)@$_is_regex_matches[$m[1]]); - }, $_to) : $_to); - $_to = preg_replace_callback('/%%\\\$([^\[]+?)(.+?)%%/i', 'wp_redirects::_url_e_gprcs_value', $_to); - $_to = preg_replace('/%%(.+?)%%/i', '', $_to); // Ditch any remaining replacement codes. - - $_to = // Cleanup any double slashes left over by replacement codes. - wp_redirects::trim(preg_replace('/(?post_id, 'wp_redirect_to_w_query_vars', TRUE)) - $_to = add_query_arg(urlencode_deep(wp_redirects::trim_strip_deep($_GET)), $_to); - - $_status = (is_numeric($_status = get_post_meta($_pattern->post_id, 'wp_redirect_status', TRUE))) ? (integer)$_status : 301; - - // Update hit counter for this redirect - $redirect_hits = (int)get_post_meta(get_the_ID(), 'wp_redirect_hits', TRUE) + 1; - update_post_meta(get_the_ID(), 'wp_redirect_hits', $redirect_hits); - - // Update last access time for this redirect - update_post_meta(get_the_ID(), 'wp_redirect_last_access', time()); - - wp_redirect($_to, $_status).exit(); // Redirection URL w/ a possible custom status code. - } - unset($_pattern, $_is_regex, $_pattern_matches, $_is_regex_matches, $_to, $_status); // Housekeeping. + echo __('

Plugin NOT active. This version of WP Redirects requires PHP v5.3+.

', 'wp-redirects'); } - public static function _url_e_gprcs_value($m) - { - if(isset($m[1], $m[2]) && in_array(($gprcs = strtoupper($m[1])), array('_GET', '_POST', '_REQUEST', '_COOKIE', '_SESSION'), TRUE)) - if(strlen($element_w_brackets = $m[2]) && preg_match('/^(?:(?:\[(["\'])[a-z0-9 \._\-]+?\\1\])|(?:\[[0-9]+\]))+$/i', $element_w_brackets)) - eval('$value = urlencode(trim(stripslashes((string)@$'.$gprcs.$element_w_brackets.')));'); - - return (!empty($value)) ? $value : ''; // Default to empty string. - } - - public static function meta_boxes() - { - add_meta_box('wp-redirect', __('Redirect Configuration', 'wp-redirects'), - 'wp_redirects::redirect_meta_box', 'redirect', 'normal', 'high'); - add_meta_box('wp-redirect-stats', __('Redirection Statistics', 'wp-redirects'), 'wp_redirects::redirect_stats_meta_box', 'redirect', 'normal', 'high'); - } - - public static function redirect_meta_box($post) - { - if(!is_object($post) || empty($post->ID) || !($post_id = $post->ID)) - return; // No can-do. Should NOT happen; but just in case. - - echo '
'."\n"; - echo '
'."\n"; - echo __('This is optional. It defaults to a value of 301 for redirection.', 'wp-redirects')."\n"; - - echo '
'."\n"; - - echo '
'."\n"; - echo '
'."\n"; - echo ' [?]'."\n"; - - echo '
'."\n"; - - echo '
'."\n"; - echo '
'."\n"; - echo __('This is optional. By default, redirection simply occurs from the Permalink for this Redirection.', 'wp-redirects').'

'."\n"; - echo __('Redirecting from additional locations: This can be accomplished here with a pattern. By default, a pattern supplied here is caSe sensitive, using one exact comparison against $_SERVER[\'REQUEST_URI\']. However, it is possible to precede your pattern with: regex: to enable advanced regular expression pattern matching. Example: regex: /pattern/i. It is also possible to use regex Replacement Codes in your Redirection URL above, referencing any parenthesized subpatterns. For example: %%0%%, %%1%%, %%2%%.', 'wp-redirects')."\n"; - - wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); - } - - public static function redirect_stats_meta_box($post) - { - if(is_object($post) && !empty($post->ID) && ($post_id = $post->ID)) - { - echo __('Total Hits:', 'wp-redirects').' '.((get_post_meta($post_id, 'wp_redirect_hits', TRUE)) ? esc_attr(get_post_meta($post_id, 'wp_redirect_hits', TRUE)) : '0').' (reset)
'."\n"; - echo '
'."\n"; - echo ''; - - echo '
'."\n"; - - wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); - } - } - - public static function meta_boxes_save($post_id) - { - if(is_numeric($post_id) && (!defined('DOING_AUTOSAVE') || !DOING_AUTOSAVE) && ($_p = wp_redirects::trim_strip_deep($_POST))) - if(!empty($_p['wp_redirect_meta_boxes']) && wp_verify_nonce($_p['wp_redirect_meta_boxes'], 'wp-redirect-meta-boxes')) - if(!empty($_p['post_type']) && $_p['post_type'] === 'redirect' && current_user_can('edit_redirect', $post_id)) - { - if(isset($_p['wp_redirect_status'])) - update_post_meta($post_id, 'wp_redirect_status', (string)$_p['wp_redirect_status']); - - if(isset($_p['wp_redirect_to'])) - update_post_meta($post_id, 'wp_redirect_to', (string)$_p['wp_redirect_to']); - - if(isset($_p)) // A checkbox may (or may NOT) be set; we update in either case. - update_post_meta($post_id, 'wp_redirect_to_w_query_vars', (int)@$_p['wp_redirect_to_w_query_vars']); - - if(isset($_p['wp_redirect_from_uri_pattern'])) - update_post_meta($post_id, 'wp_redirect_from_uri_pattern', addslashes((string)$_p['wp_redirect_from_uri_pattern'])); - - if(isset($_p['wp_redirect_hits'])) - update_post_meta($post_id, 'wp_redirect_hits', (int)$_p['wp_redirect_hits']); - - if(isset($_p['wp_redirect_last_access'])) - update_post_meta($post_id, 'wp_redirect_last_access', (int)$_p['wp_redirect_last_access']); - } - } - - public static function trim($value, $chars = NULL, $extra_chars = NULL) - { - return wp_redirects::trim_deep($value, $chars, $extra_chars); - } - - public static function trim_deep($value, $chars = NULL, $extra_chars = NULL) - { - $chars = (is_string($chars)) ? $chars : " \r\n\t\0\x0B"; - $chars = (is_string($extra_chars)) ? $chars.$extra_chars : $chars; - - if(is_array($value) || is_object($value)) // Deeply. - { - foreach($value as &$_value) - $_value = wp_redirects::trim_deep($_value, $chars); - unset($_value); // Housekeeping. - - return $value; - } - return trim((string)$value, $chars); - } - - public static function trim_strip_deep($value, $chars = NULL, $extra_chars = NULL) - { - return wp_redirects::trim_deep(stripslashes_deep($value), $chars, $extra_chars); - } - - public static function activate() - { - wp_redirects::init(); - wp_redirects::caps('activate'); - flush_rewrite_rules(); - } - - public static function deactivate() - { - wp_redirects::caps('deactivate'); - flush_rewrite_rules(); - } - - /** @return \wpdb */ - public static function wpdb() - { - return $GLOBALS['wpdb']; - } - - public static function add_admin_columns($columns) - { - return array_merge($columns, - array('hits' => __('Hits'), - 'last_access' => __('Last Access'))); - } - - public static function show_admin_column_value($column, $post_id) - { - switch($column) - { - case 'hits': - echo get_post_meta($post_id, 'wp_redirect_hits', TRUE); - break; - - case 'last_access': - if(get_post_meta($post_id, 'wp_redirect_last_access', TRUE) == '0') - { - echo __('Never', 'wp-redirects'); - } - elseif(get_post_meta($post_id, 'wp_redirect_last_access', TRUE)) - { - echo date(get_option('date_format'), get_post_meta($post_id, 'wp_redirect_last_access', TRUE)); - } - - break; - } - } - - public static function register_sortable_admin_columns($columns) - { - $columns['hits'] = 'hit'; - $columns['last_access'] = 'last_access'; - - return $columns; - } - - public static function admin_column_orderby($query) - { - if(!is_admin()) - return; - - $orderby = $query->get('orderby'); - - if('hit' == $orderby) - { - $query->set('meta_key', 'wp_redirect_hits'); - $query->set('orderby', 'meta_value_num'); - } - elseif('last_access' == $orderby) - { - $query->set('meta_key', 'wp_redirect_last_access'); - $query->set('orderby', 'meta_value_num'); - } - } - - public static function load_custom_wp_admin_style($hook) - { - if('edit.php' != $hook) // only load this style on the Edit posts admin screen - return; - wp_register_style('wp_redirects_wp_admin_css', plugin_dir_url(__FILE__).'admin-style.css', FALSE, '1.0.0'); - wp_enqueue_style('wp_redirects_wp_admin_css'); - } + add_action('all_admin_notices', 'wp_redirects_php53_dashboard_notice'); } - -add_action('init', 'wp_redirects::init', 1); -register_activation_hook(__FILE__, 'wp_redirects::activate'); -register_deactivation_hook(__FILE__, 'wp_redirects::deactivate'); \ No newline at end of file +else require_once dirname(__FILE__).'/wp-redirects.inc.php'; \ No newline at end of file From 76de215755f44060f76ccbb448b94002ef52e14e Mon Sep 17 00:00:00 2001 From: JasWSInc Date: Thu, 11 Sep 2014 03:23:45 -0800 Subject: [PATCH 06/18] Adding `/** @var \WP_Query $query */` for syntax-aware IDEs. --- wp-redirects/wp-redirects.inc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wp-redirects/wp-redirects.inc.php b/wp-redirects/wp-redirects.inc.php index c2e1828..92f858c 100644 --- a/wp-redirects/wp-redirects.inc.php +++ b/wp-redirects/wp-redirects.inc.php @@ -451,6 +451,8 @@ public static function register_sortable_admin_columns($columns) public static function admin_column_orderby($query) { + /** @var \WP_Query $query */ + if(!is_admin()) return; From a79dc1dd633d69d9f34d987d2a177ba17ac2f84b Mon Sep 17 00:00:00 2001 From: JasWSInc Date: Thu, 11 Sep 2014 03:28:02 -0800 Subject: [PATCH 07/18] Cleaning blank lines. --- wp-redirects/wp-redirects.inc.php | 3 --- wp-redirects/wp-redirects.php | 1 - 2 files changed, 4 deletions(-) diff --git a/wp-redirects/wp-redirects.inc.php b/wp-redirects/wp-redirects.inc.php index 92f858c..c4fbb25 100644 --- a/wp-redirects/wp-redirects.inc.php +++ b/wp-redirects/wp-redirects.inc.php @@ -11,7 +11,6 @@ { class plugin // Base plugin class. { - public $is_pro = FALSE; // Lite version flag. public $file = ''; // Defined by class constructor. @@ -240,7 +239,6 @@ public static function redirect_redirects() wp_redirect($to, $status).exit(); // It's a good day in Eureka :-) } - wp_redirect(home_url('/'), 301).exit(); // Default redirection (ALWAYS redirect). } @@ -436,7 +434,6 @@ public static function show_admin_column_value($column, $post_id) { echo date(get_option('date_format'), get_post_meta($post_id, 'wp_redirect_last_access', TRUE)); } - break; } } diff --git a/wp-redirects/wp-redirects.php b/wp-redirects/wp-redirects.php index 0d28439..d8c6f2f 100644 --- a/wp-redirects/wp-redirects.php +++ b/wp-redirects/wp-redirects.php @@ -19,7 +19,6 @@ function wp_redirects_php53_dashboard_notice() { echo __('

Plugin NOT active. This version of WP Redirects requires PHP v5.3+.

', 'wp-redirects'); } - add_action('all_admin_notices', 'wp_redirects_php53_dashboard_notice'); } else require_once dirname(__FILE__).'/wp-redirects.inc.php'; \ No newline at end of file From 1aecad696e2a3a2782a5ab89746e847c79c8e5ef Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Thu, 11 Sep 2014 20:47:24 -0400 Subject: [PATCH 08/18] Fix bug inrupdating egex redirect hit s andlast access --- wp-redirects/wp-redirects.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wp-redirects/wp-redirects.inc.php b/wp-redirects/wp-redirects.inc.php index c4fbb25..293d48d 100644 --- a/wp-redirects/wp-redirects.inc.php +++ b/wp-redirects/wp-redirects.inc.php @@ -286,11 +286,11 @@ public function redirect_uri_patterns() $_status = (is_numeric($_status = get_post_meta($_pattern->post_id, 'wp_redirect_status', TRUE))) ? (integer)$_status : 301; // Update hit counter for this redirect - $redirect_hits = (int)get_post_meta(get_the_ID(), 'wp_redirect_hits', TRUE) + 1; - update_post_meta(get_the_ID(), 'wp_redirect_hits', $redirect_hits); + $redirect_hits = (int)get_post_meta($_pattern->post_id, 'wp_redirect_hits', TRUE) + 1; + update_post_meta($_pattern->post_id, 'wp_redirect_hits', $redirect_hits); // Update last access time for this redirect - update_post_meta(get_the_ID(), 'wp_redirect_last_access', time()); + update_post_meta($_pattern->post_id, 'wp_redirect_last_access', time()); wp_redirect($_to, $_status).exit(); // Redirection URL w/ a possible custom status code. } From 31bd2e0d6e61332221faead0984ab6725e9bc387 Mon Sep 17 00:00:00 2001 From: JasWSInc Date: Thu, 11 Sep 2014 16:57:27 -0800 Subject: [PATCH 09/18] Optimizing calls to `get_the_ID()`. --- wp-redirects/wp-redirects.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wp-redirects/wp-redirects.inc.php b/wp-redirects/wp-redirects.inc.php index 293d48d..173df7b 100644 --- a/wp-redirects/wp-redirects.inc.php +++ b/wp-redirects/wp-redirects.inc.php @@ -231,11 +231,11 @@ public static function redirect_redirects() if($to && $status) // Redirection URL w/ a possible custom status code. { // Update hit counter for this redirect - $redirect_hits = (int)get_post_meta(get_the_ID(), 'wp_redirect_hits', TRUE) + 1; - update_post_meta(get_the_ID(), 'wp_redirect_hits', $redirect_hits); + $redirect_hits = (int)get_post_meta($redirect_id, 'wp_redirect_hits', TRUE) + 1; + update_post_meta($redirect_id, 'wp_redirect_hits', $redirect_hits); // Update last access time for this redirect - update_post_meta(get_the_ID(), 'wp_redirect_last_access', time()); + update_post_meta($redirect_id, 'wp_redirect_last_access', time()); wp_redirect($to, $status).exit(); // It's a good day in Eureka :-) } From 79c089eca46a70019faa4a5860fb7920047c63e9 Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Sat, 13 Sep 2014 14:39:53 -0400 Subject: [PATCH 10/18] Improve handling of missing hit count and last access data Resolves websharks/wp-redirects#10 --- wp-redirects/wp-redirects.inc.php | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/wp-redirects/wp-redirects.inc.php b/wp-redirects/wp-redirects.inc.php index 173df7b..f4f4c12 100644 --- a/wp-redirects/wp-redirects.inc.php +++ b/wp-redirects/wp-redirects.inc.php @@ -346,8 +346,6 @@ public static function redirect_stats_meta_box($post) echo '
'."\n"; echo ''; - echo '
'."\n"; - wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); } } @@ -422,18 +420,31 @@ public static function show_admin_column_value($column, $post_id) switch($column) { case 'hits': - echo get_post_meta($post_id, 'wp_redirect_hits', TRUE); + $_hits = get_post_meta($post_id, 'wp_redirect_hits', TRUE); + + if($_hits == '') + update_post_meta($post_id, 'wp_redirect_hits', '0'); + + echo $_hits; + + unset($_hits); break; case 'last_access': - if(get_post_meta($post_id, 'wp_redirect_last_access', TRUE) == '0') + $_last_access = get_post_meta($post_id, 'wp_redirect_last_access', TRUE); + + if($_last_access == '') { - echo __('Never', 'wp-redirects'); + update_post_meta($post_id, 'wp_redirect_last_access', '0'); + $_last_access = '0'; } - elseif(get_post_meta($post_id, 'wp_redirect_last_access', TRUE)) - { + + if($_last_access == '0') + echo __('Never', 'wp-redirects'); + else echo date(get_option('date_format'), get_post_meta($post_id, 'wp_redirect_last_access', TRUE)); - } + + unset($_last_access); break; } } From 7ab096f3f41c0bf28084ae8b78169942bb2ead2b Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Sat, 13 Sep 2014 20:49:27 -0400 Subject: [PATCH 11/18] Refactored Redirects configuration page. - Split various configuration options into separate meta boxes - Added lots of inline documentation to help novice site owners See websharks/wp-redirects#13 --- wp-redirects/wp-redirects.inc.php | 120 +++++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 19 deletions(-) diff --git a/wp-redirects/wp-redirects.inc.php b/wp-redirects/wp-redirects.inc.php index f4f4c12..fe7c024 100644 --- a/wp-redirects/wp-redirects.inc.php +++ b/wp-redirects/wp-redirects.inc.php @@ -306,45 +306,127 @@ public static function _url_e_gprcs_value($m) return (!empty($value)) ? $value : ''; // Default to empty string. } + public static function get_redirect_last_access_date($post_id) { + if(!is_integer($post_id)) + return ''; + + $_last_access = get_post_meta($post_id, 'wp_redirect_last_access', TRUE); + + if($_last_access == '') + { + update_post_meta($post_id, 'wp_redirect_last_access', '0'); + $_last_access = '0'; + } + + if($_last_access == '0') + return __('Never', 'wp-redirects'); + else + return date(get_option('date_format'), get_post_meta($post_id, 'wp_redirect_last_access', TRUE)); + } + public static function meta_boxes() { - add_meta_box('wp-redirect', __('Redirect Configuration', 'wp-redirects'), - 'wp_redirects\plugin::redirect_meta_box', 'redirect', 'normal', 'high'); - add_meta_box('wp-redirect-stats', __('Redirection Statistics', 'wp-redirects'), 'wp_redirects\plugin::redirect_stats_meta_box', 'redirect', 'normal', 'high'); + add_meta_box('wp-redirect-url', __('Target URL', 'wp-redirects'), + 'wp_redirects\plugin::redirect_meta_box_url', 'redirect', 'normal', 'high'); + add_meta_box('wp-redirect-sources', __('Source URL', 'wp-redirects'), + 'wp_redirects\plugin::redirect_meta_box_sources', 'redirect', 'normal', 'high'); + add_meta_box('wp-redirect-additional-uris', __('Additional Source URIs', 'wp-redirects'), + 'wp_redirects\plugin::redirect_meta_box_additional_uris', 'redirect', 'normal', 'high'); + add_meta_box('wp-redirect-status', __('HTTP Status Code', 'wp-redirects'), + 'wp_redirects\plugin::redirect_meta_box_status', 'redirect', 'normal', 'high'); + add_meta_box('wp-redirect-stats', __('Redirection Statistics', 'wp-redirects'), + 'wp_redirects\plugin::redirect_meta_box_stats', 'redirect', 'normal', 'high'); } - public static function redirect_meta_box($post) + public static function redirect_meta_box_url($post) { if(!is_object($post) || empty($post->ID) || !($post_id = $post->ID)) return; // No can-do. Should NOT happen; but just in case. - echo '
'."\n"; - echo '
'."\n"; - echo __('This is optional. It defaults to a value of 301 for redirection.', 'wp-redirects')."\n"; + echo __('The Target URL is the URL that your Source URL will be redirected to.', 'wp-redirects').'

'."\n"; + echo __('This is the only required field to create a Redirect with WP Redirects, as the Source URL (see below) is generated for you automatically.', 'wp-redirects').'

'."\n"; + echo '
'."\n"; + echo '

'."\n"; + echo ' [?]'."\n"; - echo '
'."\n"; + wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); + } - echo '
'."\n"; - echo '
'."\n"; - echo ' [?]'."\n"; + public static function redirect_meta_box_sources($post) + { + if(!is_object($post) || empty($post->ID) || !($post_id = $post->ID)) + return; // No can-do. Should NOT happen; but just in case. - echo '
'."\n"; + echo __('The Source URL is the URL that gets redirected to your Target URL.', 'wp-redirects').'

'."\n"; + echo __('WP Redirects automatically generates a unique Source URL for you by using the Permalink generated by WordPress for this Redirect. Once you\'ve saved this Redirect and a Permalink has been generated, you can edit the Permalink (i.e., the Source URL) using the Edit button underneath the Title. Additional Source URIs can also be configured (optional, see Additional Source URIs below).', 'wp-redirects').'

'."\n"; - echo '
'."\n"; - echo '
'."\n"; - echo __('This is optional. By default, redirection simply occurs from the Permalink for this Redirection.', 'wp-redirects').'

'."\n"; - echo __('Redirecting from additional locations: This can be accomplished here with a pattern. By default, a pattern supplied here is caSe sensitive, using one exact comparison against $_SERVER[\'REQUEST_URI\']. However, it is possible to precede your pattern with: regex: to enable advanced regular expression pattern matching. Example: regex: /pattern/i. It is also possible to use regex Replacement Codes in your Redirection URL above, referencing any parenthesized subpatterns. For example: %%0%%, %%1%%, %%2%%.', 'wp-redirects')."\n"; + list($permalink, $post_name) = get_sample_permalink($post->ID); + if(!empty($post_name)) + { + $permalink = str_replace('%pagename%', $post_name, $permalink); + echo __('Source URL: '.$permalink.'', 'wp-redirects')."\n"; + } + else + { + echo __('Source URL: Please enter a title above and click Save Draft to generate the default Source URL', 'wp-redirects')."\n"; + } wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); } - public static function redirect_stats_meta_box($post) + public static function redirect_meta_box_additional_uris($post) + { + if(!is_object($post) || empty($post->ID) || !($post_id = $post->ID)) + return; // No can-do. Should NOT happen; but just in case. + + echo __('If you want to redirect additional Source URIs to the Target URL, you can enter a single URI below or use a Regular Expression to redirect all URIs that match a specific pattern.', 'wp-redirects').'

'."\n"; + echo '
'."\n"; + echo '

'."\n"; + echo __('By default, the value supplied here is caSe sensitive and is checked using an exact comparison against $_SERVER[\'REQUEST_URI\']. For example, to redirect '.esc_url( home_url( '/example/' ) ).' to your Target URL, simply enter /example/.', 'wp-redirects').'

'."\n"; + echo __('However, it is also possible to precede your pattern with: regex: to enable advanced regular expression pattern matching. Example: regex: /pattern/i. It is also possible to use regex Replacement Codes in your Redirection URL above, referencing any parenthesized subpatterns. For example: %%0%%, %%1%%, %%2%%.', 'wp-redirects')."\n"; + + wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); + } + + public static function redirect_meta_box_status($post) + { + if(!is_object($post) || empty($post->ID) || !($post_id = $post->ID)) + return; // No can-do. Should NOT happen; but just in case. + + echo __('By default, WP Redirects sends the standard 301 HTTP status code when doing a redirect. If you want to override that value, you can enter a custom HTTP Status Code below.

', 'wp-redirects')."\n"; + echo '
'."\n"; + echo ''."\n"; + + wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); + } + + public static function redirect_meta_box_stats($post) { if(is_object($post) && !empty($post->ID) && ($post_id = $post->ID)) { - echo __('Total Hits:', 'wp-redirects').' '.((get_post_meta($post_id, 'wp_redirect_hits', TRUE)) ? esc_attr(get_post_meta($post_id, 'wp_redirect_hits', TRUE)) : '0').' (reset)
'."\n"; - echo '
'."\n"; + + $_last_access = get_post_meta($post_id, 'wp_redirect_last_access', TRUE); + + if($_last_access == '') + { + update_post_meta($post_id, 'wp_redirect_last_access', '0'); + $_last_access = '0'; + } + + if($_last_access == '0') + $_last_access = __('Never', 'wp-redirects'); + else + $_last_access = get_redirect_last_access_date($post_id); + + echo __('Total Hits:', 'wp-redirects').' '.((get_post_meta($post_id, 'wp_redirect_hits', TRUE)) ? esc_attr(get_post_meta($post_id, 'wp_redirect_hits', TRUE)) : '0').' (reset)

'."\n"; + + echo __('Last Access:', 'wp-redirects').' '.$_last_access.' (reset)
'."\n"; + + echo ''; + echo ''; + echo ''; + echo ''; wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); } From 8fec500a4df6731fcb58a111c32a07c6e0794b36 Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Sat, 13 Sep 2014 20:52:11 -0400 Subject: [PATCH 12/18] Refactored to make the code DRYer --- wp-redirects/wp-redirects.inc.php | 51 ++++++++++--------------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/wp-redirects/wp-redirects.inc.php b/wp-redirects/wp-redirects.inc.php index fe7c024..7ec6dd9 100644 --- a/wp-redirects/wp-redirects.inc.php +++ b/wp-redirects/wp-redirects.inc.php @@ -306,6 +306,18 @@ public static function _url_e_gprcs_value($m) return (!empty($value)) ? $value : ''; // Default to empty string. } + public static function get_redirect_hits($post_id) { + if(!is_integer($post_id)) + return ''; + + $_hits = get_post_meta($post_id, 'wp_redirect_hits', TRUE); + + if($_hits == '') + update_post_meta($post_id, 'wp_redirect_hits', '0'); + + return $_hits; + } + public static function get_redirect_last_access_date($post_id) { if(!is_integer($post_id)) return ''; @@ -405,22 +417,11 @@ public static function redirect_meta_box_stats($post) if(is_object($post) && !empty($post->ID) && ($post_id = $post->ID)) { - $_last_access = get_post_meta($post_id, 'wp_redirect_last_access', TRUE); - - if($_last_access == '') - { - update_post_meta($post_id, 'wp_redirect_last_access', '0'); - $_last_access = '0'; - } - - if($_last_access == '0') - $_last_access = __('Never', 'wp-redirects'); - else - $_last_access = get_redirect_last_access_date($post_id); + $last_access_date = plugin::get_redirect_last_access_date($post_id); echo __('Total Hits:', 'wp-redirects').' '.((get_post_meta($post_id, 'wp_redirect_hits', TRUE)) ? esc_attr(get_post_meta($post_id, 'wp_redirect_hits', TRUE)) : '0').' (reset)

'."\n"; - echo __('Last Access:', 'wp-redirects').' '.$_last_access.' (reset)
'."\n"; + echo __('Last Access:', 'wp-redirects').' '.$last_access_date.' (reset)
'."\n"; echo ''; echo ''; @@ -502,31 +503,11 @@ public static function show_admin_column_value($column, $post_id) switch($column) { case 'hits': - $_hits = get_post_meta($post_id, 'wp_redirect_hits', TRUE); - - if($_hits == '') - update_post_meta($post_id, 'wp_redirect_hits', '0'); - - echo $_hits; - - unset($_hits); + echo plugin::get_redirect_hits($post_id); break; case 'last_access': - $_last_access = get_post_meta($post_id, 'wp_redirect_last_access', TRUE); - - if($_last_access == '') - { - update_post_meta($post_id, 'wp_redirect_last_access', '0'); - $_last_access = '0'; - } - - if($_last_access == '0') - echo __('Never', 'wp-redirects'); - else - echo date(get_option('date_format'), get_post_meta($post_id, 'wp_redirect_last_access', TRUE)); - - unset($_last_access); + echo plugin::get_redirect_last_access_date($post_id); break; } } From 58793c38693ba4dfbcd9f07de38851e3a05b340b Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Sat, 13 Sep 2014 20:59:48 -0400 Subject: [PATCH 13/18] Removed unused tabindex attributes from input fields --- wp-redirects/wp-redirects.inc.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wp-redirects/wp-redirects.inc.php b/wp-redirects/wp-redirects.inc.php index 7ec6dd9..90541fc 100644 --- a/wp-redirects/wp-redirects.inc.php +++ b/wp-redirects/wp-redirects.inc.php @@ -358,8 +358,8 @@ public static function redirect_meta_box_url($post) echo __('The Target URL is the URL that your Source URL will be redirected to.', 'wp-redirects').'

'."\n"; echo __('This is the only required field to create a Redirect with WP Redirects, as the Source URL (see below) is generated for you automatically.', 'wp-redirects').'

'."\n"; echo '
'."\n"; - echo '

'."\n"; - echo ' [?]'."\n"; + echo '

'."\n"; + echo ' [?]'."\n"; wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); } @@ -393,7 +393,7 @@ public static function redirect_meta_box_additional_uris($post) echo __('If you want to redirect additional Source URIs to the Target URL, you can enter a single URI below or use a Regular Expression to redirect all URIs that match a specific pattern.', 'wp-redirects').'

'."\n"; echo '
'."\n"; - echo '

'."\n"; + echo '

'."\n"; echo __('By default, the value supplied here is caSe sensitive and is checked using an exact comparison against $_SERVER[\'REQUEST_URI\']. For example, to redirect '.esc_url( home_url( '/example/' ) ).' to your Target URL, simply enter /example/.', 'wp-redirects').'

'."\n"; echo __('However, it is also possible to precede your pattern with: regex: to enable advanced regular expression pattern matching. Example: regex: /pattern/i. It is also possible to use regex Replacement Codes in your Redirection URL above, referencing any parenthesized subpatterns. For example: %%0%%, %%1%%, %%2%%.', 'wp-redirects')."\n"; @@ -407,7 +407,7 @@ public static function redirect_meta_box_status($post) echo __('By default, WP Redirects sends the standard 301 HTTP status code when doing a redirect. If you want to override that value, you can enter a custom HTTP Status Code below.

', 'wp-redirects')."\n"; echo '
'."\n"; - echo ''."\n"; + echo ''."\n"; wp_nonce_field('wp-redirect-meta-boxes', 'wp_redirect_meta_boxes'); } From a14abe867e4cdd380c5974c5b8c1e3d94d72d04d Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Sat, 4 Oct 2014 16:14:13 -0400 Subject: [PATCH 14/18] Use WebSharks WP-PHP53 stub to check PHP version requirements --- wp-redirects/includes/wp-php53.php | 86 ++++++++++++++++++++++++++++++ wp-redirects/wp-redirects.php | 12 ++--- 2 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 wp-redirects/includes/wp-php53.php diff --git a/wp-redirects/includes/wp-php53.php b/wp-redirects/includes/wp-php53.php new file mode 100644 index 0000000..8ade298 --- /dev/null +++ b/wp-redirects/includes/wp-php53.php @@ -0,0 +1,86 @@ + + * @license GNU General Public License, version 2 + */ +if(!function_exists('wp_php53')) +{ + /** + * Running PHP v5.3+? + * + * @return boolean TRUE if PHP v5.3+. + */ + function wp_php53() + { + return version_compare(PHP_VERSION, '5.3', '>='); + } +} +if(!function_exists('wp_php53_notice')) +{ + /** + * Creates a WP Dashboard notice regarding PHP requirements. + * + * @param string $software_name Optional. Name of the calling theme/plugin. Defaults to `this software`. + * @param string $software_text_domain Optional i18n text domain. Defaults to slugified `$plugin_name`. + * @param string $notice_cap Optional. Capability to view notice. Defaults to `activate_plugins`. + * @param string $notice_hook Optional. Action hook. Defaults to `all_admin_notices`. + * @param string $notice Optional. Custom notice HTML; instead of default markup. + */ + function wp_php53_notice($software_name = '', $software_text_domain = '', $notice_cap = '', $notice_hook = '', $notice = '') + { + $software_name = trim((string)$software_name); + $software_text_domain = trim((string)$software_text_domain); + $notice_cap = trim((string)$notice_cap); + $notice_hook = trim((string)$notice_hook); + $notice = trim((string)$notice); + + if(!$software_name) + $software_name = 'this software'; + + if(!$software_text_domain) // We can build this dynamically. + $software_text_domain = trim(preg_replace('/[^a-z0-9\-]/i', '-', strtolower($software_name)), '-'); + + if(!$notice_cap) // WP capability. + $notice_cap = 'activate_plugins'; + + if(!$notice_hook) // Action hook. + $notice_hook = 'all_admin_notices'; + + if(!$notice) // Only if there is NOT a custom `$notice` defined already. + { + $notice = sprintf(__('%1$s is NOT active. %1$s requires PHP v5.3 (or higher).', $software_text_domain), + strpos($software_name, '-') !== FALSE ? ''.esc_html($software_name).'' : esc_html($software_name)); + + $notice .= ' '.sprintf(__('You\'re currently running PHP v%1$s.', $software_text_domain), esc_html(PHP_VERSION)); + $notice .= ' '.__('A simple update is necessary. Please ask your web hosting company to do this for you.', $software_text_domain); + + $notice .= ' '.sprintf(__('To remove this message, please deactivate %1$s.', $software_text_domain), + strpos($software_name, '-') !== FALSE ? ''.esc_html($software_name).'' : esc_html($software_name)); + } + $notice_handler = create_function('', 'if(current_user_can(\''.str_replace("'", "\\'", $notice_cap).'\'))'. + ' echo \'

'.str_replace("'", "\\'", $notice).'

\';'); + + add_action($notice_hook, $notice_handler); // Attach WP Dashboard notice. + } +} +if(!function_exists('wp_php53_custom_notice')) +{ + /** + * Creates a WP Dashboard notice regarding PHP requirements. + * + * @param string $notice Optional. Custom notice HTML; instead of default markup. + * @param string $notice_cap Optional. Capability to view notice. Defaults to `activate_plugins`. + * @param string $notice_hook Optional. Action hook. Defaults to `all_admin_notices`. + */ + function wp_php53_custom_notice($notice = '', $notice_cap = '', $notice_hook = '') + { + wp_php53_notice('', '', $notice_cap, $notice_hook, $notice); + } +} +/* + * Return on `include/require`. + */ +return wp_php53(); // TRUE if PHP v5.3+; FALSE otherwise. \ No newline at end of file diff --git a/wp-redirects/wp-redirects.php b/wp-redirects/wp-redirects.php index d8c6f2f..3fc0a5c 100644 --- a/wp-redirects/wp-redirects.php +++ b/wp-redirects/wp-redirects.php @@ -13,12 +13,6 @@ if(!defined('WPINC')) // MUST have WordPress. exit('Do NOT access this file directly: '.basename(__FILE__)); -if(version_compare(PHP_VERSION, '5.3', '<')) -{ - function wp_redirects_php53_dashboard_notice() - { - echo __('

Plugin NOT active. This version of WP Redirects requires PHP v5.3+.

', 'wp-redirects'); - } - add_action('all_admin_notices', 'wp_redirects_php53_dashboard_notice'); -} -else require_once dirname(__FILE__).'/wp-redirects.inc.php'; \ No newline at end of file +if(require(dirname(__FILE__).'/includes/wp-php53.php')) // TRUE if running PHP v5.3+. + require_once dirname(__FILE__).'/wp-redirects.inc.php'; +else wp_php53_notice('WP Redirects'); \ No newline at end of file From 2a2cd71550a2e7f4582aef8a7b7b8e72ab158ad1 Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Thu, 9 Oct 2014 14:47:51 -0400 Subject: [PATCH 15/18] Update WebSharks WP-PHP53 stub to latest version --- wp-redirects/includes/wp-php53.php | 91 ++++++++++++++++++------------ 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/wp-redirects/includes/wp-php53.php b/wp-redirects/includes/wp-php53.php index 8ade298..68d96e8 100644 --- a/wp-redirects/includes/wp-php53.php +++ b/wp-redirects/includes/wp-php53.php @@ -9,13 +9,13 @@ if(!function_exists('wp_php53')) { /** - * Running PHP v5.3+? + * This server is running PHP v5.3+? * - * @return boolean TRUE if PHP v5.3+. + * @return boolean `TRUE` if running PHP v5.3+; `FALSE` otherwise. */ - function wp_php53() + function wp_php53() // Called automatically on `include()` or `require()`. { - return version_compare(PHP_VERSION, '5.3', '>='); + return version_compare(PHP_VERSION, $GLOBALS['wp_php_rv'], '>='); } } if(!function_exists('wp_php53_notice')) @@ -23,47 +23,62 @@ function wp_php53() /** * Creates a WP Dashboard notice regarding PHP requirements. * - * @param string $software_name Optional. Name of the calling theme/plugin. Defaults to `this software`. - * @param string $software_text_domain Optional i18n text domain. Defaults to slugified `$plugin_name`. + * @param string $software_name Optional. Name of the calling theme/plugin. Defaults to `ucwords([calling file basedir])`. + * @param string $software_text_domain Optional i18n text domain. Defaults to slugified `$software_name`. * @param string $notice_cap Optional. Capability to view notice. Defaults to `activate_plugins`. - * @param string $notice_hook Optional. Action hook. Defaults to `all_admin_notices`. - * @param string $notice Optional. Custom notice HTML; instead of default markup. + * @param string $notice_action Optional. Action hook. Defaults to `all_admin_notices`. + * @param string $notice Optional. Custom notice HTML instead of default markup. */ - function wp_php53_notice($software_name = '', $software_text_domain = '', $notice_cap = '', $notice_hook = '', $notice = '') + function wp_php53_notice($software_name = '', $software_text_domain = '', $notice_cap = '', $notice_action = '', $notice = '') { $software_name = trim((string)$software_name); $software_text_domain = trim((string)$software_text_domain); $notice_cap = trim((string)$notice_cap); - $notice_hook = trim((string)$notice_hook); + $notice_action = trim((string)$notice_action); $notice = trim((string)$notice); - if(!$software_name) - $software_name = 'this software'; - - if(!$software_text_domain) // We can build this dynamically. - $software_text_domain = trim(preg_replace('/[^a-z0-9\-]/i', '-', strtolower($software_name)), '-'); - - if(!$notice_cap) // WP capability. + if(!$notice_cap) // Use default cap? $notice_cap = 'activate_plugins'; - if(!$notice_hook) // Action hook. - $notice_hook = 'all_admin_notices'; + if(!$notice_action) // Use default action? + $notice_action = 'all_admin_notices'; - if(!$notice) // Only if there is NOT a custom `$notice` defined already. + if(!$software_name) // Use default generic name? { - $notice = sprintf(__('%1$s is NOT active. %1$s requires PHP v5.3 (or higher).', $software_text_domain), - strpos($software_name, '-') !== FALSE ? ''.esc_html($software_name).'' : esc_html($software_name)); + $software_name = 'This Software'; // Default generic value. + // Let's try to do better! We can use the basedir of the calling file. + if(($_debug_backtrace = @debug_backtrace()) && !empty($_debug_backtrace[0]['file'])) + if(($_calling_file_basedir = strtolower(basename(dirname($_debug_backtrace[0]['file']))))) + $software_name = ucwords(trim(preg_replace('/[^a-z0-9]+/i', ' ', $_calling_file_basedir))); + unset($_debug_backtrace, $_calling_file_basedir); // Housekeeping. + } + if(!$software_text_domain) // Use default text domain? + $software_text_domain = trim(preg_replace('/[^a-z0-9\-]/i', '-', strtolower($software_name)), '-'); - $notice .= ' '.sprintf(__('You\'re currently running PHP v%1$s.', $software_text_domain), esc_html(PHP_VERSION)); - $notice .= ' '.__('A simple update is necessary. Please ask your web hosting company to do this for you.', $software_text_domain); + if(!$notice) // Use the default notice? This will amost always suffice. + { + $notice = ''. + 'PHP'. + ''; // PHP icon served from the WebSharks™ CDN. Supports both `http://` and `https://`. - $notice .= ' '.sprintf(__('To remove this message, please deactivate %1$s.', $software_text_domain), - strpos($software_name, '-') !== FALSE ? ''.esc_html($software_name).'' : esc_html($software_name)); + $notice .= ' '.sprintf(__('%1$s is NOT active.', $software_text_domain), esc_html($software_name)); + $notice .= ' '.sprintf(__('It requires PHP v%1$s+.', $software_text_domain), esc_html($GLOBALS['wp_php_rv'])).'
'; + $notice .= ' '.sprintf(__('↳ You\'re currently running an older copy of PHP v%1$s.', $software_text_domain), esc_html(PHP_VERSION)).'
'; + $notice .= ' '.__('A simple update is necessary. Please ask your hosting company to help resolve this quickly.', $software_text_domain).'
'; + $notice .= ' '.sprintf(__('To remove this message, please upgrade. Or, remove %1$s from WordPress.', $software_text_domain), esc_html($software_name)); } - $notice_handler = create_function('', 'if(current_user_can(\''.str_replace("'", "\\'", $notice_cap).'\'))'. - ' echo \'

'.str_replace("'", "\\'", $notice).'

\';'); + add_action($notice_action, create_function('', 'if(!current_user_can(\''.str_replace("'", "\\'", $notice_cap).'\'))'. + ' return;'."\n". // User missing capability. - add_action($notice_hook, $notice_handler); // Attach WP Dashboard notice. + 'echo \''. // Wrap `$notice` inside a WordPress error. + + '
'. + '

'. + ' '.str_replace("'", "\\'", $notice). + '

'. + '
'. + + '\';')); } } if(!function_exists('wp_php53_custom_notice')) @@ -71,16 +86,22 @@ function wp_php53_notice($software_name = '', $software_text_domain = '', $notic /** * Creates a WP Dashboard notice regarding PHP requirements. * - * @param string $notice Optional. Custom notice HTML; instead of default markup. + * @param string $notice Optional. Custom notice HTML instead of default markup. * @param string $notice_cap Optional. Capability to view notice. Defaults to `activate_plugins`. - * @param string $notice_hook Optional. Action hook. Defaults to `all_admin_notices`. + * @param string $notice_action Optional. Action hook. Defaults to `all_admin_notices`. */ - function wp_php53_custom_notice($notice = '', $notice_cap = '', $notice_hook = '') + function wp_php53_custom_notice($notice = '', $notice_cap = '', $notice_action = '') { - wp_php53_notice('', '', $notice_cap, $notice_hook, $notice); + wp_php53_notice('', '', $notice_cap, $notice_action, $notice); } } +/** + * Required PHP version. + * + * @var string Required PHP version. + */ +$GLOBALS['wp_php_rv'] = '5.3'; // Hard-coded. /* - * Return on `include/require`. + * @return boolean on `include()` or `require()`. */ -return wp_php53(); // TRUE if PHP v5.3+; FALSE otherwise. \ No newline at end of file +return wp_php53(); // `TRUE` if running PHP v5.3+; `FALSE` otherwise. \ No newline at end of file From b6a3dd60acd38f0df17a87e519344c2f953f02d6 Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Thu, 9 Oct 2014 15:10:04 -0400 Subject: [PATCH 16/18] Add icons for WordPress.org Plugin Repo --- assets/icon-128x128.png | Bin 0 -> 23054 bytes assets/icon-256x256.png | Bin 0 -> 46703 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/icon-128x128.png create mode 100644 assets/icon-256x256.png diff --git a/assets/icon-128x128.png b/assets/icon-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..779e045dbec62495bd3c2fac918e6585a4e1a829 GIT binary patch literal 23054 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%0DxiA+6q>8j08WV72SQmZ?jJ2#_ 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 b{{ Date: Thu, 9 Oct 2014 15:19:55 -0400 Subject: [PATCH 17/18] Update default language file for v141009 --- .../includes/translations/wp-redirects.pot | 191 ++++++++++++------ 1 file changed, 131 insertions(+), 60 deletions(-) diff --git a/wp-redirects/includes/translations/wp-redirects.pot b/wp-redirects/includes/translations/wp-redirects.pot index 1b1956e..e0f5523 100644 --- a/wp-redirects/includes/translations/wp-redirects.pot +++ b/wp-redirects/includes/translations/wp-redirects.pot @@ -2,9 +2,9 @@ # This file is distributed under the same license as the WP Redirects package. msgid "" msgstr "" -"Project-Id-Version: WP Redirects 131121\n" +"Project-Id-Version: WP Redirects 141009\n" "Report-Msgid-Bugs-To: http://wordpress.org/tag/wp-redirects\n" -"POT-Creation-Date: 2014-01-08 06:00:06+00:00\n" +"POT-Creation-Date: 2014-10-09 19:19:10+00:00\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -12,123 +12,196 @@ msgstr "" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" -#: wp-redirects.php:58 +#: includes/wp-php53.php:64 +msgid "%1$s is NOT active." +msgstr "" + +#: includes/wp-php53.php:65 +msgid "It requires PHP v%1$s+." +msgstr "" + +#: includes/wp-php53.php:66 +msgid "↳ You're currently running an older copy of PHP v%1$s." +msgstr "" + +#: includes/wp-php53.php:67 +msgid "A simple update is necessary. Please ask your hosting company to help resolve this quickly." +msgstr "" + +#: includes/wp-php53.php:68 +msgid "To remove this message, please upgrade. Or, remove %1$s from WordPress." +msgstr "" + +#: wp-redirects.inc.php:107 msgid "Redirects" msgstr "" -#: wp-redirects.php:59 +#: wp-redirects.inc.php:108 msgid "Redirect" msgstr "" -#: wp-redirects.php:60 +#: wp-redirects.inc.php:109 msgid "Add Redirect" msgstr "" -#: wp-redirects.php:61 +#: wp-redirects.inc.php:110 msgid "Add New Redirect" msgstr "" -#: wp-redirects.php:62 +#: wp-redirects.inc.php:111 msgid "Edit Redirect" msgstr "" -#: wp-redirects.php:63 +#: wp-redirects.inc.php:112 msgid "New Redirect" msgstr "" -#: wp-redirects.php:64 +#: wp-redirects.inc.php:113 msgid "All Redirects" msgstr "" -#: wp-redirects.php:65 +#: wp-redirects.inc.php:114 msgid "View Redirect" msgstr "" -#: wp-redirects.php:66 +#: wp-redirects.inc.php:115 msgid "Search Redirects" msgstr "" -#: wp-redirects.php:67 +#: wp-redirects.inc.php:116 msgid "No Redirects found" msgstr "" -#: wp-redirects.php:68 +#: wp-redirects.inc.php:117 msgid "No Redirects found in Trash" msgstr "" -#: wp-redirects.php:227 -msgid "Redirect Configuration" +#: wp-redirects.inc.php:334 +msgid "Never" msgstr "" -#: wp-redirects.php:238 -msgid "" -"This is optional. It defaults to a value of 301 for redirection." +#: wp-redirects.inc.php:341 +msgid "Target URL" msgstr "" -#: wp-redirects.php:242 -msgid "Redirection URL * (a full URL, absolutely required):" +#: wp-redirects.inc.php:343 +msgid "Source URL" msgstr "" -#: wp-redirects.php:244 +#: wp-redirects.inc.php:345 +msgid "Additional Source URIs" +msgstr "" + +#: wp-redirects.inc.php:347 +msgid "HTTP Status Code" +msgstr "" + +#: wp-redirects.inc.php:349 +msgid "Redirection Statistics" +msgstr "" + +#: wp-redirects.inc.php:358 +msgid "The Target URL is the URL that your Source URL will be redirected to." +msgstr "" + +#: wp-redirects.inc.php:359 +msgid "This is the only required field to create a Redirect with WP Redirects, as the Source URL (see below) is generated for you automatically." +msgstr "" + +#: wp-redirects.inc.php:360 +msgid "Target URL (a full, absolute URI, e.g., http://example.com/):" +msgstr "" + +#: wp-redirects.inc.php:362 msgid "Yes, pass all $_GET query string variables to this URL." msgstr "" -#: wp-redirects.php:244 -msgid "" -"If checked, all `$_GET` query string variables will be passed to the " -"Redirection URL (adding to any that already exist)." +#: wp-redirects.inc.php:362 +msgid "If checked, all `$_GET` query string variables will be passed to the Redirection URL (adding to any that already exist)." msgstr "" -#: wp-redirects.php:244 -msgid "" -"It is also possible to use specific Replacement Codes in your Redirection " -"URL, referencing `$_GET`, `$_POST`, `$_REQUEST`, `$_COOKIE`, or `$_SESSION` " -"values." +#: wp-redirects.inc.php:362 +msgid "It is also possible to use specific Replacement Codes in your Redirection URL, referencing `$_GET`, `$_POST`, `$_REQUEST`, `$_COOKIE`, or `$_SESSION` values." msgstr "" -#: wp-redirects.php:244 +#: wp-redirects.inc.php:362 msgid "Example Replacement Codes:" msgstr "" -#: wp-redirects.php:244 -msgid "" -"* If you\\'re using an advanced regular expression, there are Replacement " -"Codes to reference parenthesized subpatterns." +#: wp-redirects.inc.php:362 +msgid "* If you\\'re using an advanced regular expression, there are Replacement Codes to reference parenthesized subpatterns." msgstr "" -#: wp-redirects.php:244 +#: wp-redirects.inc.php:362 msgid "(string matching the full pattern)" msgstr "" -#: wp-redirects.php:244 +#: wp-redirects.inc.php:362 msgid "(1st parenthesized subpattern)" msgstr "" -#: wp-redirects.php:244 +#: wp-redirects.inc.php:362 msgid "(2nd parenthesized subpattern)" msgstr "" -#: wp-redirects.php:248 -msgid "Additional Redirections From (optional pattern matching):" +#: wp-redirects.inc.php:372 +msgid "The Source URL is the URL that gets redirected to your Target URL." msgstr "" -#: wp-redirects.php:250 -msgid "" -"This is optional. By default, redirection simply occurs from the Permalink for this Redirection." +#: wp-redirects.inc.php:373 +msgid "WP Redirects automatically generates a unique Source URL for you by using the Permalink generated by WordPress for this Redirect. Once you've saved this Redirect and a Permalink has been generated, you can edit the Permalink (i.e., the Source URL) using the Edit button underneath the Title. Additional Source URIs can also be configured (optional, see Additional Source URIs below)." msgstr "" -#: wp-redirects.php:251 -msgid "" -"Redirecting from additional locations: This can be " -"accomplished here with a pattern. By default, a pattern supplied here is " -"caSe sensitive, using one exact comparison against $_SERVER" -"['REQUEST_URI']. However, it is possible to precede your pattern " -"with: regex: to enable advanced regular expression pattern " -"matching. Example: regex: /pattern/i. It is also possible to " -"use regex Replacement Codes in your Redirection URL above, referencing any " -"parenthesized subpatterns. For example: %%0%%, %%1%%, %%2%%." +#: wp-redirects.inc.php:383 +msgid "Source URL: Please enter a title above and click Save Draft to generate the default Source URL" +msgstr "" + +#: wp-redirects.inc.php:394 +msgid "If you want to redirect additional Source URIs to the Target URL, you can enter a single URI below or use a Regular Expression to redirect all URIs that match a specific pattern." +msgstr "" + +#: wp-redirects.inc.php:395 +msgid "An Additional Single Redirect URI or a Regular Expression Pattern:" +msgstr "" + +#: wp-redirects.inc.php:398 +msgid "However, it is also possible to precede your pattern with: regex: to enable advanced regular expression pattern matching. Example: regex: /pattern/i. It is also possible to use regex Replacement Codes in your Redirection URL above, referencing any parenthesized subpatterns. For example: %%0%%, %%1%%, %%2%%." +msgstr "" + +#: wp-redirects.inc.php:408 +msgid "By default, WP Redirects sends the standard 301 HTTP status code when doing a redirect. If you want to override that value, you can enter a custom HTTP Status Code below.

" +msgstr "" + +#: wp-redirects.inc.php:422 +msgid "Total Hits:" +msgstr "" + +#: wp-redirects.inc.php:424 +msgid "Last Access:" +msgstr "" + +#: wp-redirects.inc.php:429 +msgid "The hit count for this redirect has been reset. To save these changes, click Update." +msgstr "" + +#: wp-redirects.inc.php:430 +msgid "The last access date for this redirect has been reset. To save these changes, click Update." +msgstr "" + +#: wp-redirects.inc.php:497 +msgid "Hits" +msgstr "" + +#: wp-redirects.inc.php:498 +msgid "Last Access" +msgstr "" + +#: wp-redirects.inc.php:560 +msgid "WP Redirects: detected a new version of itself. Recompiling w/ latest version... all done :-)" +msgstr "" + +#: wp-redirects.inc.php:629 +msgid "You appear to be running another instance of WP-Redirects. Please disable the other instance before enabling this one." msgstr "" #. Plugin Name of the plugin/theme @@ -140,15 +213,13 @@ msgid "http://www.websharks-inc.com/product/wp-redirects/" msgstr "" #. Description of the plugin/theme -msgid "" -"Create Redirects! This plugin adds a new Post Type. Redirect from anywhere — " -"to anywhere. A very lightweight plugin!" +msgid "Create Redirects! This plugin adds a new Post Type. Redirect from anywhere — to anywhere. A very lightweight plugin!" msgstr "" #. Author of the plugin/theme -msgid "WebSharks, Inc. (Jason Caldwell)" +msgid "WebSharks, Inc." msgstr "" #. Author URI of the plugin/theme -msgid "http://www.websharks-inc.com/" +msgid "http://www.websharks-inc.com" msgstr "" From 018a9e72e48f33aca016ff8f1b8c3ed77c109520 Mon Sep 17 00:00:00 2001 From: Raam Dev Date: Thu, 9 Oct 2014 15:20:26 -0400 Subject: [PATCH 18/18] Releasing WP Redirects v141009 --- wp-redirects/readme.txt | 14 +++++++++++--- wp-redirects/wp-redirects.inc.php | 2 +- wp-redirects/wp-redirects.php | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/wp-redirects/readme.txt b/wp-redirects/readme.txt index fb14b94..c31ed7c 100644 --- a/wp-redirects/readme.txt +++ b/wp-redirects/readme.txt @@ -1,14 +1,14 @@ === WP Redirects === -Stable tag: 131121 +Stable tag: 141009 Requires at least: 3.2 -Tested up to: 3.7.1 +Tested up to: 4.0 Text Domain: wp-redirects License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html -Contributors: WebSharks, JasWSInc +Contributors: raamdev, WebSharks, JasWSInc Donate link: http://www.websharks-inc.com/r/wp-theme-plugin-donation/ Tags: redirect, redirects, 301 redirects, links, relocate, SEO, post type, post types, utilities, posts, pages @@ -79,6 +79,14 @@ Released under the terms of the [GNU General Public License](http://www.gnu.org/ == Changelog == += v141009 = + +- **New Feature**: Hit counter. WP Redirects will now keep track of how many times a redirect has been used. There is a new, sortable Hits column in the main Redirects list that allows you to sort your redirects by the number of hits. See [#4](https://github.com/websharks/wp-redirects/issues/4). +- **New Feature**: Last Access Time. WP Redirects will now keep track of the date and time a redirect was last used. There is a new, sortable Last Access column in the main Redirects list that allows you to sort your redirect by the last access time. See [#4](https://github.com/websharks/wp-redirects/issues/4). +- **Enhancement**: Overhauled the New/Edit Redirect screen. Sections are now modular meta boxes that can be hidden/shown using the Screen Options panel. Lots of inline documentation was also added to help clarify each option. See [#13](https://github.com/websharks/wp-redirects/issues/13). +- **Enhancement**: Refactored codebase to improve readability and organization of code. See [#9](https://github.com/websharks/wp-redirects/issues/9). +- **New Maintainer**: Added raamdev to the contributors list. [Raam Dev](https://profiles.wordpress.org/raamdev/) will now be maintaining the WP Redirects plugin. + = v131121 = * General code cleanup and optimizatioon. diff --git a/wp-redirects/wp-redirects.inc.php b/wp-redirects/wp-redirects.inc.php index 90541fc..a513510 100644 --- a/wp-redirects/wp-redirects.inc.php +++ b/wp-redirects/wp-redirects.inc.php @@ -15,7 +15,7 @@ class plugin // Base plugin class. public $file = ''; // Defined by class constructor. - public $version = '140912'; // See: `readme.txt` file. + public $version = '141009'; // See: `readme.txt` file. public $text_domain = ''; // Defined by class constructor. diff --git a/wp-redirects/wp-redirects.php b/wp-redirects/wp-redirects.php index 3fc0a5c..490124f 100644 --- a/wp-redirects/wp-redirects.php +++ b/wp-redirects/wp-redirects.php @@ -1,6 +1,6 @@