2016-08-05 21:23:40 +00:00
< ? php
/**
* REST API WC System Status Tools Controller
*
* Handles requests to the / system_status / tools /* endpoints .
*
* @ package WooCommerce / API
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-08-05 21:23:40 +00:00
*/
2018-02-13 13:59:54 +00:00
defined ( 'ABSPATH' ) || exit ;
2016-08-05 21:23:40 +00:00
/**
* @ package WooCommerce / API
* @ extends WC_REST_Controller
*/
class WC_REST_System_Status_Tools_Controller extends WC_REST_Controller {
/**
* Endpoint namespace .
*
* @ var string
*/
2017-02-09 17:06:13 +00:00
protected $namespace = 'wc/v2' ;
2016-08-05 21:23:40 +00:00
/**
* Route base .
*
* @ var string
*/
protected $rest_base = 'system_status/tools' ;
/**
* Register the routes for / system_status / tools /*.
*/
public function register_routes () {
2018-03-05 20:53:06 +00:00
register_rest_route (
$this -> namespace , '/' . $this -> rest_base , array (
array (
'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' ),
)
);
2016-08-05 21:23:40 +00:00
2018-03-05 20:53:06 +00:00
register_rest_route (
$this -> namespace , '/' . $this -> rest_base . '/(?P<id>[\w-]+)' , array (
'args' => array (
'id' => array (
'description' => __ ( 'Unique identifier for the resource.' , 'woocommerce' ),
'type' => 'string' ,
),
2017-01-26 19:22:57 +00:00
),
2018-03-05 20:53:06 +00:00
array (
'methods' => WP_REST_Server :: READABLE ,
'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_item_permissions_check' ),
'args' => $this -> get_endpoint_args_for_item_schema ( WP_REST_Server :: EDITABLE ),
),
'schema' => array ( $this , 'get_public_item_schema' ),
)
);
2016-08-05 21:23:40 +00:00
}
2017-01-26 19:22:57 +00:00
/**
2016-08-05 21:23:40 +00:00
* Check whether a given request has permission to view system status tools .
*
* @ param WP_REST_Request $request Full details about the request .
* @ return WP_Error | boolean
*/
public function get_items_permissions_check ( $request ) {
2017-01-26 19:22:57 +00:00
if ( ! wc_rest_check_manager_permissions ( 'system_status' , 'read' ) ) {
return new WP_Error ( 'woocommerce_rest_cannot_view' , __ ( 'Sorry, you cannot list resources.' , 'woocommerce' ), array ( 'status' => rest_authorization_required_code () ) );
2016-08-05 21:23:40 +00:00
}
return true ;
}
/**
* Check whether a given request has permission to view a specific system status tool .
*
* @ param WP_REST_Request $request Full details about the request .
* @ return WP_Error | boolean
*/
public function get_item_permissions_check ( $request ) {
if ( ! wc_rest_check_manager_permissions ( 'system_status' , 'read' ) ) {
return new WP_Error ( 'woocommerce_rest_cannot_view' , __ ( 'Sorry, you cannot view this resource.' , 'woocommerce' ), array ( 'status' => rest_authorization_required_code () ) );
}
return true ;
}
/**
* Check whether a given request has permission to execute a specific system status tool .
*
* @ param WP_REST_Request $request Full details about the request .
* @ return WP_Error | boolean
*/
public function update_item_permissions_check ( $request ) {
if ( ! wc_rest_check_manager_permissions ( 'system_status' , 'edit' ) ) {
return new WP_Error ( 'woocommerce_rest_cannot_update' , __ ( 'Sorry, you cannot update resource.' , 'woocommerce' ), array ( 'status' => rest_authorization_required_code () ) );
}
return true ;
}
/**
2017-07-10 05:56:28 +00:00
* A list of available tools for use in the system status section .
2016-08-05 21:23:40 +00:00
* 'button' becomes 'action' in the API .
*
* @ return array
*/
public function get_tools () {
$tools = array (
2018-01-17 22:33:58 +00:00
'clear_transients' => array (
'name' => __ ( 'WooCommerce transients' , 'woocommerce' ),
'button' => __ ( 'Clear transients' , 'woocommerce' ),
'desc' => __ ( 'This tool will clear the product/shop transients cache.' , 'woocommerce' ),
2016-08-05 21:23:40 +00:00
),
2018-01-17 22:33:58 +00:00
'clear_expired_transients' => array (
'name' => __ ( 'Expired transients' , 'woocommerce' ),
'button' => __ ( 'Clear transients' , 'woocommerce' ),
'desc' => __ ( 'This tool will clear ALL expired transients from WordPress.' , 'woocommerce' ),
2016-08-05 21:23:40 +00:00
),
2016-09-30 08:39:37 +00:00
'delete_orphaned_variations' => array (
2018-01-17 22:33:58 +00:00
'name' => __ ( 'Orphaned variations' , 'woocommerce' ),
'button' => __ ( 'Delete orphaned variations' , 'woocommerce' ),
'desc' => __ ( 'This tool will delete all variations which have no parent.' , 'woocommerce' ),
2017-06-29 18:14:09 +00:00
),
2018-01-17 22:33:58 +00:00
'add_order_indexes' => array (
'name' => __ ( 'Order address indexes' , 'woocommerce' ),
'button' => __ ( 'Index orders' , 'woocommerce' ),
'desc' => __ ( 'This tool will add address indexes to orders that do not have them yet. This improves order search results.' , 'woocommerce' ),
2017-01-26 19:22:57 +00:00
),
2018-01-17 22:33:58 +00:00
'recount_terms' => array (
'name' => __ ( 'Term counts' , 'woocommerce' ),
'button' => __ ( 'Recount terms' , 'woocommerce' ),
'desc' => __ ( 'This tool will recount product terms - useful when changing your settings in a way which hides products from the catalog.' , 'woocommerce' ),
2016-08-05 21:23:40 +00:00
),
2018-01-17 22:33:58 +00:00
'reset_roles' => array (
'name' => __ ( 'Capabilities' , 'woocommerce' ),
'button' => __ ( 'Reset capabilities' , 'woocommerce' ),
'desc' => __ ( 'This tool will reset the admin, customer and shop_manager roles to default. Use this if your users cannot access all of the WooCommerce admin pages.' , 'woocommerce' ),
2016-08-05 21:23:40 +00:00
),
2018-01-17 22:33:58 +00:00
'clear_sessions' => array (
'name' => __ ( 'Clear customer sessions' , 'woocommerce' ),
'button' => __ ( 'Clear' , 'woocommerce' ),
'desc' => sprintf (
2016-10-24 23:56:38 +00:00
'<strong class="red">%1$s</strong> %2$s' ,
__ ( 'Note:' , 'woocommerce' ),
2018-01-15 17:04:50 +00:00
__ ( 'This tool will delete all customer session data from the database, including current carts and saved carts in the database.' , 'woocommerce' )
2016-10-24 23:56:38 +00:00
),
2016-08-05 21:23:40 +00:00
),
2018-01-17 22:33:58 +00:00
'install_pages' => array (
'name' => __ ( 'Create default WooCommerce pages' , 'woocommerce' ),
'button' => __ ( 'Create pages' , 'woocommerce' ),
'desc' => sprintf (
2016-10-24 23:56:38 +00:00
'<strong class="red">%1$s</strong> %2$s' ,
__ ( 'Note:' , 'woocommerce' ),
__ ( 'This tool will install all the missing WooCommerce pages. Pages already defined and set up will not be replaced.' , 'woocommerce' )
),
2016-08-05 21:23:40 +00:00
),
2018-01-17 22:33:58 +00:00
'delete_taxes' => array (
'name' => __ ( 'Delete WooCommerce tax rates' , 'woocommerce' ),
'button' => __ ( 'Delete tax rates' , 'woocommerce' ),
'desc' => sprintf (
2016-10-24 23:56:38 +00:00
'<strong class="red">%1$s</strong> %2$s' ,
__ ( 'Note:' , 'woocommerce' ),
2017-08-15 11:05:34 +00:00
__ ( 'This option will delete ALL of your tax rates, use with caution. This action cannot be reversed.' , 'woocommerce' )
2016-10-24 23:56:38 +00:00
),
2016-08-05 21:23:40 +00:00
),
2018-01-17 22:33:58 +00:00
'reset_tracking' => array (
'name' => __ ( 'Reset usage tracking' , 'woocommerce' ),
'button' => __ ( 'Reset' , 'woocommerce' ),
'desc' => __ ( 'This will reset your usage tracking settings, causing it to show the opt-in banner again and not sending any data.' , 'woocommerce' ),
2016-08-27 01:46:45 +00:00
),
2018-02-13 07:55:50 +00:00
'regenerate_thumbnails' => array (
'name' => __ ( 'Regenerate shop thumbnails' , 'woocommerce' ),
'button' => __ ( 'Regenerate' , 'woocommerce' ),
2018-02-13 13:59:54 +00:00
'desc' => __ ( 'This will regenerate all shop thumbnails to match your theme and/or image settings.' , 'woocommerce' ),
2018-03-05 20:53:06 +00:00
),
2016-08-05 21:23:40 +00:00
);
2018-02-14 11:38:18 +00:00
// Jetpack does the image resizing heavy lifting so you don't have to.
2018-02-14 17:25:52 +00:00
if ( ( class_exists ( 'Jetpack' ) && Jetpack :: is_module_active ( 'photon' ) ) || ! apply_filters ( 'woocommerce_background_image_regeneration' , true ) ) {
2018-02-14 11:38:18 +00:00
unset ( $tools [ 'regenerate_thumbnails' ] );
}
2016-08-05 21:23:40 +00:00
return apply_filters ( 'woocommerce_debug_tools' , $tools );
}
2017-01-26 19:22:57 +00:00
/**
2016-08-05 21:23:40 +00:00
* Get a list of system status tools .
*
* @ param WP_REST_Request $request Full details about the request .
* @ return WP_Error | WP_REST_Response
*/
public function get_items ( $request ) {
$tools = array ();
foreach ( $this -> get_tools () as $id => $tool ) {
2018-03-05 20:53:06 +00:00
$tools [] = $this -> prepare_response_for_collection (
$this -> prepare_item_for_response (
array (
'id' => $id ,
'name' => $tool [ 'name' ],
'action' => $tool [ 'button' ],
'description' => $tool [ 'desc' ],
), $request
)
);
2016-08-05 21:23:40 +00:00
}
$response = rest_ensure_response ( $tools );
return $response ;
}
/**
* Return a single tool .
*
* @ param WP_REST_Request $request
* @ return WP_Error | WP_REST_Response
*/
public function get_item ( $request ) {
$tools = $this -> get_tools ();
if ( empty ( $tools [ $request [ 'id' ] ] ) ) {
return new WP_Error ( 'woocommerce_rest_system_status_tool_invalid_id' , __ ( 'Invalid tool ID.' , 'woocommerce' ), array ( 'status' => 404 ) );
}
$tool = $tools [ $request [ 'id' ] ];
2018-03-05 20:53:06 +00:00
return rest_ensure_response (
$this -> prepare_item_for_response (
array (
'id' => $request [ 'id' ],
'name' => $tool [ 'name' ],
'action' => $tool [ 'button' ],
'description' => $tool [ 'desc' ],
), $request
)
);
2016-08-05 21:23:40 +00:00
}
/**
* Update ( execute ) a tool .
2018-01-17 22:33:58 +00:00
*
2016-08-05 21:23:40 +00:00
* @ param WP_REST_Request $request
* @ return WP_Error | WP_REST_Response
*/
public function update_item ( $request ) {
$tools = $this -> get_tools ();
if ( empty ( $tools [ $request [ 'id' ] ] ) ) {
return new WP_Error ( 'woocommerce_rest_system_status_tool_invalid_id' , __ ( 'Invalid tool ID.' , 'woocommerce' ), array ( 'status' => 404 ) );
}
$tool = $tools [ $request [ 'id' ] ];
$tool = array (
2018-01-17 22:33:58 +00:00
'id' => $request [ 'id' ],
'name' => $tool [ 'name' ],
'action' => $tool [ 'button' ],
'description' => $tool [ 'desc' ],
2016-08-05 21:23:40 +00:00
);
$execute_return = $this -> execute_tool ( $request [ 'id' ] );
2018-01-17 22:33:58 +00:00
$tool = array_merge ( $tool , $execute_return );
2016-08-05 21:23:40 +00:00
2018-01-17 21:48:23 +00:00
/**
* Fires after a WooCommerce REST system status tool has been executed .
*
* @ param array $tool Details about the tool that has been executed .
* @ param WP_REST_Request $request The current WP_REST_Request object .
*/
2018-01-18 16:59:47 +00:00
do_action ( 'woocommerce_rest_insert_system_status_tool' , $tool , $request );
2018-01-17 21:48:23 +00:00
2016-08-05 21:23:40 +00:00
$request -> set_param ( 'context' , 'edit' );
$response = $this -> prepare_item_for_response ( $tool , $request );
return rest_ensure_response ( $response );
}
/**
* Prepare a tool item for serialization .
*
2018-01-17 22:33:58 +00:00
* @ param array $item Object .
* @ param WP_REST_Request $request Request object .
2016-08-05 21:23:40 +00:00
* @ return WP_REST_Response $response Response data .
*/
public function prepare_item_for_response ( $item , $request ) {
$context = empty ( $request [ 'context' ] ) ? 'view' : $request [ 'context' ];
$data = $this -> add_additional_fields_to_object ( $item , $request );
$data = $this -> filter_response_by_context ( $data , $context );
$response = rest_ensure_response ( $data );
$response -> add_links ( $this -> prepare_links ( $item [ 'id' ] ) );
return $response ;
}
2017-01-26 19:22:57 +00:00
/**
2016-08-05 21:23:40 +00:00
* Get the system status tools schema , conforming to JSON Schema .
*
* @ return array
*/
public function get_item_schema () {
$schema = array (
'$schema' => 'http://json-schema.org/draft-04/schema#' ,
'title' => 'system_status_tool' ,
'type' => 'object' ,
'properties' => array (
2018-01-17 22:33:58 +00:00
'id' => array (
'description' => __ ( 'A unique identifier for the tool.' , 'woocommerce' ),
'type' => 'string' ,
'context' => array ( 'view' , 'edit' ),
'arg_options' => array (
2016-08-05 21:23:40 +00:00
'sanitize_callback' => 'sanitize_title' ,
),
),
2018-01-17 22:33:58 +00:00
'name' => array (
'description' => __ ( 'Tool name.' , 'woocommerce' ),
'type' => 'string' ,
'context' => array ( 'view' , 'edit' ),
'arg_options' => array (
2016-08-05 21:23:40 +00:00
'sanitize_callback' => 'sanitize_text_field' ,
),
),
2018-01-17 22:33:58 +00:00
'action' => array (
'description' => __ ( 'What running the tool will do.' , 'woocommerce' ),
'type' => 'string' ,
'context' => array ( 'view' , 'edit' ),
'arg_options' => array (
2016-08-05 21:23:40 +00:00
'sanitize_callback' => 'sanitize_text_field' ,
),
),
2018-01-17 22:33:58 +00:00
'description' => array (
'description' => __ ( 'Tool description.' , 'woocommerce' ),
'type' => 'string' ,
'context' => array ( 'view' , 'edit' ),
'arg_options' => array (
2016-08-05 21:23:40 +00:00
'sanitize_callback' => 'sanitize_text_field' ,
),
),
2018-01-17 22:33:58 +00:00
'success' => array (
'description' => __ ( 'Did the tool run successfully?' , 'woocommerce' ),
'type' => 'boolean' ,
'context' => array ( 'edit' ),
2016-08-05 21:23:40 +00:00
),
2018-01-17 22:33:58 +00:00
'message' => array (
'description' => __ ( 'Tool return message.' , 'woocommerce' ),
'type' => 'string' ,
'context' => array ( 'edit' ),
'arg_options' => array (
2016-08-05 21:23:40 +00:00
'sanitize_callback' => 'sanitize_text_field' ,
),
),
),
);
return $this -> add_additional_fields_schema ( $schema );
}
/**
* Prepare links for the request .
*
* @ param string $id
* @ return array
*/
protected function prepare_links ( $id ) {
$base = '/' . $this -> namespace . '/' . $this -> rest_base ;
$links = array (
'item' => array (
'href' => rest_url ( trailingslashit ( $base ) . $id ),
'embeddable' => true ,
),
);
return $links ;
}
/**
* Get any query params needed .
*
* @ return array
*/
public function get_collection_params () {
return array (
'context' => $this -> get_context_param ( array ( 'default' => 'view' ) ),
);
}
/**
* Actually executes a a tool .
*
* @ param string $tool
* @ return array
*/
public function execute_tool ( $tool ) {
global $wpdb ;
$ran = true ;
switch ( $tool ) {
2018-01-17 22:33:58 +00:00
case 'clear_transients' :
2016-08-05 21:23:40 +00:00
wc_delete_product_transients ();
wc_delete_shop_order_transients ();
WC_Cache_Helper :: get_transient_version ( 'shipping' , true );
2016-10-12 10:16:30 +00:00
$message = __ ( 'Product transients cleared' , 'woocommerce' );
2018-01-17 22:33:58 +00:00
break ;
case 'clear_expired_transients' :
2017-09-05 10:54:04 +00:00
$message = sprintf ( __ ( '%d transients rows cleared' , 'woocommerce' ), wc_delete_expired_transients () );
2018-01-17 22:33:58 +00:00
break ;
case 'delete_orphaned_variations' :
2016-09-30 08:39:37 +00:00
/**
2017-01-26 19:22:57 +00:00
* Delete orphans
*/
2018-03-05 20:53:06 +00:00
$result = absint (
$wpdb -> query (
" DELETE products
2016-09-30 08:39:37 +00:00
FROM { $wpdb -> posts } products
LEFT JOIN { $wpdb -> posts } wp ON wp . ID = products . post_parent
2018-03-05 20:53:06 +00:00
WHERE wp . ID IS NULL AND products . post_type = 'product_variation' ; "
)
);
2016-10-12 10:16:30 +00:00
$message = sprintf ( __ ( '%d orphaned variations deleted' , 'woocommerce' ), $result );
2018-01-17 22:33:58 +00:00
break ;
case 'add_order_indexes' :
2017-06-29 18:14:09 +00:00
/**
* Add billing and shipping address indexes containing the customer name for orders
* that don ' t have address indexes yet .
*/
2018-01-17 22:33:58 +00:00
$sql = " INSERT INTO { $wpdb -> postmeta } ( post_id, meta_key, meta_value )
2017-11-10 06:21:28 +00:00
SELECT post_id , '%s' , GROUP_CONCAT ( meta_value SEPARATOR ' ' )
2017-06-29 18:14:09 +00:00
FROM { $wpdb -> postmeta }
2017-11-10 06:21:28 +00:00
WHERE meta_key IN ( '%s' , '%s' )
2017-06-29 18:14:09 +00:00
AND post_id IN ( SELECT DISTINCT post_id FROM { $wpdb -> postmeta }
2017-11-10 06:21:28 +00:00
WHERE post_id NOT IN ( SELECT post_id FROM { $wpdb -> postmeta } WHERE meta_key = '%s' )
AND post_id IN ( SELECT post_id FROM { $wpdb -> postmeta } WHERE meta_key = '%s' ) )
2017-06-29 18:16:26 +00:00
GROUP BY post_id " ;
2018-01-17 22:33:58 +00:00
$rows = $wpdb -> query ( $wpdb -> prepare ( $sql , '_billing_address_index' , '_billing_first_name' , '_billing_last_name' , '_billing_address_index' , '_billing_last_name' ) );
$rows += $wpdb -> query ( $wpdb -> prepare ( $sql , '_shipping_address_index' , '_shipping_first_name' , '_shipping_last_name' , '_shipping_address_index' , '_shipping_last_name' ) );
2017-06-29 18:14:09 +00:00
$message = sprintf ( __ ( '%d indexes added' , 'woocommerce' ), $rows );
2018-01-17 22:33:58 +00:00
break ;
case 'reset_roles' :
2016-08-05 21:23:40 +00:00
// Remove then re-add caps and roles
WC_Install :: remove_roles ();
WC_Install :: create_roles ();
$message = __ ( 'Roles successfully reset' , 'woocommerce' );
2018-01-17 22:33:58 +00:00
break ;
case 'recount_terms' :
2018-03-05 20:53:06 +00:00
$product_cats = get_terms (
'product_cat' , array (
'hide_empty' => false ,
'fields' => 'id=>parent' ,
)
);
2016-08-05 21:23:40 +00:00
_wc_term_recount ( $product_cats , get_taxonomy ( 'product_cat' ), true , false );
2018-03-05 20:53:06 +00:00
$product_tags = get_terms (
'product_tag' , array (
'hide_empty' => false ,
'fields' => 'id=>parent' ,
)
);
2016-08-05 21:23:40 +00:00
_wc_term_recount ( $product_tags , get_taxonomy ( 'product_tag' ), true , false );
$message = __ ( 'Terms successfully recounted' , 'woocommerce' );
2018-01-17 22:33:58 +00:00
break ;
case 'clear_sessions' :
2016-08-05 21:23:40 +00:00
$wpdb -> query ( " TRUNCATE { $wpdb -> prefix } woocommerce_sessions " );
2018-01-15 17:04:50 +00:00
$result = absint ( $wpdb -> query ( " DELETE FROM { $wpdb -> usermeta } WHERE meta_key='_woocommerce_persistent_cart_ " . get_current_blog_id () . " '; " ) );
2016-08-05 21:23:40 +00:00
wp_cache_flush ();
2018-01-15 17:04:50 +00:00
$message = sprintf ( __ ( 'Deleted all active sessions, and %d saved carts.' , 'woocommerce' ), absint ( $result ) );
2018-01-17 22:33:58 +00:00
break ;
case 'install_pages' :
2016-08-05 21:23:40 +00:00
WC_Install :: create_pages ();
2017-04-12 21:03:39 +00:00
$message = __ ( 'All missing WooCommerce pages successfully installed' , 'woocommerce' );
2018-01-17 22:33:58 +00:00
break ;
2016-08-05 21:23:40 +00:00
2018-01-17 22:33:58 +00:00
case 'delete_taxes' :
2016-08-05 21:23:40 +00:00
$wpdb -> query ( " TRUNCATE TABLE { $wpdb -> prefix } woocommerce_tax_rates; " );
$wpdb -> query ( " TRUNCATE TABLE { $wpdb -> prefix } woocommerce_tax_rate_locations; " );
WC_Cache_Helper :: incr_cache_prefix ( 'taxes' );
$message = __ ( 'Tax rates successfully deleted' , 'woocommerce' );
2018-01-17 22:33:58 +00:00
break ;
case 'reset_tracking' :
2016-08-05 21:23:40 +00:00
delete_option ( 'woocommerce_allow_tracking' );
WC_Admin_Notices :: add_notice ( 'tracking' );
$message = __ ( 'Usage tracking settings successfully reset.' , 'woocommerce' );
2018-01-17 22:33:58 +00:00
break ;
2018-02-13 07:55:50 +00:00
case 'regenerate_thumbnails' :
WC_Regenerate_Images :: queue_image_regeneration ();
2018-02-14 08:38:59 +00:00
$message = __ ( 'Thumbnail regeneration has been scheduled to run in the background.' , 'woocommerce' );
2018-02-13 07:55:50 +00:00
break ;
2018-01-17 22:33:58 +00:00
default :
2016-08-05 21:23:40 +00:00
$tools = $this -> get_tools ();
if ( isset ( $tools [ $tool ][ 'callback' ] ) ) {
$callback = $tools [ $tool ][ 'callback' ];
2018-01-17 22:33:58 +00:00
$return = call_user_func ( $callback );
2017-04-20 16:25:19 +00:00
if ( is_string ( $return ) ) {
$message = $return ;
} elseif ( false === $return ) {
2016-08-05 21:23:40 +00:00
$callback_string = is_array ( $callback ) ? get_class ( $callback [ 0 ] ) . '::' . $callback [ 1 ] : $callback ;
2018-01-17 22:33:58 +00:00
$ran = false ;
$message = sprintf ( __ ( 'There was an error calling %s' , 'woocommerce' ), $callback_string );
2016-08-05 21:23:40 +00:00
} else {
$message = __ ( 'Tool ran.' , 'woocommerce' );
}
} else {
$ran = false ;
$message = __ ( 'There was an error calling this tool. There is no callback present.' , 'woocommerce' );
}
2018-01-17 22:33:58 +00:00
break ;
2016-08-05 21:23:40 +00:00
}
2018-01-17 22:33:58 +00:00
return array (
'success' => $ran ,
'message' => $message ,
);
2016-08-05 21:23:40 +00:00
}
}