如何在October CMS中通过RainLab Blog插件筛选多分类博客文章?
Got it, let's tackle this multi-category filtering for RainLab Blog! I've implemented this exact feature a few times, so here's a practical, step-by-step solution that avoids editing core plugin files:
1. Build the Multi-Select Filter Form
First, replace your existing single-category dropdown with a set of checkboxes. This lets users pick multiple categories, and we'll retain their selections after submission:
<form method="get" action="{{ page.url }}"> {% for category in blogCategories %} <label class="category-checkbox"> <input type="checkbox" name="categories[]" value="{{ category.slug }}" {% if category.slug in (request.query.categories ?: []) %}checked{% endif %} > {{ category.name }} </label> {% endfor %} <button type="submit" class="filter-btn">Filter Posts</button> </form>
The blogCategories variable is provided by RainLab Blog by default, and we use request.query.categories to keep checkboxes checked after the user submits the form.
2. Extend the Blog Posts Component Logic
We'll modify how the component fetches posts to handle multiple categories. The cleanest way is to create a small extension (no core plugin edits required):
Option A: Create a Custom Plugin Extension
- Create a new plugin (or use an existing one you own)
- Add this component file at
plugins/yournamespace/blogcomponents/BlogPosts.php:
<?php namespace YourNamespace\BlogComponents\Components; use RainLab\Blog\Components\BlogPosts as BaseBlogPosts; use Illuminate\Database\Eloquent\Builder; class BlogPosts extends BaseBlogPosts { protected function listPosts() { // Start with the original query logic $query = parent::listPosts(); // Grab selected category slugs from the request $selectedCategories = request()->query('categories'); if ($selectedCategories && is_array($selectedCategories)) { // Filter posts that have ALL selected categories (remove the last parameter for ANY match) $query->whereHas('categories', function(Builder $categoryQuery) use ($selectedCategories) { $categoryQuery->whereIn('slug', $selectedCategories); }, '=', count($selectedCategories)); } return $query; } }
- Register the component in your plugin's
Plugin.php:
public function registerComponents() { return [ \YourNamespace\BlogComponents\Components\BlogPosts::class => 'blogPosts', ]; }
Option B: Quick Page-Level Fix (No Plugin Needed)
If you don't want to create a plugin, add this code directly to your CMS page's PHP section:
function onInit() { // Get the default blog posts component from the page $blogComponent = $this->page->components['blogPosts']; // Save the original listPosts method $blogComponent->originalListPosts = $blogComponent->listPosts; // Override the method to add multi-category filtering $blogComponent->listPosts = function() use ($blogComponent) { $query = $blogComponent->originalListPosts(); $selectedCategories = request()->query('categories'); if ($selectedCategories && is_array($selectedCategories)) { $query->whereHas('categories', function($q) use ($selectedCategories) { $q->whereIn('slug', $selectedCategories); }, '=', count($selectedCategories)); } return $query; }; }
3. Update Your Page Component
Replace the default rainlab.blog::blogPosts component in your CMS page with your custom one (if you went with Option A). All existing settings (like posts per page, sorting) will work exactly as before.
Key Notes
- Match All vs. Match Any: If you want posts that have any of the selected categories instead of all, remove the
', '=', count($selectedCategories)part from thewhereHasmethod. - Cache Clear: After adding the extension, run
php artisan cache:clearandphp artisan october:upto make sure the changes take effect. - Styling: Feel free to add CSS to style the checkboxes and filter button to match your site's design.
That's it! Test by selecting multiple categories and submitting the form—you'll see the filtered posts show up as expected.
内容的提问来源于stack exchange,提问作者Midhun Babu

