Login redirects. Author: Peter Version: 1.8.0 Change Log: 2010-03-18 1.8.0: Added the ability to specify a username in the redirect URL for more dynamic URL generation. 2010-03-04 1.7.3: Minor tweak on settings page for better compatibility with different WordPress URL setups. 2010-01-11 1.7.2: Plugin now removes its database tables when it is uninstalled, instead of when it is deactivated. This prevents the redirect rules from being deleted when upgrading WordPress automatically. 2009-10-07 1.7.1: Minor database compatibility tweak. (Thanks KCP!) 2009-05-31 1.7.0: Added option $rul_local_only (in the plugin file itself) to bypass the WordPress default limitation of only redirecting to local URLs. 2009-02-06 1.6.1: Minor database table tweak for better compatibility with different setups. (Thanks David!) 2008-11-26 1.6.0: Added a function rul_register that acts the same as the wp_register function you see in templates, except that it will return the custom defined admin address 2008-09-17 1.5.1: Fixed compatibility for sites with a different table prefix setting in wp-config.php. (Thanks Eric!) Author URI: http://www.theblog.ca */ /* -------------- Configuration -------------- */ // Setting this to false will make it so that you can redirect to any URL you want // Setting this to true will make it so that you can only redirect to a local URL (one on the same domain) $rul_local_only = false; /* -------------- All other settings are configured in Settings > Login redirects in the WordPress admin panel -------------- */ global $wpdb; global $rul_db_addresses; global $rul_version; // Name of the database table that will hold group information and moderator rules $rul_db_addresses = $wpdb->prefix . 'login_redirects'; $rul_version = '1.8.0'; // Some helper functions, all "public static" in PHP5 land class rulRedirectFunctionCollection { // Thanks to http://wordpress.org/support/topic/97314 for this function // This extra function is necessary to support the use case where someone was previously logged in function redirect_current_user_can($capability, $current_user) { global $wpdb; $roles = get_option($wpdb->prefix . 'user_roles'); $user_roles = $current_user->{$wpdb->prefix . 'capabilities'}; $user_roles = array_keys($user_roles, true); $role = $user_roles[0]; $capabilities = $roles[$role]['capabilities']; if ( in_array( $capability, array_keys( $capabilities, true) ) ) { // check array keys of capabilities for match against requested capability return true; } return false; } // A generic function to return the value mapped to a particular variable function rul_get_variable( $variable ) { switch( $variable ) { // Returns the current user's username (only use this if you know they're logged in) case 'username': default: global $user; return $user->user_login; break; } } // Replaces the syntax [variable]variable_name[/variable] with whatever has been mapped to the variable_name in the rul_get_variable function function rul_replace_variable( $string ) { preg_match_all( "/\[variable\](.*?)\[\/variable\]/is", $string, $out ); foreach( $out[0] as $instance => $full_match ) { $replaced_variable = rulRedirectFunctionCollection::rul_get_variable( $out[1][ $instance ] ); $string = str_replace( $full_match, $replaced_variable, $string ); } return $string; } } // This function wraps around the main redirect function to determine whether or not to bypass the WordPress local URL limitation function redirect_wrapper( $redirect_to, $requested_redirect_to, $user ) { global $rul_local_only; // If they're on the login page, don't do anything if ( !isset ( $user->user_login ) ) { return $redirect_to; } $rul_url = redirect_to_front_page( $redirect_to, $requested_redirect_to, $user ); if( $rul_local_only ) { return $rul_url; } else { wp_redirect( $rul_url ); die(); } } // This function sets the URL to redirect to function redirect_to_front_page( $redirect_to, $requested_redirect_to, $user ) { global $wpdb, $rul_db_addresses; // Check for a redirect rule for this user $rul_user = $wpdb->get_var('SELECT rul_url FROM ' . $rul_db_addresses . ' WHERE rul_type = \'user\' AND rul_value = \'' . $user->user_login . '\' LIMIT 1'); if ( $rul_user ) { $redirect_to = rulRedirectFunctionCollection::rul_replace_variable( $rul_user ); return $redirect_to; } // Check for a redirect rule that matches this user's role $rul_roles = $wpdb->get_results('SELECT rul_value, rul_url FROM ' . $rul_db_addresses . ' WHERE rul_type = \'role\'', OBJECT); if ( $rul_roles ) { foreach ( $rul_roles as $rul_role ) { if ( isset ( $user->{$wpdb->prefix . 'capabilities'}[$rul_role->rul_value] ) ) { $redirect_to = rulRedirectFunctionCollection::rul_replace_variable( $rul_role->rul_url ); return $redirect_to; } } } // Check for a redirect rule that matches this user's capability $rul_levels = $wpdb->get_results('SELECT rul_value, rul_url FROM ' . $rul_db_addresses . ' WHERE rul_type = \'level\' ORDER BY rul_order, rul_value', OBJECT); if ( $rul_levels ) { foreach ( $rul_levels as $rul_level ) { if ( rulRedirectFunctionCollection::redirect_current_user_can ( $rul_level->rul_value, $user ) ) { $redirect_to = rulRedirectFunctionCollection::rul_replace_variable( $rul_level->rul_url ); return $redirect_to; } } } // If none of the above matched, look for a rule to apply to all users $rul_all = $wpdb->get_var('SELECT rul_url FROM ' . $rul_db_addresses . ' WHERE rul_type = \'all\' LIMIT 1'); if( $rul_all ) { $redirect_to = rulRedirectFunctionCollection::rul_replace_variable( $rul_all ); return $redirect_to; } // No rules matched or existed, so just send them to the WordPress admin panel as usual return $redirect_to; } // Typically this function is used in templates, similarly to the wp_register function // It returns a link to the administration panel or the one that was custom defined // If no user is logged in, it returns the "Register" link // You can specify tags to go around the returned link (or wrap it with no tags); by default this is a list item // You can also specify whether to print out the link or just return it function rul_register( $before = '
**** ERROR: Non-local or invalid URL submitted for user "' . $username . '" ****
' . "\n"; } else { // Update the existing entry or insert a new one $rul_update_username = $wpdb->query('REPLACE INTO ' . $rul_db_addresses . ' SET rul_url = \'' . $address . '\', rul_type = \'user\', rul_value = \'' . $username . '\''); if (!$rul_update_username) { $rul_submit_success = false; $rul_process_submit .= '**** ERROR: Unknown error updating user-specific URL for user "' . $username . '" ****
' . "\n"; } } // Make a note that we've updated this username $rul_usernames_updated[] = $username; } elseif ($username != -1) { $rul_submit_success = false; $rul_process_submit .= '**** ERROR: Non-existent username submitted ****
' . "\n"; } ++$rul_username_loop; } // Prepare the "not in" MySQL code $rul_usernames_notin = "'" . implode($rul_usernames_updated, "','") . "'"; // Delete all username rules in the database that weren't updated (in other words, the user unchecked the box next to it) $wpdb->query('DELETE FROM ' . $rul_db_addresses . ' WHERE rul_type = \'user\' AND rul_value NOT IN (' . $rul_usernames_notin . ')'); if ($rul_submit_success) { $rul_process_submit .= 'Successfully updated user-specific URLs
' . "\n"; } } // Close the informational div $rul_process_submit .= $rul_process_close; // We've made it this far, so success! return $rul_process_submit; } // Processes the rule updates per role function rul_submit_role($roles, $addresses) { global $wpdb, $rul_db_addresses; $rul_whitespace = ' '; // Open the informational div $rul_process_submit = '**** ERROR: Non-local or invalid URL submitted for role "' . $role . '" ****
' . "\n"; } else { // Update the existing entry or insert a new one $rul_update_role = $wpdb->query('REPLACE INTO ' . $rul_db_addresses . ' SET rul_url = \'' . $address . '\', rul_type = \'role\', rul_value = \'' . $role . '\''); if (!$rul_update_role) { $rul_submit_success = false; $rul_process_submit .= '**** ERROR: Unknown error updating role-specific URL for role "' . $role . '" ****
' . "\n"; } } // Make a note that this role name was updated $rul_roles_updated[] = $role; } elseif ($role != -1) { $rul_submit_success = false; $rul_process_submit .= '**** ERROR: Non-existent role submitted ****
' . "\n"; } ++$rul_role_loop; } // Built the "not in" MySQL query $rul_roles_notin = "'" . implode($rul_roles_updated, "','") . "'"; // Delete all role rules in the database that weren't updated (in other words, the user unchecked the box next to it) $wpdb->query('DELETE FROM ' . $rul_db_addresses . ' WHERE rul_type = \'role\' AND rul_value NOT IN (' . $rul_roles_notin . ')'); if ($rul_submit_success) { $rul_process_submit .= 'Successfully updated role-specific URLs
' . "\n"; } } // Close the informational div $rul_process_submit .= $rul_process_close; // We've made it this far, so success! return $rul_process_submit; } function rul_submit_level($levels, $orders, $addresses) { global $wpdb, $rul_db_addresses; $rul_whitespace = ' '; // Open the informational div $rul_process_submit = '**** ERROR: Non-local or invalid URL submitted for level "' . $level . '" ****
' . "\n"; } else { // Update the existing entry or insert a new one $rul_update_level = $wpdb->query('REPLACE INTO ' . $rul_db_addresses . ' SET rul_url = \'' . $address . '\', rul_type = \'level\', rul_value = \'' . $level . '\', rul_order = ' . $order); if (!$rul_update_level) { $rul_submit_success = false; $rul_process_submit .= '**** ERROR: Unknown error updating level-specific URL for level "' . $level . '" ****
' . "\n"; } } // Make a note that this level was updated $rul_levels_updated[] = $level; } elseif ($level != -1) { $rul_submit_success = false; $rul_process_submit .= '**** ERROR: Non-existent level submitted ****
' . "\n"; } ++$rul_level_loop; } // Build the "not in" MySQL code $rul_levels_notin = "'" . implode($rul_levels_updated, "','") . "'"; // Delete all level rules in the database that weren't updated (in other words, the user unchecked the box next to it) $wpdb->query('DELETE FROM ' . $rul_db_addresses . ' WHERE rul_type = \'level\' AND rul_value NOT IN (' . $rul_levels_notin . ')'); if ($rul_submit_success) { $rul_process_submit .= 'Successfully updated level-specific URLs
' . "\n"; } } // Close the informational div $rul_process_submit .= $rul_process_close; // We've made it this far, so success! return $rul_process_submit; } function rul_submit_all($update_or_delete, $address) { global $wpdb, $rul_db_addresses; $rul_whitespace = ' '; // Open the informational div $rul_process_submit = '**** ERROR: Unknown database problem removing URL for "all other users" ****
' . "\n"; } else { $rul_process_submit .= 'Successfully removed URL for "all other users"
'; } } elseif($update_or_delete == 'Update') { $address = rul_safe_redirect($address); if (!$address) { $rul_process_submit .= '**** ERROR: Non-local or invalid URL submitted ****
' . "\n"; } else { $update = $wpdb->update ( $rul_db_addresses, array ('rul_url' => $address ), array ('rul_type' => 'all') ); if ($update === false) { $rul_process_submit .= '**** ERROR: Unknown database problem updating URL for "all other users" ****
' . "\n"; } else { $rul_process_submit .= 'Successfully updated URL for "all other users"
' . "\n"; } } } // Close the informational div $rul_process_submit .= $rul_process_close; // We've made it this far, so success! return $rul_process_submit; } /* Stolen fron wp_safe_redirect, which validates the URL */ function rul_safe_redirect($location) { global $rul_local_only; if( !$rul_local_only ) { return $location; } // Need to look at the URL the way it will end up in wp_redirect() $location = wp_sanitize_redirect($location); // browsers will assume 'http' is your protocol, and will obey a redirect to a URL starting with '//' if ( substr($location, 0, 2) == '//' ) { $location = 'http:' . $location; } // In php 5 parse_url may fail if the URL query part contains http://, bug #38143 $test = ( $cut = strpos($location, '?') ) ? substr( $location, 0, $cut ) : $location; $lp = parse_url($test); $wpp = parse_url(get_option('home')); $allowed_hosts = (array) apply_filters('allowed_redirect_hosts', array($wpp['host']), isset($lp['host']) ? $lp['host'] : ''); if ( isset($lp['host']) && ( !in_array($lp['host'], $allowed_hosts) && $lp['host'] != strtolower($wpp['host'])) ) { return false; } else { return $location; } } // This is the Settings > Login redirects menu function rul_optionsmenu() { global $wpdb, $rul_db_addresses; // Process submitted information to update redirect rules if ($_POST['rul_usernamesubmit']) { $rul_process_submit = rul_submit_username($_POST['rul_username'], $_POST['rul_usernameaddress']); } elseif ($_POST['rul_rolesubmit']) { $rul_process_submit = rul_submit_role($_POST['rul_role'], $_POST['rul_roleaddress']); } elseif ($_POST['rul_levelsubmit']) { $rul_process_submit = rul_submit_level($_POST['rul_level'], $_POST['rul_levelorder'], $_POST['rul_leveladdress']); } elseif ($_POST['rul_allsubmit']) { $rul_process_submit = rul_submit_all($_POST['rul_allsubmit'], $_POST['rul_all']); } // ----------------------------------- // Get the existing rules // ----------------------------------- $rul_rules = $wpdb->get_results('SELECT rul_type, rul_value, rul_url, rul_order FROM ' . $rul_db_addresses . ' ORDER BY rul_type, rul_order, rul_value', ARRAY_N); if ($rul_rules) { $i = 0; $i_user = 0; $rul_usernames_existing = array(); $i_role = 0; $rul_roles_existing = array(); $i_level = 0; $rul_levels_existing = array(); $rul_usernamevalues = ''; while ($i < count($rul_rules)) { list($rul_type, $rul_value, $rul_url, $rul_order) = $rul_rules[$i]; // Specific users if ($rul_type == 'user') { $rul_usernamevalues .= '' . $rul_value . '
' . $rul_value . '
' . $rul_value . '
Define different local URLs to which different users, users with specific roles, users with specific levels, and all other users will be redirected.
Note that you can use the syntax [variable]username[/variable] in your URLs so that the system will build a dynamic URL upon each login, replacing that text with the user's username.