I'm using woocommerce, I changed single-product.php and placed an "if" statement inside the loop to load a custom page for a specific product.
<?php while ( have_posts() ) : the_post();
if (is_product_category( 'Benefit')) {
woocommerce_get_template_part( 'content', 'single-product-benefit' );
}else{
woocommerce_get_template_part( 'content', 'single-product' );
}
endwhile; // end of the loop. ?>
My problem is the content-single-product-benefit.php called by the first part of the "if" is ALWAYS loaded (for all products).
I suspect a very stupid php syntax error but I spent an hour on this and can't see it. Both php pages called work fine on their own. Somehow I can't get that "if" right. What am I doing wrong??
Thx for your help ^^
is_product_category() function only works if archive page is being displayed, same as the Wordpress is_category() function. Since you use this function inside the single-product.php file, and that is template for a singular page, above functions will not work. Try with:
has_term( 'Benefit', 'product_cat', $post );
Related
I am helping a friend with their Wordpress site and all of their blog posts are showing in reverse order (oldest first). I haven't found any plugins responsible and haven't identified any code that was added. I also tried adding the code
//function to modify default WordPress query
function wpb_custom_query( $query ) {
// Make sure we only modify the main query on the homepage
if( $query->is_main_query() && ! is_admin() && $query->is_home() ) {
// Set parameters to modify the query
$query->set( 'orderby', 'date' );
$query->set( 'order', 'DESC' );
$query->set( 'suppress_filters', 'true' );
}
}
// Hook our custom query function to the pre_get_posts
add_action( 'pre_get_posts', 'wpb_custom_query' );```
They are using the theme RT-Theme 18
Does anyone have any idea why this might be happening?
As mentioned by #fraggley, start off by disabling all plugins and setting the theme to TwentyTwenty (the default theme). The RT-Theme 18 also exhibits similar behaviour in their demo with no obvious setting to change this behaviour. If you aren't already, ensure you're making customisations in a child-theme. Without creating a new function, try using a standard loop to start off to see whether the order is still incorrect.
<?php
get_header();
if ( have_posts() ) :
while ( have_posts() ) : the_post();
the_content();
endwhile;
else :
_e( 'Sorry, no posts matched your criteria.', 'textdomain' );
endif;
get_footer();
?>
This would typically be placed in your home.php or index.php at the root of your child theme. WordPress provides good documentation on this in their codex. You can determine this by checking which file the original code occurs in the parent theme. So if the loop occurs in the parent theme home.php, create a file called home.php in the same relative location on your child theme. More documentation on this here.
I am trying to create a custom layout for one of our product pages in Woocommerce. I have searched and followed so many tutorials, but none are working for me. I copied 'single-product.php' and placed it into my active child theme in the folder 'woocommerce'. I then duplicated this and renamed it 'single-product-landing.php'.
I then placed the following code into my functions.php page:
add_filter( 'template_include', 'custom_single_product_template_include', 10 );
function custom_single_product_template_include( $template ) {
if ( is_product() && ( has_term( 'custom', 'product_cat') ) ) {
$template = get_stylesheet_directory() . '/woocommerce/single-product-landing.php';
}
return $template;
}
Then I tried changing items in single-product-landing.php but nothing is changing, so it can't be picking it up. To confirm, I have the product assigned to the 'custom' category.
I should also add that my product is a 'variable' product, am not sure if that has any affect on anything here.
EDIT: I have found the following code in my 'single.php' file - I think this may be interfering. Problem is, if I delete this nothing shows on any of my pages (even those not affected by the new template):
<?php
if(get_theme_mod('product_layout') == 'custom') {
wc_get_template_part( 'content', 'single-product-custom' );
} else {
wc_get_template_part( 'content', 'single-product' );
}
?>
Any idea how I can modify this to still have content show but not over-rule the template change that i'm trying to make?
Page templates are loaded after the template_filter has been run, so adding that code to a page template file will have no effect. To make that run, place the same code in your child theme's functions.php.
The 566 at the end of the add_filter line refers to the filter's loading priority and not a category id. Simply put, the higher the number the later the filter will be loaded.
Finally, your if statement can be simplified a little using Woocommerce functions - if ( is_product() && ( has_term( 'custom', 'product_cat') ) ) { - doesn't make much difference, but it's tidier.
I'm trying to retrieve the filename/path of template used on the 'Edit Page'-page in the Dashboard.
Similar to what wp-includes/template-loader.php (source) does on the front end: finding out which template to render.
Unfortunately, expressions like is_front_page() - which Wordpress' template-loader.php uses to find out if it should use get_front_page_template() - don't work correctly on the admin page. Which is to be expected because those expression use the global $wp_query object, and not the current query.
What I've tried so far:
Running a post loop inside the admin page
$args = array(
'p' => get_the_ID(),
'post_type' => 'any'
);
$query = new \WP_Query($args);
if ( $query->have_posts() ) : while ( $query->have_posts() ) : $query->the_post(); ?>
<?= the_title(); ?><br>
Is front page: <?= is_front_page() ? 'true' : 'false' ?>
<?php endwhile; endif; ?>
Displays:
Home
Is front page: false
Using get_post_meta
<?= get_post_meta(get_the_ID(), '_wp_page_template', true); ?>
Displays:
default
...which would be the same for front-page.php on Home and page.php on another default page, so this doesn't help me.
In short
What I'm trying to get is front-page.php when I'm editing my 'Home' page. Or custom-template.php when I'm editing some page with the custom template selected. Or about-page.php when I'm editing a page called 'About'. How to get the correct filename or path?
If your specific problem is with the home page, you could use a combination of get_page_template() and comparing the edited page's ID with get_option('page_on_front') (see WordPress option reference). There's also an option, show_on_front, which indicates whether the front page shows posts or a static page.
Maybe this helps? I don't know if there are other edge cases where a different template will be used...
Use get_page_template():
<?php echo realpath(get_page_template()); ?>
It outputs something like /foo/bar/baz/wp-content/themes/your-theme/{page-template}.php
You can choose not to use realpath() and just get the template name.
The only solution I found is this:
global $template;
echo basename($template); // front-page.php
I know it's ugly, but I just couldn't find a way to not use this global variable.
i'm seeing some strange behaviour I cannot explain inside a category-based template loop.
i have a custom query filter for the category template, preselecting a couple of custom post types to query for:
add_filter( 'pre_get_posts', 'cust_posts_collection' );
function cust_posts_collection( $query ) {
if ( (is_category() && $query->is_main_query()) )
$query->set( 'post_type', array( 'cust_post_type_1', 'cust_post_type1' ) );
return $query;
}
this results in a proper $wp_query object, containing among others an array of posts. let's say for a given category x there are 4 posts. when i var_dump $wp_query i can verify
["posts"]=>&array(4)
and i can see all the posts and their data in the dump.
however, when i loop then over that object:
<?php if ( $wp_query->have_posts() ) while ( $wp_query->have_posts() ) : $wp_query->the_post();
var_dump($post);
endwhile; ?>
all i see is two posts.
how is this possible?
are there any configuration defaults on the loop functions that i am missing?
I was able to solve the bug:
it turns out that there was another loop in the header partial, prior to the loop exposing the bug.
the first loop had a break statement right after an if conditional - the idea: find the first occurrence of a certain custom post type and then break out of the loop.
the problem: this break did not properly reset a global post index variable or something along those lines. the next loop then got a wrong state of the index, causing it to jump as many initial posts as had been looped over in the previous loop.
adding rewind_posts() just before the break fixed this for me.
I am reading that query_posts() should be avoided in favor of wp_query() and pre_get_posts(). I am not confident with messing with the Loop and do not fully understand the codex.
Does the code below use query_posts() ? If yes and since query_posts() should be avoided, can you suggest a method that does not use query_posts() but still accomplish the same thing?
This code in functions.php is used to sort posts by random or by price.
function my_custom_query($query){
if ( $query->is_home() && $query->is_main_query() ) {
$sort= $_GET['sort'];
if($sort == "pricelow"){
$query->set( 'meta_key', 'price' );
$query->set( 'orderby', 'meta_value_num' );
$query->set( 'order', 'ASC' );
}
if($sort == "random"){
$query->set( 'orderby', 'rand' );
}
}
}
add_action( 'pre_get_posts', 'my_custom_query' );
.
Link A (Random) and Link B (Price) are posted in my menu by using this code. Thus the visitor to the website can sort the posts simply by clicking a link.
Random
Price
I have done a very detailed explanation on this very topic on WPSE, and for the sake of the value and benefit it might have for SO users, here is the complete post copied from that question on WPSE. For interest sake, here is a link to the complete post on WPSE: Some doubts about how the main query and the custom query works in this custom theme?
Your actual question is basically when to run a custom query and when to make use of the main query. Lets break it down in three parts
PART ONE
When to run a custom query (This is not a definitive list)
To create custom content sliders
To create a featured content area in a page
On page.php templates if you need to display posts
If you require custom content on a static front page
Display related, popular or informational posts
Any other secondary or supplementary content outside the scope of the main query
When to make use of the main query.
To display the primary content on
On your homepage and the page set as a blogpage in the backend
All archive pages which includes templates like archive.php, category.php, author.php, taxonomy.php, tag.php and date.php
PART TWO
To select all the featured posts I use this line that create a new WP_Query object that define a query having the specific tag featured:
So, from what I have understand, this is not the WordPres main query but it is a new query created by me. From what I have understand it is better create a new query (as done) and not use the main query when I want perform this kind of operations
Correct. This falls out of scope for the main query. This is secondary or supplementary content which cannot be created with the main query. You SHOULD ALWAYS use either WP_Query or get_posts to create your custom queries.
NEVER USE query_posts to create custom queries, or even any other query. My emphasis.
Note: This function isn't meant to be used by plugins or themes. As explained later, there are better, more performant options to alter the main query. query_posts() is overly simplistic and problematic way to modify main query of a page by replacing it with new instance of the query. It is inefficient (re-runs SQL queries) and will outright fail in some circumstances (especially often when dealing with posts pagination).
Moving on
Ok, going on I show all the posts that have not the featured tag, to do this I use this code snippet that on the contrary modify the main query:
query_posts( array( 'tag__not_in' => array ( $term->term_id )));
So I think that this is pretty horrible. Is it true?
That is all wrong and your statement is unfortunately true. As said before, NEVER use query_posts. It runs a complete new query, which is bad for performance, and it most cases breaks pagination which is an integral part of the main query for pagination to work correctly.
This is your primary content, so you should be using the main query with the default loop, which should look like this, and this is all you need
<?php
if (have_posts()) :
// Start the Loop.
while (have_posts()) : the_post();
get_template_part('content', get_post_format());
endwhile;
else :
// If no content, include the "No posts found" template.
get_template_part('content', 'none');
endif;
?>
You can completely get rid of this part, delete it, burn it and forget about it
<?
// get the term using the slug and the tag taxonomy
$term = get_term_by( 'slug', 'featured', 'post_tag' );
// pass the term_id to tag__not_in
query_posts( array( 'tag__not_in' => array ( $term->term_id )));
?>
OK, once you've done that, you'll see that posts from the feature tag appear in your home page using the main query and default loop.
The correct way of removing this tag from the homepage is with pre_get_posts. This is the proper way to alter the main query and the hook you should always use to make changes to your primary content loop.
So, the code with pre_get_posts is correct and this is the function that you should use. Just one thing, always do a check that you are not on an admin page because pre_get_posts alters the back end as well. So this is the proper code to use in functions.php to remove posts tagged featured from the homepage
function exclude_featured_tag( $query ) {
if ( !is_admin() && $query->is_home() && $query->is_main_query() ) {
$query->set( 'tag__not_in', 'array(ID OF THE FEATURED TAG)' );
}
}
add_action( 'pre_get_posts', 'exclude_featured_tag' );
PART THREE
Extra reading material which will be helpful in future
Conditional tags
When should you use WP_Query vs query_posts() vs get_posts()?
When to use WP_query(), query_posts() and pre_get_posts
Query Overview
Guidance with The Loop for CMS
Creating a new WP_Query() object is always fine.
$sort= $_GET['sort'];
if($sort == "pricelow"){
$sort_args = array('meta_key' => 'price', 'orderby' => 'meta_value_num', 'order', 'ASC');
$new_query = new WP_Query($sort_args);
}
blah blah blah...
No no no sorry about that. I didn't see the pre_get_posts hook.
The code in your question is good for hooking queries. As in described in WordPress Plugin API/Action Reference/pre_get_posts:
pre_get_posts runs before WP_Query has been setup.
So it hooks the default WP_Query() where you want (in your code, it changes WP_Query on GET request).
In your template files, use new WP_Query($args).