WC_Webhook
Webhook class.
Description Description
Source Source
File: includes/class-wc-webhook.php
class WC_Webhook extends WC_Legacy_Webhook { /** * Store which object IDs this webhook has processed (ie scheduled to be delivered) * within the current page request. * * @var array */ protected $processed = array(); /** * Stores webhook data. * * @var array */ protected $data = array( 'date_created' => null, 'date_modified' => null, 'status' => 'disabled', 'delivery_url' => '', 'secret' => '', 'name' => '', 'topic' => '', 'hooks' => '', 'resource' => '', 'event' => '', 'failure_count' => 0, 'user_id' => 0, 'api_version' => 3, 'pending_delivery' => false, ); /** * Load webhook data based on how WC_Webhook is called. * * @param WC_Webhook|int $data Webhook ID or data. * @throws Exception If webhook cannot be read/found and $data is set. */ public function __construct( $data = 0 ) { parent::__construct( $data ); if ( $data instanceof WC_Webhook ) { $this->set_id( absint( $data->get_id() ) ); } elseif ( is_numeric( $data ) ) { $this->set_id( $data ); } $this->data_store = WC_Data_Store::load( 'webhook' ); // If we have an ID, load the webhook from the DB. if ( $this->get_id() ) { try { $this->data_store->read( $this ); } catch ( Exception $e ) { $this->set_id( 0 ); $this->set_object_read( true ); } } else { $this->set_object_read( true ); } } /** * Enqueue the hooks associated with the webhook. * * @since 2.2.0 */ public function enqueue() { $hooks = $this->get_hooks(); $url = $this->get_delivery_url(); if ( is_array( $hooks ) && ! empty( $url ) ) { foreach ( $hooks as $hook ) { add_action( $hook, array( $this, 'process' ) ); } } } /** * Process the webhook for delivery by verifying that it should be delivered. * and scheduling the delivery (in the background by default, or immediately). * * @since 2.2.0 * @param mixed $arg The first argument provided from the associated hooks. * @return mixed $arg Returns the argument in case the webhook was hooked into a filter. */ public function process( $arg ) { // Verify that webhook should be processed for delivery. if ( ! $this->should_deliver( $arg ) ) { return; } // Mark this $arg as processed to ensure it doesn't get processed again within the current request. $this->processed[] = $arg; /** * Process webhook delivery. * * @since 3.3.0 * @hooked wc_webhook_process_delivery - 10 */ do_action( 'woocommerce_webhook_process_delivery', $this, $arg ); return $arg; } /** * Helper to check if the webhook should be delivered, as some hooks. * (like `wp_trash_post`) will fire for every post type, not just ours. * * @since 2.2.0 * @param mixed $arg First hook argument. * @return bool True if webhook should be delivered, false otherwise. */ private function should_deliver( $arg ) { $should_deliver = $this->is_active() && $this->is_valid_topic() && $this->is_valid_action( $arg ) && $this->is_valid_resource( $arg ) && ! $this->is_already_processed( $arg ); /** * Let other plugins intercept deliver for some messages queue like rabbit/zeromq. * * @param bool $should_deliver True if the webhook should be sent, or false to not send it. * @param WC_Webhook $this The current webhook class. * @param mixed $arg First hook argument. */ return apply_filters( 'woocommerce_webhook_should_deliver', $should_deliver, $this, $arg ); } /** * Returns if webhook is active. * * @since 3.6.0 * @return bool True if validation passes. */ private function is_active() { return 'active' === $this->get_status(); } /** * Returns if topic is valid. * * @since 3.6.0 * @return bool True if validation passes. */ private function is_valid_topic() { return wc_is_webhook_valid_topic( $this->get_topic() ); } /** * Validates the criteria for certain actions. * * @since 3.6.0 * @param mixed $arg First hook argument. * @return bool True if validation passes. */ private function is_valid_action( $arg ) { $current_action = current_action(); $return = true; switch ( $current_action ) { case 'delete_post': case 'wp_trash_post': case 'untrashed_post': $return = $this->is_valid_post_action( $arg ); break; case 'delete_user': $return = $this->is_valid_user_action( $arg ); break; } if ( 0 === strpos( $current_action, 'woocommerce_process_shop' ) || 0 === strpos( $current_action, 'woocommerce_process_product' ) ) { $return = $this->is_valid_processing_action( $arg ); } return $return; } /** * Validates post actions. * * @since 3.6.0 * @param mixed $arg First hook argument. * @return bool True if validation passes. */ private function is_valid_post_action( $arg ) { // Only deliver deleted/restored event for coupons, orders, and products. if ( isset( $GLOBALS['post_type'] ) && ! in_array( $GLOBALS['post_type'], array( 'shop_coupon', 'shop_order', 'product' ), true ) ) { return false; } // Check if is delivering for the correct resource. if ( isset( $GLOBALS['post_type'] ) && str_replace( 'shop_', '', $GLOBALS['post_type'] ) !== $this->get_resource() ) { return false; } return true; } /** * Validates user actions. * * @since 3.6.0 * @param mixed $arg First hook argument. * @return bool True if validation passes. */ private function is_valid_user_action( $arg ) { $user = get_userdata( absint( $arg ) ); // Only deliver deleted customer event for users with customer role. if ( ! $user || ! in_array( 'customer', (array) $user->roles, true ) ) { return false; } return true; } /** * Validates WC processing actions. * * @since 3.6.0 * @param mixed $arg First hook argument. * @return bool True if validation passes. */ private function is_valid_processing_action( $arg ) { // 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. $resource = get_post( absint( $arg ) ); // Drafts don't have post_date_gmt so calculate it here. $gmt_date = get_gmt_from_date( $resource->post_date ); // A resource is considered created when the hook is executed within 10 seconds of the post creation date. $resource_created = ( ( time() - 10 ) <= strtotime( $gmt_date ) ); if ( 'created' === $this->get_event() && ! $resource_created ) { return false; } elseif ( 'updated' === $this->get_event() && $resource_created ) { return false; } return true; } /** * Checks the resource for this webhook is valid e.g. valid post status. * * @since 3.6.0 * @param mixed $arg First hook argument. * @return bool True if validation passes. */ private function is_valid_resource( $arg ) { $resource = $this->get_resource(); if ( in_array( $resource, array( 'order', 'product', 'coupon' ), true ) ) { $status = get_post_status( absint( $arg ) ); // Ignore auto drafts for all resources. if ( in_array( $status, array( 'auto-draft', 'new' ), true ) ) { return false; } // Ignore standard drafts for orders. if ( 'order' === $resource && 'draft' === $status ) { return false; } // Check registered order types for order types args. if ( 'order' === $resource && ! in_array( get_post_type( absint( $arg ) ), wc_get_order_types( 'order-webhooks' ), true ) ) { return false; } } return true; } /** * Checks if the specified resource has already been queued for delivery within the current request. * * Helps avoid duplication of data being sent for topics that have more than one hook defined. * * @param mixed $arg First hook argument. * * @return bool */ protected function is_already_processed( $arg ) { return false !== array_search( $arg, $this->processed, true ); } /** * Deliver the webhook payload using wp_safe_remote_request(). * * @since 2.2.0 * @param mixed $arg First hook argument. */ public function deliver( $arg ) { $start_time = microtime( true ); $payload = $this->build_payload( $arg ); // Setup request args. $http_args = array( 'method' => 'POST', 'timeout' => MINUTE_IN_SECONDS, 'redirection' => 0, 'httpversion' => '1.0', 'blocking' => true, 'user-agent' => sprintf( 'WooCommerce/%s Hookshot (WordPress/%s)', Constants::get_constant( 'WC_VERSION' ), $GLOBALS['wp_version'] ), 'body' => trim( wp_json_encode( $payload ) ), 'headers' => array( 'Content-Type' => 'application/json', ), 'cookies' => array(), ); $http_args = apply_filters( 'woocommerce_webhook_http_args', $http_args, $arg, $this->get_id() ); // Add custom headers. $delivery_id = $this->get_new_delivery_id(); $http_args['headers']['X-WC-Webhook-Source'] = home_url( '/' ); // Since 2.6.0. $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->get_id(); $http_args['headers']['X-WC-Webhook-Delivery-ID'] = $delivery_id; // Webhook away! $response = wp_safe_remote_request( $this->get_delivery_url(), $http_args ); $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->get_id() ); } /** * Get Legacy API payload. * * @since 3.0.0 * @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. * * @since 3.0.0 * @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 ) { switch ( $resource ) { case 'coupon': case 'customer': case 'order': case 'product': // 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(); } $version = str_replace( 'wp_api_', '', $this->get_api_version() ); $payload = wc()->api->get_endpoint_data( "/wc/{$version}/{$resource}s/{$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; } /** * Build the payload data for the webhook. * * @since 2.2.0 * @param mixed $resource_id First hook argument, typically the resource ID. * @return mixed Payload data. */ public function build_payload( $resource_id ) { // 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(); // If a resource has been deleted, just include the ID. if ( 'deleted' === $event ) { $payload = array( 'id' => $resource_id, ); } else { if ( in_array( $this->get_api_version(), wc_get_webhook_rest_api_versions(), true ) ) { $payload = $this->get_wp_api_payload( $resource, $resource_id, $event ); } else { $payload = $this->get_legacy_api_payload( $resource, $resource_id, $event ); } } // Restore the current user. wp_set_current_user( $current_user ); return apply_filters( 'woocommerce_webhook_payload', $payload, $resource, $resource_id, $this->get_id() ); } /** * 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). * * @since 2.2.0 * @param string $payload Payload data to hash. * @return string */ public function generate_signature( $payload ) { $hash_algo = apply_filters( 'woocommerce_webhook_hash_algorithm', 'sha256', $payload, $this->get_id() ); return base64_encode( hash_hmac( $hash_algo, $payload, wp_specialchars_decode( $this->get_secret(), ENT_QUOTES ), true ) ); } /** * Generate a new unique hash as a delivery id based on current time and wehbook id. * Return the hash for inclusion in the webhook request. * * @since 2.2.0 * @return string */ public function get_new_delivery_id() { // Since we no longer use comments to store delivery logs, we generate a unique hash instead based on current time and webhook ID. return wp_hash( $this->get_id() . strtotime( 'now' ) ); } /** * Log the delivery request/response. * * @since 2.2.0 * @param string $delivery_id Previously created hash. * @param array $request Request data. * @param array|WP_Error $response Response data. * @param float $duration Request duration. */ public function log_delivery( $delivery_id, $request, $response, $duration ) { $logger = wc_get_logger(); $message = array( 'Webhook Delivery' => array( 'Delivery ID' => $delivery_id, 'Date' => date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( 'now' ), true ), 'URL' => $this->get_delivery_url(), 'Duration' => $duration, 'Request' => array( 'Method' => $request['method'], 'Headers' => array_merge( array( 'User-Agent' => $request['user-agent'], ), $request['headers'] ), ), 'Body' => wp_slash( $request['body'] ), ), ); // Parse response. if ( is_wp_error( $response ) ) { $response_code = $response->get_error_code(); $response_message = $response->get_error_message(); $response_headers = array(); $response_body = ''; } 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 ); } $message['Webhook Delivery']['Response'] = array( 'Code' => $response_code, 'Message' => $response_message, 'Headers' => $response_headers, 'Body' => $response_body, ); if ( ! Constants::is_true( 'WP_DEBUG' ) ) { $message['Webhook Delivery']['Body'] = 'Webhook body is not logged unless WP_DEBUG mode is turned on. This is to avoid the storing of personal data in the logs.'; $message['Webhook Delivery']['Response']['Body'] = 'Webhook body is not logged unless WP_DEBUG mode is turned on. This is to avoid the storing of personal data in the logs.'; } $logger->info( wc_print_r( $message, true ), array( 'source' => 'webhooks-delivery', ) ); // Track failures. // Check for a success, which is a 2xx, 301 or 302 Response Code. if ( intval( $response_code ) >= 200 && intval( $response_code ) < 303 ) { $this->set_failure_count( 0 ); $this->save(); } else { $this->failed_delivery(); } } /** * Track consecutive delivery failures and automatically disable the webhook. * if more than 5 consecutive failures occur. A failure is defined as a. * non-2xx response. * * @since 2.2.0 */ private function failed_delivery() { $failures = $this->get_failure_count(); if ( $failures > apply_filters( 'woocommerce_max_webhook_delivery_failures', 5 ) ) { $this->set_status( 'disabled' ); do_action( 'woocommerce_webhook_disabled_due_delivery_failures', $this->get_id() ); } else { $this->set_failure_count( ++$failures ); } $this->save(); } /** * Get the delivery logs for this webhook. * * @since 3.3.0 * @return string */ public function get_delivery_logs() { return esc_url( add_query_arg( 'log_file', wc_get_log_file_name( 'webhooks-delivery' ), admin_url( 'admin.php?page=wc-status&tab=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 * @deprecated 3.3.0 * @param int $delivery_id Delivery ID. * @return void */ public function get_delivery_log( $delivery_id ) { wc_deprecated_function( 'WC_Webhook::get_delivery_log', '3.3' ); } /** * Send a test ping to the delivery URL, sent when the webhook is first created. * * @since 2.2.0 * @return bool|WP_Error */ public function deliver_ping() { $args = array( 'user-agent' => sprintf( 'WooCommerce/%s Hookshot (WordPress/%s)', Constants::get_constant( 'WC_VERSION' ), $GLOBALS['wp_version'] ), 'body' => 'webhook_id=' . $this->get_id(), ); $test = wp_safe_remote_post( $this->get_delivery_url(), $args ); $response_code = wp_remote_retrieve_response_code( $test ); if ( is_wp_error( $test ) ) { /* translators: error message */ return new WP_Error( 'error', sprintf( __( 'Error: Delivery URL cannot be reached: %s', 'woocommerce' ), $test->get_error_message() ) ); } if ( 200 !== $response_code ) { /* translators: error message */ return new WP_Error( 'error', sprintf( __( 'Error: Delivery URL returned response code: %s', 'woocommerce' ), absint( $response_code ) ) ); } $this->set_pending_delivery( false ); $this->save(); return true; } /* |-------------------------------------------------------------------------- | Getters |-------------------------------------------------------------------------- */ /** * Get the friendly name for the webhook. * * @since 2.2.0 * @param string $context What the value is for. * Valid values are 'view' and 'edit'. * @return string */ public function get_name( $context = 'view' ) { return apply_filters( 'woocommerce_webhook_name', $this->get_prop( 'name', $context ), $this->get_id() ); } /** * Get the webhook status. * * - 'active' - delivers payload. * - 'paused' - does not deliver payload, paused by admin. * - 'disabled' - does not delivery payload, paused automatically due to consecutive failures. * * @since 2.2.0 * @param string $context What the value is for. * Valid values are 'view' and 'edit'. * @return string status */ public function get_status( $context = 'view' ) { return apply_filters( 'woocommerce_webhook_status', $this->get_prop( 'status', $context ), $this->get_id() ); } /** * Get webhook created date. * * @since 3.2.0 * @param string $context What the value is for. * Valid values are 'view' and 'edit'. * @return WC_DateTime|null Object if the date is set or null if there is no date. */ public function get_date_created( $context = 'view' ) { return $this->get_prop( 'date_created', $context ); } /** * Get webhook modified date. * * @since 3.2.0 * @param string $context What the value is for. * Valid values are 'view' and 'edit'. * @return WC_DateTime|null Object if the date is set or null if there is no date. */ public function get_date_modified( $context = 'view' ) { return $this->get_prop( 'date_modified', $context ); } /** * Get the secret used for generating the HMAC-SHA256 signature. * * @since 2.2.0 * @param string $context What the value is for. * Valid values are 'view' and 'edit'. * @return string */ public function get_secret( $context = 'view' ) { return apply_filters( 'woocommerce_webhook_secret', $this->get_prop( 'secret', $context ), $this->get_id() ); } /** * Get the webhook topic, e.g. `order.created`. * * @since 2.2.0 * @param string $context What the value is for. * Valid values are 'view' and 'edit'. * @return string */ public function get_topic( $context = 'view' ) { return apply_filters( 'woocommerce_webhook_topic', $this->get_prop( 'topic', $context ), $this->get_id() ); } /** * Get the delivery URL. * * @since 2.2.0 * @param string $context What the value is for. * Valid values are 'view' and 'edit'. * @return string */ public function get_delivery_url( $context = 'view' ) { return apply_filters( 'woocommerce_webhook_delivery_url', $this->get_prop( 'delivery_url', $context ), $this->get_id() ); } /** * Get the user ID for this webhook. * * @since 2.2.0 * @param string $context What the value is for. * Valid values are 'view' and 'edit'. * @return int */ public function get_user_id( $context = 'view' ) { return $this->get_prop( 'user_id', $context ); } /** * API version. * * @since 3.0.0 * @param string $context What the value is for. * Valid values are 'view' and 'edit'. * @return string */ public function get_api_version( $context = 'view' ) { $version = $this->get_prop( 'api_version', $context ); return 0 < $version ? 'wp_api_v' . $version : 'legacy_v3'; } /** * Get the failure count. * * @since 2.2.0 * @param string $context What the value is for. * Valid values are 'view' and 'edit'. * @return int */ public function get_failure_count( $context = 'view' ) { return $this->get_prop( 'failure_count', $context ); } /** * Get pending delivery. * * @since 3.2.0 * @param string $context What the value is for. * Valid values are 'view' and 'edit'. * @return bool */ public function get_pending_delivery( $context = 'view' ) { return $this->get_prop( 'pending_delivery', $context ); } /* |-------------------------------------------------------------------------- | Setters |-------------------------------------------------------------------------- */ /** * Set webhook name. * * @since 3.2.0 * @param string $name Webhook name. */ public function set_name( $name ) { $this->set_prop( 'name', $name ); } /** * Set webhook created date. * * @since 3.2.0 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. * If the DateTime string has no timezone or offset, * WordPress site timezone will be assumed. * Null if their is no date. */ public function set_date_created( $date = null ) { $this->set_date_prop( 'date_created', $date ); } /** * Set webhook modified date. * * @since 3.2.0 * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. * If the DateTime string has no timezone or offset, * WordPress site timezone will be assumed. * Null if their is no date. */ public function set_date_modified( $date = null ) { $this->set_date_prop( 'date_modified', $date ); } /** * Set status. * * @since 3.2.0 * @param string $status Status. */ public function set_status( $status ) { if ( ! array_key_exists( $status, wc_get_webhook_statuses() ) ) { $status = 'disabled'; } $this->set_prop( 'status', $status ); } /** * Set the secret used for generating the HMAC-SHA256 signature. * * @since 2.2.0 * @param string $secret Secret. */ public function set_secret( $secret ) { $this->set_prop( 'secret', $secret ); } /** * Set the webhook topic and associated hooks. * The topic resource & event are also saved separately. * * @since 2.2.0 * @param string $topic Webhook topic. */ public function set_topic( $topic ) { $topic = wc_clean( $topic ); if ( ! wc_is_webhook_valid_topic( $topic ) ) { $topic = ''; } $this->set_prop( 'topic', $topic ); } /** * Set the delivery URL. * * @since 2.2.0 * @param string $url Delivery URL. */ public function set_delivery_url( $url ) { $this->set_prop( 'delivery_url', esc_url_raw( $url, array( 'http', 'https' ) ) ); } /** * Set user ID. * * @since 3.2.0 * @param int $user_id User ID. */ public function set_user_id( $user_id ) { $this->set_prop( 'user_id', (int) $user_id ); } /** * Set API version. * * @since 3.0.0 * @param int|string $version REST API version. */ public function set_api_version( $version ) { if ( ! is_numeric( $version ) ) { $version = $this->data_store->get_api_version_number( $version ); } $this->set_prop( 'api_version', (int) $version ); } /** * Set pending delivery. * * @since 3.2.0 * @param bool $pending_delivery Set true if is pending for delivery. */ public function set_pending_delivery( $pending_delivery ) { $this->set_prop( 'pending_delivery', (bool) $pending_delivery ); } /** * Set failure count. * * @since 3.2.0 * @param bool $failure_count Total of failures. */ public function set_failure_count( $failure_count ) { $this->set_prop( 'failure_count', intval( $failure_count ) ); } /* |-------------------------------------------------------------------------- | Non-CRUD Getters |-------------------------------------------------------------------------- */ /** * Get the associated hook names for a topic. * * @since 2.2.0 * @param string $topic Topic name. * @return array */ private function get_topic_hooks( $topic ) { $topic_hooks = array( 'coupon.created' => array( 'woocommerce_process_shop_coupon_meta', 'woocommerce_new_coupon', ), 'coupon.updated' => array( 'woocommerce_process_shop_coupon_meta', 'woocommerce_update_coupon', ), 'coupon.deleted' => array( 'wp_trash_post', ), 'coupon.restored' => array( 'untrashed_post', ), 'customer.created' => array( 'user_register', 'woocommerce_created_customer', 'woocommerce_new_customer', ), 'customer.updated' => array( 'profile_update', 'woocommerce_update_customer', ), 'customer.deleted' => array( 'delete_user', ), 'order.created' => array( 'woocommerce_new_order', ), 'order.updated' => array( 'woocommerce_update_order', 'woocommerce_order_refunded', ), 'order.deleted' => array( 'wp_trash_post', ), 'order.restored' => array( 'untrashed_post', ), 'product.created' => array( 'woocommerce_process_product_meta', 'woocommerce_new_product', 'woocommerce_new_product_variation', ), 'product.updated' => array( 'woocommerce_process_product_meta', 'woocommerce_update_product', 'woocommerce_update_product_variation', ), 'product.deleted' => array( 'wp_trash_post', ), 'product.restored' => array( 'untrashed_post', ), ); $topic_hooks = apply_filters( 'woocommerce_webhook_topic_hooks', $topic_hooks, $this ); return isset( $topic_hooks[ $topic ] ) ? $topic_hooks[ $topic ] : array(); } /** * Get the hook names for the webhook. * * @since 2.2.0 * @return array */ public function get_hooks() { if ( 'action' === $this->get_resource() ) { $hooks = array( $this->get_event() ); } else { $hooks = $this->get_topic_hooks( $this->get_topic() ); } return apply_filters( 'woocommerce_webhook_hooks', $hooks, $this->get_id() ); } /** * Get the resource for the webhook, e.g. `order`. * * @since 2.2.0 * @return string */ public function get_resource() { $topic = explode( '.', $this->get_topic() ); return apply_filters( 'woocommerce_webhook_resource', $topic[0], $this->get_id() ); } /** * Get the event for the webhook, e.g. `created`. * * @since 2.2.0 * @return string */ public function get_event() { $topic = explode( '.', $this->get_topic() ); return apply_filters( 'woocommerce_webhook_event', isset( $topic[1] ) ? $topic[1] : '', $this->get_id() ); } /** * Get the webhook i18n status. * * @return string */ public function get_i18n_status() { $status = $this->get_status(); $statuses = wc_get_webhook_statuses(); return isset( $statuses[ $status ] ) ? $statuses[ $status ] : $status; } }
Methods Methods
- __construct — Load webhook data based on how WC_Webhook is called.
- build_payload — Build the payload data for the webhook.
- deliver — Deliver the webhook payload using wp_safe_remote_request().
- deliver_ping — Send a test ping to the delivery URL, sent when the webhook is first created.
- enqueue — Enqueue the hooks associated with the webhook.
- failed_delivery — Track consecutive delivery failures and automatically disable the webhook.
- generate_signature — 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).
- get_api_version — API version.
- get_date_created — Get webhook created date.
- get_date_modified — Get webhook modified date.
- get_delivery_log — Get the delivery log specified by the ID. The delivery log includes: — deprecated
- get_delivery_logs — Get the delivery logs for this webhook.
- get_delivery_url — Get the delivery URL.
- get_event — Get the event for the webhook, e.g. `created`.
- get_failure_count — Get the failure count.
- get_hooks — Get the hook names for the webhook.
- get_i18n_status — Get the webhook i18n status.
- get_legacy_api_payload — Get Legacy API payload.
- get_name — Get the friendly name for the webhook.
- get_new_delivery_id — Generate a new unique hash as a delivery id based on current time and wehbook id.
- get_pending_delivery — Get pending delivery.
- get_resource — Get the resource for the webhook, e.g. `order`.
- get_secret — Get the secret used for generating the HMAC-SHA256 signature.
- get_status — Get the webhook status.
- get_topic — Get the webhook topic, e.g. `order.created`.
- get_topic_hooks — Get the associated hook names for a topic.
- get_user_id — Get the user ID for this webhook.
- get_wp_api_payload — Get WP API integration payload.
- is_active — Returns if webhook is active.
- is_already_processed — Checks if the specified resource has already been queued for delivery within the current request.
- is_valid_action — Validates the criteria for certain actions.
- is_valid_post_action — Validates post actions.
- is_valid_processing_action — Validates WC processing actions.
- is_valid_resource — Checks the resource for this webhook is valid e.g. valid post status.
- is_valid_topic — Returns if topic is valid.
- is_valid_user_action — Validates user actions.
- log_delivery — Log the delivery request/response.
- process — Process the webhook for delivery by verifying that it should be delivered.
- set_api_version — Set API version.
- set_date_created — Set webhook created date.
- set_date_modified — Set webhook modified date.
- set_delivery_url — Set the delivery URL.
- set_failure_count — Set failure count.
- set_name — Set webhook name.
- set_pending_delivery — Set pending delivery.
- set_secret — Set the secret used for generating the HMAC-SHA256 signature.
- set_status — Set status.
- set_topic — Set the webhook topic and associated hooks.
- set_user_id — Set user ID.
- should_deliver — Helper to check if the webhook should be delivered, as some hooks.