Make WordPress Core

Opened 7 years ago

Last modified 13 months ago

#39003 new defect (bug)

menu_page_url() not working on Ajax call

Reported by: vinoth06's profile vinoth06 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 4.6.1
Component: Administration Keywords: needs-testing reporter-feedback
Focuses: Cc:

Description

menu_page_url( 'menu_slug', false ) is always returning empty string on AJAX response. The global $_parent_pages; is return NULL on AJAX call. But the same menu slug is working on normal page load.

Change History (6)

#1 @mostafa.s1990
5 years ago

  • Keywords needs-testing added

#2 @SergeyBiryukov
4 years ago

  • Component changed from General to Administration

#3 @donmhico
4 years ago

  • Keywords reporter-feedback added

Hello @vinoth06,

Welcome to WordPress trac! Thank you for submitting this ticket.

I looked more into the issue and I found out that I'm getting the correct value from menu_page_url() via AJAX if the current user has the capability to see the created admin page. If the user isn't logged-in or lacking capability then I also receive nothing.

Here's the code I used for testing.

<?php
// Create admin menu page.
function test_admin_menu_page() {
        add_menu_page( 'Test Menu', 'Test Menu', 'manage_options', 'test_menu', 'test_menu_page' );
}
add_action( 'admin_init', 'test_admin_menu_page' );

// AJAX handler.
function test_ajax_menu_page_url() {
        // Outputs - http://wp.test/wp-admin/admin.php?page=test_menu if logged in as admin.
        // Outputs nothing if logged-out.
        echo menu_page_url( 'test_menu', false );
        wp_die();
}
add_action( 'wp_ajax_ampu', 'test_ajax_menu_page_url' );
add_action( 'wp_ajax_nopriv_ampu', 'test_ajax_menu_page_url' );

#4 @vinoth06
4 years ago

Hi donmhico

Thanks for you code, I have modified your code which will get the result from AJAX request. Kindly check and share feedback.

I have created as an plugin, so you can add it in your plugin directory to activate.

I have added the comments too for your clarifications.

<?php
/**
 * Plugin Name: Menu Page URL on AJAX
 * Plugin URI: https://buffercode.com/plugin/frontend-dashboard
 * Description: Menu Page URL on AJAX
 * Version: 1
 * Author: vinoth06
 * Author URI: https://buffercode.com/
 * License: GPLv2
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 *
 */

if ( ! defined( 'ABSPATH' ) ) {
        exit;
}

add_action( 'admin_init', 'enqueue_jquery' );
function enqueue_jquery() {
        wp_enqueue_script( 'jquery' );
}

// Create admin menu page.
function test_admin_menu_page() {
        add_menu_page( 'Test Menu', 'Test Menu', 'manage_options', 'test_menu_slug', 'test_menu_page' );
}

// Hope its not admin_init. it should be admin_menu like in the line 21, Correct me if am wrong
//add_action( 'admin_init', 'test_admin_menu_page' );
add_action( 'admin_menu', 'test_admin_menu_page' );

// AJAX handler.
function test_ajax_menu_page_url() {
        // Outputs - http://wp.test/wp-admin/admin.php?page=test_menu if logged in as admin.
        // Outputs nothing if logged-out.
        echo menu_page_url( 'test_menu', false );
        // Try the below it will give the exact URL of the page.
        //echo admin_url( '/admin.php?page=test_menu' );

        // Conclusion: If you use menu_page_url in ajax return it will send empty string.
        wp_die();
}

add_action( 'wp_ajax_ampu', 'test_ajax_menu_page_url' );
add_action( 'wp_ajax_nopriv_ampu', 'test_ajax_menu_page_url' );

function test_menu_page() {
        ?>
    <form method="post" class="submitOnAjax" action="<?php echo admin_url( 'admin-ajax.php?action=ampu' ) ?>">
        <button type="submit">Submit</button>
    </form>
    <script>
        jQuery(document).ready(function ($) {
            $('body').on('submit', '.submitOnAjax', function (e) {
                var form = $(this);
                $.ajax({
                    type: 'POST',
                    url: form.attr('action'),
                    data: form.serialize(),
                    success: function (results) {
                        //Check the Value here
                        console.log(results);
                        // It will echo empty string
                    }
                });
                e.preventDefault();
            });
        });
    </script>
        <?php
}

#5 @donmhico
3 years ago

Hello @vinoth06,

Sorry for the delay in response. I re-checked and you are right menu_page_url() returns nothing in AJAX. I believe it's because global $_parent_pages; is NULL in AJAX request vs in normal admin request.

Upon diving a little deeper, I don't see menu.php being loaded in admin-ajax.php. So what you can do is edit your function to be

<?php
// AJAX handler.
function test_ajax_menu_page_url() {
    // Include the menu.
    if ( WP_NETWORK_ADMIN ) {
        require ABSPATH . 'wp-admin/network/menu.php';
    } elseif ( WP_USER_ADMIN ) {
        require ABSPATH . 'wp-admin/user/menu.php';
    } else {
        require ABSPATH . 'wp-admin/menu.php';
    }

    // Outputs - http://wp.test/wp-admin/admin.php?page=test_menu if logged in as admin.
    // Outputs nothing if logged-out.
    echo menu_page_url( 'test_menu_slug', false );
    // Try the below it will give the exact URL of the page.
    //echo admin_url( '/admin.php?page=test_menu' );

    // Conclusion: If you use menu_page_url in ajax return it will send empty string.
    wp_die();
}
add_action( 'wp_ajax_ampu', 'test_ajax_menu_page_url' );
add_action( 'wp_ajax_nopriv_ampu', 'test_ajax_menu_page_url' );

As for including this in the core, i'm not sure if we are suppose to have the menu available in AJAX. Let's hear more feedback.

#6 @zamandevs
13 months ago

Use cases needed.

It doesn't make sense to get the admin menu in the ajax call as all of the menus load on admin init. if requires ajax can explicitly include necessary menu files as we do in the other areas.

Note: See TracTickets for help on using tickets.