WordPress is the most popular content management system (CMS) in the world, with a market share of more than 60%.
A big support community and a number of available free plugins make building a website with WordPress (WP) affordable, and it plays a key role in why its market share is so big.
However, as you know, installing plugins comes at a cost.
They often may degrade your Core Web Vitals scores; For example, they may load unnecessary CSS or JS files on every page where they are not needed.
To fix that, you need to hire a programmer to do it for you, buy a premium plugin, or perhaps go down a small learning path and do it yourself.
You can also go hybrid and solve some parts of your issues by custom coding, and other parts using plugins.
This article aims to help you in your learning path, and we will cover the most needed WordPress hooks to help you improve your website’s technical SEO.
What Is A WordPress Hook?
WordPress hooks are key features in WP that allow developers to extend the functionality of the CMS without a need to modify core WP files – making it easier to update themes or plugins without breaking custom modifications.
They provide a powerful way for developers to extend the functionality of WordPress and make custom changes to their sites.
What Is A Filter Hook?
The hook filter function is used to modify the output of the function before it is returned. For example, you can suffix page titles with your blog name using the wp_title filter hook.
What Is An Action Hook?
Action hooks allow programmers to perform certain actions at a specific point in the execution of WP Core, plugins, or themes, such as when a post is published, or JS and CSS files are loaded.
By learning a few basic action hooks or filters, you can perform a wide range of tasks without the need to hire developers.
We will go through the following hooks:
- wp_enqueue_scripts
- wp_head
- script_loader_tag
- template_redirect
- wp_headers
wp_enqueue_scripts
This is exactly the action hook you would use to exclude redundant CSS or JS files from loading on pages where they are not needed.
For example, the popular free Contact Form 7 plugin, which has over 5M installations, loads CSS and JS files on all pages – whereas one only needs it to load where the contact form exists.
To exclude CF7 CSS and JS files on pages other than the contact page, you can use the code snippet below.
function my_dequeue_script(){ //check if page slug isn't our contact page, alternatively, you can use is_page(25) with page ID, or if it is a post page is_single('my-post') if ( !is_page('contact') ) { wp_dequeue_script('google-recaptcha'); wp_dequeue_script('wpcf7-recaptcha'); wp_dequeue_script('contact-form-7'); wp_dequeue_style('contact-form-7'); } } add_action('wp_enqueue_scripts', 'my_dequeue_script', 99 );
There are a few key points; the action hook priority is set to 99 to ensure our modification runs last in the queue.
If you set it to, say, 10, it will not work because CF7 enqueue function uses priority 20. So to ensure yours run last and have an effect, set a priority large enough.
Also, in the code, we used as a function argument identifier “contact-form-7”; you may wonder how I found that.
It is pretty simple and intuitive. Just use inspect element tool of your browser and check for the id attribute of link or script tags.
You can check your website source code using inspect element and start dequeuing any JS or CSS file where they are not needed.
wp_head
This action hook is used to add any resource JS, CSS files, or meta tags in the <head> section of the webpage.
Using this hook, you can load preload above-the-fold resources in the head section, which can improve your LCP scores.
For example, font preloading, which is one of Google’s recommendations, or logo and featured images on article pages, always load above the fold – and you need to preload them to improve LCP.
For that, use the code snippet below.
function my_preload() { ?> <!-- Google Fonts --> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,200..900;1,200..900&family=Lora:ital,wght@0,400..700;1,400..700&display=swap"/> <link rel="preload" as="image" href="https://www.yoursite.com/path-to-logo/image.jpg"/> <?php if( has_post_thumbnail() ): // check if article has featured image?> <!-- Featured Image --> <?php // $featured_image = str_ireplace(array( '.png', '.jpg', '.jpeg'), '.webp', $featured_image ); // enable this if you have webp images. ?> <?php $featured_image = get_the_post_thumbnail_url( get_the_ID(), 'full' ); ?> <link rel="preload" as="image" href="<?php echo $featured_image;?>"/> <?php endif; } add_action('wp_head', 'my_preload', 3 );
The first two lines are for preloading Google fonts, then we preload the logo and check if the article has a featured image, then preload the featured image.
As an additional note, your theme or site may have webp images enabled; in that case, you should preload webp version of them.
script_loader_tag
You heard a lot about render-blocking resources which can be fixed by defer or async loading JavaScript tags. It is critical for improving FCP and LCP.
This filter action is used to filter the HTML output of the script tags, and you need exactly this filter to async or defer load your theme or plugin’s JS/CSS files.
function my_defer_async_load( $tag, $handle ) { // async loading scripts handles go here as an array $async_handles = array('wpcf7-recaptcha', 'another-plugin-script'); // defer loading scripts handles go here as an array $defer_handles = array('contact-form-7', 'any-theme-script'); if( in_array( $handle, $async_handles) ){ return str_replace( ' src', ' async src', $tag ); } if( in_array( $handle, $defer_handles ) ){ return str_replace( ' src', ' defer="defer" src', $tag ); } return $tag; } add_filter('script_loader_tag', 'my_defer_async_load', 10, 2);
This filter accepts two arguments: HTML tag, and script handle, which I mentioned above when examining via inspect element.
You can use the handle to decide which script to load async or defer.
After you defer or async load, always check via the browser console if you have any JS errors. If you see JS errors, you may need a developer to help you, as fixing them may not be straightforward.
template_redirect
This action hook is called before determining which template to load. You can use it to change the HTTP status code of the response.
For example, you may have spammy backlinks to your internal search query pages containing weird characters and/or common patterns.
At Search Engine Journal, we are used to having spammy backlinks pointing to our internal search pages that are in Korean – and we have learned from our server logs that Googlebot was intensively crawling them.
WordPress default response code is 404 not found, but it is better to throw in 410 in order to tell Google they are gone forever, so it stops crawling them.
function my_410_function(){ if( is_search() ) { $kw = $_GET['s']; // check if the string contains Korean characters if (preg_match('/[\x{AC00}-\x{D7AF}]+/u', $kw)) { status_header(410, 'Not Found'); } }// end of is_search } add_action( 'template_redirect', 'my_410_function', 10 );
In our case, we know that we don’t have Korean content, which is why we composed our condition like that.
But you may have international content in Korean, and conditions may differ.
Generally, for non-programmers, ChatGPT is a great tool for generating conditions using a regular expression, which you may use to build an if/else condition based on your spam pattern from GSC.
wp_headers
This action hook is used to modify HTTP headers of WordPress.
You can use this hook to add security headers to your website response HTTP headers.
function my_headers(){ $headers['content-security-policy'] = 'upgrade-insecure-requests'; $headers['strict-transport-security'] = 'max-age=31536000; preload'; $headers['X-Content-Type-Options'] = 'nosniff'; $headers['X-XSS-Protection'] = '1; mode=block'; $headers['x-frame-options'] = 'SAMEORIGIN'; $headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'; $headers['Link'] = '<https://www.yoursite.com/wp-content/uploads/themes/yourtheme/images/logo.jpg>; rel=preload; as=image'; $headers['Link'] = '<https://fonts.gstatic.com>; rel=preconnect; crossorigin'; $headers['Link'] = '</wp-content/uploads/themes/yourtheme/images/logo.webp>; rel=preload; as=image'; return $headers; } add_filter( 'wp_headers', 'my_headers', 100 );
Beside security headers, you can add “Link” tags (as many as you want) for pre-connecting or preloading any resource.
Basically, it is an alternative method of preloading, which was covered above.
You may also add “X-Robots-Tag” (as many as you want ) to your HTTP headers based on your needs.
Conclusion
Plugins are often aimed at solving a wide variety of tasks and may often not be designed specifically to fulfill your specific needs.
The ease with which you can modify WordPress core is one of its most beautiful aspects – and you can alter it with a few lines of code.
We discussed action hooks you can use to improve technical SEO, but WordPress has a large number of action hooks you can explore and use to do basically everything you want with minimal use of plugins.
More resources:
Featured Image: Grafico moze/Shutterstock
window.addEventListener( 'load2', function() { console.log('load_fin');
if( sopp != 'yes' && !window.ss_u ){
!function(f,b,e,v,n,t,s) {if(f.fbq)return;n=f.fbq=function(){n.callMethod? n.callMethod.apply(n,arguments):n.queue.push(arguments)}; if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; n.queue=[];t=b.createElement(e);t.async=!0; t.src=v;s=b.getElementsByTagName(e)[0]; s.parentNode.insertBefore(t,s)}(window,document,'script', 'https://connect.facebook.net/en_US/fbevents.js');
if( typeof sopp !== "undefined" && sopp === 'yes' ){ fbq('dataProcessingOptions', ['LDU'], 1, 1000); }else{ fbq('dataProcessingOptions', []); }
fbq('init', '1321385257908563');
fbq('track', 'PageView');
fbq('trackSingle', '1321385257908563', 'ViewContent', { content_name: 'wordpress-hooks', content_category: 'web-development wp' }); } });