been trying to figure out how to create a loop to support woocommerce's shortcode WITH Pagination.
Because currently, I have a project and would like to have a page with a certain product displayed, for example i have 50 sale products, using this shortcode [sale_products per_page="10"] it just displays 10 products without pagination. Any thoughts regarding this issue?
Regards,
add_action( 'pre_get_posts', 'so_28367762_pre_get_posts' );
function so_28367762_pre_get_posts( $q ) {
// We only want to affect the main query
if ( is_admin() || ! $q->is_main_query() ) {
return;
}
$sale_page_id = 487;
// totally modify the query on the Sale Page
if( isset( $q->queried_object_id ) && $q->queried_object_id === $sale_page_id ) {
$q->set( 'post_type', 'product' );
$q->set( 'page', '' );
$q->set( 'pagename', '' );
if ( isset( $q->query['paged'] ) ) {
$q->set( 'paged', $q->query['paged'] );
}
// Fix for verbose page rules
if ( $GLOBALS['wp_rewrite']->use_verbose_page_rules ) {
// Fix conditional Functions
$q->is_archive = true;
$q->is_post_type_archive = true;
$q->is_singular = false;
$q->is_page = false;
}
WC()->query->product_query( $q );
// We're on a shop page so queue the woocommerce_get_products_in_view function
add_action( 'wp', array( WC()->query, 'get_products_in_view' ), 2);
// And remove the pre_get_posts hook
WC()->query->remove_product_query();
}
}
Little modification and worked for me!
Well I took an alternative approach. What I've done is created a "page" that will be a product archive (just like the shop) except only for sale products. I'm sure if it wasn't almost midnight I could make it an option in WooCommerce, just like the store option to set the shop, my account pages, etc. But in the interest of speed I just made a page, took note of its ID and hard-coded it as $sale_page_id
.
First, we're going to mimic what WooCommerce does when you tell it that you want the store to be on the front page of your site. Basically, we're going to hijack the query and switch it from a page into a product archive.
add_action( 'pre_get_posts', 'so_28367762_pre_get_posts' );
function so_28367762_pre_get_posts( $q ) {
// We only want to affect the main query
if ( is_admin() || ! $q->is_main_query() ) {
return;
}
$sale_page_id = 487;
// totally modify the query on the Sale Page
if( isset( $q->queried_object_id ) && $q->queried_object_id === $sale_page_id ) {
$q->set( 'post_type', 'product' );
$q->set( 'page', '' );
$q->set( 'pagename', '' );
if ( isset( $q->query['paged'] ) ) {
$q->set( 'paged', $q->query['paged'] );
}
// Fix for verbose page rules
if ( $GLOBALS['wp_rewrite']->use_verbose_page_rules ) {
// Fix conditional Functions
$q->is_archive = true;
$q->is_post_type_archive = true;
$q->is_singular = false;
$q->is_page = false;
}
WC()->query->product_query( $q );
// We're on a shop page so queue the woocommerce_get_products_in_view function
add_action( 'wp', array( WC()->query, 'get_products_in_view' ), 2);
// And remove the pre_get_posts hook
WC()->query->remove_product_query();
}
}
And then we're going to modify the product query so that it only returns items that are on sale. I tried adding this directly above, but it didn't work since post__in
starts from scratch/null in the product_query()
method. I added the same conditional logic to make sure that this is only applied on this custom "sale" page.
add_action( 'woocommerce_product_query', 'so_28367762_product_query' );
function so_28367762_product_query( $q ){
$sale_page_id = 487;
if( isset( $q->queried_object_id ) && $q->queried_object_id === $sale_page_id ) {
$product_ids_on_sale = wc_get_product_ids_on_sale();
$q->set( 'post__in', (array) $product_ids_on_sale );
}
}
If you have enough sale products, you should have pagination. The one thing I didn't get to tonight was that the page title shows up as "Shop" and the breadcrumbs think it is "Shop". I'm sure there is a way around that... tweaking the templates, etc.