The plugin allows to insert a post list into any post/page using a shortcode and a template, placed right in the shortcode or in an external php file. Internally it uses the get_posts function and inherits its behavior and limitations. The plugin is under active development. After I finish the documentation and my home page with it :), it’ll be submitted into the WordPress database. This and future releases will be compatible with PHP 5.5+.

Github | Download


Insert this shortcode into a page:


Fetches posts with default parameters and renders them using theme/content.php. If content.php is missing, a simple list of links is rendered instead.

Use a query string with the WP_Query parameters.

[posts q="cat=2&posts_per_page=3"]

Renders three posts from a category with ID=2.

Rendering with inline templates:

[posts q="posts_per_page=5&cat=2"]

Each {tag} calls a function with corresponding name, e.g. {get_the_title} calls get_the_title(), {get_the_content} calls get_the_content(), etc. All tag functions must be registered via the DIY_Posts_Shortcode::register method (see below).
Functions can be called with space separated arguments, listed after the function name:

{get_the_post_thumbnail 0 medium}

Put values with spaces in quotes. NULL is not supported, 0 (zero) may be a substitute in some cases.


{if has_post_thumbnail}{get_the_post_thumbnail 0 medium "class=thumb"}{/if}
{if !get_the_title}(No title){/if}{if get_the_title}{get_the_title}{/if}

How to register custom tags in theme/functions.php:

// DIY_Posts_Shortcode::register(, );

DIY_Posts_Shortcode::register('subtitle', function(){ return "No subtitle"; }); // use any callable
DIY_Posts_Shortcode::register('comment_link'); // if second parameter's omitted, the function with the tag name is used
DIY_Posts_Shortcode::register(['comment_link', 'search_link']); // an array with custom callables
    'subtitle' => function(){ return "No subtitle"; },
    'date' => 'date',

All tag functions must return scalar values (strings, integers, floats).

Functions, registered by default:

Keep in mind, that the_content and get_the_content behave differently, hence both of them are registered.

Built-in templating is primitive and going to stay this way. If in need of more advanced logic, consider using of file templates. To change the template for a single item, use the item parameter, containing a file name, compatible with get_template_part:

[posts q="cat=2&posts_per_page=3" item="custom-post-template"]

Renders the post list, using theme/custom-post-template.php for each item. Examples can be found in content.php and content-*.php.

For complex queries, use a custom loop template with complete logic:

[posts loop="custom-post-template"]
 [3, 5], 'author__in' => [2, 6] ]);
foreach ($posts as $post): setup_postdata($post);


[posts q="cat=39&posts_per_page=3&meta_key=_thumbnail_id"]
{get_the_post_thumbnail 0 medium}


Lists three last posts with featured images.