Make WordPress Shortcodes From Core WP Functions, Plugin Functions and Theme Functions

This is part two of JournalXtra’s WordPress Shortcodes tutorial. This part of the tutorial shows how to make shortcodes using the functions written in active plugins, active themes and in the WordPress core scripts. Part one of this tutorial series is here.

WordPress is a collection of scripts used together to make web content management system, CMS. These scripts contain code in functions and classes. As show in part one of this series, shortcodes are tags used in post, page and widget content to display the output of code written in functions and classes.

Functions and classes that make up the WordPress core scripts can be used as shortcodes. That includes action hooks and filters.

Functions and classes found in the active theme of a WordPress site or in the site’s active plugins can be used in shortcodes as well. This is true even when the theme or plugin developer didn’t intend the code to be used in shortcodes.

Make WordPress shortcodes out of existing functions

WordPress functions and classes perform useful tasks. For instance, one function displays the website’s masthead to visitors, another loads the page title, and another shows the comment form. Everything served when the frontend or dashboard of a site is viewed is made possible by functions and classes.

A shortcode is a shorthand tag used to represent a function.

The action hook that turns any function into a shortcode is the add_shortcode() hook.

add_shortcode() is used like this:

add_shortcode( 'shortcode_name', 'function_to_run' );

// 1) Give the shortcode a name instead of shortcode_name, then
// 2) Say which function should run when the shortcode is used

Many functions within the scripts of an active theme or active plugin or even many functions within WordPress core can be used in shortcodes.

Sometimes we need to write a separate function to wrap around the the function we want to use as a shortcode. The reason for this is explained in the next few sections of this tutorial.

Find functions, hooks and filters to work with

There are tools we can use to find functions, hooks and filters within WordPress scripts.

The scripts where functions are found usually explain what the functions do and how they are used.

The Hooks Search Tool finds hooks and filters in themes, plugins and WordPress core files. Download the tool here, upload the zip package to a server where WordPress is installed, unzip the package then point a web browser to search tool script. Remember to delete the script after use. Documentation for the Hooks Search Tool is here.

The Function Reference in the WordPress Codex gives examples of how to use core WP functions. This is complimentary to the documentation found in scripts.

The WordPress Hook/API Index at Hookr has information about functions used in plugins and themes found in Github and in the WordPress repository.

PHP Cross Reference is a web application for reading WordPress core files and for seeing where functions are used within core files.

Google is a fantastic resource. Never forget Google.

Making shortcodes

The paginate_links() function displays page numbers on archive pages like the blog archive page or a category archive page. paginate_links() can be used to display previous and next navigation buttons as well. This function is shortcode friendly and easy to understand.

This part of the tutorial will use paginate_links() as a shortocde.

Simple conversion

One line of code is all it takes to make a shortcode of paginate_links().

Add this code to a functions.php file (the active theme’s functions.php file will work fine):

/* add_shortcode('shortcode tag', 'function to use') */
add_shortcode('vr-pages', 'paginate_links');

That single line of PHP creates the shortcode [vr-pages]. This shortcode can be used in a sidebar text widget to display pagination buttons in a widget area when archive pages are in view.

The vr- prefix in the shortcode tag prevents conflicts with other shortcodes that might use the pagination tag.

The raw code for paginate_links() can be read here.

Style the output

The shortcode’s output can be altered by wrapping paginate_links() in another (wrapper) function then using this wrapper function in with add_shortcode().

A simple wrapper looks like this:

/* Write a function that returns the output of paginate_links() */
function vr_pages_wrapper() {
	$content = paginate_links();
	return $content;
}

/* Call the wrapper instead of paginate_links() */
add_shortcode('vr-pages','vr_pages_wrapper');

The above wrapper does not alter the output in any way. The shortcode name is now [vr-pages].

The output of paginate_links() can now be wrapped within HTML tags or be given text.

Here is the same wrapper function but this time the output is wrapped within <div> tags:

function vr_pages_wrapper() {
	$content = '<div class="pagination-wrap">' . paginate_links() . '</div>';
	return $content;
}
add_shortcode('vr-pages','vr_pages_wrapper');

The pagination buttons displayed by the shortcode can now be styled with CSS because the <div> wrapped around the buttons has a CSS class to target.

Passing shortcode attributes to function arguments

paginate_links() can take arguments. These arguments change the appearance of the buttons.

Look at the documentation for paginate_links():

* @param string|array $args {
*     Optional. Array or string of arguments for generating paginated links for archives.
*
*     @type string $base               Base of the paginated url. Default empty.
*     @type string $format             Format for the pagination structure. Default empty.
*     @type int    $total              The total amount of pages. Default is the value WP_Query's
*                                      `max_num_pages` or 1.
*     @type int    $current            The current page number. Default is 'paged' query var or 1.
*     @type bool   $show_all           Whether to show all pages. Default false.
*     @type int    $end_size           How many numbers on either the start and the end list edges.
*                                      Default 1.
*     @type int    $mid_size           How many numbers to either side of the current pages. Default 2.
*     @type bool   $prev_next          Whether to include the previous and next links in the list. Default true.
*     @type bool   $prev_text          The previous page text. Default '« Previous'.
*     @type bool   $next_text          The next page text. Default '« Previous'.
*     @type string $type               Controls format of the returned value. Possible values are 'plain',
*                                      'array' and 'list'. Default is 'plain'.
*     @type array  $add_args           An array of query args to add. Default false.
*     @type string $add_fragment       A string to append to each link. Default empty.
*     @type string $before_page_number A string to appear before the page number. Default empty.
*     @type string $after_page_number  A string to append after the page number. Default empty.
* }

A shortcode can accept attributes. Those attributes can be passed back to the function called by the shortcode.

Arguments can be passed from a shortcode to paginate_links():

  1. The wrapper function for paginate_links() can use the WordPress Shortcode API to make a shortcode that accepts attributes. This means the wrapper function can be written to receive data (i.e. the shortcode attributes) which can then be used within the wrapper function.
  2. The attributes used by the shortcode are then passed to paginate_links() where it is used to effect the final output displayed by the shortcode.

For example, the [vr-pages] shortcode can be written to accept attributes to affect

  • the quantity of page numbers shown at the start and end list page ($end_size),
  • the quantity of page numbers shown before and after the current page ($mid_size),
  • The ‘previous’ text ($prev_text), and
  • The ‘next’ text ($next_text).
function vr_pages_with_arguments( $atts ) {

		// Part 1

		// Create an array to set the default argument values ('Argument' => 'Default Value')
		// The arguments listed here must be the same as the arguments
		// accepted by the function(s) used for the shortcode e.g. paginate_links()
		// https://codex.wordpress.org/Function_Reference/paginate_links
		// We can allow additional attributes if we are customizing the output in other ways too e.g. An attribute for styling.

		$atts = shortcode_atts(array(

			// e.g. 'Argument' => 'Default Value',

			'end_size' => '2', // $end_size		How many numbers on either the start and the end list edges.
			'mid_size' => '2', // $mid_size		How many numbers to either side of the current pages. Default 2.
			'prev_text' => '< Previous', // $prev_text	The previous page text. Default '« Previous'.
			'next_text' => 'Next >' // $next_text		The next page text. Default '« Previous'.

		), $atts, 'vr-pages' );

		// Sanitize the shortcode attributes and map them to variables

		// e.g. $Argument = acceptable_input_type['attribute']
		$end_size = intval($atts['end_size']);
		$mid_size = intval($atts['mid_size']);
		$prev_text = sanitize_text_field($atts['prev_text']);
		$next_text = sanitize_text_field($atts['next_text']);

		// Part 2

		// Pass the attributes to the function as arguments

		// The arguments in this array are the same as those
		// listed in part 1
		// 'Function Argument' => 'Sanitized Variable',
		$args = array (
			'end_size' => $end_size,
			'mid_size' => $mid_size,
			'prev_text' => $prev_text,
			'next_text' => $next_text
		);

		// Return the output

		$content = paginate_links( $args );

		return $content;
}

// Create the shortcode
// add_shortcode('shortcode_name', 'Function-to-Run')

add_shortcode('vr-pages','vr_pages_with_arguments');

The above code creates a pagination shortcode that accepts 4 attributes:

[vr-pages end_size=’3′ mid_size=’3′ prev_text='<–‘ next_text=’–>’]

Fix misbehaving shortcode output

Some functions return output that jumps outside the content area or widget area they are used in. Misbehaved shortcode output can be fixed by using output buffering.

An output buffer holds content in memory (the buffer) until it is released for use (flushed).

When activated, an output buffer prevents output going to the screen until the buffer is flushed. This can be used to maintain control of code output until we are ready to release it for other processes to work on it.

The output of paginate_links() behaves well no matter where it displays but let’s buffer the output of paginate_links() for the fun of it.

/* Create a function that uses the output buffer (ob) */
function vr_ob_pages() {
	ob_start();
		$content = paginate_links();
		print $content;
	return ob_get_clean();
}

/* Add the shortcode [vr-pages] */
add_shortcode('vr-pages','vr_ob_pages');

Compare the above buffered function to the non-buffered version:

/* No output buffer used */
function vr_ob_pages() {
	return paginate_links();
}
add_shortcode('vr-pages','vr_pagination');

The PHP functions ob_start() and ob_get_clean() start and flush the PHP output buffer.

  • ob_start() tells PHP to begin capturing output into a buffer.
  • ob_get_clean() tells PHP to clean the buffer and provide the output for further processing.

The buffered content can be returned directly to the shortcode or it can be stored in a variable which can be edited. The buffer output can be used elsewhere within the function or it can be returned directly as the shortcode output.

Here is an example of how to pass the output buffer content to a variable ($content) and return $content directly as the shortcode output without further processing:

function vr_ob_pages() {
	ob_start();
		echo paginate_links();
	$content = ob_get_clean();
	return $content;
}
add_shortcode('vr-pages','vr_ob_pages');

// The shortcode is [vr-pages]

Use output buffering when the content displayed by a shortcode behaves unexpectedly. Unexpected behavior includes shortcode output jumping outside of a sidebar or widget area or the output not respecting theme CSS styles because, for example, WordPress has filtered the output to remove disallowed HTML markup.

Example misbehaving shortcode output

The comment_form() function displays the comment form below posts.

Used as a shortcode, the comment form displayed by comment_form() jumps out of any widget area the shortcode is used within. Output buffering prevents shortcode output misbehavior.

function vr_comment_form( $atts ) {

		// Part 1

		// Create an array to set the default argument values ('Argument' => 'Default Value')
		// The arguments listed here must be the same as the arguments
		// accepted by the function(s) used for the shortcode e.g. comment_form()
		// https://codex.wordpress.org/Function_Reference/comment_form
		// We can allow additional attributes if we are customizing the output in other ways too e.g. An attribute for styling.

		$atts = shortcode_atts(array(

			// e.g. 'Argument' => 'Default Value',

			'label_submit' => 'Send',
			'title_reply' => 'Write a Reply or Comment',
			'comment_notes_after' => '<p>A custom message displayed below the comment form</p><br />'

		), $atts, 'vr-comment' );

		// Sanitize the shortcode attributes and map them to variables

		// e.g. $Argument = acceptable_input_type['attribute']
		$label_submit = sanitize_text_field($atts['label_submit']);
		$title_reply = sanitize_text_field($atts['title_reply']);
		$comment_notes_after = sanitize_text_field($atts['comment_notes_after']);

		// Part 2

		// Pass the attributes to the function as arguments

		// The arguments in this array are the same as those
		// listed in part 1
		// 'Function Argument' => 'Sanitized Variable',
		$args = array (
			'label_submit' => $label_submit,
			'title_reply' => $title_reply,
			'comment_notes_after' => $comment_notes_after,
		);


		// Return the output
		ob_start();
			// Call comment_form() function
			comment_form( $args );

		return ob_get_clean();
}

add_shortcode('vr-comment','vr_comment_form');

// The shortcode is [vr-comment]

The comment form shortcode, including attributes, is

[vr-comment label_submit=”Send” title_reply=”Respond” comment_notes_after=”Be sensible”]

Check for the existence of a class or function

When a function from a plugin or theme is used as a custom shortcode or in a custom function we need to check the function exists when we use it. Failure to check will crash the site when the plugin or theme is disabled.

We check a function exists with function_exists( ‘function_name’ ).

We check a class exists with class_exists( ‘class_name’ ).

/* Write a function that returns the output of paginate_links() */
function vr_pagination_wrapper() {
	// Check paginate_links() exists
	if ( function_exists( 'paginate_links' ) ) {
		// Use paginate_links() if it exists
		$content = paginate_links();
		return $content;
	}
}

/* Call the wrapper instead of paginate_links() */
add_shortcode('vr-pages','vr_pagination_wrapper');

We don’t usually need to confirm the existence of core WordPress functions and classes. The WordPress dev team give advance warning before they remove functions. The above example is given for simplicity.

In the above example, if paginate_links() didn’t exist the output of [vr-pages] would be nothingness: there would be nothing displayed in its place.

Final words

WordPress is a framework of functions, classes, action hooks and filters that can be used to fine-tune WordPress to suit specific needs. These core WordPress functions and classes can be used in the themes, they can be used in shortcodes, and they can be used to make plugins.

Along with core WordPress functions, the functions written in themes and plugins can be used in shortcodes provided the plugins or theme are active within the website where their functions are used as shortcodes. The presence of a function or class can be checked with function_exists() and class_exists(). Failure to confirm the presence of a function or class will crash a website that tries to call an absent function or class.

When add_shortcode() is used in functions.php we are actually making a WordPress plugin. We might not activate and deactivate the code in Dashboard > Plugins but that doesn’t make it any less of a plugin: it is still custom code being plugged into WordPress.

Over to you!

Got a question, suggestion or argument? Add it to the comments.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
Notify of

Free to your inbox

Join our mailing list to receive the latest news and updates from JournalXtra.

You have Successfully Subscribed!