From 1113b2df5a8194912c60d6751700b45335cd1f4b Mon Sep 17 00:00:00 2001 From: Jb Audras Date: Wed, 20 Sep 2023 08:08:42 +0000 Subject: [PATCH] Taxonomy: Restrict term edit link generation in `WP_Terms_List_Table::handle_row_actions()`. This changeset restricts edit term link generation if the user lacks the `edit_term` cap in order to prevent PHP 8.1+ deprecations shown when a user lacks this capability and `get_edit_term_link()` returns null. Props thelovekesh, jrf. Fixes #59336. git-svn-id: https://develop.svn.wordpress.org/trunk@56631 602fd350-edb4-49c9-b593-d223f7449a82 --- .../includes/class-wp-terms-list-table.php | 14 +-- .../phpunit/tests/admin/wpTermsListTable.php | 88 +++++++++++++++++++ 2 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 tests/phpunit/tests/admin/wpTermsListTable.php diff --git a/src/wp-admin/includes/class-wp-terms-list-table.php b/src/wp-admin/includes/class-wp-terms-list-table.php index efbf68a9f4..4160577591 100644 --- a/src/wp-admin/includes/class-wp-terms-list-table.php +++ b/src/wp-admin/includes/class-wp-terms-list-table.php @@ -474,18 +474,18 @@ class WP_Terms_List_Table extends WP_List_Table { $taxonomy = $this->screen->taxonomy; $uri = wp_doing_ajax() ? wp_get_referer() : $_SERVER['REQUEST_URI']; - $edit_link = add_query_arg( - 'wp_http_referer', - urlencode( wp_unslash( $uri ) ), - get_edit_term_link( $tag, $taxonomy, $this->screen->post_type ) - ); - $actions = array(); if ( current_user_can( 'edit_term', $tag->term_id ) ) { $actions['edit'] = sprintf( '%s', - esc_url( $edit_link ), + esc_url( + add_query_arg( + 'wp_http_referer', + urlencode( wp_unslash( $uri ) ), + get_edit_term_link( $tag, $taxonomy, $this->screen->post_type ) + ) + ), /* translators: %s: Taxonomy term name. */ esc_attr( sprintf( __( 'Edit “%s”' ), $tag->name ) ), __( 'Edit' ) diff --git a/tests/phpunit/tests/admin/wpTermsListTable.php b/tests/phpunit/tests/admin/wpTermsListTable.php new file mode 100644 index 0000000000..2eb566d970 --- /dev/null +++ b/tests/phpunit/tests/admin/wpTermsListTable.php @@ -0,0 +1,88 @@ +user->create( array( 'role' => 'administrator' ) ); + self::$author_id = self::factory()->user->create( array( 'role' => 'author' ) ); + + self::$term_object = self::factory()->term->create_and_get( array( 'taxonomy' => self::CATEGORY_TAXONOMY ) ); + + require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php'; + require_once ABSPATH . 'wp-admin/includes/class-wp-terms-list-table.php'; + } + + public function set_up() { + parent::set_up(); + + $this->terms_list_table = new WP_Terms_List_Table(); + } + + /** + * Call an inaccessible (private or protected) method. + * + * @param object|string $object Object instance or class string to call the method of. + * @param string $method_name Name of the method to call. + * @param array $args Optional. Array of arguments to pass to the method. + * @return mixed Return value of the method call. + * @throws ReflectionException If the object could not be reflected upon. + */ + private function call_inaccessible_method( $object, $method_name, $args = array() ) { + $method = ( new ReflectionClass( $object ) )->getMethod( $method_name ); + $method->setAccessible( true ); + return $method->invokeArgs( $object, $args ); + } + + /** + * @covers WP_Terms_List_Table::handle_row_actions() + * + * @ticket 59336 + */ + public function test_handle_row_actions_as_author() { + wp_set_current_user( self::$author_id ); + + $actions = $this->call_inaccessible_method( $this->terms_list_table, 'handle_row_actions', array( self::$term_object, 'title', 'title' ) ); + + $this->assertStringContainsString( '
', $actions, 'Row actions should be displayed.' ); + $this->assertStringContainsString( 'View', $actions, 'View action should be displayed to the author.' ); + $this->assertStringNotContainsString( 'Edit', $actions, 'Edit action should not be displayed to the author.' ); + $this->assertStringNotContainsString( 'Delete', $actions, 'Delete action should not be displayed to the author.' ); + } + + /** + * @covers WP_Terms_List_Table::handle_row_actions() + * + * @ticket 59336 + */ + public function test_handle_row_actions_as_admin() { + wp_set_current_user( self::$admin_id ); + + $actions = $this->call_inaccessible_method( $this->terms_list_table, 'handle_row_actions', array( self::$term_object, 'title', 'title' ) ); + + $this->assertStringContainsString( '
', $actions, 'Row actions should be displayed.' ); + $this->assertStringContainsString( 'View', $actions, 'View action should be displayed to the admin.' ); + $this->assertStringContainsString( 'Edit', $actions, 'Edit action should be displayed to the admin.' ); + $this->assertStringContainsString( 'Delete', $actions, 'Delete action should be displayed to the admin.' ); + $this->assertStringContainsString( admin_url( 'term.php' ), $actions, 'Edit term link should be displayed to the admin.' ); + } +}