Merge pull request #22760 from woocommerce/performance/webhook-loading
Performance: webhook loading
This commit is contained in:
commit
07eadfeb72
|
@ -86,8 +86,10 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
|
||||||
add_query_arg(
|
add_query_arg(
|
||||||
array(
|
array(
|
||||||
'delete' => $webhook->get_id(),
|
'delete' => $webhook->get_id(),
|
||||||
), admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=webhooks' )
|
),
|
||||||
), 'delete-webhook'
|
admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=webhooks' )
|
||||||
|
),
|
||||||
|
'delete-webhook'
|
||||||
)
|
)
|
||||||
) . '">' . esc_html__( 'Delete permanently', 'woocommerce' ) . '</a>',
|
) . '">' . esc_html__( 'Delete permanently', 'woocommerce' ) . '</a>',
|
||||||
);
|
);
|
||||||
|
@ -262,7 +264,10 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
|
||||||
echo '<label class="screen-reader-text" for="' . esc_attr( $input_id ) . '">' . esc_html( $text ) . ':</label>';
|
echo '<label class="screen-reader-text" for="' . esc_attr( $input_id ) . '">' . esc_html( $text ) . ':</label>';
|
||||||
echo '<input type="search" id="' . esc_attr( $input_id ) . '" name="s" value="' . esc_attr( $search_query ) . '" />';
|
echo '<input type="search" id="' . esc_attr( $input_id ) . '" name="s" value="' . esc_attr( $search_query ) . '" />';
|
||||||
submit_button(
|
submit_button(
|
||||||
$text, '', '', false,
|
$text,
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
false,
|
||||||
array(
|
array(
|
||||||
'id' => 'search-submit',
|
'id' => 'search-submit',
|
||||||
)
|
)
|
||||||
|
@ -292,22 +297,19 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
|
||||||
$args['search'] = sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ); // WPCS: input var okay, CSRF ok.
|
$args['search'] = sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ); // WPCS: input var okay, CSRF ok.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$args['paginate'] = true;
|
||||||
|
|
||||||
// Get the webhooks.
|
// Get the webhooks.
|
||||||
$data_store = WC_Data_Store::load( 'webhook' );
|
$data_store = WC_Data_Store::load( 'webhook' );
|
||||||
$webhooks = $data_store->search_webhooks( $args );
|
$webhooks = $data_store->search_webhooks( $args );
|
||||||
$this->items = array_map( 'wc_get_webhook', $webhooks );
|
$this->items = array_map( 'wc_get_webhook', $webhooks->webhooks );
|
||||||
|
|
||||||
// Get total items.
|
|
||||||
$args['limit'] = -1;
|
|
||||||
$args['offset'] = 0;
|
|
||||||
$total_items = count( $data_store->search_webhooks( $args ) );
|
|
||||||
|
|
||||||
// Set the pagination.
|
// Set the pagination.
|
||||||
$this->set_pagination_args(
|
$this->set_pagination_args(
|
||||||
array(
|
array(
|
||||||
'total_items' => $total_items,
|
'total_items' => $webhooks->total,
|
||||||
'per_page' => $per_page,
|
'per_page' => $per_page,
|
||||||
'total_pages' => ceil( $total_items / $per_page ),
|
'total_pages' => $webhooks->max_num_pages,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,8 +270,9 @@ class WC_Admin_Webhooks {
|
||||||
echo '<h2>' . esc_html__( 'Webhooks', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=webhooks&edit-webhook=0' ) ) . '" class="add-new-h2">' . esc_html__( 'Add webhook', 'woocommerce' ) . '</a></h2>';
|
echo '<h2>' . esc_html__( 'Webhooks', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=webhooks&edit-webhook=0' ) ) . '" class="add-new-h2">' . esc_html__( 'Add webhook', 'woocommerce' ) . '</a></h2>';
|
||||||
|
|
||||||
// Get the webhooks count.
|
// Get the webhooks count.
|
||||||
$data_store = WC_Data_Store::load( 'webhook' );
|
$data_store = WC_Data_Store::load( 'webhook' );
|
||||||
$count = count( $data_store->get_webhooks_ids() );
|
$num_webhooks = $data_store->get_count_webhooks_by_status();
|
||||||
|
$count = array_sum( $num_webhooks );
|
||||||
|
|
||||||
if ( 0 < $count ) {
|
if ( 0 < $count ) {
|
||||||
$webhooks_table_list->process_bulk_action();
|
$webhooks_table_list->process_bulk_action();
|
||||||
|
|
|
@ -326,21 +326,6 @@ class WC_API_Webhooks extends WC_API_Resource {
|
||||||
return $webhook->delete( true );
|
return $webhook->delete( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get webhooks total results
|
|
||||||
*
|
|
||||||
* @since 3.3.0
|
|
||||||
* @param array $args Request arguments for filtering query.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function get_webhooks_total_results( $args = array() ) {
|
|
||||||
$data_store = WC_Data_Store::load( 'webhook' );
|
|
||||||
$args['limit'] = -1;
|
|
||||||
$args['offset'] = 0;
|
|
||||||
|
|
||||||
return count( $data_store->search_webhooks( $args ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to get webhook post objects
|
* Helper method to get webhook post objects
|
||||||
*
|
*
|
||||||
|
@ -390,6 +375,8 @@ class WC_API_Webhooks extends WC_API_Resource {
|
||||||
unset( $args['date_query'] );
|
unset( $args['date_query'] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$args['paginate'] = true;
|
||||||
|
|
||||||
// Get the webhooks.
|
// Get the webhooks.
|
||||||
$data_store = WC_Data_Store::load( 'webhook' );
|
$data_store = WC_Data_Store::load( 'webhook' );
|
||||||
$results = $data_store->search_webhooks( $args );
|
$results = $data_store->search_webhooks( $args );
|
||||||
|
@ -397,12 +384,12 @@ class WC_API_Webhooks extends WC_API_Resource {
|
||||||
// Get total items.
|
// Get total items.
|
||||||
$headers = new stdClass;
|
$headers = new stdClass;
|
||||||
$headers->page = $page;
|
$headers->page = $page;
|
||||||
$headers->total = $this->get_webhooks_total_results( $args );
|
$headers->total = $results->total;
|
||||||
$headers->is_single = $args['limit'] > $headers->total;
|
$headers->is_single = $args['limit'] > $headers->total;
|
||||||
$headers->total_pages = ceil( $headers->total / $args['limit'] );
|
$headers->total_pages = $results->max_num_pages;
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'results' => $results,
|
'results' => $results->webhooks,
|
||||||
'headers' => $headers,
|
'headers' => $headers,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -326,21 +326,6 @@ class WC_API_Webhooks extends WC_API_Resource {
|
||||||
return $webhook->delete( true );
|
return $webhook->delete( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get webhooks total results
|
|
||||||
*
|
|
||||||
* @since 3.3.0
|
|
||||||
* @param array $args Request arguments for filtering query.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function get_webhooks_total_results( $args = array() ) {
|
|
||||||
$data_store = WC_Data_Store::load( 'webhook' );
|
|
||||||
$args['limit'] = -1;
|
|
||||||
$args['offset'] = 0;
|
|
||||||
|
|
||||||
return count( $data_store->search_webhooks( $args ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to get webhook post objects
|
* Helper method to get webhook post objects
|
||||||
*
|
*
|
||||||
|
@ -390,6 +375,8 @@ class WC_API_Webhooks extends WC_API_Resource {
|
||||||
unset( $args['date_query'] );
|
unset( $args['date_query'] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$args['paginate'] = true;
|
||||||
|
|
||||||
// Get the webhooks.
|
// Get the webhooks.
|
||||||
$data_store = WC_Data_Store::load( 'webhook' );
|
$data_store = WC_Data_Store::load( 'webhook' );
|
||||||
$results = $data_store->search_webhooks( $args );
|
$results = $data_store->search_webhooks( $args );
|
||||||
|
@ -397,12 +384,12 @@ class WC_API_Webhooks extends WC_API_Resource {
|
||||||
// Get total items.
|
// Get total items.
|
||||||
$headers = new stdClass;
|
$headers = new stdClass;
|
||||||
$headers->page = $page;
|
$headers->page = $page;
|
||||||
$headers->total = $this->get_webhooks_total_results( $args );
|
$headers->total = $results->total;
|
||||||
$headers->is_single = $args['limit'] > $headers->total;
|
$headers->is_single = $args['limit'] > $headers->total;
|
||||||
$headers->total_pages = ceil( $headers->total / $args['limit'] );
|
$headers->total_pages = $results->max_num_pages;
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'results' => $results,
|
'results' => $results->webhooks,
|
||||||
'headers' => $headers,
|
'headers' => $headers,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,32 +247,29 @@ class WC_REST_Webhooks_V1_Controller extends WC_REST_Controller {
|
||||||
*/
|
*/
|
||||||
$prepared_args = apply_filters( 'woocommerce_rest_webhook_query', $args, $request );
|
$prepared_args = apply_filters( 'woocommerce_rest_webhook_query', $args, $request );
|
||||||
unset( $prepared_args['page'] );
|
unset( $prepared_args['page'] );
|
||||||
|
$prepared_args['paginate'] = true;
|
||||||
|
|
||||||
// Get the webhooks.
|
// Get the webhooks.
|
||||||
$data_store = WC_Data_Store::load( 'webhook' );
|
$webhooks = array();
|
||||||
$results = $data_store->search_webhooks( $prepared_args );
|
$data_store = WC_Data_Store::load( 'webhook' );
|
||||||
|
$results = $data_store->search_webhooks( $prepared_args );
|
||||||
|
$webhook_ids = $results->webhooks;
|
||||||
|
|
||||||
$webhooks = array();
|
foreach ( $webhook_ids as $webhook_id ) {
|
||||||
foreach ( $results as $webhook_id ) {
|
|
||||||
$data = $this->prepare_item_for_response( $webhook_id, $request );
|
$data = $this->prepare_item_for_response( $webhook_id, $request );
|
||||||
$webhooks[] = $this->prepare_response_for_collection( $data );
|
$webhooks[] = $this->prepare_response_for_collection( $data );
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = rest_ensure_response( $webhooks );
|
$response = rest_ensure_response( $webhooks );
|
||||||
|
$per_page = (int) $prepared_args['limit'];
|
||||||
|
$page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 );
|
||||||
|
$total_webhooks = $results->total;
|
||||||
|
$max_pages = $results->max_num_pages;
|
||||||
|
$base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) );
|
||||||
|
|
||||||
// Store pagination values for headers then unset for count query.
|
$response->header( 'X-WP-Total', $total_webhooks );
|
||||||
$per_page = (int) $prepared_args['limit'];
|
$response->header( 'X-WP-TotalPages', $max_pages );
|
||||||
$page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 );
|
|
||||||
|
|
||||||
// Calculate totals.
|
|
||||||
$prepared_args['limit'] = -1;
|
|
||||||
$prepared_args['offset'] = 0;
|
|
||||||
$total_webhooks = count( $data_store->search_webhooks( $prepared_args ) );
|
|
||||||
$response->header( 'X-WP-Total', (int) $total_webhooks );
|
|
||||||
$max_pages = ceil( $total_webhooks / $per_page );
|
|
||||||
$response->header( 'X-WP-TotalPages', (int) $max_pages );
|
|
||||||
|
|
||||||
$base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) );
|
|
||||||
if ( $page > 1 ) {
|
if ( $page > 1 ) {
|
||||||
$prev_page = $page - 1;
|
$prev_page = $page - 1;
|
||||||
if ( $prev_page > $max_pages ) {
|
if ( $prev_page > $max_pages ) {
|
||||||
|
|
|
@ -688,7 +688,15 @@ final class WooCommerce {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wc_load_webhooks();
|
/**
|
||||||
|
* Hook: woocommerce_load_webhooks_limit.
|
||||||
|
*
|
||||||
|
* @since 3.6.0
|
||||||
|
* @param int $limit Used to limit how many webhooks are loaded. Default: no limit.
|
||||||
|
*/
|
||||||
|
$limit = apply_filters( 'woocommerce_load_webhooks_limit', null );
|
||||||
|
|
||||||
|
wc_load_webhooks( 'active', $limit );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -59,7 +59,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||||
$webhook->set_id( $webhook_id );
|
$webhook->set_id( $webhook_id );
|
||||||
$webhook->apply_changes();
|
$webhook->apply_changes();
|
||||||
|
|
||||||
delete_transient( 'woocommerce_webhook_ids' );
|
$this->delete_transients( $webhook->get_status( 'edit' ) );
|
||||||
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
|
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
|
||||||
do_action( 'woocommerce_new_webhook', $webhook_id );
|
do_action( 'woocommerce_new_webhook', $webhook_id );
|
||||||
}
|
}
|
||||||
|
@ -152,6 +152,10 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||||
|
|
||||||
$webhook->apply_changes();
|
$webhook->apply_changes();
|
||||||
|
|
||||||
|
if ( isset( $changes['status'] ) ) {
|
||||||
|
// We need to delete all transients, because we can't be sure of the old status.
|
||||||
|
$this->delete_transients( 'all' );
|
||||||
|
}
|
||||||
wp_cache_delete( $webhook->get_id(), 'webhooks' );
|
wp_cache_delete( $webhook->get_id(), 'webhooks' );
|
||||||
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
|
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
|
||||||
|
|
||||||
|
@ -179,7 +183,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||||
array( '%d' )
|
array( '%d' )
|
||||||
); // WPCS: cache ok, DB call ok.
|
); // WPCS: cache ok, DB call ok.
|
||||||
|
|
||||||
delete_transient( 'woocommerce_webhook_ids' );
|
$this->delete_transients( 'all' );
|
||||||
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
|
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
|
||||||
do_action( 'woocommerce_webhook_deleted', $webhook->get_id(), $webhook );
|
do_action( 'woocommerce_webhook_deleted', $webhook->get_id(), $webhook );
|
||||||
}
|
}
|
||||||
|
@ -196,21 +200,29 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all webhooks IDs.
|
* Get webhooks IDs from the database.
|
||||||
*
|
*
|
||||||
* @since 3.3.0
|
* @since 3.3.0
|
||||||
|
* @throws InvalidArgumentException If a $status value is passed in that is not in the known wc_get_webhook_statuses() keys.
|
||||||
|
* @param string $status Optional - status to filter results by. Must be a key in return value of @see wc_get_webhook_statuses(). @since 3.6.0.
|
||||||
* @return int[]
|
* @return int[]
|
||||||
*/
|
*/
|
||||||
public function get_webhooks_ids() {
|
public function get_webhooks_ids( $status = '' ) {
|
||||||
global $wpdb;
|
if ( ! empty( $status ) ) {
|
||||||
|
$this->validate_status( $status );
|
||||||
|
}
|
||||||
|
|
||||||
$ids = get_transient( 'woocommerce_webhook_ids' );
|
$ids = get_transient( $this->get_transient_key( $status ) );
|
||||||
|
|
||||||
if ( false === $ids ) {
|
if ( false === $ids ) {
|
||||||
$results = $wpdb->get_results( "SELECT webhook_id FROM {$wpdb->prefix}wc_webhooks" ); // WPCS: cache ok, DB call ok.
|
$ids = $this->search_webhooks(
|
||||||
$ids = array_map( 'intval', wp_list_pluck( $results, 'webhook_id' ) );
|
array(
|
||||||
|
'limit' => -1,
|
||||||
set_transient( 'woocommerce_webhook_ids', $ids );
|
'status' => $status,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$ids = array_map( 'absint', $ids );
|
||||||
|
set_transient( $this->get_transient_key( $status ), $ids );
|
||||||
}
|
}
|
||||||
|
|
||||||
return $ids;
|
return $ids;
|
||||||
|
@ -220,7 +232,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||||
* Search webhooks.
|
* Search webhooks.
|
||||||
*
|
*
|
||||||
* @param array $args Search arguments.
|
* @param array $args Search arguments.
|
||||||
* @return array
|
* @return array|object
|
||||||
*/
|
*/
|
||||||
public function search_webhooks( $args ) {
|
public function search_webhooks( $args ) {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
@ -228,10 +240,11 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||||
$args = wp_parse_args(
|
$args = wp_parse_args(
|
||||||
$args,
|
$args,
|
||||||
array(
|
array(
|
||||||
'limit' => 10,
|
'limit' => 10,
|
||||||
'offset' => 0,
|
'offset' => 0,
|
||||||
'order' => 'DESC',
|
'order' => 'DESC',
|
||||||
'orderby' => 'id',
|
'orderby' => 'id',
|
||||||
|
'paginate' => false,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -258,15 +271,15 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||||
'post_modified' => 'date_modified_gmt',
|
'post_modified' => 'date_modified_gmt',
|
||||||
);
|
);
|
||||||
$orderby = isset( $orderby_mapping[ $args['orderby'] ] ) ? $orderby_mapping[ $args['orderby'] ] : 'webhook_id';
|
$orderby = isset( $orderby_mapping[ $args['orderby'] ] ) ? $orderby_mapping[ $args['orderby'] ] : 'webhook_id';
|
||||||
|
$order = "ORDER BY {$orderby} " . esc_sql( strtoupper( $args['order'] ) );
|
||||||
$limit = -1 < $args['limit'] ? sprintf( 'LIMIT %d', $args['limit'] ) : '';
|
$limit = -1 < $args['limit'] ? $wpdb->prepare( 'LIMIT %d', $args['limit'] ) : '';
|
||||||
$offset = 0 < $args['offset'] ? sprintf( 'OFFSET %d', $args['offset'] ) : '';
|
$offset = 0 < $args['offset'] ? $wpdb->prepare( 'OFFSET %d', $args['offset'] ) : '';
|
||||||
$status = ! empty( $args['status'] ) ? "AND `status` = '" . sanitize_key( isset( $statuses[ $args['status'] ] ) ? $statuses[ $args['status'] ] : $args['status'] ) . "'" : '';
|
$status = ! empty( $args['status'] ) ? $wpdb->prepare( 'AND `status` = %s', isset( $statuses[ $args['status'] ] ) ? $statuses[ $args['status'] ] : $args['status'] ) : '';
|
||||||
$search = ! empty( $args['search'] ) ? "AND `name` LIKE '%" . $wpdb->esc_like( sanitize_text_field( $args['search'] ) ) . "%'" : '';
|
$search = ! empty( $args['search'] ) ? "AND `name` LIKE '%" . $wpdb->esc_like( sanitize_text_field( $args['search'] ) ) . "%'" : '';
|
||||||
$include = '';
|
$include = '';
|
||||||
$exclude = '';
|
$exclude = '';
|
||||||
$date_created = '';
|
$date_created = '';
|
||||||
$date_modified = '';
|
$date_modified = '';
|
||||||
|
|
||||||
if ( ! empty( $args['include'] ) ) {
|
if ( ! empty( $args['include'] ) ) {
|
||||||
$args['include'] = implode( ',', wp_parse_id_list( $args['include'] ) );
|
$args['include'] = implode( ',', wp_parse_id_list( $args['include'] ) );
|
||||||
|
@ -282,47 +295,91 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||||
$args['after'] = empty( $args['after'] ) ? '0000-00-00' : $args['after'];
|
$args['after'] = empty( $args['after'] ) ? '0000-00-00' : $args['after'];
|
||||||
$args['before'] = empty( $args['before'] ) ? current_time( 'mysql', 1 ) : $args['before'];
|
$args['before'] = empty( $args['before'] ) ? current_time( 'mysql', 1 ) : $args['before'];
|
||||||
|
|
||||||
$date_created = "AND `date_created_gmt` BETWEEN STR_TO_DATE('" . $args['after'] . "', '%Y-%m-%d %H:%i:%s') and STR_TO_DATE('" . $args['before'] . "', '%Y-%m-%d %H:%i:%s')";
|
$date_created = "AND `date_created_gmt` BETWEEN STR_TO_DATE('" . esc_sql( $args['after'] ) . "', '%Y-%m-%d %H:%i:%s') and STR_TO_DATE('" . esc_sql( $args['before'] ) . "', '%Y-%m-%d %H:%i:%s')";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! empty( $args['modified_after'] ) || ! empty( $args['modified_before'] ) ) {
|
if ( ! empty( $args['modified_after'] ) || ! empty( $args['modified_before'] ) ) {
|
||||||
$args['modified_after'] = empty( $args['modified_after'] ) ? '0000-00-00' : $args['modified_after'];
|
$args['modified_after'] = empty( $args['modified_after'] ) ? '0000-00-00' : $args['modified_after'];
|
||||||
$args['modified_before'] = empty( $args['modified_before'] ) ? current_time( 'mysql', 1 ) : $args['modified_before'];
|
$args['modified_before'] = empty( $args['modified_before'] ) ? current_time( 'mysql', 1 ) : $args['modified_before'];
|
||||||
|
|
||||||
$date_modified = "AND `date_modified_gmt` BETWEEN STR_TO_DATE('" . $args['modified_after'] . "', '%Y-%m-%d %H:%i:%s') and STR_TO_DATE('" . $args['modified_before'] . "', '%Y-%m-%d %H:%i:%s')";
|
$date_modified = "AND `date_modified_gmt` BETWEEN STR_TO_DATE('" . esc_sql( $args['modified_after'] ) . "', '%Y-%m-%d %H:%i:%s') and STR_TO_DATE('" . esc_sql( $args['modified_before'] ) . "', '%Y-%m-%d %H:%i:%s')";
|
||||||
}
|
}
|
||||||
|
|
||||||
$order = "ORDER BY {$orderby} " . strtoupper( sanitize_key( $args['order'] ) );
|
|
||||||
|
|
||||||
// Check for cache.
|
// Check for cache.
|
||||||
$cache_key = WC_Cache_Helper::get_cache_prefix( 'webhooks' ) . 'search_webhooks' . md5( implode( ',', $args ) );
|
$cache_key = WC_Cache_Helper::get_cache_prefix( 'webhooks' ) . 'search_webhooks' . md5( implode( ',', $args ) );
|
||||||
$ids = wp_cache_get( $cache_key, 'webhook_search_results' );
|
$cache_value = wp_cache_get( $cache_key, 'webhook_search_results' );
|
||||||
|
|
||||||
if ( false !== $ids ) {
|
if ( $cache_value ) {
|
||||||
return $ids;
|
return $cache_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = trim(
|
if ( $args['paginate'] ) {
|
||||||
"SELECT webhook_id
|
$query = trim(
|
||||||
FROM {$wpdb->prefix}wc_webhooks
|
"SELECT SQL_CALC_FOUND_ROWS webhook_id
|
||||||
WHERE 1=1
|
FROM {$wpdb->prefix}wc_webhooks
|
||||||
{$status}
|
WHERE 1=1
|
||||||
{$search}
|
{$status}
|
||||||
{$include}
|
{$search}
|
||||||
{$exclude}
|
{$include}
|
||||||
{$date_created}
|
{$exclude}
|
||||||
{$date_modified}
|
{$date_created}
|
||||||
{$order}
|
{$date_modified}
|
||||||
{$limit}
|
{$order}
|
||||||
{$offset}"
|
{$limit}
|
||||||
);
|
{$offset}"
|
||||||
|
);
|
||||||
|
|
||||||
$results = $wpdb->get_results( $query ); // WPCS: cache ok, DB call ok, unprepared SQL ok.
|
$webhook_ids = wp_parse_id_list( $wpdb->get_col( $query ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
$total = (int) $wpdb->get_var( 'SELECT FOUND_ROWS();' );
|
||||||
|
$return_value = (object) array(
|
||||||
|
'webhooks' => $webhook_ids,
|
||||||
|
'total' => $total,
|
||||||
|
'max_num_pages' => $args['limit'] > 1 ? ceil( $total / $args['limit'] ) : 1,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$query = trim(
|
||||||
|
"SELECT webhook_id
|
||||||
|
FROM {$wpdb->prefix}wc_webhooks
|
||||||
|
WHERE 1=1
|
||||||
|
{$status}
|
||||||
|
{$search}
|
||||||
|
{$include}
|
||||||
|
{$exclude}
|
||||||
|
{$date_created}
|
||||||
|
{$date_modified}
|
||||||
|
{$order}
|
||||||
|
{$limit}
|
||||||
|
{$offset}"
|
||||||
|
);
|
||||||
|
|
||||||
$ids = wp_list_pluck( $results, 'webhook_id' );
|
$webhook_ids = wp_parse_id_list( $wpdb->get_col( $query ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||||
wp_cache_set( $cache_key, $ids, 'webhook_search_results' );
|
$return_value = $webhook_ids;
|
||||||
|
}
|
||||||
|
|
||||||
return $ids;
|
wp_cache_set( $cache_key, $return_value, 'webhook_search_results' );
|
||||||
|
|
||||||
|
return $return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count webhooks.
|
||||||
|
*
|
||||||
|
* @since 3.6.0
|
||||||
|
* @param string $status Status to count.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function get_webhook_count( $status = 'active' ) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$count = wp_cache_get( $status . '_count', 'webhooks' );
|
||||||
|
|
||||||
|
if ( false === $count ) {
|
||||||
|
$count = absint( $wpdb->get_var( $wpdb->prepare( "SELECT count( webhook_id ) FROM {$wpdb->prefix}wc_webhooks WHERE `status` = %s;", $status ) ) );
|
||||||
|
|
||||||
|
wp_cache_add( $status . '_count', $count, 'webhooks' );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -335,18 +392,55 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||||
$counts = array();
|
$counts = array();
|
||||||
|
|
||||||
foreach ( $statuses as $status ) {
|
foreach ( $statuses as $status ) {
|
||||||
$count = count(
|
$counts[ $status ] = $this->get_webhook_count( $status );
|
||||||
$this->search_webhooks(
|
|
||||||
array(
|
|
||||||
'limit' => -1,
|
|
||||||
'status' => $status,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$counts[ $status ] = $count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $counts;
|
return $counts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given string is in known statuses, based on return value of @see wc_get_webhook_statuses().
|
||||||
|
*
|
||||||
|
* @since 3.6.0
|
||||||
|
* @throws InvalidArgumentException If $status is not empty and not in the known wc_get_webhook_statuses() keys.
|
||||||
|
* @param string $status Status to check.
|
||||||
|
*/
|
||||||
|
private function validate_status( $status ) {
|
||||||
|
if ( ! array_key_exists( $status, wc_get_webhook_statuses() ) ) {
|
||||||
|
throw new InvalidArgumentException( sprintf( 'Invalid status given: %s. Status must be one of: %s.', $status, implode( ', ', array_keys( wc_get_webhook_statuses() ) ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the transient key used to cache a set of webhook IDs, optionally filtered by status.
|
||||||
|
*
|
||||||
|
* @since 3.6.0
|
||||||
|
* @param string $status Optional - status of cache key.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function get_transient_key( $status = '' ) {
|
||||||
|
return empty( $status ) ? 'woocommerce_webhook_ids' : sprintf( 'woocommerce_webhook_ids_status_%s', $status );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the transients used to cache a set of webhook IDs, optionally filtered by status.
|
||||||
|
*
|
||||||
|
* @since 3.6.0
|
||||||
|
* @param string $status Optional - status of cache to delete, or 'all' to delete all caches.
|
||||||
|
*/
|
||||||
|
private function delete_transients( $status = '' ) {
|
||||||
|
|
||||||
|
// Always delete the non-filtered cache.
|
||||||
|
delete_transient( $this->get_transient_key( '' ) );
|
||||||
|
|
||||||
|
if ( ! empty( $status ) ) {
|
||||||
|
if ( 'all' === $status ) {
|
||||||
|
foreach ( wc_get_webhook_statuses() as $status_key => $status_string ) {
|
||||||
|
delete_transient( $this->get_transient_key( $status_key ) );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete_transient( $this->get_transient_key( $status ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,9 @@ interface WC_Webhook_Data_Store_Interface {
|
||||||
* Get all webhooks IDs.
|
* Get all webhooks IDs.
|
||||||
*
|
*
|
||||||
* @since 3.2.0
|
* @since 3.2.0
|
||||||
|
* @throws InvalidArgumentException If a $status value is passed in that is not in the known wc_get_webhook_statuses() keys.
|
||||||
|
* @param string $status Optional - status to filter results by. Must be a key in return value of @see wc_get_webhook_statuses(). @since 3.6.0.
|
||||||
* @return int[]
|
* @return int[]
|
||||||
*/
|
*/
|
||||||
public function get_webhooks_ids();
|
public function get_webhooks_ids( $status = '' );
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ function wc_webhook_process_delivery( $webhook, $arg ) {
|
||||||
// so as to avoid delays or failures in delivery from affecting the
|
// so as to avoid delays or failures in delivery from affecting the
|
||||||
// user who triggered it.
|
// user who triggered it.
|
||||||
if ( apply_filters( 'woocommerce_webhook_deliver_async', true, $webhook, $arg ) ) {
|
if ( apply_filters( 'woocommerce_webhook_deliver_async', true, $webhook, $arg ) ) {
|
||||||
|
|
||||||
$queue_args = array(
|
$queue_args = array(
|
||||||
'webhook_id' => $webhook->get_id(),
|
'webhook_id' => $webhook->get_id(),
|
||||||
'arg' => $arg,
|
'arg' => $arg,
|
||||||
|
@ -64,7 +65,7 @@ add_action( 'woocommerce_deliver_webhook_async', 'wc_deliver_webhook_async', 10,
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
function wc_is_webhook_valid_topic( $topic ) {
|
function wc_is_webhook_valid_topic( $topic ) {
|
||||||
$invalid_topics = array(
|
$invalid_topics = array(
|
||||||
'action.woocommerce_login_credentials',
|
'action.woocommerce_login_credentials',
|
||||||
'action.woocommerce_product_csv_importer_check_import_file_path',
|
'action.woocommerce_product_csv_importer_check_import_file_path',
|
||||||
'action.woocommerce_webhook_should_deliver',
|
'action.woocommerce_webhook_should_deliver',
|
||||||
|
@ -128,20 +129,26 @@ function wc_get_webhook_statuses() {
|
||||||
*
|
*
|
||||||
* @since 3.3.0
|
* @since 3.3.0
|
||||||
* @throws Exception If webhook cannot be read/found and $data parameter of WC_Webhook class constructor is set.
|
* @throws Exception If webhook cannot be read/found and $data parameter of WC_Webhook class constructor is set.
|
||||||
|
* @param string $status Optional - status to filter results by. Must be a key in return value of @see wc_get_webhook_statuses(). @since 3.5.0.
|
||||||
|
* @param null|int $limit Limit number of webhooks loaded. @since 3.6.0.
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
function wc_load_webhooks() {
|
function wc_load_webhooks( $status = '', $limit = null ) {
|
||||||
$data_store = WC_Data_Store::load( 'webhook' );
|
$data_store = WC_Data_Store::load( 'webhook' );
|
||||||
$webhooks = $data_store->get_webhooks_ids();
|
$webhooks = $data_store->get_webhooks_ids( $status );
|
||||||
$loaded = false;
|
$loaded = 0;
|
||||||
|
|
||||||
foreach ( $webhooks as $webhook_id ) {
|
foreach ( $webhooks as $webhook_id ) {
|
||||||
$webhook = new WC_Webhook( $webhook_id );
|
$webhook = new WC_Webhook( $webhook_id );
|
||||||
$webhook->enqueue();
|
$webhook->enqueue();
|
||||||
$loaded = true;
|
$loaded ++;
|
||||||
|
|
||||||
|
if ( ! is_null( $limit ) && $loaded >= $limit ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $loaded;
|
return 0 < $loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -103,23 +103,132 @@ class WC_Tests_Webhook_Functions extends WC_Unit_Test_Case {
|
||||||
* @since 3.2.0
|
* @since 3.2.0
|
||||||
*/
|
*/
|
||||||
public function test_wc_load_webhooks() {
|
public function test_wc_load_webhooks() {
|
||||||
|
$webhook = $this->create_webhook();
|
||||||
|
$this->assertTrue( wc_load_webhooks() );
|
||||||
|
$webhook->delete( true );
|
||||||
|
$this->assertFalse( wc_load_webhooks() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide webhook statuses for tests.
|
||||||
|
*
|
||||||
|
* @since 3.5.0
|
||||||
|
*/
|
||||||
|
public function provider_webhook_statuses() {
|
||||||
|
|
||||||
|
$webhook_statuses = array();
|
||||||
|
|
||||||
|
foreach ( wc_get_webhook_statuses() as $status_key => $status_string ) {
|
||||||
|
$webhook_statuses[] = array( $status_key );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $webhook_statuses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the $status param on wc_load_webhooks().
|
||||||
|
*
|
||||||
|
* @dataProvider provider_webhook_statuses
|
||||||
|
* @param string $status The status of the webhook to test.
|
||||||
|
* @since 3.5.0
|
||||||
|
*/
|
||||||
|
public function test_wc_load_webhooks_status( $status ) {
|
||||||
|
|
||||||
|
$webhook = $this->create_webhook( 'action.woocommerce_some_action', $status );
|
||||||
|
|
||||||
|
$this->assertTrue( wc_load_webhooks( '' ) );
|
||||||
|
$this->assertTrue( wc_load_webhooks( $status ) );
|
||||||
|
|
||||||
|
// Find a different, but still valid status.
|
||||||
|
$other_status = ( 'active' === $status ) ? 'disabled' : 'active';
|
||||||
|
|
||||||
|
$this->assertFalse( wc_load_webhooks( $other_status ) );
|
||||||
|
|
||||||
|
$webhook->delete( true );
|
||||||
|
$this->assertFalse( wc_load_webhooks( $status ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function test_wc_load_webhooks_status_invalid() {
|
||||||
|
wc_load_webhooks( 'invalid_status' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the $limit param on wc_load_webhooks().
|
||||||
|
*
|
||||||
|
* @since 3.5.0
|
||||||
|
*/
|
||||||
|
public function test_wc_load_webhooks_limit() {
|
||||||
|
global $wp_filter;
|
||||||
|
|
||||||
|
$webhook_one = $this->create_webhook( 'action.woocommerce_one_test' );
|
||||||
|
$webhook_two = $this->create_webhook( 'action.woocommerce_two_test' );
|
||||||
|
|
||||||
|
$this->assertTrue( wc_load_webhooks( '', 1 ) );
|
||||||
|
$this->assertFalse( isset( $wp_filter['woocommerce_one_test'] ) );
|
||||||
|
$this->assertTrue( isset( $wp_filter['woocommerce_two_test'] ) );
|
||||||
|
|
||||||
|
$webhook_two->delete( true );
|
||||||
|
|
||||||
|
$this->assertTrue( wc_load_webhooks( '', 1 ) );
|
||||||
|
$this->assertTrue( isset( $wp_filter['woocommerce_one_test'] ) );
|
||||||
|
|
||||||
|
$webhook_one->delete( true );
|
||||||
|
|
||||||
|
$this->assertFalse( wc_load_webhooks( '', 1 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the $status and $limit param on wc_load_webhooks().
|
||||||
|
*
|
||||||
|
* @dataProvider provider_webhook_statuses
|
||||||
|
* @param string $status The status of the webhook to test.
|
||||||
|
*/
|
||||||
|
public function test_wc_load_webhooks_status_and_limit( $status ) {
|
||||||
|
global $wp_filter;
|
||||||
|
|
||||||
|
$action_one = 'woocommerce_one_test_status_' . $status;
|
||||||
|
$webhook_one = $this->create_webhook( 'action.' . $action_one, $status );
|
||||||
|
$action_two = 'woocommerce_two_test_status_' . $status;
|
||||||
|
$webhook_two = $this->create_webhook( 'action.' . $action_two, $status );
|
||||||
|
|
||||||
|
$this->assertTrue( wc_load_webhooks( $status, 1 ) );
|
||||||
|
$this->assertFalse( isset( $wp_filter[ $action_one ] ) );
|
||||||
|
$this->assertTrue( isset( $wp_filter[ $action_two ] ) );
|
||||||
|
|
||||||
|
$webhook_two->delete( true );
|
||||||
|
|
||||||
|
$this->assertTrue( wc_load_webhooks( $status, 1 ) );
|
||||||
|
$this->assertTrue( isset( $wp_filter[ $action_one ] ) );
|
||||||
|
|
||||||
|
$webhook_one->delete( true );
|
||||||
|
$this->assertFalse( wc_load_webhooks( $status, 1 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and save a webhook for testing.
|
||||||
|
*
|
||||||
|
* @param string $topic The webhook topic for the test.
|
||||||
|
* @param string $status The status of the webhook to be tested.
|
||||||
|
*/
|
||||||
|
protected function create_webhook( $topic = 'action.woocommerce_some_action', $status = 'active' ) {
|
||||||
|
|
||||||
$webhook = new WC_Webhook();
|
$webhook = new WC_Webhook();
|
||||||
$webhook->set_props(
|
$webhook->set_props(
|
||||||
array(
|
array(
|
||||||
'status' => 'active',
|
'status' => $status,
|
||||||
'name' => 'Testing webhook',
|
'name' => 'Testing webhook',
|
||||||
'user_id' => 0,
|
'user_id' => 0,
|
||||||
'delivery_url' => 'https://requestb.in/17jajv31',
|
'delivery_url' => 'https://requestb.in/17jajv31',
|
||||||
'secret' => 'secret',
|
'secret' => 'secret',
|
||||||
'topic' => 'action.woocommerce_some_action',
|
'topic' => $topic,
|
||||||
'api_version' => 2,
|
'api_version' => 2,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$webhook->save();
|
$webhook->save();
|
||||||
|
|
||||||
$this->assertTrue( wc_load_webhooks() );
|
return $webhook;
|
||||||
|
|
||||||
$webhook->delete( true );
|
|
||||||
$this->assertFalse( wc_load_webhooks() );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue