Adding admin-ajax.php to the frontend. Good or bad idea?

I love admin-ajax.php. But I hate having to localize in order to point frontend scripts to it, and I wish there was an equivalent, easy-to-find file for themes. (It also just bothers me to see frontend requests go through “/wp-admin/”. No practical reason, just looks ugly IMO.)

So I’ve simply copied admin-ajax.php to the root dir at “/ajax.php”, adjusted the include paths and removed the WP_ADMIN constant definition. Seems to work like gangbusters (I can now just direct all my frontend AJAX requests to /ajax.php! And I can still use the normal wp_ajax hooks in my plugins!).

Read More

But is this safe? What might go wrong? Since this isn’t built into core, I assume there’s a good reason as to why not. But looking through the code, I can’t see any immediate problems.

You’re smart–tell me if this approach is crazy. Or if there’s a simpler method that I’m overlooking.

Related posts

Leave a Reply

3 comments

  1. You could just use a RewriteRule to your .htaccess above the regular permalink rewrite rules:

    RewriteRule ^ajax$ /wp-admin/admin-ajax.php [L]
    

    Now send your AJAX requests to example.com/ajax, and never miss core changes to that file after upgrades.

  2. First: standardization. If you plan on using community plugins, chances are they are not going to care about your /ajax.php file in the document root. So they won’t use it.

    If you’re going to roll everything yourself, this isn’t an issue.

    Second: what if the core updates? Will you monitor and change your ajax file?

    Third: despite admin-ajax.php residing in wp-admin, it does not load any of the admin area stuff (eg. list tables, etc). Nor does it check auth or expose anything sensitive to non-logged in users. It’s just like a front-end file, in other words. Nothing to worry about.

    Fourth: Related to the first issue, some plugins will check before blindly loading ajax related functionality. An example is below. Your modified ajax.php will likely not cause that to load.

    <?php
    if (is_admin() && defined('DOING_AJAX') && DOING_AJAX) {
        //  load ajax stuff
    }
    

    Finally: What you complain about, using the localization to get the Ajax URL is a good thing to do. Why? Because Your JS files are not aware of any of the server side stuff. You’re going to hard a URL in that will break if/when the site moves? Seems like a bad choice.

    If you really don’t want to localize every script that uses Ajax, simple hook into wp_head really early and spit out the admin ajax URL. Problem solved (this is exactly how the admin area does it, by the way).

    <?php
    add_action('wp_head', 'wpse83650_lazy_ajax', 0, 0);
    function wpse83650_lazy_ajax()
    {
        ?>
        <script type="text/javascript">
        /* <![CDATA[ */
        var ajax_url = "<?php echo esc_js(admin_url('admin-ajax.php')); ?>";
        /* ]]> */
        </script>
        <?php
    }
    
  3. As with many things in WordPress, there are a near infinite number of ways to skin the cat. While all of the accepted methods work, I have found that they are less “neat” than using wp_localize_script to include ajax capability on the front end.

    Check this out:

    add_action( 'wp_enqueue_scripts', 'se83650_js' );
    function se83650_js()
    {
        wp_enqueue_script( 'se83650-js', plugin_dir_url( __FILE__ ) . 'js/se83650.js',  'jquery', '1.0.0', true );
        // First param is the name of the script you are attaching it to - in this case
        // it is the name of the custom script we added.  Second param is the name of 
        // the javscript Object that will be attached with your information.
        // Third param is an array of attributes, in this case, ajaxurl
        wp_localize_script( 'se83650-js', 'se83650Ajax', 
            array(
                // You can put any variables here you want for your script
                // such as plugin-specific variables or nonces, etc.
                'ajaxurl'    => admin_url( 'admin-ajax.php' )
            )
        );
    }
    

    And then in the se83650.js file, you would reference your variable with se83650Ajax.ajaxurl.

    The benefit of this technique is that if you end up with many plugins that try and duplicate this functionality, they aren’t including or overwriting the same variable. ajaxurl is pretty generic to include, this gets you more contained and it plays nicer with other developers.