Creating a Custom Recent Posts Shortcode
Basic Implementation
Let's create a shortcode that displays recent posts with customizable options. Here's a step-by-step solution:
First, register the shortcode in your theme's functions.php file:
function recent_posts_shortcode($atts) {
// Default parameters
$args = shortcode_atts(array(
'posts' => 5,
'type' => 'post',
'category' => '',
'excerpt' => 'yes',
), $atts);
// Query setup
$query = new WP_Query(array(
'post_type' => $args['type'],
'posts_per_page' => $args['posts'],
'category_name' => $args['category'],
'post_status' => 'publish',
));
// Start output buffering
ob_start();
if($query->have_posts()) :
echo '<ul class="recent-posts-list">';
while($query->have_posts()) : $query->the_post();
echo '<li>';
echo '<h3><a href="' . esc_url(get_permalink()) . '">' . get_the_title() . '</a></h3>';
if($args['excerpt'] === 'yes') {
echo '<div class="excerpt">' . get_the_excerpt() . '</div>';
}
echo '</li>';
endwhile;
echo '</ul>';
endif;
wp_reset_postdata();
return ob_get_clean();
}
add_shortcode('recent_posts', 'recent_posts_shortcode');
Usage Examples
You can use the shortcode in various ways:
Basic usage:
[recent_posts]
With parameters:
[recent_posts posts="3" type="post" category="news" excerpt="no"]
Adding Styling
Add these CSS styles to your theme's stylesheet:
.recent-posts-list {
list-style: none;
padding: 0;
margin: 20px 0;
}
.recent-posts-list li {
margin-bottom: 20px;
}
.recent-posts-list h3 {
margin-bottom: 10px;
}
.recent-posts-list .excerpt {
font-size: 0.9em;
color: #666;
}
Security Considerations
- Always sanitize inputs:
- Use
shortcode_atts()
to validate parameters
- Use
esc_url()
for URLs
- Use
esc_html()
for text output
- Prevent SQL injection:
- Use WP_Query instead of direct SQL queries
- Validate numerical inputs
Best Practices
- Always use
wp_reset_postdata()
after custom queries
- Use output buffering for clean code organization
- Include error handling
- Make the shortcode parameters flexible but with sensible defaults
Enhanced Version with More Features
Here's an advanced version with additional features:
function advanced_recent_posts_shortcode($atts) {
// Default parameters
$args = shortcode_atts(array(
'posts' => 5,
'type' => 'post',
'category' => '',
'excerpt' => 'yes',
'excerpt_length' => 20,
'thumbnail' => 'yes',
'date' => 'yes',
'author' => 'no',
'class' => '',
), $atts);
// Query setup
$query = new WP_Query(array(
'post_type' => sanitize_text_field($args['type']),
'posts_per_page' => intval($args['posts']),
'category_name' => sanitize_text_field($args['category']),
'post_status' => 'publish',
));
$output = '';
if($query->have_posts()) {
$class = $args['class'] ? ' ' . esc_attr($args['class']) : '';
$output .= '<div class="advanced-recent-posts' . $class . '">';
while($query->have_posts()) : $query->the_post();
$output .= '<article class="post-item">';
if($args['thumbnail'] === 'yes' && has_post_thumbnail()) {
$output .= '<div class="post-thumbnail">';
$output .= get_the_post_thumbnail(null, 'thumbnail');
$output .= '</div>';
}
$output .= '<div class="post-content">';
$output .= '<h3><a href="' . esc_url(get_permalink()) . '">' . esc_html(get_the_title()) . '</a></h3>';
if($args['date'] === 'yes' || $args['author'] === 'yes') {
$output .= '<div class="post-meta">';
if($args['date'] === 'yes') {
$output .= '<span class="date">' . get_the_date() . '</span>';
}
if($args['author'] === 'yes') {
$output .= '<span class="author">by ' . get_the_author() . '</span>';
}
$output .= '</div>';
}
if($args['excerpt'] === 'yes') {
$output .= '<div class="excerpt">' . wp_trim_words(get_the_excerpt(), $args['excerpt_length']) . '</div>';
}
$output .= '</div>'; // .post-content
$output .= '</article>';
endwhile;
$output .= '</div>';
}
wp_reset_postdata();
return $output;
}
add_shortcode('advanced_recent_posts', 'advanced_recent_posts_shortcode');
Alternative Solutions
If you prefer not to code, these plugins offer similar functionality:
- Display Posts Shortcode
- Recent Posts Widget Extended
Common Pitfalls to Avoid
- Don't forget to reset post data
- Avoid deep nesting of queries
- Don't hardcode HTML without escape functions
- Be mindful of performance with large post counts
- Consider pagination for large datasets
Remember to test your shortcode thoroughly, especially when using it with different themes and page builders.