• Resolved svaldesm

    (@svaldesm)


    Hi, how are you?

    We have a lot of products on our store and many of our customers like to add lots of them to their wishlists, say 300-400. That means that wnenever they go to /wishlist/ the server gets a huge load because of that (searches for 300 products on 70K total).

    How can that be improved? It’s starting to turn into a huge issue for us, even with pagination active.
    Is there a way to limit the load it takes? Or is there a way to limit the amount of products on the wishlist?

    Any solution for this would be really appreciated.

    Thanks a lot for your time!

Viewing 13 replies - 1 through 13 (of 13 total)
  • Thread Starter svaldesm

    (@svaldesm)

    I don’t know if this is necessarily related, but we have 32 products per page and look at this New Relic report:

    View post on imgur.com

    View post on imgur.com

    It takes 45sec to load it fully (32 products) and I’m not really sure why

    Plugin Author YITHEMES

    (@yithemes)

    Hi there!

    Nice to hear from you again

    As far as I can see from your trace, you have problems with read_items function
    This function will read all the items of the wishlist, no matter what you currently show on your wishlist
    That’s because you’ll need the entire set to determin if a product is already in wishlist

    Anyway, this should happen at most once per wishlist, and everything should be heavly cached afterwards
    Besides, once queries retrieves ID of items in wishlist, ::get_wishlist_item should be a pretty easy method to execute, that will only select over an index in dedicated database table

    I’m not sure what to suggest; do you see spikes in db activities over certain type of queries? Maybe we could start from there

    Thread Starter svaldesm

    (@svaldesm)

    Thanks for your reply

    A few more things to consider:
    – I’m using Basel theme (XTemos) that used to be integrated with your wishlist, not sure if they might have done something that affects (It’s a remote theory, but nevertheless)
    – We have 70K products and the biggest wishlist has 500 products in it
    – We don’t have Redis or any other object cache in place
    – We are on a 16GB, 6-core server

    What I believe happens are two things:
    – Someone enters to /wishlist/ with a huge wishlist and it takes years to load
    – Somehow, when one of these same people are browsing, every page load tries to match the 32 products of that page with their wishlist, completely thrashing the machine.

    How can we test this further? I have a staging site that is exactly the same as production if you want to make a few tests.

    I’m 100% sure the issue is related to this plugin because just after disabling it, it starts to work fine and the load goes from 800% to 40%.

    Thanks!

    Thread Starter svaldesm

    (@svaldesm)

    So, disabling the option “Show “Add to wishlist” in loop” certainly reduces the load.

    I think the issue mostly relates to the plugin comparing each page load to check if those products are on the list or not.
    Is it possible to override that behavior? I just want to show the heart and if someone wants to add it, then add it, but don’t check on every load if they are there.

    I would really appreciate if there’s some kind of hook or fix for that, right now I had to disable the plugin because of those issues mentioned.

    Thanks again!

    Thread Starter svaldesm

    (@svaldesm)

    I’ve been investigating a bit more.
    Please let me know if I’m in the right direction:

    What needs to be done is to change the file /templates/add-to-wishlist.php, replacing the content between lines 42-53 and add the code that’s on /templates/add-to-wishlist-button.php` (that is the template I’m using).

    So far I think I can do that, but I’ve been unable to show the “success” template after adding to wishlist.

    Remember, what I want to do is just to let people add to wishlist, but not compare every product to check if it’s on the wishlist previously (hence, showing the added or to-add template, which is what slows my site).

    I’ve been all day without the “Shop loop” and it works very smoothly, which tells me that the issue is not that people have big lists checking them on the wishlist view, but rather that it compares, for logged in users, for every 32 products of every page to check if it’s already added to change the design of the button. It’s just not worth it and I’ve compared other big stores (as Asos) and they have it as I’m trying to achieve.

    In summary, how can I achieve what I want? I don’t care if I need to do custom work (considering updates will break) but rather being able to achieve it. I think it’s a great feature to add (check if product was already added? yes/no to avoid that load)

    Thanks again and sorry for all the messages ??

    Plugin Author YITHEMES

    (@yithemes)

    Hi again

    Sorry for my late answer, but your messages always requires some additional consideration
    Let me first share my two cents on the soruce of this problem

    When wishlist reads its items (EG. whenever you try to check if wishlist contains a product) it will perform a query that looks like this

    SELECT i.* FROM wp_yith_wcwl as i INNER JOIN wp_posts as p on i.prod_id = p.ID WHERE wishlist_id = 123 AND p.post_type IN ( 'product', 'product_variation' ) AND p.post_status = 'publish'
    

    With some additional where condition, to account for product visibility

    The problem in your case, I guess, is that we’re joining togheter two massive tables, posts with 70k+ records (those are only product, but I guess you have many orders and other posts) and yith_wcwl

    Could you try to execute the previous query, with a real wishlist_id (you can read one from yith_wcwl_lists table, maybe picking one wishlist with many items), to have an idea of execution time?
    Of course once executed, results will be cached, and just one execution won’t be a good test, but should at least show us the forces in action

    Unfortunately I cannot see much space for improvment in this query, unless we point to some lookup table and some amount of redundancy in the data
    Could you please also check that system correctly generated an index over prod_id column for yith_wcwl table? This should greatly ease join operation

    Now back to your question: how to show Add to Wishlist button without checking if product is already in wishlist

    Unfortunately this is done during shortocode processing, so any change to the template won’t fit your needs
    You’ll need to create your alternative Add to Wishlist button, but this could be a demanding task

    The easiset way to proceed would be to us a plain anchor, that redirects users to the wishlist while adding product to the list
    This could be achieved by using an anchor tag with some style, to get the “heart-like” appearance, and the url to the wishlist with ?add_to_wishlist=<product_id> paramter

    Please, let me know if you want to proceed with this test
    Have a nice day

    Thread Starter svaldesm

    (@svaldesm)

    Hi there,

    First of all, I really appreciate how complete, personal and professional your answers are, considering I’m a non-paying user. Please refer me to a place where I can write an adequate review for YITH that will be useful to you, because I really think this is very high level support. Thanks for that.

    Regarding the query, I did it with the biggest list that I have on my site: 903 products. It took 0.041 seconds to load. I tried with several other lists over 100 products and the time was almost the same. Considering it must load for 32 products, it can take up to 1,3 seconds (just adding it directly) for this to load, but if it’s happening for several customers at once, it might put a huge load on the server. What I don’t get is why it takes sometimes 100 or more seconds, apparently something breaks the loop and products some memory or CPU leak. I think it’s some kind of iterative loop. I can get over 800% CPU usage with a few customers that are browsing.

    Regarding the index on prod_id, it is created.

    Considering your solution, what would be the best way to achieve that? Should I do that on my child template or on the plugin template? If you could point me in the right direction I would really appreciate it. I know I can’t ask for you to do this, it’s out of boundaries and I think I can achieve it, but with your help on telling me which files needs to be changed and in big terms, where.

    Thanks again for such a helpful support.

    – Santiago

    • This reply was modified 4 years, 6 months ago by svaldesm.
    Plugin Author YITHEMES

    (@yithemes)

    Hi again Santiago

    Really, I’d love to help
    You could start disabling Add to Wishlist button for your loop from WP Dashboard -> YITH -> Wishlist -> Add to Wishlist options -> Loop settings

    Then you could try to add the following custom code to functions.php file of your child theme

    if ( function_exists( 'YITH_WCWL' ) && ! function_exists( 'yith_wcwl_custom_loop_add_to_wishlist' ) ) {
    	function yith_wcwl_custom_loop_add_to_wishlist() {
    		global $product;
    
    		if ( ! $product || ! $product instanceof WC_Product ) {
    			return;
    		}
    
    		$product_id        = $product->get_id();
    		$parent_product_id = $product->is_type( 'variation' ) ? $product->get_parent_id() : $product_id;
    		$base_url          = YITH_WCWL()->get_wishlist_url();
    		$icon_option       = get_option( 'yith_wcwl_add_to_wishlist_icon' );
    		$label_option      = get_option( 'yith_wcwl_add_to_wishlist_text' );
    
    		$icon  = ! empty( $icon_option ) ? '<i class="yith-wcwl-icon fa ' . $icon_option . '"></i>' : '';
    		$label = apply_filters( 'yith_wcwl_button_label', $label_option );
    
    		?>
    		<div class="yith-wcwl-add-button">
    			<a href="<?php echo esc_url( add_query_arg( 'add_to_wishlist', $product_id, $base_url ) ); ?>" rel="nofollow" data-product-id="<?php echo esc_attr( $product_id ) ?>" data-original-product-id="<?php echo $parent_product_id ?>" data-title="<?php echo esc_attr( apply_filters( 'yith_wcwl_add_to_wishlist_title', $label ) ); ?>">
    				<?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
    				<span><?php echo wp_kses_post( $label ); ?></span>
    			</a>
    		</div>
    		<?php
    	}
    
    	add_action( 'woocommerce_before_shop_loop_item', 'yith_wcwl_custom_loop_add_to_wishlist', 5 );
    }
    

    This will add a custom Add to Wishlist link to your loop, and will avoid aby check over product existance

    Obviously you’ll need to customize and improve appearance of the button, but this should be easy enough once button is correctly shown and works as expected

    Thread Starter svaldesm

    (@svaldesm)

    Hi there,

    Thank you very much for such a complete and precise answer. It works perfectly.

    I just would like to know if two modifications can be achieved:

    – when you click, not redirect to the wishlist page, just add them
    – in line with the previous item, after the product is added (click on the button), changing the class of the element so that we can change the design

    In summary, the desirable flow would be:
    – All products are loaded with a link to /add_to_wishlist= (…), without any kind of check if it’s already added or not
    – When you add a product, it’s added via AJAX and the class element changes (the heart goes from white with black borders to full black)
    – Ideally, once added if you click you remove it

    Is there a way to achieve those changes?
    For me, the ideal flow would be to load everything as it is out of the box, but only without the verification if that product is already on wishlist.

    Thanks again for your help!

    Plugin Author YITHEMES

    (@yithemes)

    Hi again Santiago

    I tweaked a bit the code to enable ajax add to wishlist and template replacement after add to wishlist
    This definitely needs some styling, but for the moment lets check that everythign works

    Here updated code

    if ( function_exists( 'YITH_WCWL' ) && ! function_exists( 'yith_wcwl_custom_loop_add_to_wishlist' ) ) {
    	function yith_wcwl_custom_loop_add_to_wishlist() {
    		global $product;
    
    		if ( ! $product || ! $product instanceof WC_Product ) {
    			return;
    		}
    
    		$product_id        = $product->get_id();
    		$parent_product_id = $product->is_type( 'variation' ) ? $product->get_parent_id() : $product_id;
    		$base_url          = YITH_WCWL()->get_wishlist_url();
    		$icon_option       = get_option( 'yith_wcwl_add_to_wishlist_icon' );
    		$label_option      = get_option( 'yith_wcwl_add_to_wishlist_text' );
    
    		$icon  = ! empty( $icon_option ) ? '<i class="yith-wcwl-icon fa ' . $icon_option . '"></i>' : '';
    		$label = apply_filters( 'yith_wcwl_button_label', $label_option );
    
    		$fragment_options = [
    			'is_single' => false,
    			'exists' => false,
    			'in_default_wishlsit' => false,
    			'base_url' => yith_wcwl_get_current_url(),
    			'product_id' => $product_id,
    			'parent_product_id' => $parent_product_id,
    			'item' => 'add_to_wishlist'
    		];
    
    		?>
    		<div class="yith-wcwl-add-to-wishlist add-to-wishlist-<?php echo esc_attr( $product_id ); ?> wishlist-fragment" data-fragment-ref="<?php echo esc_attr( $product_id ); ?>" data-fragment-options="<?php echo esc_attr( json_encode( $fragment_options ) ); ?>">
    			<div class="yith-wcwl-add-button">
    				<a class="add_to_wishlist" href="<?php echo esc_url( add_query_arg( 'add_to_wishlist', $product_id, $base_url ) ); ?>" rel="nofollow" data-product-id="<?php echo esc_attr( $product_id ) ?>" data-original-product-id="<?php echo $parent_product_id ?>" data-title="<?php echo esc_attr( apply_filters( 'yith_wcwl_add_to_wishlist_title', $label ) ); ?>">
    					<?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
    					<span><?php echo wp_kses_post( $label ); ?></span>
    				</a>
    			</div>
    		</div>
    		<?php
    	}
    
    	add_action( 'woocommerce_before_shop_loop_item', 'yith_wcwl_custom_loop_add_to_wishlist', 5 );
    }
    

    Please, let me know

    Thread Starter svaldesm

    (@svaldesm)

    I can’t thank you enough for this. It works amazingly well!

    I realized that the single-product page is checking if the product is on the wishlist as well. This is suppose to have a much lower load, but what I’m worried is that, if somehow the first user added to wishlist on the category view and then entered to the product, the cache will be saved with the icon of the product added.
    It’s no big deal, but just want to know if theres a way to adapt your current solution to this case.

    I also had a suggestion in case you want to consider them for your backlog:
    – be able to define the order in which products are shown on the wishlist asc/desc (maybe via a shortcode parameter). I think usually the products with the highest chance to be sold are the newly added.
    – have the ability (from backend and customer view) to remove all out of stock products with a button

    Thanks again for your great support, I’ve left a review on the plugin site.

    Plugin Author YITHEMES

    (@yithemes)

    Hi again Santiago

    Regarding the cache problems: actually I think you should be able to activate Ajax loading for your wishlist

    This won’t affect your loop, since items shouldn’t be loaded via AJAX; anyway, Add to Wishlist in single product page should be loaded dynamically, to avoid any possible cache problem

    Regarding your suggestions, I’ll be glad to add them to possible future developmnet of the plugin ??

    Thread Starter svaldesm

    (@svaldesm)

    Thanks again for everything! Amazing support.

Viewing 13 replies - 1 through 13 (of 13 total)
  • The topic ‘Set max number of items or limit server load’ is closed to new replies.