2014-07-30 20:23:22 +00:00
< ? php
2014-09-20 19:03:51 +00:00
if ( ! defined ( 'ABSPATH' ) ) {
exit ; // Exit if accessed directly
}
2014-07-30 20:23:22 +00:00
/**
2015-11-03 13:31:20 +00:00
* WooCommerce Webhook class .
2014-07-30 20:23:22 +00:00
*
2015-11-03 13:31:20 +00:00
* This class handles storing and retrieving webhook data from the associated .
* `shop_webhook` custom post type , as well as delivery logs from the `webhook_delivery` .
2014-07-30 20:23:22 +00:00
* comment type .
*
* Webhooks are enqueued to their associated actions , delivered , and logged .
*
* @ author WooThemes
* @ category Webhooks
* @ package WooCommerce / Webhooks
* @ since 2.2
*/
class WC_Webhook {
/** @var int webhook ID (post ID) */
public $id ;
/**
2015-11-03 13:31:20 +00:00
* Setup webhook & load post data .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ param string | int $id
*/
public function __construct ( $id ) {
$id = absint ( $id );
if ( ! $id ) {
return ;
}
$this -> id = $id ;
$this -> post_data = get_post ( $id );
}
/**
2015-11-03 13:31:20 +00:00
* Magic isset as a wrapper around metadata_exists () .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ param string $key
* @ return bool true if $key isset , false otherwise
*/
public function __isset ( $key ) {
if ( ! $this -> id ) {
return false ;
}
return metadata_exists ( 'post' , $this -> id , '_' . $key );
}
/**
2015-11-03 13:31:20 +00:00
* Magic get , wraps get_post_meta () for all keys except $status .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ param string $key
2014-11-20 00:43:09 +00:00
* @ return mixed value
2014-07-30 20:23:22 +00:00
*/
public function __get ( $key ) {
if ( 'status' === $key ) {
$value = $this -> get_status ();
} else {
$value = get_post_meta ( $this -> id , '_' . $key , true );
}
return $value ;
}
/**
2015-11-03 13:31:20 +00:00
* Enqueue the hooks associated with the webhook .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
*/
public function enqueue () {
2014-12-17 03:44:35 +00:00
$hooks = $this -> get_hooks ();
2014-12-17 03:48:29 +00:00
$url = $this -> get_delivery_url ();
2014-12-17 03:44:35 +00:00
2014-12-17 03:48:29 +00:00
if ( is_array ( $hooks ) && ! empty ( $url ) ) {
2014-12-17 03:44:35 +00:00
foreach ( $hooks as $hook ) {
2014-12-16 22:16:38 +00:00
add_action ( $hook , array ( $this , 'process' ) );
}
2014-07-30 20:23:22 +00:00
}
}
/**
2015-11-03 13:31:20 +00:00
* Process the webhook for delivery by verifying that it should be delivered .
* and scheduling the delivery ( in the background by default , or immediately ) .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ param mixed $arg the first argument provided from the associated hooks
*/
public function process ( $arg ) {
// verify that webhook should be processed for delivery
if ( ! $this -> should_deliver ( $arg ) ) {
return ;
}
// webhooks are processed in the background by default
// so as to avoid delays or failures in delivery from affecting the
// user who triggered it
2016-04-01 07:05:24 +00:00
if ( apply_filters ( 'woocommerce_webhook_deliver_async' , true , $this , $arg ) ) {
2014-07-30 20:23:22 +00:00
// deliver in background
2016-02-29 19:23:45 +00:00
wp_schedule_single_event ( time (), 'woocommerce_deliver_webhook_async' , array ( $this -> id , $arg ) );
2014-07-30 20:23:22 +00:00
} else {
// deliver immediately
$this -> deliver ( $arg );
}
}
/**
2015-11-03 13:31:20 +00:00
* Helper to check if the webhook should be delivered , as some hooks .
2014-07-30 20:23:22 +00:00
* ( like `wp_trash_post` ) will fire for every post type , not just ours .
*
* @ since 2.2
* @ param mixed $arg first hook argument
* @ return bool true if webhook should be delivered , false otherwise
*/
private function should_deliver ( $arg ) {
2016-03-03 12:52:58 +00:00
$should_deliver = true ;
$current_action = current_action ();
2014-07-30 20:23:22 +00:00
// only active webhooks can be delivered
if ( 'active' != $this -> get_status () ) {
2016-03-03 12:52:58 +00:00
$should_deliver = false ;
2017-04-27 18:44:57 +00:00
} elseif ( in_array ( $current_action , array ( 'delete_post' , 'wp_trash_post' , 'untrashed_post' ), true ) ) {
// Only deliver deleted/restored event for coupons, orders, and products.
2017-02-02 20:52:00 +00:00
if ( isset ( $GLOBALS [ 'post_type' ] ) && ! in_array ( $GLOBALS [ 'post_type' ], array ( 'shop_coupon' , 'shop_order' , 'product' ) ) ) {
2016-11-24 18:07:32 +00:00
$should_deliver = false ;
}
2014-07-30 20:23:22 +00:00
2016-11-24 18:07:32 +00:00
// Check if is delivering for the correct resource.
2017-02-02 20:52:00 +00:00
if ( isset ( $GLOBALS [ 'post_type' ] ) && str_replace ( 'shop_' , '' , $GLOBALS [ 'post_type' ] ) !== $this -> get_resource () ) {
2016-11-24 18:07:32 +00:00
$should_deliver = false ;
}
2014-07-30 20:23:22 +00:00
} elseif ( 'delete_user' == $current_action ) {
$user = get_userdata ( absint ( $arg ) );
// only deliver deleted customer event for users with customer role
if ( ! $user || ! in_array ( 'customer' , ( array ) $user -> roles ) ) {
2016-03-03 12:52:58 +00:00
$should_deliver = false ;
2014-07-30 20:23:22 +00:00
}
2015-05-12 04:01:23 +00:00
// check if the custom order type has chosen to exclude order webhooks from triggering along with its own webhooks.
2015-05-27 15:46:44 +00:00
} elseif ( 'order' == $this -> get_resource () && ! in_array ( get_post_type ( absint ( $arg ) ), wc_get_order_types ( 'order-webhooks' ) ) ) {
2016-03-03 12:52:58 +00:00
$should_deliver = false ;
2015-05-12 04:01:23 +00:00
2016-05-27 10:35:16 +00:00
} elseif ( 0 === strpos ( $current_action , 'woocommerce_process_shop' ) || 0 === strpos ( $current_action , 'woocommerce_process_product' ) ) {
// the `woocommerce_process_shop_*` and `woocommerce_process_product_*` hooks
// fire for create and update of products and orders, so check the post
// creation date to determine the actual event
2015-05-27 15:46:44 +00:00
$resource = get_post ( absint ( $arg ) );
2016-08-12 10:53:40 +00:00
// Drafts don't have post_date_gmt so calculate it here
$gmt_date = get_gmt_from_date ( $resource -> post_date );
2014-07-30 20:23:22 +00:00
// a resource is considered created when the hook is executed within 10 seconds of the post creation date
2016-08-12 10:53:40 +00:00
$resource_created = ( ( time () - 10 ) <= strtotime ( $gmt_date ) );
2014-07-30 20:23:22 +00:00
if ( 'created' == $this -> get_event () && ! $resource_created ) {
2016-03-03 12:52:58 +00:00
$should_deliver = false ;
2014-07-30 20:23:22 +00:00
} elseif ( 'updated' == $this -> get_event () && $resource_created ) {
2016-03-03 12:52:58 +00:00
$should_deliver = false ;
2014-07-30 20:23:22 +00:00
}
}
2016-03-03 12:52:58 +00:00
/*
* Let other plugins intercept deliver for some messages queue like rabbit / zeromq
*/
return apply_filters ( 'woocommerce_webhook_should_deliver' , $should_deliver , $this , $arg );
2014-07-30 20:23:22 +00:00
}
/**
2015-11-03 13:31:20 +00:00
* Deliver the webhook payload using wp_safe_remote_request () .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
2016-04-28 17:45:13 +00:00
* @ param mixed $arg First hook argument .
2014-07-30 20:23:22 +00:00
*/
public function deliver ( $arg ) {
$payload = $this -> build_payload ( $arg );
2016-04-28 17:45:13 +00:00
// Setup request args.
2014-07-30 20:23:22 +00:00
$http_args = array (
'method' => 'POST' ,
'timeout' => MINUTE_IN_SECONDS ,
'redirection' => 0 ,
'httpversion' => '1.0' ,
'blocking' => true ,
'user-agent' => sprintf ( 'WooCommerce/%s Hookshot (WordPress/%s)' , WC_VERSION , $GLOBALS [ 'wp_version' ] ),
'body' => trim ( json_encode ( $payload ) ),
'headers' => array ( 'Content-Type' => 'application/json' ),
'cookies' => array (),
);
$http_args = apply_filters ( 'woocommerce_webhook_http_args' , $http_args , $arg , $this -> id );
2016-04-28 17:45:13 +00:00
// Add custom headers.
$http_args [ 'headers' ][ 'X-WC-Webhook-Source' ] = home_url ( '/' ); // Since 2.6.0.
2014-07-30 20:23:22 +00:00
$http_args [ 'headers' ][ 'X-WC-Webhook-Topic' ] = $this -> get_topic ();
$http_args [ 'headers' ][ 'X-WC-Webhook-Resource' ] = $this -> get_resource ();
$http_args [ 'headers' ][ 'X-WC-Webhook-Event' ] = $this -> get_event ();
$http_args [ 'headers' ][ 'X-WC-Webhook-Signature' ] = $this -> generate_signature ( $http_args [ 'body' ] );
$http_args [ 'headers' ][ 'X-WC-Webhook-ID' ] = $this -> id ;
$http_args [ 'headers' ][ 'X-WC-Webhook-Delivery-ID' ] = $delivery_id = $this -> get_new_delivery_id ();
$start_time = microtime ( true );
2016-04-28 17:45:13 +00:00
// Webhook away!
2015-05-20 16:03:37 +00:00
$response = wp_safe_remote_request ( $this -> get_delivery_url (), $http_args );
2014-07-30 20:23:22 +00:00
$duration = round ( microtime ( true ) - $start_time , 5 );
$this -> log_delivery ( $delivery_id , $http_args , $response , $duration );
do_action ( 'woocommerce_webhook_delivery' , $http_args , $response , $duration , $arg , $this -> id );
}
2016-11-23 00:59:55 +00:00
/**
* Get Legacy API payload .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-11-23 00:59:55 +00:00
* @ param string $resource Resource type .
* @ param int $resource_id Resource ID .
* @ param string $event Event type .
* @ return array
*/
private function get_legacy_api_payload ( $resource , $resource_id , $event ) {
// Include & load API classes.
WC () -> api -> includes ();
WC () -> api -> register_resources ( new WC_API_Server ( '/' ) );
switch ( $resource ) {
case 'coupon' :
$payload = WC () -> api -> WC_API_Coupons -> get_coupon ( $resource_id );
break ;
case 'customer' :
$payload = WC () -> api -> WC_API_Customers -> get_customer ( $resource_id );
break ;
case 'order' :
$payload = WC () -> api -> WC_API_Orders -> get_order ( $resource_id , null , apply_filters ( 'woocommerce_webhook_order_payload_filters' , array () ) );
break ;
case 'product' :
// Bulk and quick edit action hooks return a product object instead of an ID.
if ( 'updated' === $event && is_a ( $resource_id , 'WC_Product' ) ) {
$resource_id = $resource_id -> get_id ();
}
$payload = WC () -> api -> WC_API_Products -> get_product ( $resource_id );
break ;
// Custom topics include the first hook argument.
case 'action' :
$payload = array (
'action' => current ( $this -> get_hooks () ),
'arg' => $resource_id ,
);
break ;
default :
$payload = array ();
break ;
}
return $payload ;
}
/**
* Get WP API integration payload .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-11-23 00:59:55 +00:00
* @ param string $resource Resource type .
* @ param int $resource_id Resource ID .
* @ param string $event Event type .
* @ return array
*/
private function get_wp_api_payload ( $resource , $resource_id , $event ) {
2017-04-02 06:07:09 +00:00
$version_suffix = 'wp_api_v1' === $this -> get_api_version () ? '_V1' : '' ;
2016-11-23 00:59:55 +00:00
switch ( $resource ) {
case 'coupon' :
case 'customer' :
case 'order' :
case 'product' :
2017-04-02 06:07:09 +00:00
$class = 'WC_REST_' . ucfirst ( $resource ) . 's' . $version_suffix . '_Controller' ;
2016-11-23 00:59:55 +00:00
$request = new WP_REST_Request ( 'GET' );
$controller = new $class ;
// Bulk and quick edit action hooks return a product object instead of an ID.
if ( 'product' === $resource && 'updated' === $event && is_a ( $resource_id , 'WC_Product' ) ) {
$resource_id = $resource_id -> get_id ();
}
$request -> set_param ( 'id' , $resource_id );
$result = $controller -> get_item ( $request );
$payload = isset ( $result -> data ) ? $result -> data : array ();
break ;
// Custom topics include the first hook argument.
case 'action' :
$payload = array (
'action' => current ( $this -> get_hooks () ),
'arg' => $resource_id ,
);
break ;
default :
$payload = array ();
break ;
}
return $payload ;
}
2014-07-30 20:23:22 +00:00
/**
2015-11-03 13:31:20 +00:00
* Build the payload data for the webhook .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ param mixed $resource_id first hook argument , typically the resource ID
* @ return mixed payload data
*/
2017-04-24 11:22:47 +00:00
public function build_payload ( $resource_id ) {
2014-07-30 20:23:22 +00:00
// build the payload with the same user context as the user who created
// the webhook -- this avoids permission errors as background processing
// runs with no user context
$current_user = get_current_user_id ();
wp_set_current_user ( $this -> get_user_id () );
$resource = $this -> get_resource ();
$event = $this -> get_event ();
2016-11-23 00:59:55 +00:00
// If a resource has been deleted, just include the ID.
2014-07-30 20:23:22 +00:00
if ( 'deleted' == $event ) {
$payload = array (
'id' => $resource_id ,
);
} else {
2017-04-04 00:41:00 +00:00
if ( in_array ( $this -> get_api_version (), array ( 'wp_api_v1' , 'wp_api_v2' ), true ) ) {
2016-11-23 00:59:55 +00:00
$payload = $this -> get_wp_api_payload ( $resource , $resource_id , $event );
} else {
$payload = $this -> get_legacy_api_payload ( $resource , $resource_id , $event );
2014-07-30 20:23:22 +00:00
}
}
2016-11-23 00:59:55 +00:00
// Restore the current user.
2014-07-30 20:23:22 +00:00
wp_set_current_user ( $current_user );
return apply_filters ( 'woocommerce_webhook_payload' , $payload , $resource , $resource_id , $this -> id );
}
/**
2015-11-03 13:31:20 +00:00
* Generate a base64 - encoded HMAC - SHA256 signature of the payload body so the .
* recipient can verify the authenticity of the webhook . Note that the signature .
* is calculated after the body has already been encoded ( JSON by default ) .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ param string $payload payload data to hash
* @ return string hash
*/
public function generate_signature ( $payload ) {
$hash_algo = apply_filters ( 'woocommerce_webhook_hash_algorithm' , 'sha256' , $payload , $this -> id );
return base64_encode ( hash_hmac ( $hash_algo , $payload , $this -> get_secret (), true ) );
}
/**
2015-11-03 13:31:20 +00:00
* Create a new comment for log the delivery request / response and .
* return the ID for inclusion in the webhook request .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return int delivery ( comment ) ID
*/
public function get_new_delivery_id () {
$comment_data = apply_filters ( 'woocommerce_new_webhook_delivery_data' , array (
'comment_author' => __ ( 'WooCommerce' , 'woocommerce' ),
'comment_author_email' => sanitize_email ( sprintf ( '%s@%s' , strtolower ( __ ( 'WooCommerce' , 'woocommerce' ) ), isset ( $_SERVER [ 'HTTP_HOST' ] ) ? str_replace ( 'www.' , '' , $_SERVER [ 'HTTP_HOST' ] ) : 'noreply.com' ) ),
'comment_post_ID' => $this -> id ,
'comment_agent' => 'WooCommerce Hookshot' ,
'comment_type' => 'webhook_delivery' ,
'comment_parent' => 0 ,
'comment_approved' => 1 ,
), $this -> id );
$comment_id = wp_insert_comment ( $comment_data );
return $comment_id ;
}
/**
2015-11-03 13:31:20 +00:00
* Log the delivery request / response .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ param int $delivery_id previously created comment ID
* @ param array $request request data
2016-06-06 17:57:24 +00:00
* @ param array | WP_Error $response response data
2014-07-30 20:23:22 +00:00
* @ param float $duration request duration
*/
public function log_delivery ( $delivery_id , $request , $response , $duration ) {
// save request data
add_comment_meta ( $delivery_id , '_request_method' , $request [ 'method' ] );
2014-09-07 20:10:30 +00:00
add_comment_meta ( $delivery_id , '_request_headers' , array_merge ( array ( 'User-Agent' => $request [ 'user-agent' ] ), $request [ 'headers' ] ) );
2014-07-30 20:23:22 +00:00
add_comment_meta ( $delivery_id , '_request_body' , $request [ 'body' ] );
// parse response
if ( is_wp_error ( $response ) ) {
$response_code = $response -> get_error_code ();
$response_message = $response -> get_error_message ();
2016-07-25 11:52:20 +00:00
$response_headers = array ();
$response_body = '' ;
2014-07-30 20:23:22 +00:00
} else {
$response_code = wp_remote_retrieve_response_code ( $response );
$response_message = wp_remote_retrieve_response_message ( $response );
$response_headers = wp_remote_retrieve_headers ( $response );
$response_body = wp_remote_retrieve_body ( $response );
}
// save response data
add_comment_meta ( $delivery_id , '_response_code' , $response_code );
add_comment_meta ( $delivery_id , '_response_message' , $response_message );
add_comment_meta ( $delivery_id , '_response_headers' , $response_headers );
add_comment_meta ( $delivery_id , '_response_body' , $response_body );
// save duration
add_comment_meta ( $delivery_id , '_duration' , $duration );
// set a summary for quick display
$args = array (
'comment_ID' => $delivery_id ,
'comment_content' => sprintf ( 'HTTP %s %s: %s' , $response_code , $response_message , $response_body ),
);
wp_update_comment ( $args );
// track failures
if ( intval ( $response_code ) >= 200 && intval ( $response_code ) < 300 ) {
delete_post_meta ( $this -> id , '_failure_count' );
} else {
$this -> failed_delivery ();
}
// keep the 25 most recent delivery logs
$log = wp_count_comments ( $this -> id );
if ( $log -> total_comments > apply_filters ( 'woocommerce_max_webhook_delivery_logs' , 25 ) ) {
global $wpdb ;
2014-07-31 15:52:16 +00:00
$comment_id = $wpdb -> get_var ( $wpdb -> prepare ( " SELECT comment_ID FROM { $wpdb -> comments } WHERE comment_post_ID = %d ORDER BY comment_date_gmt ASC LIMIT 1 " , $this -> id ) );
if ( $comment_id ) {
wp_delete_comment ( $comment_id , true );
}
2014-07-30 20:23:22 +00:00
}
}
/**
2015-11-03 13:31:20 +00:00
* Track consecutive delivery failures and automatically disable the webhook .
* if more than 5 consecutive failures occur . A failure is defined as a .
* non - 2 xx response .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
*/
private function failed_delivery () {
$failures = $this -> get_failure_count ();
if ( $failures > apply_filters ( 'woocommerce_max_webhook_delivery_failures' , 5 ) ) {
$this -> update_status ( 'disabled' );
} else {
update_post_meta ( $this -> id , '_failure_count' , ++ $failures );
}
}
/**
2015-11-03 13:31:20 +00:00
* Get the delivery logs for this webhook .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return array
*/
public function get_delivery_logs () {
$args = array (
'post_id' => $this -> id ,
'status' => 'approve' ,
'type' => 'webhook_delivery' ,
);
remove_filter ( 'comments_clauses' , array ( 'WC_Comments' , 'exclude_webhook_comments' ), 10 , 1 );
$logs = get_comments ( $args );
add_filter ( 'comments_clauses' , array ( 'WC_Comments' , 'exclude_webhook_comments' ), 10 , 1 );
$delivery_logs = array ();
foreach ( $logs as $log ) {
$log = $this -> get_delivery_log ( $log -> comment_ID );
$delivery_logs [] = ( ! empty ( $log ) ? $log : array () );
}
return $delivery_logs ;
}
/**
* Get the delivery log specified by the ID . The delivery log includes :
*
* + duration
* + summary
* + request method / url
* + request headers / body
* + response code / message / headers / body
*
* @ since 2.2
* @ param int $delivery_id
* @ return bool | array false if invalid delivery ID , array of log data otherwise
*/
public function get_delivery_log ( $delivery_id ) {
$log = get_comment ( $delivery_id );
// valid comment and ensure delivery log belongs to this webhook
if ( is_null ( $log ) || $log -> comment_post_ID != $this -> id ) {
return false ;
}
$delivery_log = array (
'id' => intval ( $delivery_id ),
'duration' => get_comment_meta ( $delivery_id , '_duration' , true ),
'summary' => $log -> comment_content ,
'request_method' => get_comment_meta ( $delivery_id , '_request_method' , true ),
'request_url' => $this -> get_delivery_url (),
'request_headers' => get_comment_meta ( $delivery_id , '_request_headers' , true ),
'request_body' => get_comment_meta ( $delivery_id , '_request_body' , true ),
'response_code' => get_comment_meta ( $delivery_id , '_response_code' , true ),
'response_message' => get_comment_meta ( $delivery_id , '_response_message' , true ),
'response_headers' => get_comment_meta ( $delivery_id , '_response_headers' , true ),
'response_body' => get_comment_meta ( $delivery_id , '_response_body' , true ),
'comment' => $log ,
);
return apply_filters ( 'woocommerce_webhook_delivery_log' , $delivery_log , $delivery_id , $this -> id );
}
/**
2015-11-03 13:31:20 +00:00
* Set the webhook topic and associated hooks . The topic resource & event .
2014-07-30 20:23:22 +00:00
* are also saved separately .
*
* @ since 2.2
* @ param string $topic
*/
public function set_topic ( $topic ) {
$topic = strtolower ( $topic );
list ( $resource , $event ) = explode ( '.' , $topic );
update_post_meta ( $this -> id , '_topic' , $topic );
update_post_meta ( $this -> id , '_resource' , $resource );
update_post_meta ( $this -> id , '_event' , $event );
// custom topics are mapped to a single hook
if ( 'action' === $resource ) {
update_post_meta ( $this -> id , '_hooks' , array ( $event ) );
} else {
// API topics have multiple hooks
update_post_meta ( $this -> id , '_hooks' , $this -> get_topic_hooks ( $topic ) );
}
}
/**
2015-11-03 13:31:20 +00:00
* Get the associated hook names for a topic .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ param string $topic
* @ return array hook names
*/
private function get_topic_hooks ( $topic ) {
$topic_hooks = array (
'coupon.created' => array (
'woocommerce_process_shop_coupon_meta' ,
'woocommerce_api_create_coupon' ,
),
'coupon.updated' => array (
'woocommerce_process_shop_coupon_meta' ,
'woocommerce_api_edit_coupon' ,
),
'coupon.deleted' => array (
'wp_trash_post' ,
),
2017-04-27 18:44:57 +00:00
'coupon.restored' => array (
'untrashed_post' ,
),
2014-07-30 20:23:22 +00:00
'customer.created' => array (
2016-02-11 19:22:02 +00:00
'user_register' ,
2014-07-30 20:23:22 +00:00
'woocommerce_created_customer' ,
2016-08-27 02:08:49 +00:00
'woocommerce_api_create_customer' ,
2014-07-30 20:23:22 +00:00
),
'customer.updated' => array (
'profile_update' ,
'woocommerce_api_edit_customer' ,
2016-03-08 18:54:13 +00:00
'woocommerce_customer_save_address' ,
2014-07-30 20:23:22 +00:00
),
'customer.deleted' => array (
'delete_user' ,
),
'order.created' => array (
'woocommerce_checkout_order_processed' ,
'woocommerce_process_shop_order_meta' ,
'woocommerce_api_create_order' ,
),
'order.updated' => array (
'woocommerce_process_shop_order_meta' ,
'woocommerce_api_edit_order' ,
2015-06-05 16:43:24 +00:00
'woocommerce_order_edit_status' ,
2016-08-27 02:08:49 +00:00
'woocommerce_order_status_changed' ,
2014-07-30 20:23:22 +00:00
),
'order.deleted' => array (
'wp_trash_post' ,
),
2017-04-27 18:44:57 +00:00
'order.restored' => array (
'untrashed_post' ,
),
2014-07-30 20:23:22 +00:00
'product.created' => array (
'woocommerce_process_product_meta' ,
'woocommerce_api_create_product' ,
),
'product.updated' => array (
'woocommerce_process_product_meta' ,
'woocommerce_api_edit_product' ,
2016-08-03 20:32:02 +00:00
'woocommerce_product_quick_edit_save' ,
'woocommerce_product_bulk_edit_save' ,
2014-07-30 20:23:22 +00:00
),
'product.deleted' => array (
'wp_trash_post' ,
),
2017-04-27 18:44:57 +00:00
'product.restored' => array (
'untrashed_post' ,
),
2014-07-30 20:23:22 +00:00
);
$topic_hooks = apply_filters ( 'woocommerce_webhook_topic_hooks' , $topic_hooks , $this );
return isset ( $topic_hooks [ $topic ] ) ? $topic_hooks [ $topic ] : array ();
}
/**
2015-11-03 13:31:20 +00:00
* Send a test ping to the delivery URL , sent when the webhook is first created .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
2015-12-04 12:47:30 +00:00
* @ return bool | WP_Error
2014-07-30 20:23:22 +00:00
*/
public function deliver_ping () {
$args = array (
'user-agent' => sprintf ( 'WooCommerce/%s Hookshot (WordPress/%s)' , WC_VERSION , $GLOBALS [ 'wp_version' ] ),
2014-07-31 15:52:16 +00:00
'body' => " webhook_id= { $this -> id } " ,
2014-07-30 20:23:22 +00:00
);
2015-12-04 12:47:30 +00:00
$test = wp_safe_remote_post ( $this -> get_delivery_url (), $args );
$response_code = wp_remote_retrieve_response_code ( $test );
if ( is_wp_error ( $test ) ) {
2015-12-09 15:20:53 +00:00
return new WP_Error ( 'error' , sprintf ( __ ( 'Error: Delivery URL cannot be reached: %s' , 'woocommerce' ), $test -> get_error_message () ) );
2015-12-04 12:47:30 +00:00
}
if ( 200 !== $response_code ) {
2015-12-09 15:20:53 +00:00
return new WP_Error ( 'error' , sprintf ( __ ( 'Error: Delivery URL returned response code: %s' , 'woocommerce' ), absint ( $response_code ) ) );
2015-12-04 12:47:30 +00:00
}
return true ;
2014-07-30 20:23:22 +00:00
}
/**
* Get the webhook status :
*
2015-11-03 13:31:20 +00:00
* + `active` - delivers payload .
* + `paused` - does not deliver payload , paused by admin .
* + `disabled` - does not delivery payload , paused automatically due to .
* consecutive failures .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return string status
*/
public function get_status () {
switch ( $this -> get_post_data () -> post_status ) {
case 'publish' :
$status = 'active' ;
break ;
case 'draft' :
$status = 'paused' ;
break ;
case 'pending' :
$status = 'disabled' ;
break ;
default :
$status = 'paused' ;
}
return apply_filters ( 'woocommerce_webhook_status' , $status , $this -> id );
}
2014-12-16 17:29:37 +00:00
/**
2015-11-03 13:31:20 +00:00
* Get the webhook i18n status .
2014-12-16 17:29:37 +00:00
*
* @ return string
*/
public function get_i18n_status () {
$status = $this -> get_status ();
2014-12-16 20:54:48 +00:00
$statuses = wc_get_webhook_statuses ();
2014-12-16 17:29:37 +00:00
return isset ( $statuses [ $status ] ) ? $statuses [ $status ] : $status ;
}
2014-07-30 20:23:22 +00:00
/**
2015-11-03 13:31:20 +00:00
* Update the webhook status , see get_status () for valid statuses .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ param $status
*/
public function update_status ( $status ) {
2014-12-16 20:54:48 +00:00
global $wpdb ;
2014-07-30 20:23:22 +00:00
switch ( $status ) {
2014-12-16 20:54:48 +00:00
case 'active' :
2014-07-30 20:23:22 +00:00
$post_status = 'publish' ;
break ;
2014-12-16 20:54:48 +00:00
case 'paused' :
2014-07-30 20:23:22 +00:00
$post_status = 'draft' ;
break ;
2014-12-16 20:54:48 +00:00
case 'disabled' :
2014-07-30 20:23:22 +00:00
$post_status = 'pending' ;
break ;
2014-12-16 20:54:48 +00:00
default :
2014-07-30 20:23:22 +00:00
$post_status = 'draft' ;
2014-12-16 20:54:48 +00:00
break ;
2014-07-30 20:23:22 +00:00
}
2014-12-16 20:54:48 +00:00
$wpdb -> update ( $wpdb -> posts , array ( 'post_status' => $post_status ), array ( 'ID' => $this -> id ) );
2015-12-09 11:41:18 +00:00
clean_post_cache ( $this -> id );
2014-07-30 20:23:22 +00:00
}
/**
2015-11-03 13:31:20 +00:00
* Set the delivery URL .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ param string $url
*/
public function set_delivery_url ( $url ) {
2015-12-04 12:47:30 +00:00
if ( update_post_meta ( $this -> id , '_delivery_url' , esc_url_raw ( $url , array ( 'http' , 'https' ) ) ) ) {
update_post_meta ( $this -> id , '_webhook_pending_delivery' , true );
}
2014-07-30 20:23:22 +00:00
}
/**
2015-11-03 13:31:20 +00:00
* Get the delivery URL .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return string
*/
public function get_delivery_url () {
return apply_filters ( 'woocommerce_webhook_delivery_url' , $this -> delivery_url , $this -> id );
}
/**
2015-11-03 13:31:20 +00:00
* Set the secret used for generating the HMAC - SHA256 signature .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ param string $secret
*/
public function set_secret ( $secret ) {
update_post_meta ( $this -> id , '_secret' , $secret );
}
/**
2015-11-03 13:31:20 +00:00
* Get the secret used for generating the HMAC - SHA256 signature .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return string
*/
public function get_secret () {
return apply_filters ( 'woocommerce_webhook_secret' , $this -> secret , $this -> id );
}
/**
2015-11-03 13:31:20 +00:00
* Get the friendly name for the webhook .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return string
*/
public function get_name () {
2015-05-10 14:54:15 +00:00
return apply_filters ( 'woocommerce_webhook_name' , $this -> get_post_data () -> post_title , $this -> id );
2014-07-30 20:23:22 +00:00
}
/**
2015-11-03 13:31:20 +00:00
* Get the webhook topic , e . g . `order.created` .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return string
*/
public function get_topic () {
return apply_filters ( 'woocommerce_webhook_topic' , $this -> topic , $this -> id );
}
/**
2015-11-03 13:31:20 +00:00
* Get the hook names for the webhook .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return array hook names
*/
public function get_hooks () {
return apply_filters ( 'woocommerce_webhook_hooks' , $this -> hooks , $this -> id );
}
/**
2015-11-03 13:31:20 +00:00
* Get the resource for the webhook , e . g . `order` .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return string
*/
public function get_resource () {
return apply_filters ( 'woocommerce_webhook_resource' , $this -> resource , $this -> id );
}
/**
2015-11-03 13:31:20 +00:00
* Get the event for the webhook , e . g . `created` .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return string
*/
public function get_event () {
return apply_filters ( 'woocommerce_webhook_event' , $this -> event , $this -> id );
}
/**
2015-11-03 13:31:20 +00:00
* Get the failure count .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return int
*/
public function get_failure_count () {
return intval ( $this -> failure_count );
}
/**
2015-11-03 13:31:20 +00:00
* Get the user ID for this webhook .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return int | string user ID
*/
public function get_user_id () {
return $this -> get_post_data () -> post_author ;
}
/**
2015-11-03 13:31:20 +00:00
* Get the post data for the webhook .
2014-07-30 20:23:22 +00:00
*
* @ since 2.2
* @ return null | WP_Post
*/
public function get_post_data () {
return $this -> post_data ;
}
2016-11-22 23:49:04 +00:00
/**
* Set API version .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-11-22 23:49:04 +00:00
* @ param string $version REST API version .
*/
public function set_api_version ( $version ) {
$versions = array (
2017-04-02 06:07:09 +00:00
'wp_api_v2' ,
2016-11-22 23:49:04 +00:00
'wp_api_v1' ,
'legacy_v3' ,
);
if ( ! in_array ( $version , $versions , true ) ) {
2017-04-02 06:07:09 +00:00
$version = 'wp_api_v2' ;
2016-11-22 23:49:04 +00:00
}
update_post_meta ( $this -> id , '_api_version' , $version );
}
/**
* API version .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-11-22 23:49:04 +00:00
* @ return string
*/
public function get_api_version () {
return $this -> api_version ? $this -> api_version : 'legacy_v3' ;
}
2014-07-30 20:23:22 +00:00
}