1

I have a custom post type I've created, and I've added an admin submenu page to display some data it generates. So far, so good. I'm displaying the data with my local extension of WP_List_Table, and I want one of the columns to link to a detailed view of the item in the row. So,

Add menu:

add_submenu_page('edit.php?post_type=cwr_ticket_page',
    __( 'Tickets', $this->plugin_text_domain ), // page title
    __( 'Sold Tickets', $this->plugin_text_domain ), // menu title
    'read', // capability
    'cwr-tickets', // menu slug
    array( $this, 'load_ticket_list_table' ) // callback

"Sold Tickets" correctly shows up as a sub-menu on my "Ticket Pages" admin menu.

The resulting url is http://localhost:8181/wp-admin/edit.php?post_type=cwr_ticket_page&page=cwr-tickets, and that page correctly renders my table, all nicely using WP styles, with sortable columns and pagination, etc.... But one of my columns is "Details" and I want it to contain a link to a deeper view of the data represented in the given row.

So for the entries in my "Details" column, I want something like

<a href="http://localhost:8181/wp-admin/edit.php?post_type=cwr_ticket_page&page=cwr-tickets&view=details&ticketID=abc123">view</a>

The question is, how to build that URL. I thought I could use add_query_arg, but it's behaving oddly.

My column_default method override looks like this:

public function column_default( $item, $column_name ) {
    switch ( $column_name ) {
        ...
        case 'details':
            $args = array (
                'view'    => 'details',
                'ticketID' => '12345'        //placeholder for development
            );
            return '<a href="'
                . esc_url( add_query_arg( $args,
                    menu_page_url( 'cwr-tickets', false ) ) )
                . '">View</a>';
        ...
    }
}

I've tried it both with and without the esc_url wrapper, but either way, it ends up moving the existing page query arg to the end, and prepending it with #038; instead of the ampersand. That is, I get

<a href="//localhost:8181/wp-admin/edit.php?post_type=cwr_ticket_page&view=details&ticketID=12345#038;page=cwr-tickets">View</a>

By the way, I'm in no way wed to this use of menu_page_url and add_query_arg; the question is, how to (properly / the WordPress way) construct this CPT admin submenu URL for the links?

2 Answers 2

1

From your question:

I've tried it both with and without the esc_url wrapper, but either way, it ends up moving the existing page query arg to the end, and prepending it with #038; instead of the ampersand.

And from your answer:

The root cause was determined to be that menu_page_url runs through esc_url even when display is set to false

So yes, that's correct, and you could alternatively manually construct the URL like so: admin_url( 'edit.php?post_type=cwr_ticket_page&page=cwr-tickets' ).

But as for this:

how to (properly / the WordPress way) construct this CPT admin submenu URL for the links

Since you're linking to the same page, then just use add_query_arg( $args ):

$link = '<a href="' . esc_url( add_query_arg( $args ) ) . '">View</a>';

Because add_query_arg() will default to using the current URL.

0

It appears this has been causing consternation for 11+ years, as it was reported as bug #18274 back then. The root cause was determined to be that menu_page_url runs through esc_url even when display is set to false, and it was decided that although that's probably undesirable, it was "too late" (comment #9 from lead developer @nacin).

I can't find a follow-on addition to WordPress core that returns the URL properly (i.e., unencoded), so I don't know if there's a "right WordPress way" to do this, but my workaround was to extract the relevant code from menu_page_url and not run it through esc_url:

        case 'details':
            global $_parent_pages;
            $parent_slug = $_parent_pages[ 'cwr-tickets' ];
            $url = admin_url( add_query_arg( 'page', 'cwr-tickets',
                $parent_slug ) );
            $args = array (
                'view'     => 'details',
                'ticketID' => '12345'
            );
            return '<a href="'
                . esc_url( add_query_arg( $args,
                    $url ) )
                . '">View</a>';

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.