164 lines
4.6 KiB
PHP
164 lines
4.6 KiB
PHP
<?php
|
|
/**
|
|
* Webhook Handler
|
|
*
|
|
* @package easy-digital-downloads
|
|
* @subpackage Gateways\PayPal\Webhooks
|
|
* @copyright Copyright (c) 2021, Sandhills Development, LLC
|
|
* @license GPL2+
|
|
* @since 2.11
|
|
*/
|
|
|
|
namespace EDD\Gateways\PayPal\Webhooks;
|
|
|
|
use EDD\Gateways\PayPal;
|
|
|
|
class Webhook_Handler {
|
|
/**
|
|
* Endpoint namespace.
|
|
*
|
|
* @since 2.11
|
|
*/
|
|
const REST_NAMESPACE = 'edd/webhooks/v1';
|
|
|
|
/**
|
|
* Endpoint route.
|
|
*
|
|
* @since 2.11
|
|
*/
|
|
const REST_ROUTE = 'paypal';
|
|
|
|
/**
|
|
* Webhook payload
|
|
*
|
|
* @var object
|
|
* @since 2.11
|
|
*/
|
|
private $event;
|
|
|
|
/**
|
|
* Registers REST API routes.
|
|
*
|
|
* @since 2.11
|
|
* @return void
|
|
*/
|
|
public function register_routes() {
|
|
register_rest_route( self::REST_NAMESPACE, self::REST_ROUTE, array(
|
|
'methods' => \WP_REST_Server::CREATABLE,
|
|
'callback' => array( $this, 'handle_request' ),
|
|
'permission_callback' => array( $this, 'validate_request' )
|
|
) );
|
|
}
|
|
|
|
/**
|
|
* Handles the current request.
|
|
*
|
|
* @param \WP_REST_Request $request
|
|
*
|
|
* @since 2.11
|
|
* @return \WP_REST_Response
|
|
*/
|
|
public function handle_request( \WP_REST_Request $request ) {
|
|
edd_debug_log( sprintf(
|
|
'PayPal Commerce webhook endpoint loaded. Mode: %s; Event: %s',
|
|
( edd_is_test_mode() ? 'sandbox' : 'live' ),
|
|
$request->get_param( 'event_type' )
|
|
) );
|
|
|
|
edd_debug_log( sprintf( 'Payload: %s', json_encode( $this->event ) ) ); // @todo remove
|
|
|
|
try {
|
|
// We need to match this event to one of our handlers.
|
|
$events = get_webhook_events();
|
|
if ( ! array_key_exists( $request->get_param( 'event_type' ), $events ) ) {
|
|
throw new \Exception( sprintf( 'Event not registered. Event: %s', esc_html( $request->get_param( 'event_type' ) ) ), 200 );
|
|
}
|
|
|
|
$class_name = $events[ $request->get_param( 'event_type' ) ];
|
|
|
|
if ( ! class_exists( $class_name ) ) {
|
|
throw new \Exception( sprintf( 'Class %s doesn\'t exist for event type.', $class_name ), 500 );
|
|
}
|
|
|
|
/**
|
|
* Initialize the handler for this event.
|
|
*
|
|
* @var PayPal\Webhooks\Events\Webhook_Event $handler
|
|
*/
|
|
$handler = new $class_name( $request );
|
|
|
|
if ( ! method_exists( $handler, 'handle' ) ) {
|
|
throw new \Exception( sprintf( 'handle() method doesn\'t exist in class %s.', $class_name ), 500 );
|
|
}
|
|
|
|
edd_debug_log( sprintf( 'PayPal Commerce Webhook - Passing to handler %s', esc_html( $class_name ) ) );
|
|
|
|
$handler->handle();
|
|
|
|
$action_key = sanitize_key( strtolower( str_replace( '.', '_', $request->get_param( 'event_type' ) ) ) );
|
|
/**
|
|
* Triggers once the handler has run successfully.
|
|
* $action_key is a formatted version of the event type:
|
|
* - All lowercase
|
|
* - Full stops `.` replaced with underscores `_`
|
|
*
|
|
* Note: This action hook exists so you can execute custom code *after* a handler has run.
|
|
* If you're registering a custom event, please build a custom handler by extending
|
|
* the `Webhook_Event` class and not via this hook.
|
|
*
|
|
* @param \WP_REST_Request $event
|
|
*
|
|
* @since 2.11
|
|
*/
|
|
do_action( 'edd_paypal_webhook_event_' . $action_key, $request );
|
|
|
|
return new \WP_REST_Response( 'Success', 200 );
|
|
} catch ( PayPal\Exceptions\Authentication_Exception $e ) {
|
|
// Failure with PayPal credentials.
|
|
edd_debug_log( sprintf( 'PayPal Commerce Webhook - Exiting due to authentication exception. Message: %s', $e->getMessage() ), true );
|
|
|
|
return new \WP_REST_Response( $e->getMessage(), 403 );
|
|
} catch ( PayPal\Exceptions\API_Exception $e ) {
|
|
// Failure with a PayPal API request.
|
|
edd_debug_log( sprintf( 'PayPal Commerce Webhook - Failure due to an API exception. Message: %s', $e->getMessage() ) );
|
|
|
|
return new \WP_REST_Response( $e->getMessage(), 500 );
|
|
} catch ( \Exception $e ) {
|
|
edd_debug_log( sprintf( 'PayPal Commerce - Exiting webhook due to an exception. Message: %s', $e->getMessage() ), true );
|
|
|
|
$response_code = $e->getCode() > 0 ? $e->getCode() : 500;
|
|
|
|
return new \WP_REST_Response( $e->getMessage(), $response_code );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validates the webhook
|
|
*
|
|
* @since 2.11
|
|
* @return bool|\WP_Error
|
|
*/
|
|
public function validate_request() {
|
|
if ( ! PayPal\has_rest_api_connection() ) {
|
|
return new \WP_Error( 'missing_api_credentials', 'API credentials not set.' );
|
|
}
|
|
|
|
$this->event = json_decode( file_get_contents( 'php://input' ) );
|
|
|
|
try {
|
|
Webhook_Validator::validate_from_request( $this->event );
|
|
|
|
edd_debug_log( 'PayPal Commerce webhook successfully validated.' );
|
|
|
|
return true;
|
|
} catch ( \Exception $e ) {
|
|
return new \WP_Error( 'validation_failure', $e->getMessage() );
|
|
}
|
|
}
|
|
}
|
|
|
|
add_action( 'rest_api_init', function () {
|
|
$handler = new Webhook_Handler();
|
|
$handler->register_routes();
|
|
} );
|