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 $routes[ $this->base . '/count' ] = array( array( array( $this, 'get_webhooks_count' ), WC_API_Server::READABLE ), ); # GET|PUT|DELETE /webhooks/ $routes[ $this->base . '/(?P\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//deliveries $routes[ $this->base . '/(?P\d+)/deliveries' ] = array( array( array( $this, 'get_webhook_deliveries' ), WC_API_Server::READABLE ), ); # GET /webhooks//deliveries/ $routes[ $this->base . '/(?P\d+)/deliveries/(?P\d+)' ] = array( array( array( $this, 'get_webhook_delivery' ), WC_API_Server::READABLE ), ); return $routes; } /** * Get all webhooks * * @since 2.2 * * @param array $fields * @param array $filter * @param string $status * @param int $page * * @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 * @return array|WP_Error */ 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 * * @param string $status * @param array $filter * * @return array|WP_Error */ 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 * * @param array $data parsed webhook data * * @return array|WP_Error */ 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' ) ) { throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_webhooks', __( 'You do not have permission to create webhooks.', 'woocommerce' ), 401 ); } $data = apply_filters( 'woocommerce_api_create_webhook_data', $data, $this ); // validate topic if ( empty( $data['topic'] ) || ! wc_is_webhook_valid_topic( strtolower( $data['topic'] ) ) ) { throw new WC_API_Exception( 'woocommerce_api_invalid_webhook_topic', __( 'Webhook topic is required and must be valid.', 'woocommerce' ), 400 ); } // 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, // @codingStandardsIgnoreStart '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' ) ) ), // @codingStandardsIgnoreEnd ), $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 $webhook->set_secret( ! empty( $data['secret'] ) ? $data['secret'] : '' ); // Set API version to legacy v3. $webhook->set_api_version( 'legacy_v3' ); // 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 * * @param int $id webhook ID * @param array $data parsed webhook data * * @return array|WP_Error */ 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 { throw new WC_API_Exception( 'woocommerce_api_invalid_webhook_topic', __( 'Webhook topic must be valid.', 'woocommerce' ), 400 ); } } // 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, 'post_author' => get_current_user_id(), ); // 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 * @return array|WP_Error */ 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 * @return array|WP_Error */ 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 * * @param string $webhook_id webhook ID * @param string $id delivery log ID * @param string|null $fields fields to limit response to * * @return array|WP_Error */ 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 ) ) { throw new WC_API_Exception( 'woocommerce_api_invalid_webhook_delivery_id', __( 'Invalid webhook delivery ID.', 'woocommerce' ), 404 ); } $webhook = new WC_Webhook( $webhook_id ); $log = $webhook->get_delivery_log( $id ); if ( ! $log ) { throw new WC_API_Exception( 'woocommerce_api_invalid_webhook_delivery_id', __( 'Invalid webhook delivery.', 'woocommerce' ), 400 ); } $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() ) ); } } }