I'm trying to get a post offset to work on category and tag archives with a couple of category exclusions.
I have 3 functions. The first creats a custom loop which is inserted via shortcode and contains 3 posts, and the other two functions offset the main query by 3 and fix the pagination as per this codex article
It seems to work where it should, except it's also offsetting posts in the backend admin area for all post types and I can't work out how to stop that happening.
For clarity, posts should be offset by 3 on category and tag archives only, excluding the categories added to the array.
function archive_loop_shortcode() {
$current_archive = get_queried_object();
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => 3,
'tax_query' => array(
array(
'taxonomy' => $current_archive->taxonomy,
'field' => 'term_id',
'terms' => $current_archive->term_id,
),
),
);
$archive_query = null;
$archive_query = new WP_query($args);
echo '<div class="kb-custom-archive-loop"><div class="kb-custom-archive-loop-inner">';
if($archive_query->have_posts()):
while($archive_query->have_posts()) : $archive_query->the_post();
$custom = get_post_custom( get_the_ID() );
echo '<article>';
echo '<figure><div>' . get_the_post_thumbnail() . '</div></figure>';
echo '<h2>' . get_the_title() . '</h2>';
echo '</article>';
endwhile;
wp_reset_postdata();
else :
_e( 'Sorry, no posts matched your criteria.' );
endif;
echo "</div></div>";
}
add_shortcode( 'archive_loop', 'archive_loop_shortcode' );
add_action('pre_get_posts', 'myprefix_query_offset', 1 );
function myprefix_query_offset(&$query) {
if ( ! is_admin() && ! is_home() && ! is_search() && ! is_author() && ! $query->is_main_query() ) {
if ( ! is_category(array('28770','28688')) || is_tag() ) {
return;
}
}
$offset = 3;
$ppp = get_option('posts_per_page');
if ( $query->is_paged ) {
$page_offset = $offset + ( ($query->query_vars['paged']-1) * $ppp );
$query->set('offset', $page_offset );
}
else {
$query->set('offset',$offset);
}
}
add_filter('found_posts', 'myprefix_adjust_offset_pagination', 1, 2 );
function myprefix_adjust_offset_pagination($found_posts, $query) {
$offset = 3;
if ( ! is_admin() && ! is_home() && ! is_search() && ! is_author() && ! $query->is_main_query() ) {
if ( ! is_category(array('28770','28688')) || is_tag() ) {
return $found_posts - $offset;
}
}
return $found_posts;
}
Related
On the homepage of our website, we have added a shortcode to show the product page of the featured product.
I have added a SKU 'featured' to the featured product, so I could use the following shortcode to show the featured product [product_page sku="featured"].
Now I would like to modify the code of the shortcode so the name of the product links to the full featured product page.
Below is the WooCommerce that sets up the product_page.
/**
* Show a single product page.
*
* #param array $atts Attributes.
* #return string
*/
public static function product_page( $atts ) {
if ( empty( $atts ) ) {
return '';
}
if ( ! isset( $atts['id'] ) && ! isset( $atts['sku'] ) ) {
return '';
}
$args = array(
'posts_per_page' => 1,
'post_type' => 'product',
'post_status' => 'publish',
'ignore_sticky_posts' => 1,
'no_found_rows' => 1,
);
if ( isset( $atts['sku'] ) ) {
$args['meta_query'][] = array(
'key' => '_sku',
'value' => sanitize_text_field( $atts['sku'] ),
'compare' => '=',
);
$args['post_type'] = array( 'product', 'product_variation' );
}
if ( isset( $atts['id'] ) ) {
$args['p'] = absint( $atts['id'] );
}
// Don't render titles if desired.
if ( isset( $atts['show_title'] ) && ! $atts['show_title'] ) {
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_title', 5 );
}
// Change form action to avoid redirect.
add_filter( 'woocommerce_add_to_cart_form_action', '__return_empty_string' );
$single_product = new WP_Query( $args );
$preselected_id = '0';
// Check if sku is a variation.
if ( isset( $atts['sku'] ) && $single_product->have_posts() && 'product_variation' === $single_product->post->post_type ) {
$variation = new WC_Product_Variation( $single_product->post->ID );
$attributes = $variation->get_attributes();
// Set preselected id to be used by JS to provide context.
$preselected_id = $single_product->post->ID;
// Get the parent product object.
$args = array(
'posts_per_page' => 1,
'post_type' => 'product',
'post_status' => 'publish',
'ignore_sticky_posts' => 1,
'no_found_rows' => 1,
'p' => $single_product->post->post_parent,
);
$single_product = new WP_Query( $args );
?>
<script type="text/javascript">
jQuery( document ).ready( function( $ ) {
var $variations_form = $( '[data-product-page-preselected-id="<?php echo esc_attr( $preselected_id ); ?>"]' ).find( 'form.variations_form' );
<?php foreach ( $attributes as $attr => $value ) { ?>
$variations_form.find( 'select[name="<?php echo esc_attr( $attr ); ?>"]' ).val( '<?php echo esc_js( $value ); ?>' );
<?php } ?>
});
</script>
<?php
}
// For "is_single" to always make load comments_template() for reviews.
$single_product->is_single = true;
ob_start();
global $wp_query;
// Backup query object so following loops think this is a product page.
$previous_wp_query = $wp_query;
// #codingStandardsIgnoreStart
$wp_query = $single_product;
// #codingStandardsIgnoreEnd
wp_enqueue_script( 'wc-single-product' );
while ( $single_product->have_posts() ) {
$single_product->the_post()
?>
<div class="single-product" data-product-page-preselected-id="<?php echo esc_attr( $preselected_id ); ?>">
<?php wc_get_template_part( 'content', 'single-product' ); ?>
</div>
<?php
}
// Restore $previous_wp_query and reset post data.
// #codingStandardsIgnoreStart
$wp_query = $previous_wp_query;
// #codingStandardsIgnoreEnd
wp_reset_postdata();
// Re-enable titles if they were removed.
if ( isset( $atts['show_title'] ) && ! $atts['show_title'] ) {
add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_title', 5 );
}
remove_filter( 'woocommerce_add_to_cart_form_action', '__return_empty_string' );
return '<div class="woocommerce">' . ob_get_clean() . '</div>';
}
You can see they address the product_title with $atts['show_title']. So I guess we should wrap this with a href link of the product link, but I'm afraid my knowledge in that area lacks a bit.
Can somebody assist me with this, please? Much appreciated!
Use below code snippet in your functions.php and have a look.
It will remove the existing title and add new with the anchor tag.
remove_action('woocommerce_single_product_summary','woocommerce_template_single_title',5);
add_action('woocommerce_single_product_summary', 'woocommerce_my_single_title',5);
if ( ! function_exists( 'woocommerce_my_single_title' ) ) {
function woocommerce_my_single_title() {
?>
<span>dfgdfg<?php the_title(); ?></span>
<?php
}
}
Note: If it does not remove then you can give some css to hide the existing title based on parent class.
When creating custom filtering based on ACF fields, pagination stopped working. That is, it works, but when the filter is applied, it does not update the pagination of articles, but uses the pagination as if all articles were displayed. I have already tried the standard pagination options
<?php
$free = $_COOKIE['free_article_val'];
$block = $_COOKIE['block_article_val'];
$bought = $_COOKIE['bought_article_val'];
$args = array(
'posts_per_page' => 5,
'paged' => get_query_var('paged') ?: 1
);
$query = new WP_Query($args);
if( $query->have_posts() ){
while( $query->have_posts() ){
$query->the_post();
$its_free_post_value = PostFilter::Its_free_post();
$bought_post = PostFilter::Its_bought_post();
if ($its_free_post_value == 1 && $free !== 'true_val' && $_SESSION['start_session_val'] == 1){
continue;
}
if ($bought_post == 1 && $bought !== 'true_val' && $_SESSION['start_session_val'] == 1){
continue;
}
if ($bought_post == 2 && $block !== 'true_val' && $_SESSION['start_session_val'] == 1){
continue;
}
biagiotti_mikado_get_post_format_html( $blog_type );
}
wp_reset_postdata(); // сбрасываем переменную $post
}else{
biagiotti_mikado_get_module_template_part( 'templates/parts/no-posts', 'blog' );
}
?>
</div>
<?php
previous_posts_link( 'Prev page ' );
next_posts_link( ' Next page', $query->max_num_pages );
PostFilter::Check_session(); ?>```
To start with as step 1, this is incorrect
'paged' => get_query_var('paged') ?: 1
I would replace it with
'paged' => ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
I have created a wordpress query to return all the "products" but it only returns 9. (weird number, I know). I have a total of 13 custom posts for "products". I have added post_per_page = -1 and post_per_page = 20. Both have not made a difference.
Here is my loop. Is there a way to debug it to see how it's breaking? Or does anyone know why it's breaking? Thank you
<?php
// WP_Query arguments
$args = array(
'p' => 'products',
'post_type' => array( 'products' ),
'order' => 'ASC',
'orderby' => 'meta_value_num',
'meta_key' => 'custom_product_position',
'post_per_page' => 20,
);
// The Query
$query = new WP_Query( $args );
// The Loop
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
$product_title = get_post_meta( get_the_ID(), 'custom_product_title', true );
$product_subtitle = get_post_meta( get_the_ID(), 'custom_product_subtitle', true );
$product_id = get_post_meta( get_the_ID(), 'custom_product_id', true );
?>
<div id="<?php if ( ! empty( $product_id ) ) {echo $product_id;}?>" class="section-title">
<?php
if ( ! empty( $product_title ) ) {
echo "<h2>" . $product_title . "</h2>";
}
?>
<?php
if ( ! empty( $product_subtitle ) ) {
echo "<h4>" . $product_subtitle . "</h4>";
}
?>
</div>
<?php
echo get_the_content();
}
} else {
// no posts found
}
// Restore original Post Data
wp_reset_postdata();
?>
There's also the limit that you set within the WP settings for the maximum amount of posts displayed on post loops in general ("Settings > Read"). Try to increase that - should work...
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;
}
I am trying to remove the CPT slug with hierarchical urls:
www.test.com/cpt-slug/post-name/ > www.test.com/post-name
Which I have done fine and it is working with the below code however when I have a children post i.e www.test.com/post-name/child-post-name it doesn't seem to work. I will also need this to work for this type of url too www.test.com/post-name/child-post-name/another-child-post-name
function rewrite_permalink($permalink, $post_id, $leavename) {
$post = get_post($post_id);
if ( self::$post_type != $post->post_type || 'publish' != $post->post_status ) return $permalink;
// Get post
if (!$post) return $permalink;
return strtr($permalink,array('/' . self::$post_type . '/' => '/'));
}
public static function holiday_parse_request( $query ) {
$counts = array( 2, 4 );
if ( ! $query->is_main_query() || !in_array(count( $query->query ), $counts) || ! isset( $query->query['page'] ) ) {
return;
}
$query->set( 'post_type', array( 'post', self::$post_type, 'page' ) );
if ( ! empty( $query->query['name'] ) ) {
$query->set( 'post_type', array( 'post', self::$post_type, 'page' ) );
}
}
Thanks in advance.