PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 2.2.0
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v2.2.0
2.3.0 2.2.0 2.1.1 2.1.0 2.0.0 1.10.0 1.9.1 1.9.0 1.2.1 1.2.2 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 All 59 releases
storeengine / addons / webhooks / events / dispatch.php

dispatch.php in StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More 2.2.0, at addons/webhooks/events/dispatch.php

167 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace StoreEngine\Addons\Webhooks\Events;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit;
7 }
8
9 use StoreEngine\classes\Exceptions\StoreEngineException;
10 use StoreEngine\Addons\Webhooks\Listeners\Product\{
11 Created as ProductCreated,
12 Updated as ProductUpdated,
13 Deleted as ProductDeleted,
14 Restored as ProductRestored
15 };
16 use StoreEngine\Addons\Webhooks\Listeners\Coupon\{
17 Created as CouponCreated,
18 Updated as CouponUpdated,
19 Deleted as CouponDeleted,
20 Restored as CouponRestored
21 };
22 use StoreEngine\Addons\Webhooks\Listeners\Order\{
23 Created as OrderCreated,
24 Updated as OrderUpdated,
25 Deleted as OrderDeleted,
26 Restored as OrderRestored,
27 };
28 use StoreEngine\Addons\Webhooks\Listeners\Customer\{
29 Created as CustomerCreated,
30 Updated as CustomerUpdated,
31 Deleted as CustomerDeleted,
32 };
33 use StoreEngine\Addons\Webhooks\Listeners\Page\{
34 Published as PagePublished,
35 Updated as PageUpdated,
36 Deleted as PageDeleted,
37 };
38 use StoreEngine\Addons\Webhooks\Listeners\Post\{
39 Published as PostPublished,
40 Updated as PostUpdated,
41 Deleted as PostDeleted,
42 };
43 use StoreEngine\Addons\Webhooks\Listeners\Template\{
44 Saved as TemplateSaved,
45 PartSaved as TemplatePartSaved,
46 };
47 use StoreEngine\Addons\Webhooks\Listeners\Menu\Updated as NavMenuUpdated;
48 use StoreEngine\Addons\Webhooks\Listeners\GlobalStyles\Saved as GlobalStylesSaved;
49 use StoreEngine\Classes\StoreengineDatetime;
50
51 class Dispatch {
52 protected array $listeners = [];
53
54 public static function init() {
55 $self = new self();
56
57 $self->listeners = (array) apply_filters( 'storeengine/webhooks_event_listeners', [
58 'product_created' => ProductCreated::class,
59 'product_updated' => ProductUpdated::class,
60 'product_deleted' => ProductDeleted::class,
61 'product_restored' => ProductRestored::class,
62 'coupon_created' => CouponCreated::class,
63 'coupon_updated' => CouponUpdated::class,
64 'coupon_deleted' => CouponDeleted::class,
65 'coupon_restored' => CouponRestored::class,
66 'order_created' => OrderCreated::class,
67 'order_updated' => OrderUpdated::class,
68 'order_deleted' => OrderDeleted::class,
69 'order_restored' => OrderRestored::class,
70 'customer_created' => CustomerCreated::class,
71 'customer_updated' => CustomerUpdated::class,
72 'customer_deleted' => CustomerDeleted::class,
73
74 // CMS content (pages, posts) — for headless storefronts.
75 'page_published' => PagePublished::class,
76 'page_updated' => PageUpdated::class,
77 'page_deleted' => PageDeleted::class,
78 'post_published' => PostPublished::class,
79 'post_updated' => PostUpdated::class,
80 'post_deleted' => PostDeleted::class,
81
82 // Block-theme / Site Editor.
83 'template_saved' => TemplateSaved::class,
84 'template_part_saved' => TemplatePartSaved::class,
85 'global_styles_saved' => GlobalStylesSaved::class,
86
87 // Navigation.
88 'nav_menu_updated' => NavMenuUpdated::class,
89 ] );
90
91 $self->init_webhooks();
92
93 // Dispatch hook.
94 add_action( 'storeengine/webhooks/async_delivery', [ $self, 'async_delivery' ], 10, 4 );
95 }
96
97 /**
98 * @throws StoreEngineException
99 */
100 public function async_delivery( int $id, string $topic, array $payload, string $triggeredAt ) {
101 Dispatcher::get_instance( $id, $topic, $payload, $triggeredAt )->dispatch();
102 }
103
104 public function init_webhooks() {
105 $published = GetPublished::all();
106
107 // No published webhooks — skip listener registration entirely.
108 if ( empty( $published ) ) {
109 return;
110 }
111
112 foreach ( $published as ['id' => $id, 'events' => $events] ) {
113 // Skip webhook with no delivery URL (saves an entire round-trip).
114 $delivery_url = get_post_meta( $id, '_storeengine_webhook_delivery_url', true );
115 if ( empty( $delivery_url ) ) {
116 continue;
117 }
118
119 // Skip webhook that has crossed the failure threshold (default 5 — filterable).
120 $failure_count = (int) get_post_meta( $id, 'failure_count', true );
121 $failure_threshold = (int) apply_filters( 'storeengine/webhooks/failure_threshold', 5, $id );
122 if ( $failure_threshold > 0 && $failure_count >= $failure_threshold ) {
123 continue;
124 }
125
126 foreach ( $events as $topic ) {
127 if ( array_key_exists( $topic, $this->listeners ) ) {
128 $cb = function ( int $id, array $payload ) use ( $topic ) {
129 $args = [
130 'webhook' => $id,
131 'topic' => $topic,
132 'payload' => $payload,
133 'triggeredAt' => (string) new StoreEngineDateTime(),
134 ];
135
136 // In-queue dedup: if an identical pending delivery already exists
137 // for this (webhook, topic, payload), skip enqueueing another.
138 // Note: payload-equality match. triggeredAt is excluded from the
139 // dedup signature via the 5th $unique parameter being checked
140 // against full args — so we strip it for the lookup.
141 $dedup_args = $args;
142 unset( $dedup_args['triggeredAt'] );
143
144 if ( function_exists( 'as_has_scheduled_action' ) && as_has_scheduled_action(
145 'storeengine/webhooks/async_delivery',
146 $dedup_args,
147 'storeengine-webhooks'
148 ) ) {
149 return;
150 }
151
152 as_enqueue_async_action(
153 'storeengine/webhooks/async_delivery',
154 $args,
155 'storeengine-webhooks',
156 true
157 );
158 };
159
160 call_user_func( [ $this->listeners[ $topic ], 'dispatch' ], $cb, $id );
161 }
162 }
163 }
164 }
165
166 }
167