diff --git a/plugins/woocommerce-admin/client/header/activity-panel/panels/inbox.js b/plugins/woocommerce-admin/client/header/activity-panel/panels/inbox.js index 10e2848f338..c93bc94b3ca 100644 --- a/plugins/woocommerce-admin/client/header/activity-panel/panels/inbox.js +++ b/plugins/woocommerce-admin/client/header/activity-panel/panels/inbox.js @@ -113,6 +113,8 @@ export default compose( page: 1, per_page: QUERY_DEFAULTS.pageSize, type: 'info,warning', + orderby: 'date', + order: 'desc', }; const notes = getNotes( inboxQuery ); diff --git a/plugins/woocommerce-admin/client/header/activity-panel/unread-indicators.js b/plugins/woocommerce-admin/client/header/activity-panel/unread-indicators.js index c90c33f643b..d6174b72aea 100644 --- a/plugins/woocommerce-admin/client/header/activity-panel/unread-indicators.js +++ b/plugins/woocommerce-admin/client/header/activity-panel/unread-indicators.js @@ -11,6 +11,9 @@ export function getUnreadNotes( select ) { const notesQuery = { page: 1, per_page: 1, + type: 'info,warning', + orderby: 'date', + order: 'desc', }; const latestNote = getNotes( notesQuery ); diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-admin-notes-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-admin-notes-controller.php index 87f0ed6e96d..6872f6b190b 100644 --- a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-admin-notes-controller.php +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-admin-notes-controller.php @@ -43,6 +43,7 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller { 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), + 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) @@ -108,34 +109,9 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller { * @return WP_REST_Response */ public function get_items( $request ) { - $per_page = isset( $request['per_page'] ) ? intval( $request['per_page'] ) : 10; - if ( $per_page <= 0 ) { - $per_page = 10; - } + $query_args = $this->prepare_objects_query( $request ); - $page = isset( $request['page'] ) ? intval( $request['page'] ) : 1; - if ( $page <= 0 ) { - $page = 1; - } - - $args = array( - 'per_page' => $per_page, - 'page' => $page, - ); - - $type = isset( $request['type'] ) ? $request['type'] : ''; - $type = sanitize_text_field( $type ); - if ( ! empty( $type ) ) { - $args['type'] = $type; - } - - $status = isset( $request['status'] ) ? $request['status'] : ''; - $status = sanitize_text_field( $status ); - if ( ! empty( $status ) ) { - $args['status'] = $status; - } - - $notes = WC_Admin_Notes::get_notes( 'edit', $args ); + $notes = WC_Admin_Notes::get_notes( 'edit', $query_args ); $data = array(); foreach ( (array) $notes as $note_obj ) { @@ -145,11 +121,44 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller { } $response = rest_ensure_response( $data ); - $response->header( 'X-WP-Total', WC_Admin_Notes::get_notes_count( $type, $status ) ); + $response->header( 'X-WP-Total', WC_Admin_Notes::get_notes_count( $query_args['type'], $query_args['status'] ) ); return $response; } + /** + * Prepare objects query. + * + * @param WP_REST_Request $request Full details about the request. + * @return array + */ + protected function prepare_objects_query( $request ) { + $args = array(); + $args['order'] = $request['order']; + $args['orderby'] = $request['orderby']; + $args['per_page'] = $request['per_page']; + $args['page'] = $request['page']; + $args['type'] = isset( $request['type'] ) ? $request['type'] : array(); + $args['status'] = isset( $request['status'] ) ? $request['status'] : array(); + + if ( 'date' === $args['orderby'] ) { + $args['orderby'] = 'date_created'; + } + + /** + * Filter the query arguments for a request. + * + * Enables adding extra arguments or setting defaults for a post + * collection request. + * + * @param array $args Key value array of query var to query value. + * @param WP_REST_Request $request The request used. + */ + $args = apply_filters( 'woocommerce_rest_admin_notes_object_query', $args, $request ); + + return $args; + } + /** * Check whether a given request has permission to read a single note. * @@ -300,20 +309,65 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller { * @return array */ public function get_collection_params() { - $params = array(); - $params['context'] = $this->get_context_param( array( 'default' => 'view' ) ); - $params['type'] = array( - 'description' => __( 'Type of note.', 'woocommerce-admin' ), + $params = array(); + $params['context'] = $this->get_context_param( array( 'default' => 'view' ) ); + $params['order'] = array( + 'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce-admin' ), 'type' => 'string', - 'enum' => WC_Admin_Note::get_allowed_types(), + 'default' => 'desc', + 'enum' => array( 'asc', 'desc' ), 'validate_callback' => 'rest_validate_request_arg', ); - $params['status'] = array( - 'description' => __( 'Status of note.', 'woocommerce-admin' ), + $params['orderby'] = array( + 'description' => __( 'Sort collection by object attribute.', 'woocommerce-admin' ), 'type' => 'string', - 'enum' => WC_Admin_Note::get_allowed_statuses(), + 'default' => 'date', + 'enum' => array( + 'note_id', + 'date', + 'type', + 'title', + 'status', + ), 'validate_callback' => 'rest_validate_request_arg', ); + $params['page'] = array( + 'description' => __( 'Current page of the collection.', 'woocommerce-admin' ), + 'type' => 'integer', + 'default' => 1, + 'sanitize_callback' => 'absint', + 'validate_callback' => 'rest_validate_request_arg', + 'minimum' => 1, + ); + $params['per_page'] = array( + 'description' => __( 'Maximum number of items to be returned in result set.', 'woocommerce-admin' ), + 'type' => 'integer', + 'default' => 10, + 'minimum' => 1, + 'maximum' => 100, + 'sanitize_callback' => 'absint', + 'validate_callback' => 'rest_validate_request_arg', + ); + $params['type'] = array( + 'description' => __( 'Type of note.', 'woocommerce-admin' ), + 'type' => 'array', + 'sanitize_callback' => 'wp_parse_slug_list', + 'validate_callback' => 'rest_validate_request_arg', + 'items' => array( + 'enum' => WC_Admin_Note::get_allowed_types(), + 'type' => 'string', + ), + ); + $params['status'] = array( + 'description' => __( 'Status of note.', 'woocommerce-admin' ), + 'type' => 'array', + 'sanitize_callback' => 'wp_parse_slug_list', + 'validate_callback' => 'rest_validate_request_arg', + 'items' => array( + 'enum' => WC_Admin_Note::get_allowed_statuses(), + 'type' => 'string', + ), + ); return $params; } diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-notes-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-notes-data-store.php index 78946c24e0b..2edf11074e3 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-notes-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-notes-data-store.php @@ -250,24 +250,21 @@ class WC_Admin_Notes_Data_Store extends WC_Data_Store_WP implements WC_Object_Da public function get_notes( $args = array() ) { global $wpdb; - $per_page = isset( $args['per_page'] ) ? intval( $args['per_page'] ) : 10; - if ( $per_page <= 0 ) { - $per_page = 10; - } - - $page = isset( $args['page'] ) ? intval( $args['page'] ) : 1; - if ( $page <= 0 ) { - $page = 1; - } - - $offset = $per_page * ( $page - 1 ); + $defaults = array( + 'per_page' => get_option( 'posts_per_page' ), + 'page' => 1, + 'order' => 'DESC', + 'orderby' => 'date_created', + ); + $args = wp_parse_args( $args, $defaults ); + $offset = $args['per_page'] * ( $args['page'] - 1 ); $where_clauses = $this->get_notes_where_clauses( $args ); $query = $wpdb->prepare( - "SELECT note_id, title, content FROM {$wpdb->prefix}wc_admin_notes WHERE 1=1{$where_clauses} ORDER BY note_id DESC LIMIT %d, %d", + "SELECT note_id, title, content FROM {$wpdb->prefix}wc_admin_notes WHERE 1=1{$where_clauses} ORDER BY {$args['orderby']} {$args['order']} LIMIT %d, %d", $offset, - $per_page + $args['per_page'] ); // WPCS: unprepared SQL ok. return $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared @@ -280,7 +277,7 @@ class WC_Admin_Notes_Data_Store extends WC_Data_Store_WP implements WC_Object_Da * @param string $status Comma separated list of statuses. * @return array An array of objects containing a note id. */ - public function get_notes_count( $type = '', $status = '' ) { + public function get_notes_count( $type = array(), $status = array() ) { global $wpdb; $where_clauses = $this->get_notes_where_clauses( @@ -308,8 +305,7 @@ class WC_Admin_Notes_Data_Store extends WC_Data_Store_WP implements WC_Object_Da $allowed_types = WC_Admin_Note::get_allowed_types(); $where_type_array = array(); if ( isset( $args['type'] ) ) { - $args_types = explode( ',', $args['type'] ); - foreach ( (array) $args_types as $args_type ) { + foreach ( $args['type'] as $args_type ) { $args_type = trim( $args_type ); if ( in_array( $args_type, $allowed_types, true ) ) { $where_type_array[] = "'" . esc_sql( $args_type ) . "'"; @@ -320,8 +316,7 @@ class WC_Admin_Notes_Data_Store extends WC_Data_Store_WP implements WC_Object_Da $allowed_statuses = WC_Admin_Note::get_allowed_statuses(); $where_status_array = array(); if ( isset( $args['status'] ) ) { - $args_statuses = explode( ',', $args['status'] ); - foreach ( (array) $args_statuses as $args_status ) { + foreach ( $args['status'] as $args_status ) { $args_status = trim( $args_status ); if ( in_array( $args_status, $allowed_statuses, true ) ) { $where_status_array[] = "'" . esc_sql( $args_status ) . "'"; diff --git a/plugins/woocommerce-admin/includes/notes/class-wc-admin-notes.php b/plugins/woocommerce-admin/includes/notes/class-wc-admin-notes.php index d009e4cb660..9f48b8fdb37 100644 --- a/plugins/woocommerce-admin/includes/notes/class-wc-admin-notes.php +++ b/plugins/woocommerce-admin/includes/notes/class-wc-admin-notes.php @@ -86,7 +86,7 @@ class WC_Admin_Notes { * @param string $status Comma separated list of statuses. * @return int */ - public static function get_notes_count( $type = '', $status = '' ) { + public static function get_notes_count( $type = array(), $status = array() ) { $data_store = WC_Data_Store::load( 'admin-note' ); return $data_store->get_notes_count( $type, $status ); } @@ -112,7 +112,7 @@ class WC_Admin_Notes { $data_store = WC_Data_Store::load( 'admin-note' ); $raw_notes = $data_store->get_notes( array( - 'status' => WC_Admin_Note::E_WC_ADMIN_NOTE_SNOOZED, + 'status' => array( WC_Admin_Note::E_WC_ADMIN_NOTE_SNOOZED ), ) ); $now = new DateTime(); diff --git a/plugins/woocommerce-admin/lib/client-assets.php b/plugins/woocommerce-admin/lib/client-assets.php index c61e3825c0d..31b2f35a2a9 100644 --- a/plugins/woocommerce-admin/lib/client-assets.php +++ b/plugins/woocommerce-admin/lib/client-assets.php @@ -194,7 +194,7 @@ function wc_admin_print_script_settings() { 'weekdaysShort' => array_values( $wp_locale->weekday_abbrev ), ), 'currentUserData' => $current_user_data, - 'alertCount' => WC_Admin_Notes::get_notes_count( 'error,update', 'unactioned' ), + 'alertCount' => WC_Admin_Notes::get_notes_count( array( 'error', 'update' ), array( 'unactioned' ) ), 'reviewsEnabled' => get_option( 'woocommerce_enable_reviews' ), 'manageStock' => get_option( 'woocommerce_manage_stock' ), 'commentModeration' => get_option( 'comment_moderation' ), diff --git a/plugins/woocommerce-admin/tests/api/admin-notes.php b/plugins/woocommerce-admin/tests/api/admin-notes.php index 2a93ef5a335..54b63a23c94 100644 --- a/plugins/woocommerce-admin/tests/api/admin-notes.php +++ b/plugins/woocommerce-admin/tests/api/admin-notes.php @@ -228,6 +228,44 @@ class WC_Tests_API_Admin_Notes extends WC_REST_Unit_Test_Case { $this->assertEmpty( $notes ); } + /** + * Test ordering of notes. + */ + public function test_order_notes() { + wp_set_current_user( $this->user ); + + $request = new WP_REST_Request( 'GET', $this->endpoint ); + $request->set_query_params( + array( + 'orderby' => 'title', + 'order' => 'asc', + ) + ); + $response = $this->server->dispatch( $request ); + $notes = $response->get_data(); + + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( 3, count( $notes ) ); + $this->assertEquals( $notes[0]['title'], 'PHPUNIT_TEST_NOTE_1_TITLE' ); + $this->assertEquals( $notes[1]['title'], 'PHPUNIT_TEST_NOTE_2_TITLE' ); + $this->assertEquals( $notes[2]['title'], 'PHPUNIT_TEST_NOTE_3_TITLE' ); + + $request = new WP_REST_Request( 'GET', $this->endpoint ); + $request->set_query_params( + array( + 'orderby' => 'status', + 'order' => 'desc', + ) + ); + $response = $this->server->dispatch( $request ); + $notes = $response->get_data(); + + $this->assertEquals( 3, count( $notes ) ); + $this->assertEquals( $notes[0]['status'], WC_Admin_Note::E_WC_ADMIN_NOTE_UNACTIONED ); + $this->assertEquals( $notes[1]['status'], WC_Admin_Note::E_WC_ADMIN_NOTE_SNOOZED ); + $this->assertEquals( $notes[2]['status'], WC_Admin_Note::E_WC_ADMIN_NOTE_ACTIONED ); + } + /** * Test getting lots of notes without permission. It should fail. *