It’s easy to create URLs with WP that find and map to content. Making URLs that trigger an action is a bit harder.
The main idea here is that I want a specific action to take place when a user clicks a link to a specific URL. Let’s say unsubscribe from a mailing list.
The unsubscribe link may look like this: http://yoursite.com/unsubscribe/21225/jdf94jjf9o45jrjsdja8kjm4
That link represents http://yoursite.com/unsubscribe/user_id/hash ( where hash is a value that has been stored in usermeta )
The rewrite rule might look like so:
add_rewrite_rule( 'unsubscribe/([0-9]+)/([^/]+)/?$', 'index.php?unsubscribe=1&uid=$matches[1]&hash=$matches[2]', 'top' );
After the rule has been added it’s necessary to flush all the rewrite_rules. Easiest way to do that is by saving permalinks. If the rule is added in a plugin, the activation hook is a good place, just before flushing all rules
flush_rewrite_rules();
We will also need to add query vars for the user_id and hash. This can be done using the query_vars filter:
add_filter ( 'query_vars', 'add_unsubscribe_query_vars' );
That hook provides you with an array of the existing query_vars. You just need to add your own and return the array:
function add_unsubscribe_query_var( $query_vars ) { $query_vars[] = 'uid'; $query_vars[] = 'hash'; $query_vars[] = 'unsubscribe'; return $query_vars; }
Now we need a way to intercept the data. Remember, this is not redirecting to an existing page. We can do this with the parse_request action hook:
add_action ( ‘parse_request’, ‘process_unsubscribe’ );
parse_request is the first action after the URL has been parsed. This happens before any headers are sent, before the main query is run, etc…
function process_unsubscribe_endpoint() { global $wp; // if the query var is not available, bail if ( ! isset ( $wp->query_vars['unsubscribe'] ) ) { return; } $opt_out_key = 'opt_out_of_email'; // your query vars should be available in the $wp object $hash = $wp->query_vars['hash']; $user = get_userdata( $wp->query_vars['uid'] ); $user_id = $user->ID; if ( false !== update_user_meta( $user_id, $opt_out_key, true ) ) { echo 'You have been unsubscribed.'; } else { echo 'this means there was a problem updating the usermeta table. } }