Wordpress - How to add custom content template part for a custom post type on main query using a plugin
Background
Unfortunately get_template_part()
function doesn't have any suitable filter to achieve what you want. It's possible to use the get_template_part_{$slug}
action hook to inject template parts, however, without any change to your theme or a child theme, the original template part will be added anyway. So this way you'll not be able to replace existing template parts.
However, you'll be able to achieve the desired result by following one of the options below:
Option 1: Use the default CSS classes:
If only thing you want is to change the style for the paper
custom post type, then you may simply use the generated CSS class by WordPress. Any standard theme in WordPress will generate $post_type
and type-{$post_type}
CSS classes for the post content. For example, the custom post type paper
will have paper
& type-paper
CSS classes and general post
will have post
and type-post
CSS classes. Also home page will have home
CSS class in the body. So to target paper
entries in the home page, you may use the following CSS rules:
body.home .type-paper {
/* Custom CSS for paper entries in the home page */
}
Option 2: Modify CSS classes:
If the default CSS classes are not enough for you, you can also modify (add / remove) CSS classes using the post_class
filter hook in your plugin. Like this:
add_filter( 'post_class', 'paper_post_class' );
function paper_post_class( $class ) {
if ( get_post_type() === 'paper' && is_home() ) {
// remove these classes
$remove = array( 'css-class-to-remove', 'another-class-to-remove' );
$class = array_diff( $class, $remove );
// add these classes
$add = array( 'custom-paper', 'my-paper-class' );
$class = array_merge( $add, $class );
}
return $class;
}
This way you'll be able to remove CSS classes you don't want for paper
entries and add new CSS classes you want for paper
entries without modifying the theme files. Then use those CSS classes to change the style of paper
entries as needed.
Option 3: Modify template & template parts
If your desired style change is not possible by only targeting CSS classes, then you may change the template parts from your plugin too. However, since replacing template parts added by get_template_part()
is not possible by using hooks, you'll have to change the template in a way so that you may modify the get_template_part()
call from within the plugin.
To do that, you may target your pre_get_posts
hook function and use template_include
filter hook to modify the home page template, like the following:
function add_custom_post_types_to_query( $query ) {
if ( is_home() && $query->is_main_query() ) {
$query->set( 'post_type', array( 'post', 'paper' ) );
// now also change the home page template, but only when this condition matches
add_filter( 'template_include', 'wpse258844_custom_template', 999 );
}
}
add_action( 'pre_get_posts', 'add_custom_post_types_to_query' );
Then use the following CODE (modify as you need):
// for better file management, use a separate "theme-{$theme_name_slug}" directory within your plugin directory
// so if the active theme name is "OnePress", the directory name will be "theme-onepress"
// This will save you a ton of headache if you change the theme,
// as different themes may use different function calls within the templates, which other themes may not have
define( 'wpse258844_TEMPLATE_DIR', plugin_dir_path( __FILE__ ) . sprintf( 'theme-%s/', sanitize_title( wp_get_theme() ) ) );
function wpse258844_custom_template( $template ) {
// this file will replace your homepage template file
$index_paper = wpse258844_TEMPLATE_DIR . 'custom-home.php';
// file_exists() check may need clearing stat cache if you change file name, delete the file etc.
// Once you are done, comment out or remove clearstatcache(); in production
clearstatcache();
if ( file_exists( $index_paper ) ) {
$template = $index_paper;
}
return $template;
}
function wpse258844_get_template_part( $slug, $name = null ) {
if( get_post_type() === 'paper' ) {
// just to be consistant with get_template_part() function
do_action( "get_template_part_{$slug}", $slug, $name );
$located = '';
$name = (string) $name;
// file_exists() check may need clearing stat cache if you change file name, delete the file etc.
// Once you are done, comment out or remove clearstatcache(); in production
clearstatcache();
if ( '' !== $name && file_exists( wpse258844_TEMPLATE_DIR . "{$slug}-{$name}.php" ) ) {
$located = wpse258844_TEMPLATE_DIR . "{$slug}-{$name}.php";
}
else if ( file_exists( wpse258844_TEMPLATE_DIR . "{$slug}.php" ) ) {
$located = wpse258844_TEMPLATE_DIR . "{$slug}.php";
}
if ( '' != $located ) {
load_template( $located, false );
return;
}
}
get_template_part( $slug, $name );
}
Once you have the above CODE in your plugin (read the comments within the CODE):
Create a new directory within you plugin directory to keep theme template files, e.g.
theme-onepress
. This will help you in the future if you want to test design changes with a different theme (I suppose that's the main purpose of all these mess ;) ).Within the new
theme-onepress
directory, create a file namedcustom-home.php
. Copy the CODE of home page template from your theme (may beindex.php
, orhome.php
or whatever your theme is using for the home page template).Now in
custom-home.php
change all the call ofget_template_part
towpse258844_get_template_part
. No need to change the parameter, only function name.wpse258844_get_template_part()
function in the above CODE is identical toget_template_part()
function and falls back to default behaviour if custom template part is not found within your plugin'stheme-{$theme_name_slug}
(e.g.theme-onepress
) directory.Finally, replace whatever template part file you wanted to replace in your plugin's
theme-{$theme_name_slug}
directory.For example, if the original call was
get_template_part( 'template-parts/content', get_post_format() )
and you want to replacecontent.php
template part, then simply place a file namedcontent.php
in your plugin'stheme-onepress/template-parts
directory. That means, thetheme-onepress
directory will behave like a child theme for template parts - i.e. simple drop-in replacement.