Skip Navigation

[Resolved] Issues with map loading speed and issues with distance value…

This thread is resolved. Here is a description of the problem and solution.

Problem: I have a View of custom posts that displays a map with markers, using a distance filter and sorting results by distance. In some cases the distance center is set by a URL parameter, and in others, it is set by a shortcode attribute. I have implemented some custom code in a wpv_view_settings filter to toggle between the shortcode attribute and the URL parameter. In the cases where distance center is set by a shortcode attribute, I am using another custom shortcode to get the User's predicted zip code. That shortcodes an external service to get a predicted zip code based on the User's IP address. The custom zip code service seems to be working correctly, and the results of the View seem to be accurate.

However, in the cases where this zip code shortcode is used to set the View's distance Query Filter by shortcode attribute, the View consistently causes the page generation time to jump by 3 or more seconds. I would like to try to optimize the page load time as much as possible.

Solution: In this case, testing revealed that using the custom zip shortcode inside a wpv_view_settings filter callback was the source of the delay in page generation, for some reason not fully understood. Replacing that shortcode with a hard-coded zip code resulted in a page generation time just a fraction of a second higher than the page without the View present at all.
Optimization of the zip code shortcode is necessary to prevent the latency seen in page generation time.

This support ticket is created 3 years, 4 months ago. There's a good chance that you are reading advice that it now obsolete.

This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.

Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.

Sun Mon Tue Wed Thu Fri Sat
8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 - -
13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 - -

Supporter timezone: America/New_York (GMT-04:00)

This topic contains 16 replies, has 2 voices.

Last updated by shawnW-3 3 years, 4 months ago.

Assisted by: Christian Cox.

Author
Posts
#2109563

Tell us what you are trying to do?
I have two issues. First is speed:

Please see our previous tickets involving map speed issues...

With Toolset support, I was able to build a map that functions exactly as I need it to.

This map uses a users IP address to generate a shortcode which informs a view, and sorts by distance. Then if the user searches, after ajax runs a url parameter is used to inform a view for results. When there are no results in either, the results output results outside the radius of the location. It's not nearly so straight forward.

My concern from the very beginning has been speed. Every Toolset Map build I've done so far has been a significant drag on our performance scores.

This latest map (one intended to speed up the page load) accounts for up to 8 seconds of load time. That is completely unacceptable.

In a previous ticket W3 Total Cache was recommended. This didn't help, as the speed improvement was only granted on a second viewing and the plugin actually caused more issues elsewhere, eliminating any net value.

Is there any documentation that you are following?
I have read numerous posts from other users citing speed issues with maps that weren't resolved.
I have worked with Toolset support to implement changes to improve speed. A few of those attempts, such as deferring the view rendering to occur via ajax, were determined to be impossible with Toolset Views. The others seemed promising, but haven't delivered us positive results.

Right now the view structure for the 'buy local map' is:

1. Master View
- Renders search controls, primary map, and html structure for controls, map and results
This view is set to render no results with PHP for $query_args['post__in'] = array(0);, and in the no results section we have conditionals to handle which nested view should be delivered.

2. Shortcode Attribute Results View - INSIDE Radius - Nested in "1. Master View"
- Renders results based on a shortcode attribute which is a variable generated by a very fast and simple IP API JSON service.
- This outputs 50 closest results within a 60 radius which is sorted by distance.

3. URL Parameter Results View - INSIDE Radius - Nested in "1. Master View"
- Renders results based on the URL Parameter which is generated when a user clicks 'use my location' or searches an address. This also renders if a user is coming from an IP address that is associated with a mobile service provider, again, using the very fast and simple IP API JSON service to make that determination.
- This outputs 50 closest results within a 60 radius which is sorted by distance.

4. Shortcode Attribute Results View - OUTSIDE Radius - Nested in "2. Shortcode Attribute Results View - INSIDE Radius"
- Renders results based on a shortcode attribute which is a variable generated by a very fast and simple IP API JSON service.
- When INSIDE Radius has no results within 60 miles of the location, this outputs 50 closest results starting at 1 mile outside the radius which is sorted by distance.

5. URL Parameter Results View - OUTSIDE Radius - Nested in "3. URL Parameter Results View - INSIDE Radius"
- Renders results based on the URL Parameter which is generated when a user clicks 'use my location' or searches an address.
- When INSIDE Radius has no results within 60 miles of the location, this outputs 50 closest results starting at 1 mile outside the radius which is sorted by distance.

The reason this is so complicated is because a single view apparently doesn't have a simple way to switch from a shortcode attribute as the query source to a URL parameter as the query source. Additionally, a single view's only way for managing what to do when a location queried has no results within a radius is to default to a second view. That being said, the average user should only ever have 2 to 3 views in this structure rendering. In my testing, where only two views render, the "Reduce initial server response time" is consistently between 8 and 9 seconds (without these views this doesn't drag doesn't even register). Two views, 50 results, 8-9 seconds. The total difference between the page load with and without this map view are as follows:

With the "1. Master View" (and thus "2. Shortcode Attribute Results View - INSIDE Radius"):
Performance Score - 30
First Contentful Paint - 3.8s
Speed Index - 18.4s
Largest Contentful Paint - 8.7s
Time to Interactive - 11.0s
Total Blocking Time - 490ms
Cumulative Layout Shift - 0.296

Without the Master View:
Performance Score - 48
First Contentful Paint - 3.7s
Speed Index - 4.4s
Largest Contentful Paint - 8.3s
Time to Interactive - 8.6s
Total Blocking Time - 360ms
Cumulative Layout Shift - 0.291

I'll add that just counting the seconds out loud, I can confirm a difference of 8 full seconds.

Outside of the slow queries, I've found that having my custom php for sorting by distance on a shortcode attribute view slows things down: accounting for about 4 of the 8 to 9 seconds. The custom php to kill the query (mentioned above) is probably having a similar effect, but I don't know how to rework what I have without that php. It seems these will never be added as features on Views.

Okay, the second issue...
[toolset-maps-distance-value location='[users_ip_location]' target_source='postmeta' postmeta='wpcf-dealer-address' postmeta_id='[wpv-post-id]' decimals='2']
...and...[toolset-maps-distance-value origin_source='visitor_location' postmeta='wpcf-dealer-address']

These shortcodes only work in the first few iterations of a loop. Sometimes if you refresh the page or run ajax you can get all the iterations. But I've never seen all iterations show up on the first load.
What is the link to your site?
hidden link - click buy local

I'll take whoever is assigned, but I'd prefer someone in my timezone (central US) as it's always easier with the schedule.

New threads created by Christian Cox and linked to this one are listed below:

https://toolset.com/forums/topic/distance-value-not-appearing-for-all-results-in-a-view-upon-page-load/

#2110251
view-info.PNG

I'll add that in debug, it looks like the average view in this page is using about 200kbs of memory, where as the Master View is using 25.1669MB (and Render Time: 7.6298) the Shortcode Attribute Results View - INSIDE Radius is using 25.0476MB (with Render Time: 6.98569).

#2110491

Reduced the size of the map cache and got the memory usage WAY DOWN - but Render Time is still very high. Master View is using 1.4887MB (and Render Time: 5.9564) the Shortcode Attribute Results View - INSIDE Radius is using 1.3695MB (with Render Time: 5.29376).

That's a 94% reduction to the memory usage for a render time reduction of 21% on Master View and 95% reduction of the memory usage for a render time reduction of 24% on the Shortcode Attribute Results View - INSIDE Radius.

I don't know closely these numbers should be correlated, but I was hoping for something more substantial.

I reran lighthouse and here's what I have...

With the "1. Master View" (and thus "2. Shortcode Attribute Results View - INSIDE Radius"):
Performance Score - 28
First Contentful Paint - 3.7s
Speed Index - 15.0s
Largest Contentful Paint - 7.6s
Time to Interactive - 11.0s
Total Blocking Time - 600ms
Cumulative Layout Shift - 0.296

Opportunity: Reduce initial server response time: 6.52s

Without the Master View:
Performance Score - 49
First Contentful Paint - 3.6s
Speed Index - 4.1s
Largest Contentful Paint - 7.5s
Time to Interactive - 7.8s
Total Blocking Time - 410ms
Cumulative Layout Shift - 0.291

"Reduce initial server response time" doesn't register as an opportunity

#2111531

Hi, our supporters over the last couple of days have been mostly outside of your timezone, unfortunately. I've split off a separate ticket to discuss the distance value shortcode not working for all iterations of a loop, as these two issues are both complex enough to warrant individual tickets. It may still make sense to address them sequentially instead of concurrently, but it's better for organization to separate concerns.

Reduced the size of the map cache and got the memory usage WAY DOWN - but Render Time is still very high.
I am not sure if you're aware of all the ramifications of deleting an address from the cache, so I want to give you a warning here. The post or posts corresponding to any address you delete from cache will never appear as results in any View filtered by distance until the address is geocoded again by the map service. That means no map markers and no listings for these posts in any View with distance filtering. I am not sure if you are completely aware of that, so just a warning to be careful with this type of direct cache manipulation. Geocoding may be triggered again by:
- Editing the corresponding post in wp-admin, or creating/editing a different post containing the same address in any address field
- Displaying a marker at this address in a different map (i.e. a standalone map in the post template, or a map View with no distance filtering)
These are the most common geocoding triggers but there are a few others. In the next release of Maps, an automatic process will become available in the Maps settings page that will scan for uncached addresses and query the Google Maps API again to fetch missing values.

I think it will be helpful to establish a baseline of performance - a best-case scenario measurement of the time-to-first-byte (TTFB) for a test page containing this View and map. Then I can inspect each database query with Query Monitor.

For a baseline measurement, can you set up or advise me how best to go about setting up a standalone test of View #2: Shortcode Attribute Results View - INSIDE Radius? Or a clone of that View we can mess around with, without breaking the existing View #2?
I'd like to test the performance of this View dropped into a custom Page on the site as a standalone, without being placed inside Master View, without an API service providing the location, without being deferred in any way upon page load, with the minimum number of plugins and custom theme implementations possible. As close to a basic default Page as we can possibly make it. The shortcode attribute value normally provided by the API service should be hard-coded somehow using a known location that will produce results (circumventing the need for the nested OUTSIDE views for now). In the results of the View, I would like to include limited output in the loop as well. The post link shortcode and a map marker shortcode containing a popup with the post link shortcode again should be sufficient.

After we review and discuss the results, we can begin iteratively adding back other components and content to see where the bottlenecks occur.

It seems my IP is still whitelisted, at first glance. Can share staging login credentials again here? For your security credentials are deleted from existing tickets once they are resolved.

#2112567
Screen Shot 2021-07-12 at 2.34.00 PM.png
Screen Shot 2021-07-12 at 2.36.48 PM.png
Screen Shot 2021-07-12 at 2.34.08 PM.png

Please use this landing page - hidden link;
Okay I'm trying to get started, but on the front-end, I can't see anything in the post contents area for this page. The main site header, menu, and footer seem to be functioning but nothing appears in the_content() area. I tried to edit the page to see how the map and View were added or add them myself, but it seems my User has limited permissions and cannot edit the contents using the Yootheme builder (screenshots attached). Can you grant that permission for me so I can continue?

#2112607

Sorry about that, give me just a moment and I'll see what's missing.

#2112611

You're good to go! Missed a few permissions.

#2113701
Screen Shot 2021-07-13 at 4.49.21 PM.png

Doesn't seem to have had that effect. From what I can tell all results are showing and the map is search correctly. We ran this on both our live site and staging site. We followed the same steps outlined here...https://toolset.com/forums/topic/map-view-is-broken-no-changes-were-made/page/2/...Please let me know if you think I'm misunderstanding, but as of right now I'm not seeing any issues.
Oh this was a misunderstanding on my end. I didn't make the connection between this query and reducing the maps cache size. I thought maybe you had just dropped a chunk of rows/entries from the database's maps cache table arbitrarily, hoping to improve performance by limiting the query set. The SQL script you are referring to should not have the same negative impact I described since it was designed to drop entries that are unrelated to custom field values.

On to the testing. A very stripped-down baseline test of a View I created from scratch. It has a similar distance filter, with center set using a shortcode attribute, that value is hard-coded to a geocoded zip code location "Atlanta, GA 30313, USA". The results are sorted by distance from the same fixed location. I added this View to the baseline test page you created, along with a simple map shortcode:

[wpv-map-render map_id="map-tssupp-baseline" map_width="500px" map_height="300px"][/wpv-map-render]
[wpv-view name="toolset-baseline-view-test" mapcenter="Atlanta, GA 30313, USA"]

The baseline View's Loop editor contents :

[wpv-layout-start]
	[wpv-items-found]
	<!-- wpv-loop-start -->
		<wpv-loop>[wpv-post-link][wpv-map-marker map_id='map-tssupp-baseline' marker_id='marker-tssupp-baseline-[wpv-post-id]' marker_field='wpcf-dealer-address'][wpv-post-link][/wpv-map-marker]<br />
		</wpv-loop>
	<!-- wpv-loop-end -->
	[/wpv-items-found]
	[wpv-no-items-found]
		<strong>[wpml-string context="wpv-views"]No items found[/wpml-string]</strong>
	[/wpv-no-items-found]
[wpv-layout-end]

Page generation time is < 0.3 seconds according to Query Monitor (top right corner of screenshot). So the baseline of this simplified View's performance is not bad at all here, including distance filter and results sorted by distance too. I will spend some more time on this tomorrow. I'll start iteratively adding elements from the buy-local-dealer-locator-view-for-blocked-shortcode-attribute View to see when delays start adding up.

#2114293

A few more iterations and their results. I edited the baseline test page contents again:
hidden link

In the test View shortcode, I replaced a hard-coded mapcenter with a nested users_zip shortcode:

[wpv-view name="toolset-baseline-view-test" mapcenter="[users_zip]"]

Page generation time jumps from about .3 to about .5 in my case...not much significant difference.

Next, I replaced the Toolset Baseline View Test shortcode with the Blocked Master shortcode to reflect the setup on the live site:
[wpv-view name="buy-local-dealer-locator-view-for-blocked-master"]
Page generation time jumps back up to about 4.5 - 5 seconds, as expected based on the live site.

So next I edited the Blocked Master View:
hidden link
I replaced the shortcode for the View "Buy Local Dealer Locator View for Blocked - Shortcode Attribute" inside the Blocked Master View with my View Toolset Baseline View Test. I edited my baseline test View and adjusted the map marker shortcodes so they would be displayed in the map shown in the Blocked Master View. Page generation time drops back to around 1 second now.

So if I'm analyzing this correctly now, the majority of the difference in page generation time - from 1s to 4.5s - can be accounted for by the differences between the Views "Toolset Baseline View Test" and "Buy Local Dealer Locator View for Blocked - Shortcode Attribute", since that's the only thing that really changed in my local workflow/test scenario.

As far as I can tell, the differences between those Views cannot be accounted for in the View editor - the Views are too similar in terms of content and filters. The difference must be due to external factors. I suppose one such factor would be custom code applied to the View "Buy Local Dealer Locator View for Blocked - Shortcode Attribute". I see this relevant snippet you already mentioned:

function bl_users_distance_from_shortcode( $view_settings, $view_id ) {

  if ( $view_id == 155777 || $view_id == 155770 ) {
      $userscenter = wpv_do_shortcode('[users_zip]');
      $view_settings['distance_order']['source'] = 'fixed';
      $view_settings['distance_order']['center'] = $userscenter;
  }
  return $view_settings;
}
add_filter( 'wpv_view_settings', 'bl_users_distance_from_shortcode', 5, 2 );

As a quick test, I tried temporarily changing 155770 to something else, to effectively drop this filter. I'm not able to save that change, though:
"There was an error when updating snippets."
Maybe a separate permission I'm missing - can you check?

#2114381

I went ahead and made that change, but also I changed your role from Toolset Supporter to Administrator so there shouldn't be any other issues like that. You're free to continue testing and I look forward to seeing the numbers.

A note regarding permission: it appears that Toolset Access doesn't include anything for the settings in Custom Roles. Let me know if you know otherwise, because I would like to create a fully customized role for Toolset Supporters and any other guest support in the future.

Back to the custom php. This was written to solve a pretty important issue with that view. The results for a map using shortcode attribute need to be in order by distance from the location given. I was in disbelief when I realized that this wasn't a built in option, so I went the php route, but if you think the code is clunky and can give me pointers or if you think I'm mistaken and php isn't necessary, I'll happily put it in the bin. But I've got to have those results in order of distance. That's a no brainer.

BTW, made one small change when I was in there: wpv_do_shortcode() became do_shortcode(). I figured the wpv was specific to Toolset Views(?). Let me know if I'm mistaken. Don't think it affect speed though.

#2114431

I replaced the View ID to continue testing:

function bl_users_distance_from_shortcode( $view_settings, $view_id ) {

  if ( $view_id == 155777 || $view_id == 155770 ) {
      $userscenter = '29456';
      //$userscenter = do_shortcode('[users_zip]');
      $view_settings['distance_order']['source'] = 'fixed';
      $view_settings['distance_order']['center'] = $userscenter;
  }
  return $view_settings;
}
add_filter( 'wpv_view_settings', 'bl_users_distance_from_shortcode', 5, 2 );

Hard-coding a zip here results in a page generation time around 1 second for me, whereas setting $userscenter with the custom users_zip shortcode results in a page generation time around 4.5 seconds. I left that change in place, and you can compare with your own zip locally. That shortcode seems to be the source of about 3.5 seconds of delay for me. If that's the case for you as well, you're going to need to look for a solution that evaluates this shortcode in advance and allows you to access the value in a more performant way, in order to eliminate this bottleneck.

#2114435

Okay, let me try something, and I'll report back. Please keep the ticket open. I will be reworking this function starting now.

#2114533

Sure, I'll stand by for your update.

#2119221

"That shortcode seems to be the source of about 3.5 seconds of delay for me. If that's the case for you as well, you're going to need to look for a solution that evaluates this shortcode in advance and allows you to access the value in a more performant way, in order to eliminate this bottleneck."

Update... I've rewritten the add_filter function completely. Took out the do_shortcode portion and used the same php as the add_shortcode to build it out separately. That didn't speed it up. I replaced get_file_contents with cURL, and that didn't speed it up.

I'm working with the API developer to confirm there are no issues with the service. It's hard to imagine given how quickly the same API renders in other areas. Certainly not 6 seconds. On that note, I also tried using multiple IP API keys for each function, thinking maybe one key was getting crowded by 5 functions reaching out at once. That was a longshot, and it didn't pay off.

So, I'm still working to eliminate the latency. Please stand by in case the API devs don't find anything.

And if you think I'm misunderstood or have more ideas, please let me know.

#2119329

Hmmm, okay. Seems wasteful to hit the service more than once. There's no way to hold on to that value after the first service hit and bypass the service altogether next time the shortcode is called? Some kind of global or session variable?