Ticket 1540800: “I want the Flake Ice collection and the PPM collection to show first on the list of products. Can I add something to the shortcode for this?”
Short answer
Not out of the box. A SureCart product list can only be sorted by newest, name or price. There is no setting, filter or shortcode option that puts one collection ahead of another. So I wrote a small snippet that adds one: a show_first setting for the shortcode. Everything on this page is running live on this test store.
See it working
- Before (your corrected shortcode, no show_first): zz-1540800-r4-fixed-quoted. 15 products, four collections mixed together, newest first.
- After (same shortcode plus show_first with two collection ids): zz-1540800-r5-show-first-ids. Kits (4) first, then Accessories (3), then the other 8.
- Same thing with slugs, in the opposite order: zz-1540800-r5-show-first-slugs. Accessories first, then Kits. The order you write them in is the order they appear in.
- With pagination (4 per page): zz-1540800-r5-show-first-paged. The order carries on across the pages.
- Whole catalogue instead of chosen collections (
[sc_product_list]with show_first): zz-1540800-r5-show-first-whole-catalogue. Kits, then Accessories, then every other product in the store. - Product List block instead of a shortcode (page rule): two-collections-block-1540800. Servicing first, then Parts, sorted A to Z inside each group.
On the After page try the Sort dropdown and the search box: the chosen collections stay on top and the sort is applied inside each group.
The shortcode (your ids)
Add show_first="..." with the ids of the collections you want on top, in the order you want them. Replace the two placeholders with the ids of Flake Ice and PPM. You find a collection id in the address bar when you open it under SureCart > Products > Collections: ...page=sc-product-collections&action=edit&id=THIS-PART. Same rules as before: everything inside quotes, commas only, no spaces, one line.
[sc_product_collection collection_id="d8766f4b-4556-4931-93e5-26b5e3903c53,faaf2492-b4d9-4b69-9ea9-a2847f889693,16c1fd81-d950-49e1-891e-c796769172d9,0ecfdfd5-f2c8-4d9a-9914-a4cf7a9cf140" show_first="FLAKE-ICE-COLLECTION-ID,PPM-COLLECTION-ID" columns="4" sort_enabled="1" search_enabled="1" pagination_enabled="0" limit="50"]
Collection slugs work too, so show_first="flake-ice,ppm" is fine if you prefer. Flake Ice and PPM do not have to be in collection_id for this to work, but they do on your page, which is what you want.
This is the exact shortcode running on the After page above:
[sc_product_collection collection_id="a11da7fc-1621-44b7-a68d-e667edd1be8e,211dfe18-7780-4a1b-a24a-a31a8ee509d4,bd7b05de-182a-4519-a0d1-ece8df84950c,0ac73272-5751-49cd-9077-09c7eb4604b0" show_first="0ac73272-5751-49cd-9077-09c7eb4604b0,bd7b05de-182a-4519-a0d1-ece8df84950c" columns="4" sort_enabled="1" search_enabled="1" pagination_enabled="1" ajax_pagination="1" limit="50"]
Install (about two minutes)
- Open the snippets plugin you installed last time (WPCode, Code Snippets or WPCodeBox), or your child theme’s functions.php.
- Add a new PHP snippet, paste the code below, set it to run everywhere, and activate it.
- Add
show_first="..."to your shortcode and save the page. - If nothing changes, clear your site cache (and Cloudflare if you use it) and reload.
The snippet
<?php
/**
* SureCart: show chosen collections first in a Product List.
*
* Adds a `show_first` setting to the [sc_product_collection] and [sc_product_list] shortcodes:
*
* [sc_product_collection collection_id="A,B,C,D" show_first="A,B" columns="4" limit="50"]
*
* Products in collection A come first, then products in B, then everything else in the list.
* The order you write them in is the order the groups appear in. Inside each group the normal
* sorting still applies (newest first by default). Search, the Collections filter, the Sort
* dropdown and pagination keep working.
*
* `show_first` accepts collection ids (the id in the address bar when you open a collection
* under SureCart > Products > Collections) or collection slugs. Mix them if you like.
*
* Install: add as a PHP snippet (WPCode, Code Snippets, WPCodeBox) or in your child theme's
* functions.php. Custom code, not an official part of SureCart. Test on staging or take a backup first.
*/
/**
* KEEP_WHEN_SORTED
* true = the chosen collections stay on top even when a shopper picks something in the Sort dropdown
* (the sort is applied inside each group).
* false = as soon as a shopper picks a Sort option, the whole list follows that sort and the
* "show first" grouping is dropped until they clear it.
*/
if ( ! defined( 'SCSF_KEEP_WHEN_SORTED' ) ) {
define( 'SCSF_KEEP_WHEN_SORTED', true );
}
/**
* Optional. For a Product List that is built with blocks (no shortcode), list the page here:
* 'page-slug' => 'collection-id-or-slug,another-one'
* The page slug is the last part of the page address, e.g. 'shop' for https://example.com/shop/.
*/
function scsf_page_rules() {
return array(
// 'shop' => 'flake-ice,ppm',
);
}
/**
* Remember which collections should come first for the list being rendered right now.
*/
function scsf_state( $set = null ) {
static $current = null;
if ( func_num_args() ) {
$current = $set;
}
return $current;
}
/**
* Turn "id,id,slug" into an ordered list of WordPress term_taxonomy_ids for the sc_collection taxonomy.
*/
function scsf_resolve( $raw ) {
static $cache = array();
$raw = trim( (string) $raw );
if ( '' === $raw ) {
return array();
}
if ( isset( $cache[ $raw ] ) ) {
return $cache[ $raw ];
}
$out = array();
foreach ( array_filter( array_map( 'trim', explode( ',', $raw ) ) ) as $token ) {
$term = null;
if ( preg_match( '/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $token ) ) {
// A SureCart collection id: find the WordPress term that mirrors it.
$found = get_terms(
array(
'taxonomy' => 'sc_collection',
'hide_empty' => false,
'number' => 1,
'meta_key' => 'sc_id',
'meta_value' => $token,
)
);
$term = ( ! is_wp_error( $found ) && ! empty( $found ) ) ? $found[0] : null;
} else {
$term = get_term_by( 'slug', sanitize_title( $token ), 'sc_collection' );
}
if ( $term && ! is_wp_error( $term ) ) {
$out[] = (int) $term->term_taxonomy_id;
}
}
$cache[ $raw ] = array_values( array_unique( $out ) );
return $cache[ $raw ];
}
/**
* 1. When a Product List starts rendering, read its show_first setting (shortcode attribute or page rule).
*/
add_filter(
'render_block_data',
function ( $parsed_block ) {
if ( 'surecart/product-list' !== ( $parsed_block['blockName'] ?? '' ) ) {
return $parsed_block;
}
$raw = $parsed_block['attrs']['show_first'] ?? '';
if ( '' === $raw && is_singular() ) {
$rules = scsf_page_rules();
$slug = get_post_field( 'post_name', get_queried_object_id() );
$raw = $rules[ $slug ] ?? '';
}
scsf_state( scsf_resolve( $raw ) );
return $parsed_block;
}
);
/**
* 2. When that Product List has finished rendering, forget the setting so other lists are untouched.
*/
add_filter(
'render_block_surecart/product-list',
function ( $content ) {
scsf_state( null );
return $content;
}
);
/**
* 3. Put the chosen collections first in the product query. Everything else about the query is untouched.
*/
add_filter(
'posts_orderby',
function ( $orderby, $query ) {
global $wpdb;
$tt_ids = scsf_state();
if ( empty( $tt_ids ) || 'sc_product' !== $query->get( 'post_type' ) ) {
return $orderby;
}
if ( ! SCSF_KEEP_WHEN_SORTED ) {
// A shopper picked something in the Sort dropdown: let that sort win.
foreach ( array_keys( $_GET ) as $key ) { // phpcs:ignore WordPress.Security.NonceVerification
if ( preg_match( '/(^|-)orderby$/', (string) $key ) ) {
return $orderby;
}
}
}
$when = '';
foreach ( array_values( $tt_ids ) as $rank => $tt_id ) {
$when .= sprintf(
' WHEN EXISTS (SELECT 1 FROM %s scsf WHERE scsf.object_id = %s.ID AND scsf.term_taxonomy_id = %d) THEN %d',
$wpdb->term_relationships,
$wpdb->posts,
(int) $tt_id,
(int) $rank
);
}
$rank_sql = 'CASE' . $when . ' ELSE ' . count( $tt_ids ) . ' END';
return $rank_sql . ( $orderby ? ', ' . $orderby : '' );
},
10,
2
);
Good to know
- Order of the ids = order of the groups. Put Flake Ice first if it should be above PPM.
- A product that is in both chosen collections lands in the first group it matches.
- Inside each group the normal sorting applies: newest first by default, or whatever the shopper picks in the Sort dropdown. If you would rather have the Sort dropdown override the grouping completely, change
SCSF_KEEP_WHEN_SORTEDfromtruetofalseat the top of the snippet. - It only touches lists that have
show_first(or a page rule). Every other product list on the site is left alone. - For a list built with the Product List block instead of a shortcode, add the page slug to
scsf_page_rules()in the snippet, like the commented example. - Custom code, not an official part of SureCart. Add it on a staging copy first or take a backup.
Side note: pagination under a collection shortcode
While testing I noticed that the page numbers under an [sc_product_collection] shortcode are counted from your whole catalogue, not from the collections in the list. With 27 products in the list, a limit of 50 and 100+ products in the store, you may see page links 2 and 3 that lead to empty pages. Everything fits on one page anyway, so the clean fix for now is pagination_enabled="0", which is already in the shortcode above. I have reported the counting issue to the team.