Owl Carousel Blog Posts
August 7, 2025 · AI Conversations
– Shows **3 posts at a time** by default.
– Accepts `category` (slug), `active` (`yes`/`no`), and `inactive` (`yes`/`no`) as shortcode attributes.
– Enqueues Owl Carousel CSS and JS properly.
– Uses featured image, title, and excerpt.
– Fully responsive.
—
### ✅ Step 1: Add this code in your `functions.php` (child theme) or custom plugin
function owl_blog_post_slider_shortcode($atts) {
// Shortcode attributes with defaults
$atts = shortcode_atts([
'category' => '', // category slug
'active' => 'yes', // show active
'inactive' => 'no', // show inactive
], $atts);
// Enqueue Owl Carousel assets
wp_enqueue_style('owl-carousel-css', 'https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.carousel.min.css');
wp_enqueue_style('owl-carousel-theme', 'https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.theme.default.min.css');
wp_enqueue_script('owl-carousel-js', 'https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js', ['jquery'], null, true);
// Query blog posts
$query_args = [
'post_type' => 'post',
'posts_per_page' => 6,
'post_status' => 'publish',
];
if (!empty($atts['category'])) {
$query_args['tax_query'][] = [
'taxonomy' => 'category',
'field' => 'slug',
'terms' => sanitize_text_field($atts['category']),
];
}
$query = new WP_Query($query_args);
ob_start();
if ($query->have_posts()) {
?>
<div class="owl-blog-slider owl-carousel owl-theme">
<?php while ($query->have_posts()) : $query->the_post(); ?>
<div class="item">
<div class="post-slide">
<?php if (has_post_thumbnail()): ?>
<div class="post-thumb">
<a href="<?php the_permalink(); ?>"><?php the_post_thumbnail('medium'); ?></a>
</div>
<?php endif; ?>
<h3 class="post-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
<p class="post-excerpt"><?php echo wp_trim_words(get_the_excerpt(), 20); ?></p>
</div>
</div>
<?php endwhile; ?>
</div>
<script>
jQuery(document).ready(function($) {
$('.owl-blog-slider').owlCarousel({
loop: true,
margin: 20,
nav: true,
dots: true,
responsive: {
0: { items: 1 },
600: { items: 2 },
1000: { items: 3 }
}
});
});
</script>
<style>
.owl-blog-slider .post-slide {
background: #fff;
padding: 15px;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
text-align: center;
}
.owl-blog-slider .post-title {
font-size: 18px;
margin: 10px 0;
}
</style>
<?php
} else {
echo '<p>No posts found.</p>';
}
wp_reset_postdata();
return ob_get_clean();
}
add_shortcode('latest_blog_owl', 'owl_blog_post_slider_shortcode');
—
### ✅ Example Shortcode Usage
[latest_blog_owl category="news"]
You can also call it without a category:
[latest_blog_owl]
—
If you want to toggle the slider **active/inactive**:
[latest_blog_owl active="no"]
You can add a conditional wrapper if needed to **completely hide the carousel** when `active="no"` — let me know if you want that included.
Would you like arrows styled or autoplay included too?
—
### ✅ Updated WordPress Shortcode with `active` Control
function owl_blog_post_slider_shortcode($atts) {
$atts = shortcode_atts([
'category' => '',
'active' => 'yes', // 'yes' = use owl carousel, 'no' = normal 3-column layout
], $atts);
// Query blog posts
$query_args = [
'post_type' => 'post',
'posts_per_page' => 6,
'post_status' => 'publish',
];
if (!empty($atts['category'])) {
$query_args['tax_query'][] = [
'taxonomy' => 'category',
'field' => 'slug',
'terms' => sanitize_text_field($atts['category']),
];
}
$query = new WP_Query($query_args);
ob_start();
if ($query->have_posts()) {
$wrapper_class = ($atts['active'] === 'yes') ? 'owl-carousel owl-theme owl-blog-slider' : 'static-blog-grid';
// Enqueue Owl Carousel if active
if ($atts['active'] === 'yes') {
wp_enqueue_style('owl-carousel-css', 'https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.carousel.min.css');
wp_enqueue_style('owl-carousel-theme', 'https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.theme.default.min.css');
wp_enqueue_script('owl-carousel-js', 'https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js', ['jquery'], null, true);
}
?>
<div class="<?php echo esc_attr($wrapper_class); ?>">
<?php while ($query->have_posts()) : $query->the_post(); ?>
<div class="item">
<div class="post-slide">
<?php if (has_post_thumbnail()) : ?>
<div class="post-thumb">
<a href="<?php the_permalink(); ?>"><?php the_post_thumbnail('medium'); ?></a>
</div>
<?php endif; ?>
<h3 class="post-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
<p class="post-excerpt"><?php echo wp_trim_words(get_the_excerpt(), 20); ?></p>
</div>
</div>
<?php endwhile; ?>
</div>
<?php if ($atts['active'] === 'yes') : ?>
<script>
jQuery(document).ready(function($) {
$('.owl-blog-slider').owlCarousel({
loop: true,
margin: 20,
nav: true,
dots: true,
responsive: {
0: { items: 1 },
600: { items: 2 },
1000: { items: 3 }
}
});
});
</script>
<?php else : ?>
<style>
.static-blog-grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.static-blog-grid .item {
flex: 0 0 32%;
}
</style>
<?php endif; ?>
<style>
.post-slide {
background: #fff;
padding: 15px;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
text-align: center;
}
.post-title {
font-size: 18px;
margin: 10px 0;
}
</style>
<?php
} else {
echo '<p>No posts found.</p>';
}
wp_reset_postdata();
return ob_get_clean();
}
add_shortcode('latest_blog_owl', 'owl_blog_post_slider_shortcode');
—
### ✅ Usage Examples
**With Owl Carousel:**
[latest_blog_owl category="news" active="yes"]
**Without Owl Carousel (static 3-column):**
[latest_blog_owl category="news" active="no"]
Let me know if you want to add autoplay, pause-on-hover, or customize the arrow styles next.
– Shows latest blog posts.
– Accepts `category`, `active`, and now also `limit` attributes.
– Supports Owl Carousel when `active="yes"`.
– Displays a **static grid** when `active="no"`.
—
### ✅ Updated Shortcode Code (with `limit` support)
function owl_blog_post_slider_shortcode($atts) {
$atts = shortcode_atts([
'category' => '',
'active' => 'yes', // yes = owl, no = static grid
'limit' => 6, // number of posts
], $atts);
// Query blog posts
$query_args = [
'post_type' => 'post',
'posts_per_page' => intval($atts['limit']),
'post_status' => 'publish',
];
if (!empty($atts['category'])) {
$query_args['tax_query'][] = [
'taxonomy' => 'category',
'field' => 'slug',
'terms' => sanitize_text_field($atts['category']),
];
}
$query = new WP_Query($query_args);
ob_start();
if ($query->have_posts()) {
$wrapper_class = ($atts['active'] === 'yes') ? 'owl-carousel owl-theme owl-blog-slider' : 'static-blog-grid';
// Enqueue Owl Carousel if active
if ($atts['active'] === 'yes') {
wp_enqueue_style('owl-carousel-css', 'https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.carousel.min.css');
wp_enqueue_style('owl-carousel-theme', 'https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.theme.default.min.css');
wp_enqueue_script('owl-carousel-js', 'https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js', ['jquery'], null, true);
}
?>
<div class="<?php echo esc_attr($wrapper_class); ?>">
<?php while ($query->have_posts()) : $query->the_post(); ?>
<div class="item">
<div class="post-slide">
<?php if (has_post_thumbnail()) : ?>
<div class="post-thumb">
<a href="<?php the_permalink(); ?>"><?php the_post_thumbnail('medium'); ?></a>
</div>
<?php endif; ?>
<h3 class="post-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
<p class="post-excerpt"><?php echo wp_trim_words(get_the_excerpt(), 20); ?></p>
</div>
</div>
<?php endwhile; ?>
</div>
<?php if ($atts['active'] === 'yes') : ?>
<script>
jQuery(document).ready(function($) {
$('.owl-blog-slider').owlCarousel({
loop: true,
margin: 20,
nav: true,
dots: true,
responsive: {
0: { items: 1 },
600: { items: 2 },
1000: { items: 3 }
}
});
});
</script>
<?php else : ?>
<style>
.static-blog-grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.static-blog-grid .item {
flex: 0 0 32%;
}
</style>
<?php endif; ?>
<style>
.post-slide {
background: #fff;
padding: 15px;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
text-align: center;
}
.post-title {
font-size: 18px;
margin: 10px 0;
}
</style>
<?php
} else {
echo '<p>No posts found.</p>';
}
wp_reset_postdata();
return ob_get_clean();
}
add_shortcode('latest_blog_owl', 'owl_blog_post_slider_shortcode');
—
### ✅ Example Usages
**Owl Carousel (6 posts):**
[latest_blog_owl category="news" active="yes" limit="6"]
**Static Grid (9 posts):**
[latest_blog_owl category="events" active="no" limit="9"]
Let me know if you'd like to support post types other than `post` (like `custom_post_type`) or include a "Read More" button.
—
### ✅ Get Blog Page URL in PHP
$blog_page_url = get_permalink( get_option('page_for_posts') );
—
### ✅ Example: Use in a Template or Function
<a href="<?php echo esc_url( get_permalink( get_option('page_for_posts') ) ); ?>">View All Posts</a>
—
### ✅ Notes:
– `get_option('page_for_posts')` returns the page ID set as the "Posts page".
– If no page is set, `get_permalink()` will return `false`, so you may want to add a fallback.
—
### ✅ Optional Fallback Example
$page_id = get_option('page_for_posts');
if ($page_id) {
$blog_page_url = get_permalink($page_id);
} else {
$blog_page_url = home_url('/blog/');
}
Let me know if you want this integrated as a button at the end of your blog carousel or grid.
Instead, use **one of these smart workarounds**:
—
### ✅ ✅ BEST PRACTICE: Use a Custom Page Template + Builder + Manual Blog Loop
1. **Create a regular WordPress page** (e.g., `Blog`).
2. **Do not assign it** as the "Posts page" in **Settings > Reading**.
3. Use your page builder (like Elementor) to design the page.
4. **Add a blog post loop widget** or shortcode that pulls recent posts.
– Elementor: Use the **Posts** widget.
– WPBakery: Use **Post Grid** or similar.
– Or use a custom shortcode like the `latest_blog_owl` shortcode you already created.
—
### 🛠️ Optional: Redirect or leave `page_for_posts` unset
If `Settings > Reading > Posts Page` is already set to "Blog", unset it:
– Go to **Settings > Reading**
– Set "Posts page" to **— Select —**
– Click **Save Changes**
Why? Because if set, WordPress overrides your builder content with its default blog loop.
—
### ✅ If You *Must* Keep the `Posts Page` Set:
If you **must** keep the default blog page set in Settings > Reading, and still want to use your own layout:
1. Create a page template in your theme:
<?php
/* Template Name: Custom Blog Page */
get_header(); ?>
<div class="custom-blog-wrapper">
<!-- Your custom loop or builder code -->
<?php
$query = new WP_Query([
'post_type' => 'post',
'posts_per_page' => 10,
]);
if ($query->have_posts()) :
while ($query->have_posts()) : $query->the_post(); ?>
<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<?php endwhile;
wp_reset_postdata();
else :
echo '<p>No posts found.</p>';
endif;
?>
</div>
<?php get_footer(); ?>
2. Assign this template to your Blog page in the page editor under "Page Attributes > Template".
—
### ✅ Summary
| Goal | Recommended Way |
|——|——————|
| Custom design for blog | Create a page, don’t set it as "Posts page", and use a builder or shortcode to display posts |
| Use builder with blog loop | Use builder's post widgets or custom shortcode |
| Already set as Posts Page | Use a custom template file to override the loop |
—
Let me know which builder you're using (Elementor, WPBakery, etc.) and I can give a tailored setup.