Add store notice around processing historical data. (https://github.com/woocommerce/woocommerce-admin/pull/1763)

* Add store notice around processing historical data.

* Cleanup

* Handle PR feedback.

* Clean up `add` logic and add empty content_data. Also add logic to get_notes_count so that we can hide unactioned statuses.

* Add the ability to update a note, and to also mark a status when an alert is clicked.

* Remove mark_actioned call on sync

* add missing todo
This commit is contained in:
Justin Shreve 2019-03-12 09:13:20 -04:00 committed by GitHub
parent 6c9b96f49a
commit 1348245406
20 changed files with 391 additions and 105 deletions

View File

@ -37,6 +37,38 @@ const orderStatuses = Object.keys( wcSettings.orderStatuses )
} );
export const analyticsSettings = applyFilters( SETTINGS_FILTER, [
{
name: 'woocommerce_rebuild_reports_data',
label: __( 'Rebuild reports data:', 'wc-admin' ),
inputType: 'button',
inputText: __( 'Rebuild reports', 'wc-admin' ),
helpText: __(
'This tool will rebuild all of the information used by the reports. ' +
'Data will be processed in the background and may take some time depending on the size of your store.',
'wc-admin'
),
callback: ( resolve, reject, addNotice ) => {
const errorMessage = __( 'There was a problem rebuilding your report data.', 'wc-admin' );
apiFetch( { path: '/wc/v3/system_status/tools/rebuild_stats', method: 'PUT' } )
.then( response => {
if ( response.success ) {
addNotice( { status: 'success', message: response.message } );
// @todo This should be changed to detect when the lookup table population is complete.
setTimeout( () => resolve(), 300000 );
} else {
addNotice( { status: 'error', message: errorMessage } );
reject();
}
} )
.catch( error => {
if ( error && error.message ) {
addNotice( { status: 'error', message: error.message } );
}
reject();
} );
},
},
{
name: 'woocommerce_excluded_report_order_statuses',
label: __( 'Excluded Statuses:', 'wc-admin' ),
@ -89,36 +121,4 @@ export const analyticsSettings = applyFilters( SETTINGS_FILTER, [
initialValue: wcSettings.wcAdminSettings.woocommerce_actionable_order_statuses || [],
defaultValue: [ 'processing', 'on-hold' ],
},
{
name: 'woocommerce_rebuild_reports_data',
label: __( 'Rebuild reports data:', 'wc-admin' ),
inputType: 'button',
inputText: __( 'Rebuild reports', 'wc-admin' ),
helpText: __(
'This tool will rebuild all of the information used by the reports. ' +
'Data will be processed in the background and may take some time depending on the size of your store.',
'wc-admin'
),
callback: ( resolve, reject, addNotice ) => {
const errorMessage = __( 'There was a problem rebuilding your report data.', 'wc-admin' );
apiFetch( { path: '/wc/v3/system_status/tools/rebuild_stats', method: 'PUT' } )
.then( response => {
if ( response.success ) {
addNotice( { status: 'success', message: response.message } );
// @todo This should be changed to detect when the lookup table population is complete.
setTimeout( () => resolve(), 300000 );
} else {
addNotice( { status: 'error', message: errorMessage } );
reject();
}
} )
.catch( error => {
if ( error && error.message ) {
addNotice( { status: 'error', message: error.message } );
}
reject();
} );
},
},
] );

View File

@ -8,6 +8,8 @@ import { IconButton, Button, Dashicon } from '@wordpress/components';
import classnames from 'classnames';
import interpolateComponents from 'interpolate-components';
import { compose } from '@wordpress/compose';
import { noop } from 'lodash';
import { withDispatch } from '@wordpress/data';
/**
* WooCommerce dependencies
@ -64,7 +66,7 @@ class StoreAlerts extends Component {
const alerts = this.props.alerts || [];
const preloadAlertCount = wcSettings.alertCount && parseInt( wcSettings.alertCount );
if ( preloadAlertCount > 0 && 0 === alerts.length ) {
if ( preloadAlertCount > 0 && this.props.isLoading ) {
return <StoreAlertsPlaceholder hasMultipleAlerts={ preloadAlertCount > 1 } />;
} else if ( 0 === alerts.length ) {
return null;
@ -78,11 +80,22 @@ class StoreAlerts extends Component {
'is-alert-error': 'error' === type,
'is-alert-update': 'update' === type,
} );
const actions = alert.actions.map( action => (
<Button key={ action.name } isDefault href={ action.url }>
{ action.label }
</Button>
) );
const actions = alert.actions.map( action => {
const markStatus = () => {
this.props.updateNote( alert.id, { status: action.status } );
};
return (
<Button
key={ action.name }
isDefault
href={ action.url }
onClick={ '' === action.status ? noop : markStatus }
>
{ action.label }
</Button>
);
} );
return (
<Card
@ -135,15 +148,29 @@ class StoreAlerts extends Component {
export default compose(
withSelect( select => {
const { getNotes } = select( 'wc-api' );
const { getNotes, isGetNotesRequesting } = select( 'wc-api' );
const alertsQuery = {
page: 1,
per_page: QUERY_DEFAULTS.pageSize,
type: 'error,update',
status: 'unactioned',
};
const alerts = getNotes( alertsQuery );
// Filter out notes that may have been marked actioned or not delayed after the initial request
const filterNotes = note => 'unactioned' === note.status;
const alerts = getNotes( alertsQuery ).filter( filterNotes );
return { alerts };
const isLoading = isGetNotesRequesting( alertsQuery );
return {
alerts,
isLoading,
};
} ),
withDispatch( dispatch => {
const { updateNote } = dispatch( 'wc-api' );
return {
updateNote,
};
} )
)( StoreAlerts );

View File

@ -4,8 +4,10 @@
*/
import operations from './operations';
import selectors from './selectors';
import mutations from './mutations';
export default {
operations,
selectors,
mutations,
};

View File

@ -0,0 +1,10 @@
/** @format */
const updateNote = operations => ( noteId, noteFields ) => {
const resourceKey = 'note';
operations.update( [ resourceKey ], { [ resourceKey ]: { noteId, ...noteFields } } );
};
export default {
updateNote,
};

View File

@ -19,6 +19,10 @@ function read( resourceNames, fetch = apiFetch ) {
return [ ...readNotes( resourceNames, fetch ), ...readNoteQueries( resourceNames, fetch ) ];
}
function update( resourceNames, data, fetch = apiFetch ) {
return [ ...updateNote( resourceNames, data, fetch ) ];
}
function readNoteQueries( resourceNames, fetch ) {
const filteredNames = resourceNames.filter( name => isResourcePrefix( name, 'note-query' ) );
@ -71,6 +75,25 @@ function readNote( resourceName, fetch ) {
} );
}
function updateNote( resourceNames, data, fetch ) {
const resourceName = 'note';
if ( resourceNames.includes( resourceName ) ) {
const { noteId, ...noteFields } = data[ resourceName ];
const url = `${ NAMESPACE }/admin/notes/${ noteId }`;
return [
fetch( { path: url, method: 'PUT', data: noteFields } )
.then( note => {
return { [ resourceName + ':' + noteId ]: { data: note } };
} )
.catch( error => {
return { [ resourceName + ':' + noteId ]: { error } };
} ),
];
}
return [];
}
export default {
read,
update,
};

View File

@ -16,6 +16,7 @@ function createWcApiSpec() {
mutations: {
...settings.mutations,
...user.mutations,
...notes.mutations,
},
selectors: {
...items.selectors,
@ -42,6 +43,7 @@ function createWcApiSpec() {
return [
...settings.operations.update( resourceNames, data ),
...user.operations.update( resourceNames, data ),
...notes.operations.update( resourceNames, data ),
];
},
},

View File

@ -63,6 +63,11 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller {
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_item' ),
'permission_callback' => array( $this, 'update_items_permissions_check' ),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);
@ -124,6 +129,12 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller {
$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 );
$data = array();
@ -134,7 +145,7 @@ 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() );
$response->header( 'X-WP-Total', WC_Admin_Notes::get_notes_count( $type, $status ) );
return $response;
}
@ -167,6 +178,49 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller {
return true;
}
/**
* Update a single note.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_REST_Request|WP_Error
*/
public function update_item( $request ) {
$note = WC_Admin_Notes::get_note( $request->get_param( 'id' ) );
if ( ! $note ) {
return new WP_Error(
'woocommerce_admin_notes_invalid_id',
__( 'Sorry, there is no resouce with that ID.', 'wc-admin' ),
array( 'status' => 404 )
);
}
// @todo Status is the only field that can be updated at the moment. We should also implement the "date reminder" setting.
$note_changed = false;
if ( ! is_null( $request->get_param( 'status' ) ) ) {
$note->set_status( $request->get_param( 'status' ) );
$note_changed = true;
}
if ( $note_changed ) {
$note->save();
}
return $this->get_item( $request );
}
/**
* Makes sure the current user has access to WRITE the settings APIs.
*
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|bool
*/
public function update_items_permissions_check( $request ) {
if ( ! wc_rest_check_manager_permissions( 'settings', 'edit' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'wc-admin' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Prepare a path or query for serialization to the client.
*
@ -204,8 +258,9 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller {
$data['title'] = stripslashes( $data['title'] );
$data['content'] = stripslashes( $data['content'] );
foreach ( (array) $data['actions'] as $key => $value ) {
$data['actions'][ $key ]->label = stripslashes( $data['actions'][ $key ]->label );
$data['actions'][ $key ]->url = $this->prepare_query_for_response( $data['actions'][ $key ]->query );
$data['actions'][ $key ]->label = stripslashes( $data['actions'][ $key ]->label );
$data['actions'][ $key ]->url = $this->prepare_query_for_response( $data['actions'][ $key ]->query );
$data['actions'][ $key ]->status = stripslashes( $data['actions'][ $key ]->status );
}
$data = $this->filter_response_by_context( $data, $context );
@ -233,6 +288,29 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller {
return apply_filters( 'woocommerce_rest_prepare_admin_note', $response, $data, $request );
}
/**
* Get the query params for collections.
*
* @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.', 'wc-admin' ),
'type' => 'string',
'enum' => WC_Admin_Note::get_allowed_types(),
'validate_callback' => 'rest_validate_request_arg',
);
$params['status'] = array(
'description' => __( 'Status of note.', 'wc-admin' ),
'type' => 'string',
'enum' => WC_Admin_Note::get_allowed_statuses(),
'validate_callback' => 'rest_validate_request_arg',
);
return $params;
}
/**
* Get the note's schema, conforming to JSON Schema.
*
@ -296,7 +374,6 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller {
'description' => __( 'The status of the note (e.g. unactioned, actioned).', 'wc-admin' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'source' => array(
'description' => __( 'Source of the note.', 'wc-admin' ),
@ -320,7 +397,7 @@ class WC_Admin_REST_Admin_Notes_Controller extends WC_REST_CRUD_Controller {
'description' => __( 'Date after which the user should be reminded of the note, if any.', 'wc-admin' ),
'type' => 'string',
'context' => array( 'view', 'edit' ),
'readonly' => true,
'readonly' => true, // @todo Allow date_reminder to be updated.
),
'date_reminder_gmt' => array(
'description' => __( 'Date after which the user should be reminded of the note, if any (GMT).', 'wc-admin' ),

View File

@ -16,7 +16,7 @@ class WC_Admin_Install {
*
* @todo get this dynamically?
*/
const VERSION_NUMBER = '0.6.0';
const VERSION_NUMBER = '0.8.0';
/**
* Plugin version option name.
@ -76,6 +76,8 @@ class WC_Admin_Install {
self::create_tables();
self::update_wc_admin_version();
WC_Admin_Notes_Historical_Data::add_note();
delete_transient( 'wc_admin_installing' );
do_action( 'wc_admin_installed' );
@ -174,6 +176,7 @@ class WC_Admin_Install {
name varchar(255) NOT NULL,
label varchar(255) NOT NULL,
query longtext NOT NULL,
status varchar(255) NOT NULL,
PRIMARY KEY (action_id),
KEY note_id (note_id)
) $collate;

View File

@ -365,6 +365,7 @@ class WC_Admin_Note extends WC_Data {
/**
* Set note data for potential re-localization.
*
* @todo Set a default empty array? https://github.com/woocommerce/wc-admin/pull/1763#pullrequestreview-212442921.
* @param object $content_data Note data.
*/
public function set_content_data( $content_data ) {
@ -450,11 +451,13 @@ class WC_Admin_Note extends WC_Data {
* @param string $name Label name (not presented to user).
* @param string $label Note label (e.g. presented as button label).
* @param string $query Note query (for redirect).
* @param string $status The status to set for the action should on click.
*/
public function add_action( $name, $label, $query ) {
$name = wc_clean( $name );
$label = wc_clean( $label );
$query = wc_clean( $query );
public function add_action( $name, $label, $query, $status = '' ) {
$name = wc_clean( $name );
$label = wc_clean( $label );
$query = wc_clean( $query );
$status = wc_clean( $status );
if ( empty( $name ) ) {
$this->error( 'admin_note_invalid_data', __( 'The admin note action name prop cannot be empty.', 'wc-admin' ) );
@ -469,9 +472,10 @@ class WC_Admin_Note extends WC_Data {
}
$action = array(
'name' => $name,
'label' => $label,
'query' => $query,
'name' => $name,
'label' => $label,
'query' => $query,
'status' => $status,
);
$note_actions = $this->get_prop( 'actions', 'edit' );

View File

@ -0,0 +1,50 @@
<?php
/**
* WooCommerce Admin: Historical Analytics Data Note.
*
* Adds a notes to store alerts area concerning the historial analytics data tool.
*
* @package WooCommerce Admin
*/
defined( 'ABSPATH' ) || exit;
/**
* WC_Admin_Notes_Historical_Data.
*/
class WC_Admin_Notes_Historical_Data {
const NOTE_NAME = 'wc-admin-historical-data';
/**
* Creates a note for regenerating historical data.
*/
public static function add_note() {
$data_store = WC_Data_Store::load( 'admin-note' );
// First, see if we've already created this kind of note so we don't do it again.
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
if ( ! empty( $note_ids ) ) {
return;
}
$note = new WC_Admin_Note();
$note->set_title( __( 'WooCommerce Admin: Historical Analytics Data', 'wc-admin' ) );
$note->set_content( __( 'To view your historical analytics data, you must process your existing orders and customers.', 'wc-admin' ) );
$note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_UPDATE );
$note->set_icon( 'info' );
$note->set_name( self::NOTE_NAME );
$note->set_content_data( (object) array() );
$note->set_source( 'woocommerce-admin' );
// @todo Add remind me later option. See https://github.com/woocommerce/wc-admin/issues/1756.
$note->add_action(
'get-started',
__( 'Get Started', 'wc-admin' ),
'?page=wc-admin#/analytics/settings',
'actioned'
);
$note->save();
}
}
new WC_Admin_Notes_Historical_Data();

View File

@ -94,7 +94,7 @@ class WC_Admin_Notes_New_Sales_Record {
$note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_icon( 'trophy' );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'wc-admin' );
$note->set_source( 'woocommerce-admin' );
$note->add_action( 'view-report', __( 'View report', 'wc-admin' ), '?page=wc-admin#/analytics' );
$note->save();
}

View File

@ -42,7 +42,7 @@ class WC_Admin_Notes_Settings_Notes {
$note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_icon( 'info' );
$note->set_name( $name );
$note->set_source( 'wc-admin' );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
'open-customizer',
__( 'Open Customizer', 'wc-admin' ),

View File

@ -185,7 +185,7 @@ class WC_Admin_Notes_Woo_Subscriptions_Notes {
$note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_icon( 'info' );
$note->set_name( self::CONNECTION_NOTE_NAME );
$note->set_source( 'wc-admin' );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
'connect',
__( 'Connect', 'wc-admin' ),
@ -334,7 +334,7 @@ class WC_Admin_Notes_Woo_Subscriptions_Notes {
$note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_WARNING );
$note->set_icon( 'notice' );
$note->set_name( self::SUBSCRIPTION_NOTE_NAME );
$note->set_source( 'wc-admin' );
$note->set_source( 'woocommerce-admin' );
$note->clear_actions();
$note->add_action(
'enable-autorenew',
@ -398,7 +398,7 @@ class WC_Admin_Notes_Woo_Subscriptions_Notes {
$note->set_type( WC_Admin_Note::E_WC_ADMIN_NOTE_WARNING );
$note->set_icon( 'notice' );
$note->set_name( self::SUBSCRIPTION_NOTE_NAME );
$note->set_source( 'wc-admin' );
$note->set_source( 'woocommerce-admin' );
$note->clear_actions();
$note->add_action(
'renew-subscription',

View File

@ -64,11 +64,12 @@ class WC_Admin_Notes {
* Get the total number of notes
*
* @param string $type Comma separated list of note types.
* @param string $status Comma separated list of statuses.
* @return int
*/
public static function get_notes_count( $type = '' ) {
public static function get_notes_count( $type = '', $status = '' ) {
$data_store = WC_Data_Store::load( 'admin-note' );
return $data_store->get_notes_count( $type );
return $data_store->get_notes_count( $type, $status );
}
/**

View File

@ -148,7 +148,6 @@ class WC_Admin_Reports_Sync {
);
}
/**
* Schedule an action to process a single Order.
*

View File

@ -197,13 +197,13 @@ class WC_Admin_Notes_Data_Store extends WC_Data_Store_WP implements WC_Object_Da
$actions = $wpdb->get_results(
$wpdb->prepare(
"SELECT name, label, query FROM {$wpdb->prefix}wc_admin_note_actions WHERE note_id = %d",
"SELECT name, label, query, status FROM {$wpdb->prefix}wc_admin_note_actions WHERE note_id = %d",
$note->get_id()
)
);
if ( $actions ) {
foreach ( $actions as $action ) {
$note->add_action( $action->name, $action->label, $action->query );
$note->add_action( $action->name, $action->label, $action->query, $action->status );
}
}
}
@ -232,6 +232,7 @@ class WC_Admin_Notes_Data_Store extends WC_Data_Store_WP implements WC_Object_Da
'name' => $action->name,
'label' => $action->label,
'query' => $action->query,
'status' => $action->status,
)
);
}
@ -258,6 +259,49 @@ class WC_Admin_Notes_Data_Store extends WC_Data_Store_WP implements WC_Object_Da
$offset = $per_page * ( $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",
$offset,
$per_page
); // WPCS: unprepared SQL ok.
return $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
}
/**
* Return a count of notes.
*
* @param string $type Comma separated list of note types.
* @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 = '' ) {
global $wpdb;
$where_clauses = $this->get_notes_where_clauses(
array(
'type' => $type,
'status' => $status,
)
);
if ( ! empty( $where_clauses ) ) {
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
return $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}wc_admin_notes WHERE 1=1{$where_clauses}" );
}
return $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}wc_admin_notes" );
}
/**
* Return where clauses for getting notes by status and type. For use in both the count and listing queries.
*
* @param array $args Array of args to pass.
* @return string Where clauses for the query.
*/
public function get_notes_where_clauses( $args = array() ) {
$allowed_types = WC_Admin_Note::get_allowed_types();
$where_type_array = array();
if ( isset( $args['type'] ) ) {
@ -269,54 +313,32 @@ class WC_Admin_Notes_Data_Store extends WC_Data_Store_WP implements WC_Object_Da
}
}
}
$escaped_where_types = implode( ',', $where_type_array );
if ( empty( $escaped_where_types ) ) {
$query = $wpdb->prepare(
"SELECT note_id, title, content FROM {$wpdb->prefix}wc_admin_notes ORDER BY note_id DESC LIMIT %d, %d",
$offset,
$per_page
);
} else {
$query = $wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
"SELECT note_id, title, content FROM {$wpdb->prefix}wc_admin_notes WHERE type IN ($escaped_where_types) ORDER BY note_id DESC LIMIT %d, %d",
$offset,
$per_page
);
}
return $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
}
/**
* Return a count of notes.
*
* @param string $type Comma separated list of note types.
* @return array An array of objects containing a note id.
*/
public function get_notes_count( $type = '' ) {
global $wpdb;
$allowed_types = WC_Admin_Note::get_allowed_types();
$where_type_array = array();
if ( ! empty( $type ) ) {
$args_types = explode( ',', $type );
foreach ( (array) $args_types as $args_type ) {
$args_type = trim( $args_type );
if ( in_array( $args_type, $allowed_types, true ) ) {
$where_type_array[] = "'" . esc_sql( $args_type ) . "'";
$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 ) {
$args_status = trim( $args_status );
if ( in_array( $args_status, $allowed_statuses, true ) ) {
$where_status_array[] = "'" . esc_sql( $args_status ) . "'";
}
}
}
$escaped_where_types = implode( ',', $where_type_array );
$escaped_where_types = implode( ',', $where_type_array );
$escaped_status_types = implode( ',', $where_status_array );
$where_clauses = '';
if ( ! empty( $escaped_where_types ) ) {
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
return $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}wc_admin_notes WHERE type IN ($escaped_where_types)" );
$where_clauses .= " AND type IN ($escaped_where_types)";
}
return $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}wc_admin_notes" );
if ( ! empty( $escaped_status_types ) ) {
$where_clauses .= " AND status IN ($escaped_status_types)";
}
return $where_clauses;
}
/**

View File

@ -191,7 +191,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' ),
'alertCount' => WC_Admin_Notes::get_notes_count( 'error,update', 'unactioned' ),
);
$settings = wc_admin_add_custom_settings( $settings );

View File

@ -106,6 +106,45 @@ class WC_Tests_API_Admin_Notes extends WC_REST_Unit_Test_Case {
$this->assertEquals( 401, $response->get_status() );
}
/**
* Test updating a single note.
*/
public function test_update_note() {
wp_set_current_user( $this->user );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint . '/1' ) );
$note = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 'unactioned', $note['status'] );
$request = new WP_REST_Request( 'PUT', $this->endpoint . '/1' );
$request->set_body_params(
array(
'status' => 'actioned',
)
);
$response = $this->server->dispatch( $request );
$note = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 'actioned', $note['status'] );
}
/**
* Test updating a single note without permission. It should fail.
*/
public function test_update_note_without_permission() {
$request = new WP_REST_Request( 'PUT', $this->endpoint . '/1' );
$request->set_body_params(
array(
'status' => 'actioned',
)
);
$response = $this->server->dispatch( $request );
$this->assertEquals( 401, $response->get_status() );
}
/**
* Test getting lots of notes.
*
@ -139,6 +178,31 @@ class WC_Tests_API_Admin_Notes extends WC_REST_Unit_Test_Case {
$this->assertEquals( $notes[0]['title'], 'PHPUNIT_TEST_NOTE_2_TITLE' );
}
/**
* Test getting notes of a certain status.
*/
public function test_get_actioned_notes() {
wp_set_current_user( $this->user );
$request = new WP_REST_Request( 'GET', $this->endpoint );
$request->set_query_params( array( 'status' => 'actioned' ) );
$response = $this->server->dispatch( $request );
$notes = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 1, count( $notes ) );
$this->assertEquals( $notes[0]['title'], 'PHPUNIT_TEST_NOTE_2_TITLE' );
$request = new WP_REST_Request( 'GET', $this->endpoint );
$request->set_query_params( array( 'status' => 'invalid' ) );
$response = $this->server->dispatch( $request );
$notes = $response->get_data();
// get_notes returns all results since 'status' is not one of actioned or unactioned.
$this->assertEquals( 2, count( $notes ) );
}
/**
* Test getting lots of notes without permission. It should fail.
*

View File

@ -55,6 +55,7 @@ class WC_Helper_Admin_Notes {
$note_2->set_icon( 'info' );
$note_2->set_name( 'PHPUNIT_TEST_NOTE_NAME' );
$note_2->set_source( 'PHPUNIT_TEST' );
$note_2->set_status( WC_Admin_Note::E_WC_ADMIN_NOTE_ACTIONED );
// This note has no actions.
$note_2->save();

View File

@ -153,6 +153,7 @@ function wc_admin_plugins_loaded() {
require_once WC_ADMIN_ABSPATH . '/includes/class-wc-admin-notes-new-sales-record.php';
require_once WC_ADMIN_ABSPATH . '/includes/class-wc-admin-notes-settings-notes.php';
require_once WC_ADMIN_ABSPATH . '/includes/class-wc-admin-notes-woo-subscriptions-notes.php';
require_once WC_ADMIN_ABSPATH . '/includes/class-wc-admin-notes-historical-data.php';
// Verify we have a proper build.
if ( ! wc_admin_build_file_exists() ) {