wordpress plugin function firing twice - php

Followed through on this post for manipulating woocommerce menu.
This plugin code:
function product_subcategories( $args = array() ) {
$parentid = get_queried_object_id();
$args = array(
'parent' => $parentid
);
$terms = get_terms( 'product_cat', $args );
if ( $terms ) {
echo '<ul class="product-cats">';
foreach ( $terms as $term ) {
echo '<li class="category">';
woocommerce_subcategory_thumbnail( $term );
echo '<h2>';
echo '<a href="' . esc_url( get_term_link( $term ) ) . '" class="' . $term->slug . '">';
echo $term->name;
echo '</a>';
echo '</h2>';
echo '</li>';
}
echo '</ul>';
}
}
add_action( 'woocommerce_before_shop_loop', 'product_subcategories', 50 );
Fires twice.
Why is that??
Thanx
EDIT
Original post link: Display WooCommerce Categories, Subcategories, and Products in Separate Lists

Woocommerce does allow you to register two events with the same tag source. Thus, if the file is loaded twice (e.g. if you use include/require instead of include_once/require_once) it can cause this problem: check it anyhow(!).
The hook itself is called twice in woocommerce, so technically it is possible that the hook is called twice. I do however not know if both templates are loaded in the same call... You might however have registered the call twice w/o knowing: thus check your code for another call to this function, perhaps with a different tag (other than woocommerce_before_shop_loop).

Update:
With your code you are just doing what WooCommerce is already doing, that's why you are seeing duplicated category/subcategory menu items and you say that it's "fired twice".
Anyway, if you keep your code, and then you want to remove that WooCommerce generated category/subcategory items, you can use this hooked function:
add_filter('woocommerce_product_subcategories_args', function( $args ){
$args['taxonomy']= '';
return $args;
});
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This will remove the WooCommerce duplicated items…
Original answer:
The woocommerce_before_shop_loop hook:
has no arguments (no need to add $args = array() )
is called many times, but only fired once. Check it replacing your code by this:
add_action( 'woocommerce_before_shop_loop', function(){
wc_print_notice('test message', 'notice');
}, 50 );
Kindly, as your question is not very explicit and detailed, we don't really know what is your problem and can't help you further than that…

While the previous answers are no doubt accurate, I don't think they are truly the reason for multiple calls. I believe the true reason is that you're simply receiving multiple HTTP requests when, to your eyes, it seems like there should only be one. Remember, your plugin is going to load upon every interaction with WP, not just the ones for your application. So /wp-cron.php links, for example, will trigger your plugin "invisibly", as will many other requests like Ajax or JSON calls. Please see https://wordpress.stackexchange.com/questions/170768/wordpress-plugin-executing-code-twice#answer-170784.

Related

Custom Category Filter Dropdown Displaying Twice

I needed to build a dropdown category filter for my WordPress child theme. Here's what I have in my functions.php:
function blog_category_filter() {
if
( $terms = get_terms
( array
('taxonomy' => 'category', // to make it simple I use default categories
'orderby' => 'name'
)
)
) :
// if categories exist, display the dropdown
echo '<select name="category_filter"><option value="">Filter By Category</option>';
foreach ( $terms as $term ) :
echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as an option value
endforeach;
echo '</select>';
endif;
}
add_action( 'wp_enqueue_scripts', 'blog_category_filter' );
I call the function in my index.php like so:
<?php blog_category_filter() ?>
The dropdown is displaying twice, once at the very top of the page (where I do not want it to be) and again further down in the body (where I do want it to be).
When I look at the code in Dev Tools, I see the dropdown directly under the body tag, followed by stylesheets, WP scripts, the rest of the HTML, then my scripts. No idea why that is happening, but one catastrophe at a time, amirite?
Is this an enqueue issue? It's the only thing I can think of as I am totally lost on where to start.

When changing woocommerce title hook the first item doesn't change

I have a strange behaviour that I don't understand
I've changed the woocommerce_shop_loop_item_title hook to add a link to the title of the product. This is my code inside functions.php
// Add HREF TO TITLE
function abChangeProductsTitleHook(){
remove_action( 'woocommerce_shop_loop_item_title', 'woocommerce_template_loop_product_title', 10 );
add_action('woocommerce_shop_loop_item_title', 'abChangeProductsTitle', 10 );
}
add_action( 'woocommerce_shop_loop_item_title', 'abChangeProductsTitleHook' );
function abChangeProductsTitle() {
echo '<h2 class="woocommerce-loop-product_title">' . get_the_title() . '</h2>';
}
It works perfectly on all the products except the first one.
I've also made a similar change to another hook to change the thumbnail image to a background image and also this one doesn't work on the first product. It's always the first product even if I change the order of the products.
Below you see a screenshot of the the first row of products on the page and that the first one is displayed differently
It would be really helpful if anyone knows that problem or can point me in the right direction .
Thank you very much
Alex
The way you are removing and adding the woocommerce_shop_loop_item_title is the problem. Try it this way.
remove_action( 'woocommerce_shop_loop_item_title','woocommerce_template_loop_product_title', 10 );
add_action('woocommerce_shop_loop_item_title', 'abChangeProductsTitle', 10 );
function abChangeProductsTitle() {
echo '<h2 class="woocommerce-loop-product_title">' . get_the_title() . '</h2>';
}
Although the accepted answer works, but why do we have to remove the title and then add it back in again? We could simply filter it in the first place.
add_filter('the_title', 'your_shop_custom_title', 20, 2);
function your_shop_custom_title($the_title, $id)
{
if (is_shop() && get_post_type($id) == 'product') : // runs only on the shop page
$the_title = '' . $the_title . '';
endif;
return $the_title;
}

Woocommerce Multiple single product templates using single-product.php to redirect

I've been pulling my hair out with this all day, please forgive the short description, I just need to validate my sanity!!
As the title says, I'm trying to create two or three different single-product layouts within woocommerce. The minimum is trying to achieve would be to have multiple single-product folders each with their own name and configurations.
No matter which way I try to override the single-product.php and make this file use logic to check for the product_cat and give out templates accordingly, I either the page not loading or what I write is skipped over and the default is loaded.
So far I've been through the following methods multiple times, trying to piece together what may be outdated code or otherwise causing all the fuss:
WooCommerce - How to create multiple single product template based on category?
Woocommerce single product - template by categories
Creating a different template file for certain Product Categories - Wordpress/Woocommerce?
I was more hoping someone may know something about this that I'm obviously missing as there are many articles out there on what to try and most claim success but I'm unable to do so.
[Update] using template_include code from #helgatheviking
No success just yet but here's where I'm up to;
File structure
team-shops is the category I'm trying to get
/mytheme/woocommerce/single-product.php - no changes
/mytheme/woocommerce/content-single-product.php
/mytheme/woocommerce/single-product-team-shops.php - changed line 37 to<?php wc_get_template_part( 'content', 'single-product-team-shops' ); ?>
/mytheme/woocommerce/content-single-product-team-shops.php - added additional id to #product-id (line 39)
/mytheme/woocommerce/single-product-team-shops/ folder with all single product files to change.
As I said above this isn't working but hopefully with what I've provided the problem may be more obvious.
Thanks again for any help :)
[Think I've got it]
Ok so I think I've something that works, at least for now it seems to, still have some further testing to do but any thoughts more than welcome, this is what I've got so far along with a single-product-team-shops folder in my theme
add_filter( 'woocommerce_locate_template', 'so_25789472_locate_template', 10, 3 );
function so_25789472_locate_template( $template, $template_name, $template_path ){
$term_id = 2854;
$taxonomy_name = 'product_cat';
$term_children = get_term_children( $term_id, $taxonomy_name );
foreach ( $term_children as $child ) {
// on single posts with mock category and only for single-product/something.php templates
if( is_product() && has_term( $child, 'product_cat' ) && strpos( $template_name, 'single-product/') !== false ){
// replace single-product with single-product-mock in template name
$mock_template_name = str_replace("single-product/", "single-product-team-shops/", $template_name );
// look for templates in the single-product-mock/ folder
$mock_template = locate_template(
array(
trailingslashit( $template_path ) . $mock_template_name,
$mock_template_name
)
);
// if found, replace template with that in the single-product-mock/ folder
if ( $mock_template ) {
$template = $mock_template;
}
}}
return $template;
}
Use a single-product-custom.php template for any product in the "custom" category:
add_filter( 'template_include', 'so_43621049_template_include' );
function so_43621049_template_include( $template ) {
if ( is_singular('product') && (has_term( 'custom', 'product_cat')) ) {
$template = get_stylesheet_directory() . '/woocommerce/single-product-custom.php';
}
return $template;
}
NB: If you use the same action hooks in your single-product-custom.php template you will get the same look as the default single-product.php. You could 'rename' all the hooks and then could add existing functions (such as those for add to cart buttons, etc) to the new hooks in order to achieve a totally custom look.

Add login form shortcode programatically to every published product page

I am running a wholesale shop on Woocommerce. Login is required to see the prices. This is set up and working properly. Now I wish to add a logon form on every product page to only show to visitors (not logged on users).
I am using the WooCommerce Catalog Visibility plugin. This plugin offers the functionality I described above, but my theme is somehow messing it up. The plugin author says to talk to the theme developer and the theme developer says to talk to the plugin author. So now I am trying to find a workaround.
First issue: The plugin comes with a shortcode [woocommerce_logon_form] that will display a logon form. I don't want to manually add this to every existing product since I have thousands of products on my site. I am looking for a way to get it in through the code for the product page layout.
I found this code (to be added to the functions.php) to work well:
// adds notice at single product page above add to cart
add_action( 'woocommerce_single_product_summary', 'return_policy', 20 );
function return_policy() {
echo '<p id="rtrn">30-day return policy offered. See Terms and Conditions for details.</p>';
}
However, it will only show text. The short code won't work when added instead of the sample text.
Second issue: The short code shows the form even when the customer is already logged in.
I am currently using this nice code that shows or hides content depending on whether the user is logged in or not:
add_shortcode( 'access', 'access_check_shortcode' );
function access_check_shortcode( $attr, $content = null ) {
extract( shortcode_atts( array( 'capability' => 'read' ), $attr ) );
if ( current_user_can( $capability ) && !is_null( $content ) && !is_feed() )
return $content;
return '';
}
add_shortcode( 'visitor', 'visitor_check_shortcode' );
function visitor_check_shortcode( $atts, $content = null ) {
if ( ( !is_user_logged_in() && !is_null( $content ) ) || is_feed() )
return $content;
return '';
}
That shortcode works perfectly for text, but not with other shortcodes.
So the combination of these short codes: [visitor][woocommerce_logon_form][/visitor] will not show the logon form to visitors. Instead it will only show them this as text [woocommerce_logon_form].
Please help! I am sure this is probably easily fixed by someone with coding skills.
I appreciate your effort to answer to this question. Keep in mind that my understanding of code is very limited and it would be great if you can also point out in which file to add or modify code.
To make your shortcode working in php code or in php/html code you need to use a native WordPress function do_shortcode() … You can use it with your shortcode for example in your 1st function this way:
add_action( 'woocommerce_single_product_summary', 'return_policy', 20 );
function return_policy() {
echo do_shortcode('[woocommerce_logon_form]');
}
And this will work…
To see all the different hooks you can use instead of woocommerce_single_product_summary, please see this 2 templates code to chose in case a more convenient hook:
WooCommerce single-product.php template
WooCommerce content-single-product.php template
You can also add it the same way in one of your existing short codes, this way:
add_shortcode( 'visitor', 'visitor_check_shortcode' );
function visitor_check_shortcode( $atts, $content = null ) {
if ( ( !is_user_logged_in() && !is_null( $content ) ) || is_feed() )
return do_shortcode('[woocommerce_logon_form]');
return '';
}
And this will work too.
See as reference this answer: Change markup in WooCommerce shortcode output
So as you can see your problem is solved on both issues

Moving Page/Post Titles outside the Loop in WordPress

I have a client site running on WordPress. It uses WooThemes Canvas as its base theme (with a customized child theme), and utilizes the Time.ly All-in-one-Event Calendar. It can be viewed here.
The design I came up with required me to move the page/post titles outside the main content area. I followed the instructions on this WooThemes customization document, and made modifications based on the comments so that it would also work for posts and the Time.ly event postings. The entries in my functions.php file looked like this:
add_filter( 'the_title', 'woo_custom_hide_single_post_title', 10 );
function woo_custom_hide_single_post_title ( $title ) {
if ( is_singular( array( 'post', 'ai1ec_event' ) ) && in_the_loop() ) { $title = ''; }
return $title;
} // End woo_custom_hide_single_post_title()
add_filter( 'the_title', 'woo_custom_hide_single_page_title', 10 );
function woo_custom_hide_single_page_title ( $title ) {
if ( is_page() && in_the_loop() ) { $title = ''; }
return $title;
} // End woo_custom_hide_single_page_title()
// Add Titles above Content Area on all Posts & Pages
add_action( 'woo_content_before_singular-post', 'woo_custom_add_title', 10 );
add_action( 'woo_content_before_singular-ai1ec_event', 'woo_custom_add_title', 10 );
add_action( 'woo_content_before_singular-page', 'woo_custom_add_title', 10 );
function woo_custom_add_title () {
if ( ! is_page_template(array('template-biz.php', 'template-brewpub.php')) ) {
global $post;
$title = '<h1 class="page-title">' . get_the_title( $post->ID ) . '</h1>' . "";
echo '<div id="title_container"><header class="col-full">';
echo $title;
woo_post_meta();
echo '</header></div>';
}
} // End woo_custom_add_post_title()
This produced some undesirable results, which can be seen on the DEV site I setup for this post (dev.thebrewworks.com):
Since the Time.ly event calendar also uses the_title to display it's events, in the three instances I used the calendar inside a page loop (the homepage and the two restaurant location pages), the event titles don't show up. This was confirmed by creating a Test Page (dev.thebrewworks.com/test-page), where you can see two instances of the calendar inside the loop, and one outside (in the sidebar). The two instances in the Loop have no titles, while the sidebar does.
Supressing the_title in the Loop didn't suppress the Post Meta, which still shows up in the main content area, but I want it under the title in the new DIV, so reposting woo_post_meta outside the Loop leaves me with two instances of the Post Meta.
In order to get the site live I had to make some concessions in my functions.php file:
// Hide Titles on All Posts & Pages
add_filter( 'the_title', 'woo_custom_hide_single_post_title', 10 );
function woo_custom_hide_single_post_title ( $title ) {
if ( is_singular( array( 'post', 'ai1ec_event' ) ) && in_the_loop() ) { $title = ''; }
return $title;
} // End woo_custom_hide_single_post_title()
add_filter( 'the_title', 'woo_custom_hide_single_page_title', 10 );
function woo_custom_hide_single_page_title ( $title ) {
if ( is_page() && in_the_loop() && is_page_template( array('page.php', 'template-contact.php' ) ) ) { $title = ''; }
return $title;
} // End woo_custom_hide_single_page_title()
// Add Titles above Content Area on all Posts & Pages
add_action( 'woo_content_before_singular-post', 'woo_custom_add_title', 10 );
add_action( 'woo_content_before_singular-ai1ec_event', 'woo_custom_add_title', 10 );
add_action( 'woo_content_before_singular-page', 'woo_custom_add_title', 10 );
function woo_custom_add_title () {
if ( ! is_page_template(array('template-biz.php', 'template-brewpub.php')) ) {
global $post;
$title = '<h1 class="page-title">' . get_the_title( $post->ID ) . '</h1>' . "";
echo '<div id="title_container"><header class="col-full">';
echo $title;
woo_post_meta();
echo '</header></div>';
}
} // End woo_custom_add_post_title()
// Disable Post Meta
function woo_post_meta() {}
?>
Note the changes:
I disabled the post_meta completely. Not exactly what I was looking for, but better than having it show up twice.
I modified the function that disables the page title so that it only works on pages that use certain templates (the three instances I mentioned above use the Business Template in Canvas that already suppresses the page title). This would require me to go in and add each new page template that I want to suppress the title on, though...and on top of that, it's not working. Take a look at the live site. The page title is showing up twice on static pages. Once inside the white content area and once outside in the yellow header.
I'm no PHP-developer...I'm more of an Design/HTML/CSS person. I know enough to be dangerous...how to modify existing code, etc., but not necessarily how to write my own from scratch. I have no idea if the way I came up with things is even the best/most elegant way to go about it. Now that you have all the facts, here are my questions:
In an ideal world, the Post Meta would ONLY show up on the blog entries (not on the calendar entries...no need for them there, really), and OUTSIDE the main content area underneath the page title that I moved. How can I achieve this? I'm guessing it's going to be some sort of conditional statement that removes the woo_post_meta from all instances inside the loop, and adds it to the woo_custom_add_title ONLY if it's a standard post, but how to get there I have no idea.
How can I suppress the_title that shows up at the top of the content area on ALL static pages, regardless of template, but have it not affect instances of the_title that appear elsewhere in the loop (like the calendar syndication). In my head there has to be a way to indicate that you ONLY want to disable the_title if it's in a certain div/id, etc., but again...only enough to be dangerous, unless I see it done elsewhere, I can't come up with the solution on my own.
Thanks in advance for your input.

Categories