Hello,
That hybrid behaviour is not a built-in HikaShop option, but it can be done with a small product listing view override that builds on top of HikaShop's existing infinite scroll.
The idea: keep HikaShop's regular infinite scroll, wrap its trigger so that after the configured number of pages have been auto-loaded it stops, hides the "Load more" block, and reveals / scrolls to a numbered pagination block. A direct navigation to a page past the threshold (the customer arrives at page 11 from a bookmark, a deep link, an SEO crawler, etc.) skips infinite scroll entirely and behaves as a normal paginated page.
Two notes before the override itself:
(1) HikaShop's stock listing_div.php suppresses the bottom pagination block entirely when infinite scroll is on (its render condition has "&& !$infinite_scroll"). So the override re-renders that same pagination block itself, hidden via display:none, so there is something for the JS to reveal once the threshold is reached.
(2) Make sure infinite scroll is enabled on the relevant menu item (Menus > Edit menu item > HikaShop Options > Use the infinite scroll = Yes) so HikaShop's stock scroll runs in the first place; the override only changes when to stop it.
Drop this file at:
templates/YOUR_TEMPLATE/html/com_hikashop/product/listing.php
It includes the unmodified core listing.php from your HikaShop install and then appends the hidden pagination block and the cap JS. The only thing to tune is the HK_HYBRID_THRESHOLD_PAGES constant at the top of the JS block (set to 10 below to match what you asked).
<?php
defined('_JEXEC') or die('Restricted access');
include rtrim(HIKASHOP_FRONT, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR
. 'views' . DIRECTORY_SEPARATOR . 'product' . DIRECTORY_SEPARATOR
. 'tmpl' . DIRECTORY_SEPARATOR . 'listing.php';
$hk_hyb_pagination = null;
if(!empty($this->pagination) && !empty($this->pageInfo->elements->total)
&& !empty($this->pageInfo->limit->value)
&& $this->pageInfo->elements->total > $this->pageInfo->limit->value) {
$hk_hyb_pagination = $this->pagination;
$hk_hyb_form_suffix = '_bottom_hybrid';
$hk_hyb_pagination->form = $hk_hyb_form_suffix;
$hk_hyb_main_div = isset($this->params) ? $this->params->get('main_div_name', '') : '';
$hk_hyb_cat_sel = isset($this->category_selected) ? $this->category_selected : '';
?>
<form action="<?php echo str_replace(array('&tmpl=raw', '&tmpl=component'), '', hikashop_currentURL()); ?>" method="post" name="adminForm_<?php echo $hk_hyb_main_div . $hk_hyb_cat_sel . $hk_hyb_form_suffix; ?>" style="display:none;" class="hikashop_hybrid_pagination_wrapper">
<div class="hikashop_products_pagination hikashop_products_pagination_bottom">
<?php
// Strip tmpl=raw / tmpl=component from the rendered page links.
// The list-footer helper inherits the request URI, so when the
// listing template runs in an AJAX (tmpl=raw) context, the
// links carry that parameter and would land on a raw layout if
// clicked. Cover the leading-? form too, not just the
// &-prefixed one.
$hk_hyb_footer = $hk_hyb_pagination->getListFooter((int)$this->pageInfo->limit->value);
$hk_hyb_footer = preg_replace('/([?&])tmpl=(raw|component)(&|"|\')/i', '$1$3', $hk_hyb_footer);
$hk_hyb_footer = str_replace('?&', '?', $hk_hyb_footer);
echo $hk_hyb_footer;
?>
<span class="hikashop_results_counter"><?php echo $hk_hyb_pagination->getResultsCounter(); ?></span>
</div>
<?php if(isset($this->pageInfo->filter->order)) { ?>
<input type="hidden" name="filter_order_<?php echo $hk_hyb_main_div . $hk_hyb_cat_sel; ?>" value="<?php echo $this->pageInfo->filter->order->value; ?>" />
<input type="hidden" name="filter_order_Dir_<?php echo $hk_hyb_main_div . $hk_hyb_cat_sel; ?>" value="<?php echo $this->pageInfo->filter->order->dir; ?>" />
<?php } ?>
<?php echo JHTML::_('form.token'); ?>
</form>
<?php
}
?>
<script type="text/javascript">
(function(){
var HK_HYBRID_THRESHOLD_PAGES = 10;
function init(){
if(!window.localPage || typeof window.localPage.infiniteScroll !== 'function'){
setTimeout(init, 200);
return;
}
var params = new URLSearchParams(window.location.search);
var limit = parseInt(params.get('limit')) || <?php echo (int)max(1, $this->pageInfo->limit->value); ?>;
var limitStart = parseInt(params.get('limitstart')) || parseInt(params.get('start')) || <?php echo (int)$this->pageInfo->limit->start; ?>;
var initialPage = Math.floor(limitStart / limit) + 1;
if(initialPage > HK_HYBRID_THRESHOLD_PAGES){
window.localPage.infiniteScrollPage = -1;
var loadMore = document.querySelector('[id$="_infinite_scroll"]');
if(loadMore) loadMore.style.display = 'none';
revealPagination();
return;
}
var origInfiniteScroll = window.localPage.infiniteScroll;
window.localPage.infiniteScroll = function(container_name){
var nextPage = initialPage + window.localPage.infiniteScrollPage;
if(nextPage > HK_HYBRID_THRESHOLD_PAGES){
window.localPage.infiniteScrollPage = -1;
var container = document.getElementById(container_name + '_infinite_scroll');
if(container) container.style.display = 'none';
revealPagination();
return false;
}
return origInfiniteScroll(container_name);
};
}
function revealPagination(){
var wrapper = document.querySelector('.hikashop_hybrid_pagination_wrapper');
if(!wrapper) return;
wrapper.style.display = '';
try { wrapper.scrollIntoView({behavior:'smooth', block:'center'}); } catch(e){}
}
init();
})();
</script>
We tested this on a local Joomla 6 / HikaShop 6.4.1 install (10 dummy products, limit 2, threshold reduced to 2 for the visible transition) and confirmed: pages 1 and 2 load via auto-scroll, the load-more then hides and the pagination block reveals with numbered links to pages 3 to 5, and clicking a numbered link lands on a clean URL with the full template chrome.