Requests for some kind of wp_loaded hook have crept up here and there in trac over the years.

Typically, the requester is looking into doing front-end ajax requests and the like. There are other use cases, such as wanting to catch specific URIs -- e.g. a trailing /print/ to the url, which the permalink API is incapable of catching.

They all got rejected on grounds that there is the init hook that can be used just as well for ajax. Or the template_redirect hook in place of an ob_start hook. The list goes on.

When you want WP and plugins to be loaded and fully initialized, instantiated and ready to go, setting a priority to obscene levels on the init hook works (I typically use 1000000)... but it always feels like you're working around a crippled API.

Then, there is the front-end ajax. Yes, admin-ajax.php can be used unauthenticated... But the fact of the matter is, you can end up with SSL turned on when it's not useful, and the lack of an wp-ajax.php file makes many a plugin dev wonder where in the bloody hell he should catch his own requests.

It would be sweet if this all got fixed in WP 3.0.

The argument that goes "a hook already exists" seems extremely invalid to me. There are many places in WP where two hooks (and oftentimes many more) can be used to achieve the same result. Think wp_headers and send_headers, for instance. What they have in common is some kind of before/after flow, which init and template_redirect are currently lacking.

One could argue that parse_request is nearby init, and that wp is nearby template_redirect, so they'd be good enough. But the first of these parses expensive regular expressions before firing, and both are only known to WP junkies.

Suggested hooks for WP 3.0:

a wp-ajax.php file built similarly to admin-ajax.php.

an wp_loaded hook at the very end of wp-settings.php, with a commentary that tells plugin authors that init should be used to instantiate, wp_loaded should be used to act once everything is instantiated, and that wp-ajax.php has hooks that are specific to ajax requests.

an ob_start (or pre_load_template, or whatever...) hook at the very beginning of template-loader.php, with a commentary that tells plugin authors that the new hook should be used to instantiate such as output buffering once WP is fully loaded, while the second is traditionally used to pick an arbitrary template.

I'm not too sure thats a good idea myself. A front end ajax handler should be just that, a front end ajax hander, theres no real point having multiple entry points into the same actions.

I'm fine with the idea of making new hooks, personally. As long as *something* gets checked into WP 3.0 that makes it clear to plugin authors where they should be hooking ajax handlers.

The difference between init @ 1000 and wp_loaded, would be the same as the difference between, say, wp_headers and send_headers; or between request, and parse_request. It goes down to semantics: on the one hand side, you're "doing". On the other you're "done" - with no chance of seeing escalation races.

A functionality on the template_redirect hook might make the example more clear. Suppose you've a plugin that starts an output buffer on template_redirect. You'll make the hook start very early (e.g. -1000). The last thing you want is users who complain that your plugin isn't compatible with XYZ, only to note that XYZ is using the same hook as you are, and happens to doing its stuff, then die, before the template_redirect hook is fully executed.

The same goes here on the init hook. There are cases where you want to do something once WP is loaded, but the lack of a second hook is so that you'll occasionally see a plugin finish initializing itself *after* another plugin has decided that "it's my go, time to do something and die". Having a second hook around would make the first hook about instantiation, without action; the second would be about "at this point, everything that needs to be initialized is initialized; do stuff and die at will".

another potential addition could be to automatically set the wp-ajax.php url on the wp_head hook, much like we're doing in the backend. that way, plugins won't have to worry about inserting it, and will be able to use it directly.

I agree that it should be dropped, if it causes too much trouble. On the other hand however, it really is a great thing as it enables (nopriv) AJAX requests from the frontend, for those sites where admin-ajax.php is e.g. behind a .htaccess or running on SSL. So, I'd really like for it to be kept to have something to work with in those situations.

Thanks for that .htaccess. While it would work of course, I don't think it really is an option for a plugin that wants to use frontend AJAX, to have the site admin edit his original .htaccess.

And of course I agree, that SSL for the admin is awesome! However, if a plugin just wanted to do some AJAX (to obtain some arbitrary plugin value/string for display on the frontend), it would be total overhead to do that over a SSL connection, in my opinion.

What I'm saying: Frontend AJAX should be easy. The correct end-point is not really admin-ajax.php, as there might be cases were that would not be optimal, as stated for the two possibilities of .htaccess or SSL.

There's still some cleanup necessary, beyond the removal of the file. The attached patch removes the now obsolete wp_ajaxurl() again (as the URL would be wrong anyway) and fixes a doc line.

(To come back to the dev chat: I now understand the security problems caused by wp-ajax.php, so I agree to the removal. However, I would appreciate, if a core dev could maybe write a blog post on how to do frontend AJAX the correct way (including workarounds for the mentioned problems). nacin, might be something for your site :-) )

Reopening this because I believe there may be a way to accomplish this in a way that doesn't duplicate a lot of code and cause security vulnerabilities and be backwards compatible, and add no new ajax hooks.

I think we can make wp-ajax.php the primary ajax handler, at least from the standpoint that the actions are fired in this file, separate out the functionality in the switch statements in admin-ajax.php into actual functions, have admin-ajax.php hook into the wp_ajax_ and wp_ajax_nopriv_ actions, and include wp-ajax.php

This is just a thought, with a proof of concept patch.

Let me know what your thoughts are, if it is deemed that this still isn't a good scenario then we can close the ticket.

I still believe we can do without this patch as long as we keep pushing education as the answer. One of the biggest points of confusion I see is surrounding the fact that admin-ajax.php lives in wp-admin, and people assume that it should not be used for frontend ajax. We also see scenarios where the security put in place on wp-admin causes issues. I offered a suggestion in a previous comment for this as well.

This patch should be backwards compatible, and would allow both admin-ajax.php and wp-ajax.php to be used as ajax endpoints. It moves a lot of code that should have probably been in separated functions to begin with, and utilizes the WP API for hooking in, rather than huge switch statements.

In any case, I figured I had some free time, an idea and thought we could give this another go.

admin-ajax.php fires the 'admin_init' action, executing code hooked to it from inside the above mentioned included files.

Theoretically, the only way to avoid loading admin code for theme-side AJAX requests is to explicitly check for DOING_AJAX before loading anything. This pollutes plugin code with a lame constant check that is likely to go away eventually, given the move away from constant usage in recent WordPress versions.

I'd settle for a front-ajax.php inside of /wp-admin/ that didn't set WP_ADMIN and didn't fire the 'admin_init' action. I'd even go for a $_GET hack to bypass those two issues:

admin-ajax.php fires the 'admin_init' action, executing code hooked to it from inside the above mentioned included files.

Theoretically, the only way to avoid loading admin code for theme-side AJAX requests is to explicitly check for DOING_AJAX before loading anything. This pollutes plugin code with a lame constant check that is likely to go away eventually, given the move away from constant usage in recent WordPress versions.

I'd settle for a front-ajax.php inside of /wp-admin/ that didn't set WP_ADMIN and didn't fire the 'admin_init' action. I'd even go for a $_GET hack to bypass those two issues:

var ajaxurl = 'http://bbp.com/wp-admin/admin-ajax.php?admin=false';

I'm beginning to think that we should have the frontend-ajax.php live in wp-includes.

We can update the secure cookie setting to also set the cookie for this path / folder.

It's more obvious that it isn't an admin request.

It shouldn't accidentally trigger a bad plugin test for admin requests that looks at the url.

We can update the secure cookie setting to also set the cookie for this path / folder.

Not sure I like this. But I do like the idea overall. I would probably like to keep it in wp-admin though, to get that cookie benefit. I've been wanting to retire the wp-content/plugins secure cookie for a while; adding another is kind of lame. (Though could be paired nicely with an overhaul of our cookie handling, in particular to set us up for cross-domain login for multisite, but I digress.)

Yeah, it's time for a new ajax handler that does not set WP_ADMIN or fire admin_init. This was a mess when working with the customizer. I wouldn't mind having all new core handlers go through it, either. We do have some decisions to make on exactly how it should work and load things — probably worth going through tickets to see what other complaints and ideas there are.

I think that a front-end Ajax would be very handy! One thing that I think would be beneficial to have is a core-supported way of handling javascript enqueues via javascript. Let's say we have a theme that loads full posts via Ajax (P2 would be a good example, also any theme with built in infinite scroll) and we also have a custom plugin installed which provides a shortcode that relies on javascript for some of it's functionality. More times than not this plugin will conditionally print its javascript in the footer (​like a Jedi!). The problem is that the current page has already loaded all of it's scripts and the shortcode's script will never be loaded.