Only load JS/CSS for Contact Form 7 when needed

Contact Form 7 is a popular plugin for WordPress to add forms to a site. The plugin is free, and a lot of add-ons are also available.

To add a form to a page you will have to use a shortcode. A problem with shortcodes is, that one does not know when a shortcode is used. That is why plugins load their JavaScript and stylesheets on all pages. This is not good for performance, because functionality is always loaded, even if no form is present on a page.

WordPress doesn't have an out-of-the-box solution for this problem. If you know on which pages forms are used, you could unload scripts/styles on all other pages.


<?php
function customize_cf7_dequeue() {
  if ( ! is_page( 'contact' ) && ! is_single( 27 ) ) {
    wp_dequeue_script( 'contact-form-7' );
    wp_dequeue_style( 'contact-form-7' );
  }
}
add_action( 'wp_enqueue_scripts', 'customize_cf7_dequeue' );

But this is not very reliable, because you have to know the slug or post ID. And these are different for each site.

So I came up with a solution that works, without having to know slugs or post IDs.

Because Contact Form 7 relies on shortcodes. So you could only load the JS and CSS if the shortcode is actually used. To do this, you will have to unload scripts and styles for Contact Form 7. And then you check if its shortcode is present on the page.


<?php
function customize_cf7_dequeue() {
  wp_dequeue_script( 'contact-form-7' );
  wp_dequeue_style( 'contact-form-7' );
}
add_action( 'wp_enqueue_scripts', 'customize_cf7_dequeue' );

function customize_cf7_enqueue( $content ) {
  if ( has_shortcode( $content, 'contact-form-7' ) && function_exists( 'wpcf7_enqueue_styles' ) ) {
    wpcf7_enqueue_styles();
    wpcf7_enqueue_scripts();
  }
  return $content;
}
add_filter( 'the_content', 'customize_cf7_enqueue' );

This solution has one drawback. All scripts and styles are loaded at the bottom of the page (so after the form). This could lead to a flash of unstyled content where forms are briefly shown with default browser CSS styling. But it depends on how the browser handles this situation. In modern browsers the preloader will probably catch this. It is generally recommended to load CSS in the HTML <head>, but it works in all browsers if you load it in <body>.

For me, the performance benefit is far more important than following common practices. These are a rule of thumb and not laws. Because wasting bandwidth and slowing down pages is not in the best interest of your visitors.

[update] Alternatively you can add the CSS to the beginning of the shortcode. This would prevent a flash of unstyled content.


<?php
function customize_cf7_dequeue() {
  wp_dequeue_script( 'contact-form-7' );
  wp_dequeue_style( 'contact-form-7' );
}
add_action( 'wp_enqueue_scripts', 'customize_cf7_dequeue' );

function customize_cf7_enqueue( $content ) {
  if ( has_shortcode( $content, 'contact-form-7' ) && function_exists( 'wpcf7_enqueue_styles' ) ) {
    $content = '<link href="' . esc_url( wpcf7_plugin_url( 'includes/css/styles.css' ) . '?ver=' . WPCF7_VERSION ) . '" rel="stylesheet" type="text/css">' .
               $content;
    wpcf7_enqueue_scripts();
  }
  return $content;
}
add_filter( 'the_content', 'customize_cf7_enqueue' );