How to use WordPress template parts like React.js components

Sep 4, 2019

One of the best patterns I’ve learned from React.js is to abstract your data from your components in a way that the component can be used in any context. I touched this topic as a part of my previous post, but it’s such a cool trick so I wanted to give it the attention it deserves. It’s really quick to implement into your current theme and will definitely improve your life as a WordPress theme developer.

In React.js this pattern looks like this:

import React from "react";
import MyComponent from "./MyComponent";

class App extends React.Component {
	render() {
		return (
			<MyComponent title={"Hey there"} />
		);
	}
}
export default App;

and then you can use the data inside that component like this:

import React from "react";

class MyComponent extends React.Component {
	render() {
		return (
			<h1 className="title">{this.props.title}</h1>
		);
	}
}

export default MyComponent;

This way we can use “MyComponent” in any context and you can pass any title for that component.

In WordPress people are usually doing something like this when splitting a template into smaller partials:

<div class="container">
	<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
	<h1 class="post-title">
		<?php the_title(); ?>
	</h1>
	<?php get_template_part( 'templates/post-meta', '' ); ?>
	<?php the_content(); ?>
</div>

and then in that template part:

<span class="post-date"><?php the_time( 'M j, Y' ); ?></span>
 / <span class="post-author"><?php the_author(); ?></span>

What if you wanted to hide author for all entries in post type ‘my_post_type’?. For sure you could do something like this:

<span class="post-date"><?php the_time( 'M j, Y' ); ?></span>
<?php if ( 'my_post_type' !== get_post_type() ) : ?>
 / <span class="post-author"><?php the_author(); ?></span>
<?php endif; ?>

but this way things can get out of hand pretty quickly.

Let’s refactor this example to use a similar component pattern to our earlier React.js example. First we add a modified version of get_template_part() function functions into your functions.php with the additional get_template_param() function:

<?php

function get_template_part_with_params( $slug, $name, $params ) {
$templates = array();
	$name      = (string) $name;

	if ( '' !== $name ) {
		$templates[] = "{$slug}-{$name}.php";
	}

	$templates[] = "{$slug}.php";

	// Save params to globals
	$GLOBALS['my_template_params'] = $params;

	locate_template( $templates, true, false );

	// Empty params to prevent some possible bugs
	$GLOBALS['my_template_params'] = [];
}

function get_template_param( $template_param ) {
	if ( isset( $GLOBALS['my_template_params'][ $template_param ] ) ) {
		return $GLOBALS['my_template_params'][ $template_param ];
	}

	return false;
}

The get_template_part_with_params() function allows you to pass your data as the third parameter and it offloads that data into globals. Then, by using get_template_param() function, you can get that data back in your template part. Let’s refactor our previous example with these functions:

<div class="container">
	<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
	<h1 class="post-title">
		<?php the_title(); ?>
	</h1>
	<?php 
		$params = [
			'date' => get_the_time( 'M j, Y' ),
		];

		if ( 'my_post_type' !== get_post_type() ) {
			$params['author'] = get_the_author();
		}

		get_template_part_with_params( 'templates/post-meta', '', $params );
	?>
	<div class="post-content">
		<?php the_content(); ?>
	</div>
</div>

and then in post-meta.php:

<?php

$date = get_template_param( 'date' );
$author = get_template_param( 'author' );

?>

<?php if( $date ); ?>
	<span class="post-date"><?php echo esc_html( $date ); ?></span>
<?php endif; ?>
<?php if( $author ); ?>
 / <span class="post-author"><?php esc_html( $author ); ?></span>
<?php endif; ?>
<?php

$params = [
	'title' => "Let's nest another one",
];

get_template_part_with_params( 'my-sub-partial', '', $params );

and in my-sub-partial.php:

<?php

// my-sub-partial.php

$title = get_template_param( 'title' );

?>

<p><?php echo esc_html( $title ); ?></p>

At first this seems to add a lot of boilerplate code into your projects, but after using it for a while you’ll hopefully start to understand the power of this technique.

Now, instead of bloating your template parts with endless if statements, you can start controlling the outcome of that template part just by passing different kinds of data to that template.

And that, my friend, is going to allow you to write some pretty well maintainable WordPress templates 🙂