Skip Navigation

[Closed] WP_Query action hook on AJAX requests

This support ticket is created 7 years, 6 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.

No supporters are available to work today on Toolset forum. Feel free to create tickets and we will handle it as soon as we are online. Thank you for your understanding.

Sun Mon Tue Wed Thu Fri Sat
- 7:00 – 14:00 7:00 – 14:00 7:00 – 14:00 7:00 – 14:00 7:00 – 14:00 -
- 15:00 – 16:00 15:00 – 16:00 15:00 – 16:00 15:00 – 16:00 15:00 – 16:00 -

Supporter timezone: Europe/London (GMT+01:00)

Tagged: 

This topic contains 25 replies, has 3 voices.

Last updated by Nigel 7 years, 5 months ago.

Assisted by: Nigel.

Author
Posts
#448359

I am trying to:

Apply a filter using a hook to all AJAX\parametric search updates

What Happens:

I have my own plugin, that adds a filter to WP_Query. When a page loads the results are filtered perfectly. As soon as I update any of the results using AJAX parametric search, my filter is ignored and all posts are returned and then filtered according to parametric search settings only.

I expected to see:

I need all AJAX updates (across my entire site) to be subjected to my filter - is there any hook or something I can use?

Instead, I got:

My developer told me that the process for AJAX is different than that of a normal page. A page is executing WP_Query and then a filter, but AJAX is not executing the WP_Query - it is returning every post and then just filtering.

How can I make sure that all AJAX updates are subjected to my filter site-wide as they are with normal WP_Query?

The same thing also happens when using any of the Views Filters:

https://toolset.com/documentation/user-guides/views-filters/

#448427

Nigel
Supporter

Languages: English (English ) Spanish (Español )

Timezone: Europe/London (GMT+01:00)

Hi Tristian

The answer to whether or not WP_Query is run during ajax requests or not is... it depends.

Take a simple posts view with a category filter that outputs all results in one go with no pagination (and updates via ajax).

When you first load the page that view queries the database (via WP_Query) for all matching results.

Now, if you then set a filter to a category you are narrowing down the search results to exclude those which don't match the category.

So there is no need—and it would be wasteful—to re-query the database, because Views knows that the results to be returned are a sub-set of the initial results already obtained.

So WP_Query is not invoked, and none of the usual hooks (Views query filters or WordPress query hooks such as pre_get_posts) are triggered.

The depends part is...

If you now add pagination to the view then Views will re-interrogate the database when you modify a filter to return the correct number of results for the page of results currently being displayed because simply culling non-matching results isn't enough once you go past the first page.

So you can force your Views to trigger the usual hooks if you are using pagination.

If that is not viable for some reason, can you tell me more about what it is you are doing with your custom hooks so I can see if there is another solution?

#448523

Hi Nigel,

Thanks for the information... I'll explain the scenario. I think you have previously looked over similar issues in a different thread.

I have a CPT called 'Container' that has a parent CPT 'Company' set. I also have users that have a custom user meta field set to the 'Company' id.

'Container' posts are filtered so the only posts returned are where _wpcf_belongs_company_id=user-meta-value

I am trying to filter posts so a user only sees posts where their company is a parent.

The code below works until any type of AJAX search is performed - then all posts are returned for all companies - essentially the filter is bypassed.

I was previously experiencing a similar issue when using Access (nothing to do with my filter - just Access to restrict posts). Access was working, but then AJAX updates returned all posts. This errata was released:

https://toolset.com/errata/ajax-custom-search-wordpress-archives-always-return-results-regardless-access-permissions/

I was hoping this would solve my problem - but same thing happens.

I can give access to site easily with full links to demonstrate the issue.

It would be great to get this working!

Here is the main part of my filter

        ->registerFilter('container', $utils->getRoles('company-level-access'), function (\WP_Query $wpQuery) {

            // Get current user's company ID
            $companyId = Utils::getInstance()->getCurrentUserCompanyId();

            // Limit the query results to the containers that are child of the company owned by the logged-in user
            $wpQuery->set('meta_query', [
                [
                    'key' => '_wpcf_belongs_company_id',
                    'value' => $companyId,
                    'compare' => 'LIKE'
                ]
            ]);

        })
#448616

I can show the exact issue...

hidden link

When the page loads, there are no Container records (search button is also removed on this instance). However, place the cursor in the search textfield and press 'Return' to submit the form and all records are returned by AJAX.

If I switch the form to not use AJAX then things work as expected again (i.e. reload page).

The site will normally require a login throughout which I have temporarily removed - so this is showing the results for the 'Guest' user - but the issue is the same throughout the site.

This used to be the same issue that was affecting 'Access' that I mentioned in my previous post and was updated using the Errata released - so maybe someone has already troubleshooted a very similar problem and can point us in the right direction?

https://toolset.com/errata/ajax-custom-search-wordpress-archives-always-return-results-regardless-access-permissions/

Thanks

#448643

Nigel
Supporter

Languages: English (English ) Spanish (Español )

Timezone: Europe/London (GMT+01:00)

Hi Tristian

Yes, I remember working on the ajax issue with you before.

I've been running some tests locally to reproduce what's happening with your site.

Can I get credentials for that test site so I can see exactly how you have things set up?

I will mark your next reply as private so that I can get log-in credentials from you—you may want to create a temporary admin user for me to use that you can later delete. And be sure to have a current backup of your site if you need one, even though I don't intend to make any changes.

#448676

Nigel
Supporter

Languages: English (English ) Spanish (Español )

Timezone: Europe/London (GMT+01:00)

Screen Shot 2016-10-20 at 09.46.49.png

Quick update with an alternate approach that might work for your specific issue.

If the problem is that unauthorised users can trigger an ajax refresh by hitting enter in the text search field, why show the unauthorised users the filter controls at all?

Previously when speaking with devs about restricting access to views the response was to restrict access to the page where the view is placed.

You can't do that on an archive page.

But you can add some conditional shortcodes to determine whether or not to display the form filters on the archive page.

See the attached screenshot where guest users see an alternative to the filters (or could simply see nothing at all). Note that for guest users, role is empty. Depending on your needs you should be able to set the condition(s) so that only authorised users see the filters (and the results, of course).

#448678

Thanks...

I am already using conditionals like this elsewhere, however it would only solve part of the problem here.

Users with the same role will see the same filters, but depending on their user-meta will see different posts when using the filters

At the moment, when a user is allowed to filter using AJAX, my custom filter is being ignored...

#448680

I am just setting up access to my site - please can you mark the next reply as private so I can provide details? Thanks

#448697

Nigel
Supporter

Languages: English (English ) Spanish (Español )

Timezone: Europe/London (GMT+01:00)

Sorry, my second reply borked the private reply.

Here you go...

#448701

Thanks Nigel. All details provided. You should be able to see the exact problem easily now...

#448746

Nigel
Supporter

Languages: English (English ) Spanish (Español )

Timezone: Europe/London (GMT+01:00)

tristian.gif

OK, I dug deep.

I looked at how you have things set up but in the end created a test site to abstract from some of your customisations etc. (content templates for submit and reset buttons and for paginations controls? I haven't seen that one before).

I created a test site with the same custom post types and the same user field to store the company for that user, and created a custom WordPress archive for the container post type.

If you can follow what's going on, you will see it working in the screenshot, where the left browser is for a logged-in user that works at Microsoft, and the right browser is for a user that works at Apple. I hit enter in a custom text field to trigger an ajax refresh in each, and both maintain the restriction that the user only sees containers for their company.

Contrary to my earlier thinking, this does trigger a renewed query, which we can hook into with pre_get_posts.

But dumping the $query to the error logs to inspect what happens, views sets up what it itself calls a fake query, you can see $query contains an array wpv_fake_archive_loop.

So, testing for this we can add the meta query arguments which check the parent post id against the id stored in the user meta for our ajax updates.

Here is the code I added to set that up:

/**
 *	Limit containers according to user's company
 */
function filter_container_archive( $query ){

	$is_fake = $query->get('wpv_fake_archive_loop');

	if ( is_array( $is_fake ) ) {
		$archive_type = $is_fake['name'];		
	} else {
		$archive_type = '';		
	}

	if ( $archive_type == 'container' || is_post_type_archive( 'container' ) && !is_admin() ) {
         // for ajax updates .............  for initial page load

		$user_id = get_current_user_id();
		$user_company_id = get_user_meta( $user_id, 'wpcf-company-id', true );

		$query->set('meta_key', '_wpcf_belongs_company_id');
		$query->set('meta_value', $user_company_id );

	}

}
add_action( 'pre_get_posts', 'filter_container_archive', 101, 1 );

Take a look at that, I think you should be able to adapt it for your own site. Let me know how you get on.

#448760

Thanks for the info... I am going to review it with my developer and will let you know.

It looks like there are 2 issues - firstly, making AJAX updates work. Secondly, they need to work everywhere (archives, pages, posts, even nested views, etc.)

This is why I am hoping that there is 1 solution that is defined in my plugin and applies to all CPT's (Containers, etc.) regardless of how or where they are accessed.

It seems positive that a new query is triggered for AJAX updates as presumably it is easier to hook into.

I am aware that there are a lot of customisations that I have made (such as content templates for pagination\submit buttons\etc.) as well as many others.

For the most part however, it is almost an exclusively Toolset based site with almost no other plugins and almost all customisations are made through 1 plugin that uses CRED hooks to carry out related field updates, etc.

Thanks for your help so far. Will let you know once we've tried the code...

#448768

Nigel
Supporter

Languages: English (English ) Spanish (Español )

Timezone: Europe/London (GMT+01:00)

If you want it to work across different post types (each with their own custom query args etc.) the above will need modifying obviously, but the principle should be the same and you may be able to come up with a more generic solution for setting up your customisations across post types.

Anyway, yes, please, do let me know how you get on.

#448775

All CPT's where a parent is set will be included and once we can get it working for Containers it should be easy to add the others.

The only difference will be the companies themselves, where instead of filtering based on _wpcf_belongs_company_id, we will filter on the Company Post ID.

I'll let you know how we get on with the code shortly...

#448806

Hi Nigel,

We managed to restrict the 'Container' posts, but in doing so every other single page\post\etc. in the site. I thought it would be simple from here to just apply to Containers but apparently using pre_get_posts the post_type just has a value of "wp-types-user-group" so we can't filter explicitly by Container. Also it mentions on WordPress Codex that pre_get_posts may not work on archive pages so I am not sure if this is the right hook to use?

Also, have dumped the "$query" but cannot see "wpv_fake_archive_loop" which my developer thinks would be helpful.

It seems we are much closer without ultimately having something that works.

Would you be able to look at the code in my plugin - would really be appreciated?

The topic ‘[Closed] WP_Query action hook on AJAX requests’ is closed to new replies.