WooCommerce products: Wrong product permalink in custom loop - php

I'm using a custom loop to show a selection of products.
The loop works fine and shows the products with the correct title, image and the other stuff.
But the permalink is the URL of the current page.
If I add $post inside the permalink, everything works fine: get_permalink($post)
Here's my current code:
<?php $featured_posts = $products_select; if( $products_select ): ?>
<div>
<ul>
<?php foreach( $featured_posts as $post ): setup_postdata($post); ?>
<?php wc_get_template_part( 'content', 'product' ); ?>
<?php endforeach; ?>
</ul>
<?php wp_reset_postdata(); ?>
</div>
I checked the content of $products_select and saw, that there is no link stored.
Could that be the problem? Is there any way to correct the permalink?
The variable $products_select is the output of a custom field based on relationship field from Advanced Custom Fields. It is stored as post object.

Update
Don't use get_posts() function, instead use a real WP_Query like in the following example:
<?php
$loop = new WP_Query( array(
'post_status' => 'publish',
'post_type' => 'product',
'posts_per_page' => 10,
) );
?>
<div>
<ul><?php
if ( $loop->have_posts() ) :
while ( $loop->have_posts() ) : $loop->the_post();
echo '<pre>ID: '.get_the_id().' | Title: '. get_the_title() . ' | Link: ' . get_permalink() . '</pre>';
wc_get_template_part( 'content', 'product' );
endwhile;
wp_reset_postdata();
endif;?>
</ul>
</div>
This time it will works, without any issue.
An alternative: To avoid this problem, you could use instead WooCommerce [products] shortcode as follows:
<?php
$featured_posts = $products_select; if( $products_select ):
// get a comma separated string of product Ids
$post_ids = implode( ',', wp_list_pluck( $featured_posts, 'ID' ) );
// Use [products] shortcode with the comma separated string of product Ids
echo do_shortcode("[products ids='$post_ids']" ); ?>
</div>
Tested and works.

I also found a soultion that will work with Advanced Custom Fields and keeps the custom order of the relationship field:
<?php
$args = array(
'post_type' => 'product',
'post__in' => $products_select,
'posts_per_page' => 4,
'orderby' => 'post__in'
);
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) : ?>
<div>
<ul>
<?php while ( $loop->have_posts() ) : $loop->the_post(); ?>
<?php wc_get_template_part( 'content', 'product' ); ?>
<?php endwhile; ?>
</ul>
</div>
<?php endif; wp_reset_postdata(); ?>

Related

Modify Woocommerce template files to display products by product category

I'm pulling my hair over here searching and trying to modify the WooCommerce core files.
So, what I am trying to do is modify my theme's woocommerce.php file because I want to display the products on my shop by category.
What I've figured out so far is that at woocommerce.php file in my theme's root folder there is this line
<?php woocommerce_content(); ?>
which displays all of the products. Then, I found out that the file content-product.php at mytheme/woocommerce/ is being ran for each product and in a few words, that file contains the styling and classes of each product. In other words, this file is being ran inside the loop.
So I now know that I have to modify some function that actually calls that file and I want to pass the product category to that function so I can display the products I want.
Doing some digging I have found that in wp-content/plugins/woocommerce/includes/wc-template-functions.php there is the function woocommerce_content() with the following code
function woocommerce_content() {
if ( is_singular( 'product' ) ) {
while ( have_posts() ) :
the_post();
wc_get_template_part( 'content', 'single-product' );
endwhile;
} else {
?>
<?php if ( apply_filters( 'woocommerce_show_page_title', true ) ) : ?>
<h1 class="page-title"><?php woocommerce_page_title(); ?></h1>
<?php endif; ?>
<?php do_action( 'woocommerce_archive_description' ); ?>
<?php if ( woocommerce_product_loop() ) : ?>
<?php do_action( 'woocommerce_before_shop_loop' ); ?>
<?php woocommerce_product_loop_start(); ?>
<?php if ( wc_get_loop_prop( 'total' ) ) : ?>
<?php while ( have_posts() ) : ?>
<?php the_post(); ?>
<?php wc_get_template_part( 'content', 'product' ); ?>
<?php endwhile; ?>
<?php endif; ?>
<?php woocommerce_product_loop_end(); ?>
<?php do_action( 'woocommerce_after_shop_loop' ); ?>
<?php else : ?>
<?php do_action( 'woocommerce_no_products_found' ); ?>
<?php
endif;
}
}
Finally, I think that wc_get_loop_prop function is what initializes the loop and I am trying to find a way to pass a param to that function (the product category ID for example) so I can call woocommerce_content(118) where 118 a product category and display my products the way I want.
Is there any way I can do this? I am stuck at this part for long now and can't seem to find a solution.
SOLUTION:
Finally, what I had to do was to simply create a function
function getProductsByCat($theCat) {
$args = array(
'post_type' => 'product',
'posts_per_page' => 50,
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'id',
'terms' => $theCat
)
)
);
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post();
wc_get_template_part( 'content', 'product' );
endwhile;
} else {
return false;
}
return true;
}
And call it anywhere in my website to display products by cat ID like
<div class="col-md-12"><h4>Special Offers</h4></div>
<?php
if(!getProductsByCat(191)){
//echo "<p>No products available.</p>";
}
?>
I hope this will be helpful for those out there who are trying to do the same.

How to show post from just two categories on Wordpress Home page?

Only two categories need to be showed in the homepage. Can anyone help.
You can use WP_Query to get your posts list, and display it with the loop
Example :
$the_query = new WP_Query( array( 'category_name' => 'staff,news' ) );
// The Loop
if ( $the_query->have_posts() ) {
echo '<ul>';
while ( $the_query->have_posts() ) {
$the_query->the_post();
echo '<li>' . get_the_title() . '</li>';
}
echo '</ul>';
/* Restore original Post Data */
wp_reset_postdata();
} else {
// no posts found
}
In your functions.php file paste the below code:
I am assuming that you want to show categories from two categories which are having ids 5 and 9.
function kiran_home_category( $query ) {
if ( $query->is_home() && $query->is_main_query() ) {
$query->set( 'cat', '5,9');
}
}
add_action( 'pre_get_posts', 'kiran_home_category' );
Explanation:
kiran_home_category is just a custom name for the function. That can be any name. The way it works is you attach a function to the action hook pre_get_posts. So before getting the posts the function kiran_home_category will be called. And then inside the function I am changing the query here to only load categories with ID 5 and 9
In wordpress WP_query, category__in parameter used to select category with posts.
<?php
$query = new WP_Query( array( 'category__in' => array( 2, 6 ),'post_status'=>'publish','orderby'=>'menu_order','order'=>'Asc' ) );
if($query->have_posts()):
echo '<ul>';
while ( $query->have_posts() ) : the_post();
echo '<li>' . get_the_title() . '</li>';
endwhile;
echo '</ul>';
endif;
?>
For more information about wordpress query click here , you can read more information.
<?php
$args = array( 'post_type' => 'post', 'posts_per_page' => -1,'category_name' => array('Latest News','News') );
$loop = new WP_Query( $args );
if($loop->have_posts()):
?><ul>
<?php
while ( $loop->have_posts() ) : $loop->the_post();
?>
<li> <span class="date"><?php echo get_the_date( 'd F Y');?></span>
<h3><?php echo get_the_title();?></h3>
<?php echo $description = get_the_content(); ?>
</li>
<?php endwhile;?>
</ul>
<?php endif;?>
<?php wp_reset_postdata(); ?>
Do the following, usually in page.php or single.php or if you want a custom page for a category, you can do, category-samplecat.php..
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'category_name' => array('samplecat', 'anothercat'),
'paged' => $paged
);
$arr_posts = new WP_Query($args);
Then do the usual if, while statement..
if($arr_posts->have_posts() ) :
// Start the loop.
while ( $arr_posts->have_posts() ) :
$arr_posts->the_post();?>
<?php endwhile;
endif;

Wordpress Advanced Custom Fields display field not working in loop

I am using Advanced Custom Fields with Wordpress.
I have a custom post type called VIDEOS which has two fields - video_link and video_artist.
I can call and output the video_link field, but I cannot seem to display the 'video_artist' field using the code below...
<?php
$posts = get_posts(array(
'post_type' => 'videos',
'posts_per_page' => -1
)
));
if( $posts ): ?>
<?php foreach( $posts as $post ):
setup_postdata( $post )
?>
<?php echo wp_oembed_get( get_field( 'video_link' ) ); ?>
<?php the_title(); ?>
<?php the_field('video_artist'); ?>
</div>
<?php endforeach; ?>
<?php wp_reset_postdata(); ?>
<?php endif; ?>
In fact, this line...
<?php the_field('video_artist'); ?>
...breaks the site and displays nothing at all after it appears. No html of any kind.
It's more or less the same code as your, just tested, and it works fine
As #admcfadn said, your are note in a wordpress loop, so you need to add the post id as a parameter of the_field
$posts = get_posts(array(
'post_type' => 'videos',
'posts_per_page' => -1
));
if( $posts ):
foreach( $posts as $post ):
setup_postdata( $post );
the_title();
the_field('video_link', $post->ID);
the_field('video_artist', $post->ID);
endforeach;
wp_reset_postdata();
endif;
If you like to use the loop without arg in the_field that will look like that:
$options = array(
'post_type' => 'videos',
'posts_per_page' => -1
);
$query = new WP_Query( $options );
if ( $query->have_posts() ) : while ( $query->have_posts() ) : $query->the_post();
the_title();
the_field('video_link');
the_field('video_artist');
endwhile; endif;
ps: you don't need to use <?php ?> on each line
$post->the_field('video_artist');
you're using get_posts, not wp_query, so you might need to refer to the variables via $post.
&/or troubleshoot it with the following:
the_field('video_artist', $post->ID);
might get if for you.
Or...
$baz = get_field( 'video_artist' ); echo $baz;
Also, looks like you're missing a semi-colon after setup_postdata( $post ) and have an extra closing parentheses after get_posts

WordPress Function - fix to stop repeating code

I'm using the following PHP script to find the most recent post on the Team area of my site.
I also use a very similar one to find the most recent news entry on my home page.
To reduce the amount of repeated code (DRY), is there a way I can use a function and just pull in a specific custom post type e.g. most_recent('team'); would show the most recent post from my Team CPT.
Here's my existing code:
<?php
// find most recent post
$new_loop = new WP_Query( array(
'post_type' => 'team',
'posts_per_page' => 1,
"post_status"=>"publish"
));
?>
<?php if ( $new_loop->have_posts() ) : ?>
<?php while ( $new_loop->have_posts() ) : $new_loop->the_post(); ?>
<h2><?php the_title(); ?></h2>
<?php the_content(); ?>
<?php endwhile;?>
<?php else: ?>
<?php endif; ?>
<?php wp_reset_query(); ?>
<?php
function most_recent($type) {
$new_loop = new WP_Query( array(
'post_type' => $type,
'posts_per_page' => 1,
"post_status"=>"publish"
));
if ( $new_loop->have_posts() ) {
while ( $new_loop->have_posts() ) : $new_loop->the_post();
echo '<h2>'.the_title().'</h2>';
the_content();
endwhile;
}
wp_reset_query();
}
?>
Yes, It is indeed possible.
First what you need to do is ,
Add below code to your theme's functions.php file:
function most_recent($name){
// find most recent post
$new_loop = new WP_Query( array(
'post_type' => $name,
'posts_per_page' => 1,
"post_status"=>"publish"
));
if ( $new_loop->have_posts() ) :
while ( $new_loop->have_posts() ) : $new_loop->the_post();
echo "<h2>".the_title()."</h2>";
the_content();
endwhile;
else:
endif;
wp_reset_query();
}
Now you can use it any where in your theme folder template like below:
$most_recent = most_recent('product');
echo $most_recent;
So in your case, it would be most_recent('team') or even you can use for other as well just like I did for product.
Tell me if you have any doubt.

Custom Post Query WordPress and a better way to display posts

This seems a little noob, but I didn't found a better option. I created a custom loop to display only the title of custom post type I created.
Example:
Custom Post Type: Atuação
Contratos (Cível e Societário)
Direito Penal Empresarial
The problem is: I can't "validate" at the menu if the post is active or only a link. Example: My visitor is visiting the Direito Penal Empresarial page. But the menu don't display any class so I can customize it. It just shows the <a href> link.
See the code of the custom loop below.
<ul class="menu-advogados">
<?php
// WP_Query arguments
$args = array (
'post_type' => 'atuacao_posts',
'pagination' => false,
'order' => 'ASC',
'orderby' => 'title',
);
// The Query
$exibir_atuacao_posts = new WP_Query( $args );
// The Loop
if ( $exibir_atuacao_posts->have_posts() ) {
while ( $exibir_atuacao_posts->have_posts() ) {
$exibir_atuacao_posts->the_post();
?>
<li><?php the_title(); ?></li>
<?php
}
} else {
echo "Nenhum post encontrado";
}
// Restore original Post Data
wp_reset_postdata();
?>
</ul>
There is any better solution for this? Or if not, how can I add the "active" class to the href?
UPDATE: You can check out the website live.
You need to store current post ID in a variable then you need to compare current Post ID with list item Post ID if both are same then apply active class. So your code will be something like this-
<ul class="menu-advogados">
<?php
global $post;
$post_id = $post->ID; // Store current page ID in a variable.
// WP_Query arguments
$args = array (
'post_type' => 'atuacao_posts',
'pagination' => false,
'order' => 'ASC',
'orderby' => 'title',
);
// The Query
$exibir_atuacao_posts = new WP_Query( $args );
// The Loop
if ( $exibir_atuacao_posts->have_posts() ) {
while ( $exibir_atuacao_posts->have_posts() ) {
$exibir_atuacao_posts->the_post();
?>
<li><a href="<?php the_permalink(); ?>" <?php echo ($post_id==$post->ID)?'class="active"':''; ?> ><?php the_title(); ?></a></li>
<?php
}
} else {
echo "Nenhum post encontrado";
}
// Restore original Post Data
wp_reset_postdata();
?>
</ul>
use this
// WP_Query arguments
$args = array (
'post_type' => 'atuacao_posts',
'post_status' => 'publish',
'pagination' => false,
'order' => 'ASC',
'orderby' => 'title',
);
// The Query
$query = new WP_Query( $args );
<?php if ( $query ->have_posts() ) : ?>
<!-- the loop -->
<?php while ( $query ->have_posts() ) : $query ->the_post(); ?>
<h2><?php the_title(); ?></h2>
<?php endwhile; ?>
<!-- end of the loop -->
<?php wp_reset_postdata(); ?>
<?php else : ?>
<p><?php _e( 'Sorry, no posts matched your criteria.' ); ?></p>
<?php endif; ?>
for WP_Query consider this link it's great article...

Categories