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>