How to filter the output of Contact Form 7 or any other shortcode in WordPress

WordPress 4.7, released in December 2017, introduced a new filter hook called do_shortcode_tag. This new hook makes it easy to modify the output generated by shortcodes, either all shortcodes or shortcodes that meet specific conditions.

The do_shortcode_tag filter hook supports four arguments.

  1. The first argument is the output to be filtered. It is the only required argument.
  2. The second argument is the tag (that is, the name) of the shortcode to be filtered.
  3. The third argument is an array of the shortcode attributes. This argument makes it possible to target specific instances of a shortcode.
  4. The fourth argument is an array of the six group matches returned by get_shortcode_regex(). With this argument we can, for example, target shortcodes wrapping content that contains a certain string.

Let’s see four examples of using do_shortcode_tag, one for each argument it supports.

Example 1

function op111_shortcodes_add_msg($output, $tag, $attr, $m) {
    $msg = '<p>';
    $msg .= 'The above was generated with a WordPress shortcode.';
    $msg .= '</p>';

    return $output . $msg;
}

add_filter('do_shortcode_tag', 'op111_shortcodes_add_msg', 10, 4);

This will add a message under any content generated by any shortcode.

Example 2

Now we will add some text under forms generated by Contact Form 7. In order to limit the filtering to output generated by Contact Form 7, we check if the shortcode tag (that is, the shortcode name) is the one used by Contact Form 7. If it is, we append our text to the output of the shortcode and then return the result. If it is not, we return the output unchanged.

function op111_wpcf7_add_msg($output, $tag, $attr, $m) {
    if ($tag === 'contact-form-7') {
        $msg = '<p>';
        $msg .= 'This form was made with Contact Form 7.';
        $msg .= '</p>';

        $output .= $msg;
    }

    return $output;
}

add_filter('do_shortcode_tag', 'op111_wpcf7_add_msg', 10, 4);

Example 3

The third argument of do_shortcode_tag allows us to be even more specific. Let’s say that we have several forms made with Contact Form 7 and we want to add a CSS class to the submit button of our main form, which we have named Main, without changing the output of other forms generated by Contact Form 7:

function op111_wpcf7_main_add_class($output, $tag, $attr, $m) {
    if ($tag === 'contact-form-7' && $attr['title'] === 'Main') {
        $output = str_replace(
            'wpcf7-submit',
            'wpcf7-submit wpcf7-submit-main',
            $output
        );
    }

    return $output;
}

add_filter('do_shortcode_tag', 'op111_wpcf7_main_add_class', 10, 4);

Example 4

One of our magazine’s authors gets angry when typing text wrapped in shortcodes and sometimes types the swear word foo. The editor said we should print an apology when this happens. Here is how we automated the job:

function op111_offer_apology($output, $tag, $attr, $m) {
    if (preg_match('/\bfoo\b/', $m[5])) {
        $msg = '<p>';
        $msg .= 'Our apologies for the bad language.';
        $msg .= '</p>';

        $output .= $msg;
    }

    return $output;
}

add_filter('do_shortcode_tag', 'op111_offer_apology', 10, 4);

In this example we use a regular expression to look for the string foo at the fifth match returned by get_shortcode_regex(). The fifth match is the content of the shortcode if the shortcode wraps any content. If our string exists there, we add an apology at the end of the shortcode output. If it is not, we return the output unchanged.

Documentation and other links