An in-depth guide on using Ajax with WordPress

WordPress Loading Techniques

So far we’ve gone through loading scripts and styles properly. We even covered localizing scripts, and how to use page detection to load your scripts exactly where needed.

What’s next? Let’s call this the chapter of questionable hacks and techniques in order to load your scripts, disable scripts and styles, and other unfavorable techniques. Please consider this chapter the black sheep of this book.

Let’s get started and figure out how to override the scripts and styles that other plugins or themes have provided.

Overriding Scripts and Styles

The beauty of queuing scripts and styles is that a rogue plugin author (such as myself) can override and/or disable the queued items at will. This can amount to disabling core WordPress scripts and styles, or dequeuing scripts and styles from a third-party plugin or theme.

Why in the world would anyone want to do this?

Say, for example, that you have a plugin that handles pagination such as WP PageNavi. It’s a popular plugin with over 800,000 installs (yikes) as of this publication. It does one thing pretty much, and does it well: it makes your pagination on your WordPress site pretty. Instead of the next page and previous page prompts you often see on default WordPress themes, it adds nice numeric options so you can easily navigate through pages.

Some themes I’ve seen even include WP PageNavi as a hard-coded option because of the deep customization that is required to make WP PageNavi match your theme.

WP PageNavi requires child theme modifications, so let’s create one real quick using WordPress 5.3’s Twenty Twenty theme. We’ll just call this one Twenty Twenty Child. I won’t go over the details of creating a child theme here, but you’re welcome to download the code and investigate for yourself. A child theme for one plugin is overkill, but it’s a good practice to always make modifications to your theme through a child theme.

Once the child theme and WP PageNavi is installed, we can activate both. Within the child theme, I override a template part for pagination.

<?php
/**
 * Override TwentyTwenty's pagination and use WP PageNavi
 *
 * @package twentytwenty-child
 */

if ( function_exists( 'wp_pagenavi' ) ) {
	wp_pagenavi();
}

And… it looks a bit ugly.

WP PageNavi Unmodified Style
WP PageNavi Unmodified Style

Let’s override it! We’ll use the child theme’s functions.php file to de-register WP PageNavi’s styles and include our own CSS.

<?php
/**
 * Main functions file for child theme TwentyTwenty.
 *
 * @package twentytwenty-child
 */

add_action( 'wp_enqueue_scripts', 'twentytwenty_child_enqueue_styles', 100 );
/**
 * Dequeue PageNavi's styles and include our own.
 */
function twentytwenty_child_enqueue_styles() {
	// Dequeue PageNavi's styles.
	wp_deregister_style( 'wp-pagenavi' );

	// Enqueue our own.
	wp_enqueue_style(
		'wp-pagenavi',
		get_stylesheet_directory_uri() . '/pagenavi.css',
		array(),
		'1.0.0'
	);
}

And here’s the contents of our pagenavi.css file.

/*
Default style for WP-PageNavi plugin

http://wordpress.org/extend/plugins/wp-pagenavi/
*/

.wp-pagenavi {
	clear: both;
	text-align: center;
}

.wp-pagenavi a, .wp-pagenavi span {
	display: inline-block;
	text-decoration: none;
	border: 4px solid #cd2653;
	padding: 10px 20px;
	margin: 2px;
	background: #000;
	color: #FFF;
}

.wp-pagenavi a:hover, .wp-pagenavi span.current {
	border-color: #cd2653;
}

.wp-pagenavi span.current {
	font-weight: 700;
}

And here’s what the new layout looks like. I’m no designer, but I did my best to match Twenty Twenty’s default styles and it appears reasonable.

WP PageNavi Styled
WP PageNavi Styled to Match Theme

In summary, we created a child theme, overwrote the theme’s pagination with WP PageNavi, deregistered WP PageNavi’s styles, and finally included our own. Overkill? Yes! But hopefully, you learned something.

Let’s go over a few more examples with WP PageNavi. Examining the plugin’s code, it registers its scripts and styles with the default priority for an action: 10. Let’s execute some code in a lower priority so we can trick WordPress in thinking that it should use our script instead.

add_action( 'wp_enqueue_scripts', 'twentytwenty_child_enqueue_styles', 1 );
/**
 * Register our style before PageNavi.
 */
function twentytwenty_child_enqueue_styles() {

	// Enqueue our own.
	wp_register_style(
		'wp-pagenavi',
		get_stylesheet_directory_uri() . '/pagenavi.css',
		array(),
		'1.0.0'
	);
}

You’ll notice above a third argument for the add_action argument, which is the priority. We’ve assigned a low priority so we can register our style before WP PageNavi gets a chance. As a result, our style is loaded instead.

By registering our style first, the handler name becomes reserved. Even though PageNavi queues its style with its own stylesheet, WordPress sees the handler that we previously registered and uses that one instead.

If PageNavi decided to change its priority lower, we’d just have to use a higher priority and deregister it like we did in the Twenty Twenty example.

An alternative to the above examining PageNavi’s code is to just simply remove the action that PageNavi uses to register its styles. This requires a bit of code exploration, but the plugin is coded well and it was easy to find the static method that loads its styles.

<?php
/**
 * Main functions file for child theme TwentyTwenty.
 *
 * @package twentytwenty-child
 */

add_action( 'init', 'wp_pagenavi_style_disable' );
/**
 * Disable PageNavi's hook enabling its stylesheet.
 */
function wp_pagenavi_style_disable() {
	remove_action( 'wp_enqueue_scripts', 'PageNavi_Core::stylesheets' );
}
add_action( 'wp_enqueue_scripts', 'twentytwenty_child_enqueue_styles' );
/**
 * Enqueue our own stylesheet for PageNavi.
 */
function twentytwenty_child_enqueue_styles() {

	// Enqueue our own.
	wp_enqueue_style(
		'wp-pagenavi',
		get_stylesheet_directory_uri() . '/pagenavi.css',
		array(),
		'1.0.0'
	);
}

Okay, enough of picking on PageNavi! It’s fun, but there are a few more techniques out there I’d like to get through.

Loading a Custom Template

What if you want to load scripts in an iframe or even override WordPress’s default template? You can easily override a template in WordPress and supply your own if the need arises.

With this technique, you can load your own scripts, prevent others from loading, and provide your own styling outside of the theme installed.

A use-case would be if you want to load a full-width interface for a certain plugin’s interface. For example, I had a need for a full-width template for a plugin called UpdraftCentral. It’s designed to be full-width, but often the theme adds a sidebar, which truncates the width and it just doesn’t look well in a smaller interface.

Let’s get started! With UpdraftCentral, I just used a piece of post meta to determine if a new template should be loaded. Here’s some example code:

add_filter( 'template_include', 'block_for_updraftcentral_single_override', 99 );

/**
 * Overrides UpdraftPlus
 *
 * @param string $template The template file to override.
 *
 * @return string updated template file.
 */
function block_for_updraftcentral_single_override( $template ) {
	$id = absint( get_queried_object_id() );
	if ( 'full' === get_post_meta( $id, '_updraftcentral_template', true ) ) {
		return plugin_dir_path( __FILE__ ) . '/templates/updraftcentral.php';
	}
	return $template;
}

In the above code sample, we add a filter called template_include. This allows us to override the template. We then check for some post meta, and if it matches, we load a template that is not the default.

Here’s what’s in the template. It’s bare-bones and just outputs the contents of a post.

<?php
/**
 * Output slide content for single slide.
 *
 * @package   Block_for_UpdraftCentral
 */

add_filter( 'show_admin_bar', '__return_false' );
?>
<?php
/**
 * The template for displaying the header.
 *
 * @package Block_for_UpdraftCentral
 */
?>
<!DOCTYPE html>
<html lang="en" style="margin: 0 !important;">
<head>
	<meta charset="utf-8">
	<meta name="apple-mobile-web-app-capable" content="yes"/>
	<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<?php
	do_action( 'wp_head' );
	?>
</head>
<body>
<div class="updraftcentral">
	<?php
	if ( have_posts() ) {
		while ( have_posts() ) {
			the_post();
			the_content();
		}
	}
	?>
</div>
<?php
do_action( 'wp_footer' );
?>
</body>
</html>

What if we want a template that loads just our scripts and styles? I’m going to be scolded for this, but you can re-use the above example and remove the wp_head and wp_footer actions. The wp_head and wp_footer actions, for the most part, are required so other plugins and themes can load their own assets. But in this case, we don’t want to allow this.

We can use the WordPress functions wp_print_scripts and wp_print_styles to output just our assets. Let’s assume we have previously registered our scripts and styles. We can then output our theme in this custom template.

<?php
/**
 * Output slide content for single slide.
 *
 * @package   Block_for_UpdraftCentral
 */

add_filter( 'show_admin_bar', '__return_false' );
?>
<!DOCTYPE html>
<html lang="en" style="margin: 0 !important;">
<head>
	<meta charset="utf-8">
	<meta name="apple-mobile-web-app-capable" content="yes"/>
	<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/>
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<?php
	wp_print_styles(
		array(
			'my-custom-stylesheet',
		)
	);
	?>
</head>
<body>
<!-- my custom HTML or PHP -->
<?php
wp_print_scripts(
	array(
		'my-custom-script',
		'another-script',
	)
);
?>
</body>
</html>

In the above example, we load styles in the header and scripts in the footer. Since we’ve removed the actions wp_head and wp_footer, we’re basically on our own as far as styles and scripts go. But if you really want your own template, this is one technique.

Loading Scripts and Styles for a Specific Template

Say you’re creating an add-on plugin for a theme and you want to load your scripts and styles for only a specific page template. This technique essentially falls under page detection, but you can get really creative.

First, let’s check to see if a page template has been applied to a page.

<?php
if ( is_page() ) {
	$page_id = absint( get_queried_object_id() );

	// Get the template.
	$template = get_post_meta( $page_id, '_wp_page_template', true );
	if ( 'custom-page-full-width.php' ) {
		// enqueue our scripts and styles here.
	}
}

In the above example, we use the is_page conditional to check if we’re on a page, which is typically where page templates get assigned. We then get the page id via the WordPress function get_queried_object_id. We then check for a custom field called _wp_page_template. If a certain page template is being used, we can enqueue our scripts and styles and have them load only for that specific page template.

Loading WordPress Via a Template Redirect

When you are performing a template redirect, you are (in effect) taking control and dictating to WordPress which path to take. You can load custom templates, perform 301 redirects, set headers, and much more.

In this case, we’ll be using a template redirect to load a custom page based on query variables. Since the WordPress environment has already been loaded by the time it gets to our redirect, we don’t have to worry about WordPress functions not being initiated yet.

First things first: let’s set up the actions and filters needed to add a query variable.

add_action( 'template_redirect', 'my_prefix_load_page' );
add_filter( 'query_vars', 'my_prefix_query_trigger' );

You can place the above code in a theme’s functions.php file or include it in your plugin’s base file (if writing a plugin). Since we’re using procedural code, I’ve prepended my_prefix to the beginning of the function callback. Prefixing is necessary in order to prevent naming conflicts. Alternatively, we could just do a PHP namespace and not have to worry about prefixes, but I won’t go over that in this chapter.

The query_vars filter enables us to add a query variable to WordPress. The template_redirect action allows us to capture this query variable and perform an action on it.

Let’s start with the my_prefix_query_trigger function first.

<?php
function my_prefix_query_trigger( $queries ) {
	$queries[] = 'my_page';
	return $queries;
}

With the query_trigger function, we are automatically passed a list of existing WordPress query variables. It’s our job to add in our query (in this case, my_page) and return the queries array.

Now we have to do something with our query variable, so let’s move on to the my_prefix_load_page function.

<?php
function my_prefix_load_page() {
	$pagepath = plugin_dir_path( __FILE__ );
	switch ( get_query_var( 'my_page' ) ) {
		case 'help.php':
			$path = $pagepath . 'help.php'
			if ( file_exists( $path ) ) {
				include $path;
			}
			exit;
		case 'changelog.php':
			$path = $pagepath . 'changelog.php'
			if ( file_exists( $path ) ) {
				include $path;
			}
			exit;
		default:
			break;
	}
}

The first thing the my_prefix_load_page function does is establish an include path, which is captured in the $pagepath variable. The function performs a switch statement in order to capture the query variable (if applicable). It might take a feel tries to get this right. Trial and error is your good, albeit always drunk, friend.

Right now, we have two cases: one for help.php and another for changelog.php. If any of those are found, we load the appropriate page.

So here’s how it works. Instead of pointing your browser to a WordPress page, you would point it to a query.

Using https://mydomain.com/?my_page=help.php would load the help.php file. Likewise, using https://mydomain.com/?my_page=changelog.php would load the changelog.php file.

The benefits of this technique? WordPress has already loaded and there’s no need for hacks such as loading WordPress manually. You also have access to all the available WordPress functions, classes, actions, filters, and so on.

Please note that in both help.php and changelog.php, you’ll have to enqueue your scripts and styles manually.

WordPress Loading Techniques Conclusion

Within this chapter you learned how to:

  • Override scripts and styles
  • Load just your scripts
  • Create a stand-alone page using a template override and also with query variables

Some of these techniques are just out-right hacks, but I’ll leave it up to you to decide which ones make sense for your use-cases.

Since we’ve got all the basics out of the way, let’s move on to doing a little bit of jQuery in the next chapter.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top