Magento 2集成Fishpig后,如何按分类展示单篇最新博客文章?
Got it, let's tackle this problem step by step. The core issue here is that your current setup pulls multiple posts from a single category, but we need to loop through each valid category and fetch just its most recent published post. Here's how to implement this properly, following Magento 2's MVC best practices (avoiding direct core file edits as much as possible):
1. Create a Custom Block (Recommended Approach)
First, we'll build a custom block to handle the data logic (keeping template files clean, which is Magento's preferred pattern).
Step 1: Create the Block Class
In your custom module (replace Vendor\Module with your actual module namespace), create this file:app/code/Vendor/Module/Block/Blog/CategoryLatestPosts.php
<?php namespace Vendor\Module\Block\Blog; use FishPig\WordPress\Block\AbstractBlock; use FishPig\WordPress\Model\ResourceModel\Post\CollectionFactory as PostCollectionFactory; use FishPig\WordPress\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory; class CategoryLatestPosts extends AbstractBlock { protected $postCollectionFactory; protected $categoryCollectionFactory; public function __construct( \Magento\Framework\View\Element\Template\Context $context, PostCollectionFactory $postCollectionFactory, CategoryCollectionFactory $categoryCollectionFactory, array $data = [] ) { $this->postCollectionFactory = $postCollectionFactory; $this->categoryCollectionFactory = $categoryCollectionFactory; parent::__construct($context, $data); } public function getCategoriesWithLatestPost() { // Fetch all categories, exclude Uncategorized and empty categories $categoryCollection = $this->categoryCollectionFactory->create(); $categoryCollection->addFieldToFilter('slug', ['neq' => 'uncategorized']) ->addFieldToFilter('count', ['gt' => 0]); // Only show categories with posts $categoriesWithPosts = []; foreach ($categoryCollection as $category) { // Get the latest published post for this category $postCollection = $this->postCollectionFactory->create(); $postCollection->addIsPublishedFilter() ->addCategoryFilter($category) ->setOrder('post_date', 'DESC') ->setPageSize(1); if ($post = $postCollection->getFirstItem()) { $categoriesWithPosts[] = [ 'category' => $category, 'latest_post' => $post ]; } } return $categoriesWithPosts; } }
Step 2: Create the Template File
Next, create the template to render the data:app/code/Vendor/Module/view/frontend/templates/blog/category-latest-posts.phtml
<?php $categoriesWithPosts = $block->getCategoriesWithLatestPost(); ?> <?php if (!empty($categoriesWithPosts)): ?> <div class="category-latest-posts grid-container"> <?php foreach ($categoriesWithPosts as $item): ?> <?php $category = $item['category']; ?> <?php $post = $item['latest_post']; ?> <div class="category-post-item grid-item"> <h3 class="category-title"> <a href="<?= $block->escapeUrl($category->getUrl()) ?>"> <?= $block->escapeHtml($category->getName()) ?> </a> </h3> <div class="latest-post-card"> <?php if ($featuredImage = $post->getFeaturedImage()): ?> <img src="<?= $block->escapeUrl($featuredImage->getAvailableImageUrl()) ?>" alt="<?= $block->escapeHtmlAttr($post->getPostTitle()) ?>" class="post-featured-image" > <?php endif; ?> <h4 class="post-title"> <a href="<?= $block->escapeUrl($post->getUrl()) ?>"> <?= $block->escapeHtml($post->getPostTitle()) ?> </a> </h4> <p class="post-excerpt"> <?= $block->escapeHtml($post->getPostExcerpt()) ?> </p> <span class="post-date"> <?= $block->escapeHtml($post->getPostDate()) ?> </span> </div> </div> <?php endforeach; ?> </div> <?php endif; ?>
Step 3: Add the Block to Your Blog Layout
To display this on your blog homepage, update the FishPig blog layout file (or your custom layout override):app/design/frontend/YourTheme/YourThemeChild/Magento_Theme/layout/fishpig_wordpress_blog_index.xml
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceContainer name="content"> <block class="Vendor\Module\Block\Blog\CategoryLatestPosts" name="category.latest.posts" template="Vendor_Module::blog/category-latest-posts.phtml" before="-"/> </referenceContainer> </body> </page>
2. Quick Test (Direct Template Edit, Not Recommended)
If you just want to test the logic without building a custom module, you can add this code directly to your existing FishPig/WordPress/view/frontend/templates/post/list.phtml (note: core file edits are not ideal for long-term maintenance):
<?php // Fetch valid categories (exclude Uncategorized and empty ones) $categoryCollection = $this->getLayout()->createObject(\FishPig\WordPress\Model\ResourceModel\Category\Collection::class); $categoryCollection->addFieldToFilter('slug', ['neq' => 'uncategorized']) ->addFieldToFilter('count', ['gt' => 0]); ?> <div class="category-latest-posts"> <?php foreach ($categoryCollection as $category): ?> <?php // Get latest post for this category $postCollection = $this->getLayout()->createObject(\FishPig\WordPress\Model\ResourceModel\Post\Collection::class); $postCollection->addIsPublishedFilter() ->addCategoryFilter($category) ->setOrder('post_date', 'DESC') ->setPageSize(1); $post = $postCollection->getFirstItem(); ?> <?php if ($post->getId()): ?> <div class="category-post"> <h3><?= $block->escapeHtml($category->getName()) ?></h3> <a href="<?= $block->escapeUrl($post->getUrl()) ?>"> <?= $block->escapeHtml($post->getPostTitle()) ?> </a> <?php if ($post->getPostExcerpt()): ?> <p><?= $block->escapeHtml($post->getPostExcerpt()) ?></p> <?php endif; ?> <span class="post-date"><?= $block->escapeHtml($post->getPostDate()) ?></span> </div> <?php endif; ?> <?php endforeach; ?> </div>
Key Notes
- Excluding Uncategorized: We use the category slug
uncategorizedinstead of ID because the ID can vary (default is 1, but it's not guaranteed). - Empty Categories: The
addFieldToFilter('count', ['gt' => 0])line ensures we only show categories that have at least one published post. - Security: Always use
escapeHtml(),escapeUrl(), andescapeHtmlAttr()to prevent XSS vulnerabilities in your templates. - Performance: If you have a lot of categories, consider adding caching to the block to improve load times.
内容的提问来源于stack exchange,提问作者Joey

