2015-06-17 16:25:33 +00:00
< ? php
/**
* WooCommerce API Webhooks class
*
* Handles requests to the / webhooks endpoint
*
* @ author WooThemes
* @ category API
* @ package WooCommerce / API
* @ since 2.2
*/
if ( ! defined ( 'ABSPATH' ) ) {
exit ; // Exit if accessed directly
}
class WC_API_Webhooks extends WC_API_Resource {
/** @var string $base the route base */
protected $base = '/webhooks' ;
/**
* Register the routes for this class
*
* @ since 2.2
* @ param array $routes
* @ return array
*/
public function register_routes ( $routes ) {
# GET|POST /webhooks
$routes [ $this -> base ] = array (
array ( array ( $this , 'get_webhooks' ), WC_API_Server :: READABLE ),
array ( array ( $this , 'create_webhook' ), WC_API_Server :: CREATABLE | WC_API_Server :: ACCEPT_DATA ),
);
# GET /webhooks/count
2016-08-27 03:11:30 +00:00
$routes [ $this -> base . '/count' ] = array (
2015-06-17 16:25:33 +00:00
array ( array ( $this , 'get_webhooks_count' ), WC_API_Server :: READABLE ),
);
# GET|PUT|DELETE /webhooks/<id>
$routes [ $this -> base . '/(?P<id>\d+)' ] = array (
array ( array ( $this , 'get_webhook' ), WC_API_Server :: READABLE ),
array ( array ( $this , 'edit_webhook' ), WC_API_Server :: EDITABLE | WC_API_Server :: ACCEPT_DATA ),
array ( array ( $this , 'delete_webhook' ), WC_API_Server :: DELETABLE ),
);
# GET /webhooks/<id>/deliveries
$routes [ $this -> base . '/(?P<webhook_id>\d+)/deliveries' ] = array (
array ( array ( $this , 'get_webhook_deliveries' ), WC_API_Server :: READABLE ),
);
# GET /webhooks/<webhook_id>/deliveries/<id>
$routes [ $this -> base . '/(?P<webhook_id>\d+)/deliveries/(?P<id>\d+)' ] = array (
array ( array ( $this , 'get_webhook_delivery' ), WC_API_Server :: READABLE ),
);
return $routes ;
}
/**
* Get all webhooks
*
* @ since 2.2
2017-05-15 11:50:52 +00:00
*
2015-06-17 16:25:33 +00:00
* @ param array $fields
* @ param array $filter
2017-05-15 11:50:52 +00:00
* @ param string $status
2015-06-17 16:25:33 +00:00
* @ param int $page
2017-05-15 11:50:52 +00:00
*
2015-06-17 16:25:33 +00:00
* @ return array
*/
public function get_webhooks ( $fields = null , $filter = array (), $status = null , $page = 1 ) {
if ( ! empty ( $status ) ) {
$filter [ 'status' ] = $status ;
}
$filter [ 'page' ] = $page ;
$query = $this -> query_webhooks ( $filter );
$webhooks = array ();
foreach ( $query -> posts as $webhook_id ) {
if ( ! $this -> is_readable ( $webhook_id ) ) {
continue ;
}
$webhooks [] = current ( $this -> get_webhook ( $webhook_id , $fields ) );
}
$this -> server -> add_pagination_headers ( $query );
return array ( 'webhooks' => $webhooks );
}
/**
* Get the webhook for the given ID
*
* @ since 2.2
* @ param int $id webhook ID
* @ param array $fields
2017-05-15 11:50:52 +00:00
* @ return array | WP_Error
2015-06-17 16:25:33 +00:00
*/
public function get_webhook ( $id , $fields = null ) {
// ensure webhook ID is valid & user has permission to read
$id = $this -> validate_request ( $id , 'shop_webhook' , 'read' );
if ( is_wp_error ( $id ) ) {
return $id ;
}
$webhook = new WC_Webhook ( $id );
$webhook_data = array (
'id' => $webhook -> id ,
'name' => $webhook -> get_name (),
'status' => $webhook -> get_status (),
'topic' => $webhook -> get_topic (),
'resource' => $webhook -> get_resource (),
'event' => $webhook -> get_event (),
'hooks' => $webhook -> get_hooks (),
'delivery_url' => $webhook -> get_delivery_url (),
'created_at' => $this -> server -> format_datetime ( $webhook -> get_post_data () -> post_date_gmt ),
'updated_at' => $this -> server -> format_datetime ( $webhook -> get_post_data () -> post_modified_gmt ),
);
return array ( 'webhook' => apply_filters ( 'woocommerce_api_webhook_response' , $webhook_data , $webhook , $fields , $this ) );
}
/**
* Get the total number of webhooks
*
* @ since 2.2
2017-05-15 11:50:52 +00:00
*
2015-06-17 16:25:33 +00:00
* @ param string $status
* @ param array $filter
2017-05-15 11:50:52 +00:00
*
* @ return array | WP_Error
2015-06-17 16:25:33 +00:00
*/
public function get_webhooks_count ( $status = null , $filter = array () ) {
try {
if ( ! current_user_can ( 'read_private_shop_webhooks' ) ) {
throw new WC_API_Exception ( 'woocommerce_api_user_cannot_read_webhooks_count' , __ ( 'You do not have permission to read the webhooks count' , 'woocommerce' ), 401 );
}
if ( ! empty ( $status ) ) {
$filter [ 'status' ] = $status ;
}
$query = $this -> query_webhooks ( $filter );
return array ( 'count' => ( int ) $query -> found_posts );
} catch ( WC_API_Exception $e ) {
return new WP_Error ( $e -> getErrorCode (), $e -> getMessage (), array ( 'status' => $e -> getCode () ) );
}
}
/**
* Create an webhook
*
* @ since 2.2
2017-05-15 11:50:52 +00:00
*
2015-06-17 16:25:33 +00:00
* @ param array $data parsed webhook data
2017-05-15 11:50:52 +00:00
*
* @ return array | WP_Error
2015-06-17 16:25:33 +00:00
*/
public function create_webhook ( $data ) {
try {
if ( ! isset ( $data [ 'webhook' ] ) ) {
throw new WC_API_Exception ( 'woocommerce_api_missing_webhook_data' , sprintf ( __ ( 'No %1$s data specified to create %1$s' , 'woocommerce' ), 'webhook' ), 400 );
}
$data = $data [ 'webhook' ];
// permission check
if ( ! current_user_can ( 'publish_shop_webhooks' ) ) {
2016-10-11 01:39:13 +00:00
throw new WC_API_Exception ( 'woocommerce_api_user_cannot_create_webhooks' , __ ( 'You do not have permission to create webhooks.' , 'woocommerce' ), 401 );
2015-06-17 16:25:33 +00:00
}
$data = apply_filters ( 'woocommerce_api_create_webhook_data' , $data , $this );
// validate topic
if ( empty ( $data [ 'topic' ] ) || ! wc_is_webhook_valid_topic ( strtolower ( $data [ 'topic' ] ) ) ) {
2016-10-11 01:39:13 +00:00
throw new WC_API_Exception ( 'woocommerce_api_invalid_webhook_topic' , __ ( 'Webhook topic is required and must be valid.' , 'woocommerce' ), 400 );
2015-06-17 16:25:33 +00:00
}
// validate delivery URL
if ( empty ( $data [ 'delivery_url' ] ) || ! wc_is_valid_url ( $data [ 'delivery_url' ] ) ) {
throw new WC_API_Exception ( 'woocommerce_api_invalid_webhook_delivery_url' , __ ( 'Webhook delivery URL must be a valid URL starting with http:// or https://' , 'woocommerce' ), 400 );
}
$webhook_data = apply_filters ( 'woocommerce_new_webhook_data' , array (
'post_type' => 'shop_webhook' ,
'post_status' => 'publish' ,
'ping_status' => 'closed' ,
'post_author' => get_current_user_id (),
'post_password' => strlen ( ( $password = uniqid ( 'webhook_' ) ) ) > 20 ? substr ( $password , 0 , 20 ) : $password ,
2016-09-02 00:26:24 +00:00
// @codingStandardsIgnoreStart
2015-06-17 16:25:33 +00:00
'post_title' => ! empty ( $data [ 'name' ] ) ? $data [ 'name' ] : sprintf ( __ ( 'Webhook created on %s' , 'woocommerce' ), strftime ( _x ( '%b %d, %Y @ %I:%M %p' , 'Webhook created on date parsed by strftime' , 'woocommerce' ) ) ),
2016-09-02 00:26:24 +00:00
// @codingStandardsIgnoreEnd
2015-06-17 16:25:33 +00:00
), $data , $this );
$webhook_id = wp_insert_post ( $webhook_data );
if ( is_wp_error ( $webhook_id ) || ! $webhook_id ) {
throw new WC_API_Exception ( 'woocommerce_api_cannot_create_webhook' , sprintf ( __ ( 'Cannot create webhook: %s' , 'woocommerce' ), is_wp_error ( $webhook_id ) ? implode ( ', ' , $webhook_id -> get_error_messages () ) : '0' ), 500 );
}
$webhook = new WC_Webhook ( $webhook_id );
// set topic, delivery URL, and optional secret
$webhook -> set_topic ( $data [ 'topic' ] );
$webhook -> set_delivery_url ( $data [ 'delivery_url' ] );
// set secret if provided, defaults to API users consumer secret
2016-06-28 00:55:54 +00:00
$webhook -> set_secret ( ! empty ( $data [ 'secret' ] ) ? $data [ 'secret' ] : '' );
2015-06-17 16:25:33 +00:00
2016-11-23 00:01:16 +00:00
// Set API version to legacy v3.
$webhook -> set_api_version ( 'legacy_v3' );
2015-06-17 16:25:33 +00:00
// send ping
$webhook -> deliver_ping ();
// HTTP 201 Created
$this -> server -> send_status ( 201 );
do_action ( 'woocommerce_api_create_webhook' , $webhook -> id , $this );
delete_transient ( 'woocommerce_webhook_ids' );
return $this -> get_webhook ( $webhook -> id );
} catch ( WC_API_Exception $e ) {
return new WP_Error ( $e -> getErrorCode (), $e -> getMessage (), array ( 'status' => $e -> getCode () ) );
}
}
/**
* Edit a webhook
*
* @ since 2.2
2017-05-15 11:50:52 +00:00
*
2015-06-17 16:25:33 +00:00
* @ param int $id webhook ID
* @ param array $data parsed webhook data
2017-05-15 11:50:52 +00:00
*
* @ return array | WP_Error
2015-06-17 16:25:33 +00:00
*/
public function edit_webhook ( $id , $data ) {
try {
if ( ! isset ( $data [ 'webhook' ] ) ) {
throw new WC_API_Exception ( 'woocommerce_api_missing_webhook_data' , sprintf ( __ ( 'No %1$s data specified to edit %1$s' , 'woocommerce' ), 'webhook' ), 400 );
}
$data = $data [ 'webhook' ];
$id = $this -> validate_request ( $id , 'shop_webhook' , 'edit' );
if ( is_wp_error ( $id ) ) {
return $id ;
}
$data = apply_filters ( 'woocommerce_api_edit_webhook_data' , $data , $id , $this );
$webhook = new WC_Webhook ( $id );
// update topic
if ( ! empty ( $data [ 'topic' ] ) ) {
if ( wc_is_webhook_valid_topic ( strtolower ( $data [ 'topic' ] ) ) ) {
$webhook -> set_topic ( $data [ 'topic' ] );
} else {
2016-10-11 01:39:13 +00:00
throw new WC_API_Exception ( 'woocommerce_api_invalid_webhook_topic' , __ ( 'Webhook topic must be valid.' , 'woocommerce' ), 400 );
2015-06-17 16:25:33 +00:00
}
}
// update delivery URL
if ( ! empty ( $data [ 'delivery_url' ] ) ) {
if ( wc_is_valid_url ( $data [ 'delivery_url' ] ) ) {
$webhook -> set_delivery_url ( $data [ 'delivery_url' ] );
} else {
throw new WC_API_Exception ( 'woocommerce_api_invalid_webhook_delivery_url' , __ ( 'Webhook delivery URL must be a valid URL starting with http:// or https://' , 'woocommerce' ), 400 );
}
}
// update secret
if ( ! empty ( $data [ 'secret' ] ) ) {
$webhook -> set_secret ( $data [ 'secret' ] );
}
// update status
if ( ! empty ( $data [ 'status' ] ) ) {
$webhook -> update_status ( $data [ 'status' ] );
}
// update user ID
$webhook_data = array (
'ID' => $webhook -> id ,
2016-08-27 01:46:45 +00:00
'post_author' => get_current_user_id (),
2015-06-17 16:25:33 +00:00
);
// update name
if ( ! empty ( $data [ 'name' ] ) ) {
$webhook_data [ 'post_title' ] = $data [ 'name' ];
}
// update post
wp_update_post ( $webhook_data );
do_action ( 'woocommerce_api_edit_webhook' , $webhook -> id , $this );
delete_transient ( 'woocommerce_webhook_ids' );
return $this -> get_webhook ( $id );
} catch ( WC_API_Exception $e ) {
return new WP_Error ( $e -> getErrorCode (), $e -> getMessage (), array ( 'status' => $e -> getCode () ) );
}
}
/**
* Delete a webhook
*
* @ since 2.2
* @ param int $id webhook ID
2017-05-15 11:50:52 +00:00
* @ return array | WP_Error
2015-06-17 16:25:33 +00:00
*/
public function delete_webhook ( $id ) {
$id = $this -> validate_request ( $id , 'shop_webhook' , 'delete' );
if ( is_wp_error ( $id ) ) {
return $id ;
}
do_action ( 'woocommerce_api_delete_webhook' , $id , $this );
delete_transient ( 'woocommerce_webhook_ids' );
// no way to manage trashed webhooks at the moment, so force delete
return $this -> delete ( $id , 'webhook' , true );
}
/**
* Helper method to get webhook post objects
*
* @ since 2.2
* @ param array $args request arguments for filtering query
* @ return WP_Query
*/
private function query_webhooks ( $args ) {
// Set base query arguments
$query_args = array (
'fields' => 'ids' ,
'post_type' => 'shop_webhook' ,
);
// Add status argument
if ( ! empty ( $args [ 'status' ] ) ) {
switch ( $args [ 'status' ] ) {
case 'active' :
$query_args [ 'post_status' ] = 'publish' ;
break ;
case 'paused' :
$query_args [ 'post_status' ] = 'draft' ;
break ;
case 'disabled' :
$query_args [ 'post_status' ] = 'pending' ;
break ;
default :
$query_args [ 'post_status' ] = 'publish' ;
}
unset ( $args [ 'status' ] );
}
$query_args = $this -> merge_query_args ( $query_args , $args );
return new WP_Query ( $query_args );
}
/**
* Get deliveries for a webhook
*
* @ since 2.2
* @ param string $webhook_id webhook ID
* @ param string | null $fields fields to include in response
2017-05-15 11:50:52 +00:00
* @ return array | WP_Error
2015-06-17 16:25:33 +00:00
*/
public function get_webhook_deliveries ( $webhook_id , $fields = null ) {
// Ensure ID is valid webhook ID
$webhook_id = $this -> validate_request ( $webhook_id , 'shop_webhook' , 'read' );
if ( is_wp_error ( $webhook_id ) ) {
return $webhook_id ;
}
$webhook = new WC_Webhook ( $webhook_id );
$logs = $webhook -> get_delivery_logs ();
$delivery_logs = array ();
foreach ( $logs as $log ) {
// Add timestamp
$log [ 'created_at' ] = $this -> server -> format_datetime ( $log [ 'comment' ] -> comment_date_gmt );
// Remove comment object
unset ( $log [ 'comment' ] );
$delivery_logs [] = $log ;
}
return array ( 'webhook_deliveries' => $delivery_logs );
}
/**
* Get the delivery log for the given webhook ID and delivery ID
*
* @ since 2.2
2017-05-15 11:50:52 +00:00
*
2015-06-17 16:25:33 +00:00
* @ param string $webhook_id webhook ID
* @ param string $id delivery log ID
* @ param string | null $fields fields to limit response to
2017-05-15 11:50:52 +00:00
*
* @ return array | WP_Error
2015-06-17 16:25:33 +00:00
*/
public function get_webhook_delivery ( $webhook_id , $id , $fields = null ) {
try {
// Validate webhook ID
$webhook_id = $this -> validate_request ( $webhook_id , 'shop_webhook' , 'read' );
if ( is_wp_error ( $webhook_id ) ) {
return $webhook_id ;
}
$id = absint ( $id );
if ( empty ( $id ) ) {
2016-10-11 01:39:13 +00:00
throw new WC_API_Exception ( 'woocommerce_api_invalid_webhook_delivery_id' , __ ( 'Invalid webhook delivery ID.' , 'woocommerce' ), 404 );
2015-06-17 16:25:33 +00:00
}
$webhook = new WC_Webhook ( $webhook_id );
$log = $webhook -> get_delivery_log ( $id );
if ( ! $log ) {
2016-10-11 01:39:13 +00:00
throw new WC_API_Exception ( 'woocommerce_api_invalid_webhook_delivery_id' , __ ( 'Invalid webhook delivery.' , 'woocommerce' ), 400 );
2015-06-17 16:25:33 +00:00
}
$delivery_log = $log ;
// Add timestamp
$delivery_log [ 'created_at' ] = $this -> server -> format_datetime ( $log [ 'comment' ] -> comment_date_gmt );
// Remove comment object
unset ( $delivery_log [ 'comment' ] );
return array ( 'webhook_delivery' => apply_filters ( 'woocommerce_api_webhook_delivery_response' , $delivery_log , $id , $fields , $log , $webhook_id , $this ) );
} catch ( WC_API_Exception $e ) {
return new WP_Error ( $e -> getErrorCode (), $e -> getMessage (), array ( 'status' => $e -> getCode () ) );
}
}
}