I am looking for a hook that fires before a specific page is loaded on the front end.
So something before wp_head() if possible?
I’d be very appreciative of any suggestions.
Thank you.
EDIT: I am considering template_redirect()
Any feelings on the pros / cons?
I would like to do an additional authorization check for specific pages before any data on the page is sent to the user.
Would template_redirect() cover this? Or do I need to “go earlier” than that?
So basically I have a number of roles set up.
But within that role, there is also different experience levels.
So to use a somewhat similar analogy that may be more familiar to everyone in the forums, let’s say new / basic / leader / committee.
And these users can have something similar to reputation levels.
I am checking that the user has the necessary role AND the necessary reputation to access the page.
If they don’t, I don’t want anything on the page to show up in their network traffic.
So I want the check to happen before anything, including the header on the page, is loaded.
I am not sure what exactly the hook sequence looks like, so I am not sure what is the best hook to use.
EDIT: I am not sure that I am using exactly the right terminology, so to make it as clear as I can, I want a redirect to happen before the page’s custom PHP (added via a reputable plugin from repo), or any of the custom JavaScript (added by another reputable plugin from repo) or any of the page’s HTML is loaded.
Here is front end actions sequence
(list from kama.ru with my comments):
mu_plugin_loaded
network_plugin_loaded
muplugins_loaded
registered_taxonomy
registered_post_type
plugin_loaded
plugins_loaded
sanitize_comment_cookies
setup_theme
load_textdomain
after_setup_theme// The earliest for a theme; user is not authorised, pugins are not initialized
auth_cookie_malformed
auth_cookie_valid
set_current_user// Triggered by kses, user is set
init// The most common and popular hook for plugins. Here you can get and process request vars if needed. All globals are set, as well as user & taxonomies, but no headers sent still to client
widgets_init
register_sidebar
wp_register_sidebar_widget
wp_default_scripts // Provides access to WP_Scripts object
wp_default_styles
admin_bar_init
add_admin_bar_menus
wp_loaded// Almost the same state as init, check docs for differences
parse_request
send_headers// That’s just where output starts technically
parse_query// Main query object is ready, you can check its parmeters
pre_get_posts
posts_clauses
posts_selection
wp// The most suitable place to edit main query before it executes
template_redirect // The most suitable place to redirect. No content displayed still
get_header// before displaying header.php
wp_head// insecure third-party output starts just here
wp_enqueue_scripts
wp_print_styles
wp_print_scripts
But depending on your task, you might not use hooks at all. If you are writing a page template and just want to hide some content for some users or roles, you can just do manual checks right before calling get_header. Something like this:
<?php /* Template Name: My Special Template */
global $wp, $wp_query, $wpdb; // if you need those
// Filtering anonymous users
if ( ! is_user_logged_in() ) {
header("HTTP/1.0 403 Forbidden");
exit;
}
// Filtering access by whitelist of IDs
$allowed_user_ids = array( 1, 2, 3 );
$current_user = wp_get_current_user();
if ( ! in_array ( $current_user->ID, $allowed_user_ids ) ) {
header("HTTP/1.0 403 Forbidden");
exit;
}
// Filtering access by user capability (role-based strategy)
$required_capability = 'edit_others_post';
if ( ! current_user_can( $required_capability ) ) {
header("HTTP/1.0 403 Forbidden");
exit;
};
// ... Enque your scripts and styles
// Call get_header() for standard design. Or just wp_head().
get_header();
// This is the part that I want to move to some point before wp_head();
// It is currently on the page itself
if ( $current_user_role === “new” ) { wp_safe_redirect ( $url_of_a_page ); exit; }
// This is the part that I want to stay on the page like you have in the custom template example
if ( in_array ($current_user_role, $allowed_roles) && in_array ($current_user_reputation, $allowed_reputation ) { // show this content }
elseif (in_array ($current_user_role, $allowed_roles) ) { // show that content }
elseif (in_array ($current_user_reputation, $allowed_reputation) ) { // show something different }
else { // catch all other scenarios content }
So if I understand your description above correctly, I need to choose a hook for the redirect that is after number 14, because if I understand correctly, I won’t be able to use wp_get_current_user(); before then, since the user is not set, and before number 32, since no content is displayed at 31 yet.
Well, I’m not an expert in this, but here are some thoughts.
As wp_safe_redirect() is a pluggable function you can’t call it before all plugins are loaded anyway. So the absolute minimum is ‘plugins_loaded’. But as you also need access to current user, you have to wait al least till ‘init’ fires (all global and functions loaded).
Next step depends on what kind of content you plan to show. I’m not sure about how wp_redirect works in detail, so you’d better check the code. But to my mind If the target url is external it’s safer to to hook before ‘send_headers’. Just to be sure you won’t get PHP warning ‘Headers already sent’. Perhups ‘init’ or ‘wp_loaded’ as they are most common. But once again, it’s not an expert advice. Maybe it’s no trouble to hook later and I play safe too much.
If you want an internal redirect, it might be wiser to use template inclusion or template redirection instead, as @joyously mentioned above.
And of course you can use any conditional logic inside a loaded template to show different content to different types of user. As you control calling wp_head() or get_header() you can check required user meta before them without any additional hooks.
If you are going to use wp_safe_redirect, then I would definitely recommend using the template_redirect hook. I do this a lot. Just remember to exit after the redirect.
is_page() is just a shortcut for $wp_query->is_page(). So yes, function is available since global $wp_query is set. There is a proper check, so otherwise it returns false anyway.
$page is listed in “Inside the Loop variables”. In general you shouldn’t use it outside the Loop, because it can be overriden by secondary loops/queries in some cases.
Might also help:
get_queried_object()
get_queried_object_id()
The key concept here is WP_Query. All other stuff is just shortcuts/wrappers/getters for its methods and variables. Once you get global $wp_query, you get access to all needed values.
This action hook executes just before WordPress determines which template page to load. It is a good hook to use if you need to do a redirect with full knowledge of the content that has been queried.
Also, in the future please enclose multi-line code blocks in three backquotes so that they are rendered correctly:
This sums up exactly where my issue is.
I’ve read through the entire Action Reference in the Codex and more details on the individual action hooks in the Codex, but I didn’t feel that I understand the nuance before @norske answered with solution marked as correct.
It really helps to see it in the order it happens with the comments.
I feel I am starting to understand, but not there yet. Still reading more.
My concern is exactly that I don’t want the redirect to happen “with full knowledge of the content being queried”.
I want the redirect to happen at the earliest possible opportunity when it is known that a user is requesting to view those specific pages. I don’t want the (full?) query to happen in the first place, if that makes sense.
In order to know (correctly according to the WP loading cycle) which page a user is requesting, then you need to let the full query happen. Functions that are based on WP_Query like is_page() are only available after the query executes during the wp action.
You might be able to get away with checking the URL during init, but I would expect this to cause problems with some plugins. I still think template_redirect is the best choice for this task.
I have no personal relation to that resourse. It’s a WP reference guide/handbook created by a passionte person - Timur. Probably this site is the oldest and the most popular wp-focused resourse in Runet. Many pages are in my bookmarks. The licence disallows direct copying of articles in whole, but allows quotations with opened hyperlinks, so I’m pretty sure you can use those lists in tutorial. But if you need some kind of guarantee, I can try to contact author and ask for a direct permission.