1

I'm trying to modify the Category List of the com_content component via override, so that it shows both the articles of the selected category and its subcategories.

I tried to edit the default_articles.php file (in category folder) adding this code:

if (!empty($this->items) && $this->params->get('show_subcats') != '0')
{
    $sub_categories = $this->children[$this->category->id];
    foreach($sub_categories as $sub_category){
        $subcategory_model = JModelList::getInstance('Articles', 'ContentModel', array('ignore_request'=>true));
        $appParams = JFactory::getApplication()->getParams();
        $subcategory_model->setState('params', $appParams);
        $subcategory_model->setState('filter.category_id', $sub_category->id);
        $subcategory_items = $subcategory_model->getItems();
        $this->items = array_merge($this->items, $subcategory_items);
    }
    //Sort new items by date
    usort($this->items, function ($a, $b) {
        $order_date = ($this->params->get('order_date') == 'published') ? 'publish_up' : $this->params->get('order_date');
        return strtotime($b->{$order_date}) - strtotime($a->{$order_date});
    });
}

But I noticed that it's a wrong idea, because pagination and filter are applied before my editing, and they don't consider my new $this->items array.

I was also thinking of editing the pagination and filtering in the default_articles.php, after my edit of $this->items, but I don't know how to do it and if it's possible. Do you have some advice or alternative solution to make a category and subcategories articles list?

3
  • Please do not add resolutions to your question body. If you have resolved your question, please post a new answer to your question then "Rollback" your question to remove the resolving info. Oct 15, 2022 at 16:42
  • I did as you told me, thank you.
    – Nintendomi
    Oct 17, 2022 at 7:40
  • Okay, I didn't explain the trick well enough. You haven't damaged anything, but I want to teach you the dedicated Rollback feature. Click on the blue text under your question that says "edited X ago". Then scroll down to version "1" of your edit history and click on the Rollback link text. Admittedly, it will look like nothing changed, but that is because the manually deleted text in your 3rd edit looks like the 1st. Have a go. And you should accept the best answer (which may be your own). Oct 17, 2022 at 8:19

2 Answers 2

1

I realised that the solution was not to use the article array provided by Joomla but to create a new one...

I created an array of the articles in the category, merged it with the arrays of articles in the subcategories. Then I recreated the pagination and applied the filter to the newly created array.

Below is the code with these additions and changes.

use Joomla\CMS\Pagination\Pagination;

// To add subcategories items to the list we need to make a new array of items, 
// because the original one made by the component have already applied pagination and filter

// Make a new items array of our category
$model = JModelList::getInstance('Articles', 'ContentModel', array('ignore_request'=>true));
$appParams = JFactory::getApplication()->getParams();
$model->setState('params', $appParams);
$model->setState('filter.category_id', $this->category->id);
$model->setState('filter.published', 1);
$this->items = $model->getItems();
$this->total = count($this->items);
$catItems = $model->getItems();
$catItemsCount = count($this->items);

// Get subcategories items and merge them to category items
if ($this->params->get('show_subcats') != '0')
{
    $sub_categories = $this->children[$this->category->id];
    foreach($sub_categories as $sub_category){
        $subcategory_model = JModelList::getInstance('Articles', 'ContentModel', array('ignore_request'=>true));
        $appParams = JFactory::getApplication()->getParams();
        $subcategory_model->setState('params', $appParams);
        $subcategory_model->setState('filter.category_id', $sub_category->id);
        $subcategory_model->setState('filter.published', 1);
        $subcategory_items = $subcategory_model->getItems();
        $this->items = array_merge($this->items, $subcategory_items);
        $this->total = count($this->items);
    }
    // Sort new items by date
    usort($this->items, function ($a, $b) {
        $order_date = ($this->params->get('order_date') == 'published') ? 'publish_up' : $this->params->get('order_date');
        return strtotime($b->{$order_date}) - strtotime($a->{$order_date});
    });
}

// If the filter has been used, make a new array with only matching items
if (strlen($this->escape($this->state->get('list.filter'))) > 0){
    $filteredItems = [];
    foreach($this->items as $item){
        $word = strtolower($this->escape($this->state->get('list.filter')));
        if (strpos(strtolower($item->title), $word) !== false){
            array_push($filteredItems, $item);
        }
    }
    // Get the count of filtered articles from the category only (we need it for the "all" in the limitbox)
    $catItemsCount = 0;
    foreach($catItems as $item){
        $word = strtolower($this->escape($this->state->get('list.filter')));
        if (strpos(strtolower($item->title), $word) !== false){
            $catItemsCount++;
        }
    }
    $this->items = $filteredItems;
    $this->total = count($this->items);
}

// Set limit and limitstart for pagination
$this->pagination->limitstart = ($_GET['start'] == '') ? $this->pagination->limitstart : $_GET['start'];
if ($this->pagination->limit > $this->total){
    $this->pagination->limitstart = 0;
}
    //It's used when is selected "all" in the limitbox
if ($this->pagination->limit == $catItemsCount) {
    $this->pagination->limitstart = 0;
    $this->pagination->limit = 0;
}

// Make a new pagination object
$this->pagination = new Pagination($this->total, $this->pagination->limitstart, $this->pagination->limit);
$limitstart = $this->pagination->limitstart;
$limit = $this->pagination->limit;

//The list is ready to be printed ?>

<ul>
    <?php foreach ($this->items as $i => $article) : ?>
        <?php $this->article = &$article; ?>
        <?php $this->article->counter = $i + 1; ?>
        <?php $max_results = $limitstart + $limit;?>
        <?php // Display only the result of the current page ?>
        <?php if ($this->article->counter > $limitstart && $this->article->counter <= $max_results) : ?>
            <li>
                <?php echo $article->title; ?>
                // or everything you want to show of your articles
            </li>
        <?php endif; ?>
    <?php endforeach; ?>
</ul>

1
  • If $a->$order_date and $b->$order_date are formatted as Y-m-d H:i:s (big-endian), then you can use return $b->$order_date <=> $a->$order_date; ]Explained here.](stackoverflow.com/a/67124505/2943403) Oct 17, 2022 at 9:01
0

As far as I remember 'category list' menu item can be configured. You can set 'subcategory levels' to 'All' and it will include all the articles from sublevels.

Overrides are meant to change display/views - not the actual business logic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.