wordpress sticky post on archive page with pagination - php

I have category page which is redirecing to archieve.php.
you can see here : https://www.dealfinder.lk/category/dining/
There are two sticky posts at the top.
1) Up to 25% OFF at &Co Pub and Kitchen with COMBANK Cards
2) 20% OFF at Robata – Movenpick Hotel Colombo for all HSBC Credit Cards
My pagination is 10 items per post
Right now, it shows me 12 items per post.
Here is my code :
function yell_category_sticky_posts( $posts, $wp_query ) {
global $wp_the_query;
// Don't continue if this isn't a category query, we're not in the main query or we're in the admin
if ( ! $wp_query->is_category || $wp_query !== $wp_the_query || is_admin() )
return $posts;
global $wpdb;
$q = $wp_query->query_vars;
$page = absint( $q['paged'] );
if ( empty( $page ) )
$page = 1;
$post_type = $q['post_type'];
$sticky_posts = get_option( 'sticky_posts' );
if ( $wp_query->is_category && $page <= 1 && is_array( $sticky_posts ) && !empty( $sticky_posts ) && ! $q['ignore_sticky_posts'] ) {
$num_posts = count( $posts );
$sticky_offset = 0;
// Loop over posts and relocate stickies to the front.
for ( $i = 0; $i < $num_posts; $i++ ) {
if ( in_array( $posts[$i]->ID, $sticky_posts ) ) {
$sticky_post = $posts[$i];
// Remove sticky from current position
array_splice( $posts, $i, 1 );
// Move to front, after other stickies
array_splice( $posts, $sticky_offset, 0, array( $sticky_post ) );
// Increment the sticky offset. The next sticky will be placed at this offset.
$sticky_offset++;
// Remove post from sticky posts array
$offset = array_search( $sticky_post->ID, $sticky_posts );
unset( $sticky_posts[$offset] );
}
}
// If any posts have been excluded specifically, Ignore those that are sticky.
if ( !empty( $sticky_posts ) && !empty( $q['post__not_in'] ) )
$sticky_posts = array_diff( $sticky_posts, $q['post__not_in'] );
// Fetch sticky posts that weren't in the query results
if ( !empty( $sticky_posts ) ) {
$stickies__in = implode( ',', array_map( 'absint', $sticky_posts ));
// honor post type(s) if not set to any
$stickies_where = '';
if ( 'any' != $post_type && '' != $post_type ) {
if ( is_array( $post_type ) )
$post_types = join( "', '", $post_type );
else
$post_types = $post_type;
$stickies_where = "AND $wpdb->posts.post_type IN ('" . $post_types . "')";
}
$stickies = $wpdb->get_results( "SELECT wp_posts.* FROM $wpdb->posts INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) WHERE 1=1 AND ( wp_term_relationships.term_taxonomy_id IN (" . get_term( $wp_query->query_vars['cat'], 'category' )->term_taxonomy_id . ") ) AND $wpdb->posts.ID IN ($stickies__in) $stickies_where" );
foreach ( $stickies as $sticky_post ) {
// Ignore sticky posts are not published.
if ( 'publish' != $sticky_post->post_status )
continue;
array_splice( $posts, $sticky_offset, 0, array( $sticky_post ) );
$sticky_offset++;
}
}
}
return $posts;
}
add_filter( 'the_posts', 'yell_category_sticky_posts', 10, 2 );
My Issue:
I want to show 10 posts per page, currently it shows 12 posts
per page with sticky post.
This question is for master not for new learner.
Anybody master here? Thanks in advance

The below function pushes stickies to the top, you should be able to use this to help in your case.
add_filter('the_posts', 'bump_sticky_posts_to_top');
function bump_sticky_posts_to_top($posts) {
$stickies = array();
foreach($posts as $i => $post) {
if(is_sticky($post->ID)) {
$stickies[] = $post;
unset($posts[$i]);
}
}
return array_merge($stickies, $posts);
}

As I suggested in the comment, save the 'sticky posts' in meta (assuming is_featured_post as the 'meta key').
Run these only once to set the meta value for existing posts. You can skip this since you are already saving in the meta.
// set meta value of all posts to 0
$all_posts = get_posts(array('post_type'=>'post','posts_per_page'=>-1));
if( is_array( $all_posts ) )
{
foreach( $all_posts as $post ) {
update_post_meta( $post->ID, 'is_featured_post', '0' );
}
}
// set meta value of all sticky posts alone to 1
$sticky_posts = get_option( 'sticky_posts' );
if( is_array( $sticky_posts ) )
{
foreach ( $sticky_posts as $sticky_post ) {
update_post_meta( $sticky_post, 'is_featured_post', '1' );
}
}
The below function will update the new sticky meta is_featured_post each time a post updated (or new post saved).
function save_sticky_meta( $post_id ) {
if ( isset( $_REQUEST['sticky'] ) ) {
update_post_meta( $post_id, 'is_featured_post', '1' );
}
else {
update_post_meta( $post_id, 'is_featured_post', '0' );
}
}
add_action( 'save_post', 'save_sticky_meta' );
add_action( 'edit_post', 'save_sticky_meta' );
Then use pre_get_posts action to set the category query. We are ordering by both 'meta' and 'date' descending to show the latest at top.
function include_sticky_posts( $query ) {
if ( ! is_admin() && $query->is_main_query() && $query->is_category() ) {
$query->set( 'meta_key', 'is_featured_post' );
$query->set( 'sticky_sort', true ); //custom sticky order query
$query->set( 'orderby', 'meta_value_num date' );
$query->set( 'order', 'DESC' );
}
}
add_action( 'pre_get_posts', 'include_sticky_posts' );
If you want to randomize non-sticky posts, change the order using the_posts filter as below.
add_filter( 'the_posts', 'sticky_posts_sort', 10, 2 );
function sticky_posts_sort( $posts, $query )
{
// if custom sort set from category query
if ( true !== $query->get( 'sticky_sort' ) )
return $posts;
// loop through posts & save sticky & other posts in seperate arrays
$sticky_posts = get_option( 'sticky_posts' );
$sticky_array = array();
$posts_array = array();
foreach ( $posts as $p ) {
if( in_array( $p->ID, $sticky_posts ) )
$sticky_array[] = $p;
else
$posts_array[] = $p;
}
// merge both arrays and randomize non-sticky posts alone
if( is_array( $posts_array ) )
shuffle( $posts_array );
if( is_array( $sticky_array ) && is_array( $posts_array ) )
$posts = array_merge( $sticky_array, $posts_array );
elseif( is_array( $sticky_array ) )
$posts = $sticky_array;
else
$posts = $posts_array;
return $posts;
}

Related

WooCommerce recently view product count

If I am using the following code to track recently viewed products...
/**
* Track user woocommerce viewed products.
*/
function dorzki_wc_track_product_views() {
if( ! is_singular( 'product' ) || is_active_widget( false, false, 'woocommerce_recently_viewed_products', true ) ) {
return;
}
global $post;
if ( empty( $_COOKIE['woocommerce_recently_viewed'] ) ) {
$viewed_products = array();
} else {
$viewed_products = wp_parse_id_list( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) );
}
$keys = array_flip( $viewed_products );
if ( isset( $keys[ $post->ID ] ) ) {
unset( $viewed_products[ $keys[ $post->ID ] ] );
}
$viewed_products[] = $post->ID;
if ( count( $viewed_products ) > 15 ) {
array_shift( $viewed_products );
}
wc_setcookie( 'woocommerce_recently_viewed', implode( '|', $viewed_products ) );
}
add_action( 'template_redirect', 'dorzki_wc_track_product_views', 20 );
and this code to display recently view products...
/**
* Display recently viewed products.
*/
function dorzki_wc_display_products_viewed() {
if ( empty( $_COOKIE['woocommerce_recently_viewed'] ) ) {
return;
}
$total_products = apply_filters( 'loop_shop_columns', get_option( 'woocommerce_catalog_columns', 4 ) );
$viewed_products = wp_parse_id_list( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) );
$products = array_slice( $viewed_products, 0, $total_products );
$ids = implode( ',', $products );
echo "<h2>" . esc_html__( 'Recently Viewed Products', 'dorzki' ) . "</h2>";
echo do_shortcode( "[products ids='{$ids}']" );
}
add_action( 'woocommerce_after_cart', 'dorzki_wc_display_products_viewed' );
How can I obtain the 'count'? Ideally I would like to create a shortcode that will output how many products the user has viewed recently.
I've tried this and I 'think' it works??
function recently_count() {
$total_products = apply_filters( 'loop_shop_columns', get_option( 'woocommerce_catalog_columns', 4 ) );
$viewed_products = wp_parse_id_list( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) );
$products = array_slice( $viewed_products, 0, $total_products );
$ids = implode( ',', $products );
if ($ids == 0) {
echo '0';
}
else {
echo count($ids);
}
}
add_shortcode( 'recently_count', 'recently_count' );
To just count the number of recently viewed products and return that in a shortcode, then you just have to count the exploded array of the cookie value.
Also, remember that you never echo a shortcode output, it must be returned.
function recently_count() {
return isset( $_COOKIE['woocommerce_recently_viewed'] ) ? count( (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) ) : 0;
}
add_shortcode( 'recently_count', 'recently_count' );
This will return an integer.

Hide multiple child-category from displaying on category page in woocommerce

I would like to hide multiple child-categories (CAT1, CAT2) from displaying on the main category page in woocommerce. I have found some code that works for this.
add_filter( 'get_terms', 'exclude_category', 10, 3 );
function exclude_category( $terms, $taxonomies, $args ) {
$new_terms = array();
if ( is_product_category() ){
foreach ( $terms as $key => $term ) {
if( is_object ( $term ) ) {
if ( 'CAT1' == $term->slug && $term->taxonomy = 'product_cat' ) {
unset($terms[$key]);
}
elseif ( 'CAT2' == $term->slug && $term->taxonomy = 'product_cat' ) {
unset($terms[$key]);
}
}
}
}
return $terms;
}
But the only way it works if I create a new "elseif" line for every category that i want to hide.
Is there a way to chain these two together?
if ( 'CAT1' == $term->slug && $term->taxonomy = 'product_cat' ) {
unset($terms[$key]);
}
elseif ( 'CAT2' == $term->slug && $term->taxonomy = 'product_cat' ) {
unset($terms[$key]);
}
Yes, you can use in_array(), store terms you want to unset in $exclude_terms and pass that in in_array($term->slug, $exclude_terms). Here is the complete code:
add_filter( 'get_terms', 'exclude_category', 10, 3 );
function exclude_category( $terms, $taxonomies, $args ) {
$exclude_terms = array('CAT1', 'CAT2', 'CAT3');
if ( is_product_category() ){
foreach ( $terms as $key => $term ) {
if( is_object ( $term ) ) {
if ( in_array($term->slug, $exclude_terms) && $term->taxonomy = 'product_cat' ) {
unset($terms[$key]);
}
}
}
}
return $terms;
}

Append WooCommerce product categories on products instead of overwriting

I am trying to force woocommerce to append product categories instead of overwriting when uploading new categories via csv.
I have tried finding code snippets.searched the codex and tried to use wp-includes/post.php to create function.
function wp_set_post_terms( $post_id = 0, $tags = '', $taxonomy = 'post_tag', $append = true ) {
$post_id = (int) $post_id;
if ( ! $post_id ) {
return true;
}
if ( empty( $tags ) ) {
$tags = array();
}
if ( ! is_array( $tags ) ) {
$comma = _x( ',', 'tag delimiter' );
if ( ',' !== $comma ) {
$tags = str_replace( $comma, ',', $tags );
}
$tags = explode( ',', trim( $tags, " \n\t\r\0\x0B," ) );
}
if ( is_taxonomy_hierarchical( $taxonomy ) ) {
$tags = array_unique( array_map( 'intval', $tags ) );
}
return wp_set_object_terms( $post_id, $tags, $taxonomy, $append );
}
I expect woocommerce product categories to be appended rather than overwritten.
actual result
fatal error on line 29: Cannot redeclare wp_set_post_terms()
(previously declared in /var/www/html/wp-includes/post.php:4108)
tried this code. no errors but does not append categories
function append_post_categories( $post_ID = array(), $post_categories = array(), $append = true ) {
$post_ID = (int) $post_ID;
$post_type = get_post_type( $post_ID );
$post_status = get_post_status( $post_ID );
// If $post_categories isn't already an array, make it one:
$post_categories = (array) $post_categories;
if ( empty( $post_categories ) ) {
if ( 'post' == $post_type && 'auto-draft' != $post_status ) {
$post_categories = array( get_option( 'default_category' ) );
$append = true;
} else {
$post_categories = array();
}
} elseif ( 1 == count( $post_categories ) && '' == reset( $post_categories ) ) {
return true;
}
return wp_set_post_terms( $post_ID, $post_categories, 'category', $append );
}
The post type for WooCommerce products is product but not post and the taxonomy for "product category" is not category but product_cat instead as it is a custom taxonomy for product custom post type…
So if you want to use your function for WooCommerce product category on products, try this:
function append_product_categories( $product_id, $term_ids, $append = true ) {
$product_id = (int) $product_id;
$post_type = get_post_type( $product_id );
$post_status = get_post_status( $product_id );
$term_ids = (array) $term_ids;
if ( empty( $term_ids ) ) {
if ( 'product' == $post_type && 'auto-draft' != $post_status ) {
$term_ids = array( get_option( 'default_product_cat' ) );
$append = true;
} else {
$term_ids = array();
}
} elseif ( 1 == count( $term_ids ) && '' == reset( $term_ids ) ) {
return true;
}
// Check for existing term id in the product | Check if term exist in Woocommerce
foreach( $term_ids as $key => $term_id ) {
if( hast_term( $term_id, 'product_cat', $product_id ) || ! term_exists( $term_id, 'product_cat' ) ) {
unset($term_ids[$key]); // remove term id from the array
}
}
return wp_set_post_terms( $product_id, $term_ids, 'product_cat', $append );
}
It should better works for WooCommerce Product categories (untested)

Extend Admin product search for custom meta fields in Woocommerce

I am trying to extend the ADMIN WooCommerce Product Search to include custom fields (e.g. _sku_2 which I added via functions)
Admin Product Search
Using this as a guide, I tried to add this code to my functions, but with no luck:
// EXTEND ADMIN PRODUCT SEARCH
add_action( 'pre_get_posts', 'extend_admin_search' );
function extend_admin_search( $query ) {
// Extend search for document post type
$post_type = 'product';
// Custom fields to search for
$custom_fields = array(
"_supplier_sku",
"_sku_2"
);
if( ! is_admin() )
return;
if ( $query->query['post_type'] != $post_type )
return;
$search_term = $query->query_vars['s'];
// Set to empty, otherwise it won't find anything
//$query->query_vars['s'] = '';
if ( $search_term != '' ) {
$meta_query = array( 'relation' => 'OR' );
foreach( $custom_fields as $custom_field ) {
array_push( $meta_query, array(
'key' => $custom_field,
'value' => $search_term,
'compare' => 'LIKE'
));
}
$query->set( 'meta_query', $meta_query );
};
}
It seems not to be editing the query results at all. Is the product search even using the default query?
This other way will work to extend admin product search for custom post meta keys values:
add_filter( 'posts_search', 'extend_product_search', 20, 2 );
function extend_product_search( $where, $query ) {
global $pagenow, $wpdb;
if ( 'edit.php' != $pagenow || ! is_search() || ! isset( $query->query_vars['s'] ) || 'product' != $query->query_vars['post_type'] ) {
return $where;
}
// Here your post meta keys
$meta_keys = array('_supplier_sku', '_sku_2');
$meta_keys = implode("','", $meta_keys);
// get the search value
$term = sanitize_text_field( $query->query_vars['s'] );
// Light SQL Query to get the corresponding product IDs
$search_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->prefix}posts as p
LEFT JOIN {$wpdb->prefix}postmeta as pm ON p.ID = pm.post_id
WHERE pm.meta_key IN ('$meta_keys') AND pm.meta_value LIKE '%$term%'" );
// Cleaning
$search_ids = array_filter( array_unique( array_map( 'absint', $search_ids ) ) );
// Alter the WHERE clause in the WP_Query search
if ( count( $search_ids ) > 0 ) {
$where = str_replace( 'AND (((', "AND ( ({$wpdb->posts}.ID IN (" . implode( ',', $search_ids ) . ")) OR ((", $where );
}
return $where;
}
Code goes in function.php file of your active child theme (or active theme). Tested and work.

WordPress user grid custom column sort

I added a custom column to WordPress admin user grid area by adding this codes to functions.php
function new_modify_user_table( $column ) {
$column['progress'] = 'Progress';
return $column;
}
add_filter( 'manage_users_columns', 'new_modify_user_table',11 );
function new_modify_user_table_row( $val, $column_name, $user_id ) {
switch ($column_name) {
case 'progress' :
$course_id=7238;
$course = learn_press_get_course( $course_id );
$force = true;
$num_of_decimal = 0;
$current = $course->evaluate_course_results( $user_id, $force );
$current = absint( $current );
return '<strong style="color: green">'.$current.'%</strong>';
break;
default:
}
return $val;
}
add_filter( 'manage_users_custom_column', 'new_modify_user_table_row', 11, 3 );
It shows the column at the end of table as below
But it doesn't allow me to sort.
I added this code to add sort link to table header column
add_filter( 'manage_users_sortable_columns', 'my_sortable_cake_column' );
function my_sortable_cake_column( $columns ) {
$columns['progress'] = 'progress';
return $columns;
}
And also found where to trigger sort
add_action( 'pre_user_query', 'my_pre_user_query', 1 );
function my_pre_user_query( $query ) {
global $wpdb, $current_screen;
// Only filter in the admin
if ( ! is_admin() )
return;
// Only filter on the users screen
if ( ! ( isset( $current_screen ) && 'users' == $current_screen->id ) )
return;
// Only filter if orderby is set to 'progress'
if ( isset( $query->query_vars ) && isset( $query->query_vars[ 'orderby' ] )
&& ( 'progress' == $query->query_vars[ 'orderby' ] ) ) {
// We need the order - default is ASC
$order = isset( $query->query_vars ) && isset( $query->query_vars[ 'order' ] ) && strcasecmp( $query->query_vars[ 'order' ], 'desc' ) == 0 ? 'DESC' : 'ASC';
//need to write code to apply to grid
}
}
can someone help me write a code which set the sort to the grid

Categories