How to use "has_term" correctly - wordpress

Im working with the single product page and I need to have a different image (depending on the category) after the add to cart button.
I tried this code but it doesn't show me the image that I need
add_action ( 'woocommerce_after_add_to_cart_button', 'content_after_button' );
function content_after_button() {
if (has_term( 'Categoria', 'Accesorios' ) ) {
echo 'https://prueba.soygorrion.com.ar/wp-content/uploads/2019/08/iconos2.jpg';
}
I think im using has_term in the wrong way.
What im trying to accomplish is:
I have a parent category that is "Accesorios" and inside that I have other child categories like "Billeteras". For each one of this child categories it has to show a diferent image.
thank you

First of all there is issue with your has_term checking. If you check has_term docs, you can find it takes first parameter as category term and second parameter as taxonomy.
Add secondly you are just echo image url that is not going to display image.
So, do as follows -
add_action ( 'woocommerce_after_add_to_cart_button', 'content_after_button' );
function content_after_button() {
// do check with has_term( $term = '', $taxonomy = '', $post = null )
if( has_term( 'Accesorios', 'product_cat' ) ) {
echo '<img src="https://prueba.soygorrion.com.ar/wp-content/uploads/2019/08/iconos2.jpg" />';
}
}

Since you mentioned that the problem is with has_term function. If you can get the product ID inside add to cart, then you can use this code to get categories and check them:
$categories = wp_get_post_terms($product_id, 'product_cat');
if(in_array("Accesorios", $categories))
{
echo "bla bla";
}
I have tested this code for another purpose, it works fine. I hope this will help. Please inform me when you test it and if you face any errors update your question with your new code.

Related

Add a symbol before every single category inside a list display categories widget - Wordpress - WP_Widget_Categories

I want to add a symbol (the Hash symbol - #) before every category displayed inside the list display categoris widget in wordpress.
I am not adding the WP_Widget_Categories code to the post question because it is the very basic one that anyone will find with wordpress.
Anyway I am trying to make something like this:
Example
That's all. I started to study php from a few days and I don't know how to do this, any help will be really appriciated.
You can use a filter to modify the results generated by the default categories widget. Try adding this in your functions file:
function modify_widget_categories_listing( $content ) {
return "#$content";
}
add_filter( 'list_cats', 'modify_widget_categories_listing', 10, 2 );
You may have to make some changes to what is being returned to get exactly what you're looking for, but that's the gist of it.
Put this in your functions.php
function show_categories_with_hash() {
$terms = get_terms( 'categories' );
echo '<ul>';
foreach ( $terms as $term ) {
$term_link = get_term_link( $term );
if ( is_wp_error( $term_link ) ) {
continue;
}
echo '<li>#' . $term->name . '</li>';
}
echo '</ul>';
}

Get a sidebar widget that show products of the same categories in Woocommerce

I’m trying to set a sidebar in the single product page that show all products of the same categories as the product displayed.
That's how I proceed:
1) First I’ve created a sidebar called “Products_of_same_Category” to put in there a widget to show what I needed, then in function.php of my child theme I added the following snippet to execute php code in text widget:
// Enable PHP in widgets
add_filter('widget_text','execute_php',100);
function execute_php($html){
if(strpos($html,"<"."?php")!==false){
ob_start();
eval("?".">".$html);
$html=ob_get_contents();
ob_end_clean();
}
return $html;
}
2) Then when I saw that the snippet runs ok I added that code to test it:
<?php
$prod=get_the_term_list( $post->ID, 'product_cat');
echo $prod;
?>
And all worked fine, it gave me the exact name of the current category of the product displayed in the single product page.
3) So I've tried another test, deleting the previous code, to view if a shortcode translated in php should works in a widget too (writing at this time the exact category name requested, in this case "towels" - in the code below I substitute it with THE-CATEGORY-I-LIKE):
<?php echo do_shortcode('[product_category category=“THE-CATEGORY-I-LIKE” per_page="20" columns="1" orderby="title" order="desc"]'); ?>`
And all was again well done!
4) Finally I mixed all in this code to show the list of products of same categories but something goes wrong:
<?php $prod=get_the_term_list( $post->ID, 'product_cat', '', '', '' );
echo do_shortcode('[product_category category="'.$prod.'" per_page="20" columns="1" orderby="title" order="desc"]'); ?>
In last case the code doesn't display anything. I don't understand where I made mistakes, the syntax is wrong or the solving approach is illogical?
I really appreciate any help about this.
The problem is how you get the category slug. get_the_term_list will give you a formatted linked list of the categories, so it will display category names, not category slugs, which are different things. "Towels" would be your category name, but the category slug would be "towels". And product_category shortcode expect a slug, not a name.
The correct approach to get the category product slug is the following:
$terms = get_the_terms($post, 'product_cat');
if($terms && ! is_wp_error($terms)) {
foreach($terms as $term) {
echo do_shortcode('[product_category category="'.$term->slug.'" per_page="20" columns="1" orderby="title" order="desc"]');
}
}
This will display the products of all the categories associated to your product. See get_the_terms doc for reference.
In order to remove from the results the current product shown, you can make use of the woocommerce_shortcode_products_query filter. It isn't documented, but you can find it by looking at the product_category shortcode code located in includes/class-wc-shortcodes.php. In the product_category() method you will find the following line:
$return = self::product_loop( $query_args, $atts, 'product_cat' );
Where $query_args is a WP_Query parameters array. In the same class you will find the method product_loop() called here and see the following:
$products = new WP_Query( apply_filters( 'woocommerce_shortcode_products_query', $query_args, $atts ) );
So the query arguments are filtered - you will be able to work with that to add the desirated behavour. What you want to do is to use the post__not_in parameter to the query like this:
function remove_current_product_from_wc_shortcode($args, $atts) {
if(is_product()) { // check if we're on a single product page
$args['post__not_in'] = array(get_queried_object_id());
}
return $args;
}
add_filter('woocommerce_shortcode_products_query', 'remove_current_product_from_wc_shortcode');
This code should go in your theme functions.php - please not this is untested, so if it doesn't work look at the get_queried_object_id() return if it contain the current product ID.

Woocommerce: how to jump directly to product page when category only holds one item

I have a top menu which permits the display of product categories.
In this case, the name of the application I am selling.
When this menu item is clicked, it shows the contents of the category - as it should do.
However, as this category only contains one item, I want to jump straight to the product page, instead of displaying a category page with one item.
Here is a link to the page in question : boutique.zimrahapp.com/categorie-produit/app/
I have not been able to find either a hook or a template where I can adjust the output or do a redirect.
Has this kind of thing already been done ?
The above code didn't work for me. I have a solution that works, but it redirects all single archive results. In my case I wanted to also redirect single tags.
/* Redirect if there is only one product in the category or tag, or anywhere... */
function redirect_to_single_post(){
global $wp_query;
if( is_archive() && $wp_query->post_count == 1 ){
the_post();
$post_url = get_permalink();
wp_safe_redirect($post_url , 302 );
exit;
}
}
add_action('template_redirect', 'redirect_to_single_post');
I had asked this same question here: Woocommerce: How to automatically redirect to the single product if there is only one product on a category page?
WooCommerce redirects a search query with only one result to that result. You can see how they are doing it here.
Modifying their code you get something like this:
function so_35012094_template_redirect() {
global $wp_query;
// Redirect to the product page if we have a single product
if ( is_product_category() && 1 === $wp_query->found_posts ) {
$product = wc_get_product( $wp_query->post );
if ( $product && $product->is_visible() ) {
wp_safe_redirect( get_permalink( $product->id ), 302 );
exit;
}
}
}
add_action( 'template_redirect', 'so_35012094_template_redirect' );
Untested, so watch out for copy/paste fails. Always use WP_DEBUG so you can figure out what went wrong.

Do I have to add_filter() before apply_filters() in Wordpress?

I'm trying to understand Wordpress plugin like:
apply_filters( 'gettext', $translations->translate( $text ), $text, $domain );
I'm looking for all codes in Wordpress, I can't find:
add_filter( 'gettext', ....);
Why there is no add_filter for this plugin? Or I missed something? Same thing like:
do_action('wp_loaded');
I can't find:
add_action('wp_loaded', ....);
apply_filters is like, 'if there are any filters with this name, run the attached callbacks with these parameters'. So if there is no add_filter for that name, it means that there is no filter that's going to be run with the apply_filters call at the moment.
The same goes with do_action and add_action.
I am a beginner in PHP - WordPress stack as well, but this is from my understanding.
The plugins call apply_filters without having any add_filter in their codes is to allow the website users to add custom logic to their plugins. We - the users, can add our own function and use add_filter to register our functions.
For example, this piece of code is from the plugin. Normally, it shows all products but it provides us a way to not show a specific product.
// Plugin's
if (apply_filters( 'plugin_show_products', true, $product->get_id() ) ) {
$this->show_products();
}
So, if we - the users, want to customize a bit. We can add our own function as following (maybe in functions.php)
// Our custom changes
function my_own_changes($boolean, $product_id) {
if ( $product_id === 5 ) return false;
return true;
}
add_filter( 'plugin_show_products', 'my_own_changes', 10, 2 );
This translates to: The plugin will behave normally but for my own site, it will not show the product with ID of 5!
I have come across this type of code in a plugin or theme where the apply_filter is used without necessarily having an existing filter or add_filter
In this case, where the apply_filters is used without a filter you will have to call the function again where you want to run it. For example, in the header of a theme.
The following is an example of apply filters used in a function that is again called in the header.php
if ( ! function_exists( 'header_apply_filter_test' ) ) {
function header_apply_filter_test() {
$filter_this_content = "Example of content to filter";
ob_start();
echo $filter_this_content;
$output = ob_get_clean();
echo apply_filters( 'header_apply_filter_test', $output );//used here
}
}
Now in the header.php file, you would have to call this function since it is not hooked anywhere. So, in this case, to display the output in the header you would call the function like this :
<?php header_apply_filter_test(); ?>
You could as well write this code with a hook and it would do the same thing i.e display the output in the header.
add_filter('wp_head', 'header_apply_filter_test');
if ( ! function_exists( 'header_apply_filter_test' ) ) {
function header_apply_filter_test() {
$filter_this_content = "Example of content to filter";
ob_start();
echo $filter_this_content;
$output = ob_get_clean();
echo $output;
}
}
For this second option, you would still have the capability of using apply_filters anywhere else to call the callback function header_apply_filter_test() since the filter now exists.
So the bottom line in my view is a use case since either approach works!

How can I get the current page name in WordPress?

What PHP code can be used to retrieve the current page name in a WordPress theme?
All the solutions I have seen so far:
the_title()
get_page()->post_name
get_post()
etc.
But these don't work for a page that contains post entries. They will all return the name of the latest blog entry.
Stated another way, assume that you have a page created in WordPress with the name "My News". This page is set as the "post page". Add a couple of posts to the page.
Now, what API can be used to retrieve the string "my-news" instead of the name of the latest post?
I've found the following variable which seems to work.
$wp_query->queried_object->post_name
This is actually the URL friendly version of the page name (slug), which is what I was looking for too. This was tested with the default template (Twenty Ten). I'm really not sure why the two variables given below do not work on my site. Thanks to keatch for the print_r() tip.
Now, why is this information hidden so deep down?
The WordPress global variable $pagename should be available for you. I have just tried with the same setup you specified.
$pagename is defined in the file wp-includes/theme.php, inside the function get_page_template(), which is of course is called before your page theme files are parsed, so it is available at any point inside your templates for pages.
Although it doesn't appear to be documented, the $pagename var is only set if you use permalinks. I guess this is because if you don't use them, WordPress doesn't need the page slug, so it doesn't set it up.
$pagename is not set if you use the page as a static front page.
This is the code inside /wp-includes/theme.php, which uses the solution you pointed out when $pagename can't be set:
--
if ( !$pagename && $id > 0 ) {
// If a static page is set as the front page, $pagename will not be set. Retrieve it from the queried object
$post = $wp_query->get_queried_object();
$pagename = $post->post_name;
}
My approach to get the slug name of the page:
$slug = basename(get_permalink());
<?php wp_title(''); ?>
This worked for me.
If I understand correctly, you want to get the page name on a page that has post entries.
Ok, you must grab the page title before the loop.
$page_title = $wp_query->post->post_title;
Check for the reference: http://codex.wordpress.org/Function_Reference/WP_Query#Properties.
Do a
print_r($wp_query)
before the loop to see all the values of the $wp_query object.
You can get the current page, post, or custom post type with the global variable $post:
echo $post->post_title
Note: In a function or class you'll need to specify global $post; prior to trying to use $post.
If you have loops on your page, make sure you end each loop with wp_reset_postdata(); to set $post back to the default item being displayed (the page).
Note, the 'post_title' variable is also available for any custom loop / query... including menu items and media attachments... everything in WordPress is a 'post'.
We just need to use the "post" global variable:
global $post;
echo $post->post_title;
This will echo the current page/post title.
If you're looking to access the current page from within your functions.php file (so, before the loop, before $post is populated, before $wp_query is initialized, etc...) you really have no choice but to access the server variables themselves and extract the requested page from the query string.
$page_slug = trim( $_SERVER["REQUEST_URI"] , '/' )
Note that this is a "dumb" solution. It doesn't know, for instance that the page with the slug 'coming-soon' is also p=6. And it assumes that your permalink settings are set to pagename (which they should be anyway!).
Still, can be a useful little trick if you have a controlled scenario. I'm using this in a situation where I wish to redirect non-logged in visitors to a "coming soon" page; but I have to make sure that I'm not throwing them into the dreaded "redirect loop", so I need to exclude the "coming soon" page from this rule:
global $pagenow;
if (
! is_admin() &&
'wp-login.php' != $pagenow &&
'coming-soon' != trim( $_SERVER["REQUEST_URI"] , '/' ) &&
! is_user_logged_in()
){
wp_safe_redirect( 'coming-soon' );
}
I believe that the Roots starter theme has a fantastic function to get the current page title. It is very hackable, covers all bases, and can be easily used with the wp_title hook.
/**
* Page titles
*/
function roots_title() {
if (is_home()) {
if (get_option('page_for_posts', true)) {
echo get_the_title(get_option('page_for_posts', true));
} else {
_e('Latest Posts', 'roots');
}
} elseif (is_archive()) {
$term = get_term_by('slug', get_query_var('term'), get_query_var('taxonomy'));
if ($term) {
echo $term->name;
} elseif (is_post_type_archive()) {
echo get_queried_object()->labels->name;
} elseif (is_day()) {
printf(__('Daily Archives: %s', 'roots'), get_the_date());
} elseif (is_month()) {
printf(__('Monthly Archives: %s', 'roots'), get_the_date('F Y'));
} elseif (is_year()) {
printf(__('Yearly Archives: %s', 'roots'), get_the_date('Y'));
} elseif (is_author()) {
$author = get_queried_object();
printf(__('Author Archives: %s', 'roots'), $author->display_name);
} else {
single_cat_title();
}
} elseif (is_search()) {
printf(__('Search Results for %s', 'roots'), get_search_query());
} elseif (is_404()) {
_e('Not Found', 'roots');
} else {
the_title();
}
}
Try this:
$pagename = get_query_var('pagename');
I have come up with a simpler solution.
Get the returned value of the page name from wp_title(). If empty, print homepage name, otherwise echo the wp_title() value.
<?php $title = wp_title('', false); ?>
Remember to remove the separation with the first argument and then set display to false to use as an input to the variable. Then just bung the code between your heading, etc. tags.
<?php if ( $title == "" ) : echo "Home"; else : echo $title; endif; ?>
It worked a treat for me and ensuring that the first is declared in the section where you wish to extract the $title, this can be tuned to return different variables.
Use:
$title = get_the_title($post);
$parent_title = get_the_title($post->post_parent);
echo $title;
echo $parent_title;
This seems to be the easiest to use:
<?php single_post_title(); ?>
One option, if you're looking for the actual queried page, rather than the page ID or slug is to intercept the query:
add_action('parse_request', 'show_query', 10, 1);
Within your function, you have access to the $wp object and you can get either the pagename or the post name with:
function show_query($wp){
if ( ! is_admin() ){ // heck we don't need the admin pages
echo $wp->query_vars['pagename'];
echo $wp->query_vars['name'];
}
}
If, on the other hand, you really need the post data, the first place to get it (and arguably in this context, the best) is:
add_action('wp', 'show_page_name', 10, 1);
function show_page_name($wp){
if ( ! is_admin() ){
global $post;
echo $post->ID, " : ", $post->post_name;
}
}
Finally, I realize this probably wasn't the OP's question, but if you're looking for the Admin page name, use the global $pagenow.
Within the WordPress Loop:
if ( have_posts() ) : while ( have_posts() ) : the_post();
/******************************************/
echo get_the_title();
/******************************************/
endwhile; endif;
This will show you the current page title.
For reference: get_the_title()
Here's my version:
$title = ucwords(str_replace('-', ' ', get_query_var('pagename')));
get_query_var('pagename') was just giving me the page slug. So the above replaces all the dashes, and makes the first letter of each word uppercase - so it can actually be used as a title.
Show the title before the loop starts:
$page_title = $wp_query->post->post_title;
This is what I ended up using, as of 2018:
<section id="top-<?=(is_front_page() ? 'home' : basename(get_permalink()));?>">
I've now found this function on WordPress Codec,
get queried
which is a wrapper for $wp_query->get_queried_object.
This post put me in the right direction, but it seems that it needs this update.
This also works if you are in the functions.php. It is not the best approach since you have to use the global array, but it works.
First, we need to add a filter. There must exist a better filter to use than the template_include, but I don't know all of them. Please point me to the right one.
add_filter( 'template_include', 'var_template_include', 1000 );
function var_template_include( $template ){
global $wp_query;
$GLOBALS['current_page'] = $wp_query->get_queried_object()->post_name;
return $template;
}
Avoid using the variable directly
function get_current_page( $echo = false ) {
if( !isset( $GLOBALS['current_page'] ) )
return false;
return $GLOBALS['current_page'];
}
Now you can use the function get_current_page() in any other part of the functions.php.

Resources