PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.7.1
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.7.1
1.7.1 1.7.0 1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 All 51 releases
fluent-cart / app / Hooks / actions.php

actions.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.7.1, at app/Hooks/actions.php

317 lines 13.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php if (!defined('ABSPATH')) exit; ?>
2 <?php
3
4 /**
5 * All registered action's handlers should be in app\Hooks\Handlers,
6 * addAction is similar to add_action and addCustomAction is just a
7 * wrapper over add_action which will add a prefix to the hook name
8 * using the plugin slug to make it unique in all WordPress plugins,
9 * ex: $app->addCustomAction('foo', ['FooHandler', 'handleFoo']) is
10 * equivalent to add_action('slug-foo', ['FooHandler', 'handleFoo']).
11 */
12
13 /**
14 * @var $app FluentCart\Framework\Foundation\Application
15 */
16
17 use FluentCart\App\Http\Routes\WebRoutes;
18
19 (new \FluentCart\App\CPT\FluentProducts)->register();
20 (new \FluentCart\App\Services\Email\EmailNotificationMailer)->register();
21 (new \FluentCart\App\Hooks\Handlers\CPTHandler)->register();
22 (new \FluentCart\App\Hooks\Handlers\MenuHandler)->register();
23 (new \FluentCart\App\Hooks\Handlers\AdminMenuBarHandler)->register();
24 (new \FluentCart\App\Hooks\Handlers\FluentCartHandler)->register();
25 (new \FluentCart\App\Hooks\Handlers\RetentionSnapshotHandler)->register();
26 (new \FluentCart\App\Hooks\Handlers\ReminderHandler)->register();
27
28 (new \FluentCart\App\Hooks\Handlers\ShortCodes\ShopAppHandler)->register();
29 (new \FluentCart\App\Hooks\Handlers\ShortCodes\OrderReviewShortCode)->register();
30
31 (new FluentCart\App\Hooks\Handlers\CustomCheckout\CustomCheckout())->register();
32
33 // Tax Module Init
34 add_action('init', function () {
35 (new \FluentCart\App\Modules\Tax\TaxModule())->register();
36 }, 1);
37
38 // Turnstile Module Init
39 (new \FluentCart\App\Modules\Turnstile\TurnstileInit())->register(\FluentCart\App\App::getInstance());
40
41 // Reviews Module Init
42 (new \FluentCart\App\Modules\Reviews\ReviewModule())->register();
43
44 (new \FluentCart\App\Modules\FluentPlayer\FluentPlayerAdminAssets())->register();
45
46 // Register Pro Gateways Promo
47 (new \FluentCart\App\Hooks\Handlers\PromoGatewaysHandler())->register();
48
49 // Register Addon Gateways
50 (new \FluentCart\App\Hooks\Handlers\AddonGatewaysHandler())->register();
51
52 // Web Checkout
53 (new \FluentCart\App\Hooks\Cart\WebCheckoutHandler())->register();
54
55
56 \FluentCart\App\Hooks\Handlers\BlockEditors\ShopApp\ShopAppBlockEditor::register();
57 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductCarousel\ProductCarouselBlockEditor::register();
58 \FluentCart\App\Hooks\Handlers\BlockEditors\MediaCarousel\MediaCarouselBlockEditor::register();
59
60 \FluentCart\App\Hooks\Handlers\ShortCodes\SearchBarShortCode::register();
61 \FluentCart\App\Hooks\Handlers\BlockEditors\SearchBarBlockEditor::register();
62 \FluentCart\App\Hooks\Handlers\BlockEditors\PricingTableBlockEditor::register();
63 \FluentCart\App\Hooks\Handlers\BlockEditors\CustomerProfileBlockEditor::register();
64 \FluentCart\App\Hooks\Handlers\ShortCodes\CustomerProfileHandler::register();
65 \FluentCart\App\Hooks\Handlers\BlockEditors\Checkout\CheckoutBlockEditor::register();
66 \FluentCart\App\Hooks\Handlers\ShortCodes\CartShortcode::register();
67 \FluentCart\App\Hooks\Handlers\ShortCodes\PricingTableShortCode::register();
68 \FluentCart\App\Hooks\Handlers\ShortCodes\Checkout\CheckoutPageHandler::register();
69 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductCardBlockEditor::register();
70 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductGalleryBlockEditor::register();
71 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductInfoBlockEditor::register();
72 \FluentCart\App\Hooks\Handlers\BlockEditors\BuySectionBlockEditor::register();
73 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductTitleBlockEditor::register();
74 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductImageBlockEditor::register();
75 \FluentCart\App\Hooks\Handlers\BlockEditors\PriceRangeBlockEditor::register();
76 \FluentCart\App\Hooks\Handlers\BlockEditors\SaleBadgeBlockEditor::register();
77 \FluentCart\App\Hooks\Handlers\BlockEditors\ExcerptBlockEditor::register();
78 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductDescriptionBlockEditor::register();
79 \FluentCart\App\Hooks\Handlers\ShortCodes\ProductCardShortCode::register();
80 \FluentCart\App\Hooks\Handlers\BlockEditors\Buttons\BuyNowButtonBlockEditor::register();
81 \FluentCart\App\Hooks\Handlers\BlockEditors\Buttons\AddToCartButtonBlockEditor::register();
82
83 \FluentCart\App\Hooks\Handlers\BlockEditors\MiniCartBlockEditor::register();
84 \FluentCart\App\Hooks\Handlers\BlockEditors\Cart\CartBlockEditor::register();
85 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductCategoriesListBlockEditor::register();
86 \FluentCart\App\Hooks\Handlers\BlockEditors\RelatedProduct\RelatedProductBlockEditor::register();
87 \FluentCart\App\Hooks\Handlers\ShortCodes\Buttons\DirectCheckoutShortcode::register();
88 \FluentCart\App\Hooks\Handlers\ShortCodes\Buttons\AddToCartShortcode::register();
89 \FluentCart\App\Hooks\Handlers\ShortCodes\MiniCartShortcode::register();
90 \FluentCart\App\Hooks\Handlers\ShortCodes\ProductCategoriesListShortcode::register();
91 \FluentCart\App\Hooks\Handlers\ShortCodes\ProductTitleShortCode::register();
92 \FluentCart\App\Hooks\Handlers\ShortCodes\ProductImageShortCode::register();
93 \FluentCart\App\Hooks\Handlers\ShortCodes\SingleProductShortCode::register();
94
95
96 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductSkuBlockEditor::register();
97 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductPackageDescriptionBlockEditor::register();
98 \FluentCart\App\Hooks\Handlers\BlockEditors\StoreLogoBlockEditor::register();
99 \FluentCart\App\Hooks\Handlers\ShortCodes\StoreLogoShortCode::register();
100 \FluentCart\App\Hooks\Handlers\BlockEditors\CustomerDashboardButtonBlockEditor::register();
101 \FluentCart\App\Hooks\Handlers\ShortCodes\CustomerDashboardButtonShortcode::register();
102
103
104 (new \FluentCart\App\Modules\StockManagement\StockManagement())->register(fluentCart());
105
106 if (\FluentCart\Api\ModuleSettings::isActive('stock_management')) {
107 \FluentCart\App\Hooks\Handlers\BlockEditors\StockBlock::register();
108 \FluentCart\App\Hooks\Handlers\BlockEditors\SoldOutBadgeBlockEditor::register();
109 }
110
111 // Registered whether or not the reviews module is active: the block ships
112 // inside the Shop App, Product Info and Related Products card templates, so
113 // an unregistered block would greet the editor with "your site doesn't
114 // include support for this block" on every card. With the module off it
115 // stays out of the inserter and renders nothing, in the editor and on the
116 // page — see ProductRatingBlockEditor.
117 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductRatingBlockEditor::register();
118
119 if (\FluentCart\Api\ModuleSettings::isActive('reviews') && class_exists(\FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewsBlockEditor::class)) {
120 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewsBlockEditor::register();
121 \FluentCart\App\Hooks\Handlers\BlockEditors\WriteAReviewButtonBlockEditor::register();
122 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewFormBlockEditor::register();
123 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewSummaryBlockEditor::register();
124 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewList\ProductReviewListBlockEditor::register();
125 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewSummaryGroupBlockEditor::register();
126 \FluentCart\App\Hooks\Handlers\ShortCodes\ProductReviewsShortCode::register();
127 }
128
129 (new \FluentCart\App\Hooks\Cart\CartLoader)->register();
130 (new \FluentCart\App\Hooks\Handlers\GlobalPaymentHandler)->register();
131
132 \FluentCart\App\Http\Routes\WebRoutes::register();
133
134 (new \FluentCart\App\Modules\IntegrationActions\GlobalIntegrationActionHandler())->register();
135 (new \FluentCart\App\Hooks\Handlers\GlobalStorageHandler)->register();
136
137
138 //Register Page Handlers
139 (new \FluentCart\App\Hooks\Handlers\ShortCodes\ReceiptHandler)->register();
140
141 (new \FluentCart\App\Modules\Coupon\CouponHandler)->register();
142
143 \FluentCart\App\Services\Theme\AdminTheme::applyTheme();
144 \FluentCart\App\Services\Theme\FrontendTheme::applyTheme();
145
146 (new \FluentCart\App\CPT\Pages)->handlePageDelete();
147 (new \FluentCart\App\Services\FileSystem\DownloadService)->register();
148
149 (new \FluentCart\App\Hooks\Handlers\UserHandler())->register();
150
151 // Corrected hook name: fluent_cart/order_paid_async_private_handle
152 // Legacy (typo'd) listener kept for any pending Action Scheduler jobs
153 $orderPaidAsyncHandler = function ($data) {
154 $orderId = \FluentCart\Framework\Support\Arr::get($data, 'order_id');
155
156 if (!$orderId) {
157 return;
158 }
159
160 $order = \FluentCart\App\Models\Order::find($orderId);
161 if (!$order || $order->payment_status !== 'paid') {
162 return;
163 }
164
165 // Claim the run by deleting the meta and branching on the affected-row count.
166 // The Action Scheduler worker and the receipt-page AJAX nudge
167 // (IntegrationEventListener::runOrderActionsAjax) can arrive together, so a
168 // read-then-delete would let both pass the guard and fire order_paid_done
169 // twice. A single DELETE is atomic: MySQL hands the row to exactly one
170 // caller, and the loser sees 0 rows and returns.
171 if (!$order->deleteMeta('action_scheduler_id')) {
172 return;
173 }
174
175 $transaction = \FluentCart\App\Models\OrderTransaction::query()
176 ->where('order_id', $order->id)
177 ->where('status', \FluentCart\App\Helpers\Status::TRANSACTION_SUCCEEDED)
178 ->orderBy('id', 'DESC')
179 ->first();
180
181 $eventData = [
182 'order' => $order,
183 'transaction' => $transaction,
184 'customer' => $order->customer
185 ];
186
187 if ($order->type === 'subscription' || $order->type === 'renewal') {
188 $subscription = \FluentCart\App\Models\Subscription::query()->where('parent_order_id', $order->id)->first();
189 if ($subscription) {
190 $eventData['subscription'] = $subscription;
191 }
192 }
193
194 do_action('fluent_cart/order_paid_done', $eventData);
195
196 };
197 add_action('fluent_cart/order_paid_async_private_handle', $orderPaidAsyncHandler, 1, 1);
198
199 // The settled half of a review approval — see ReviewApproved::afterDispatch().
200 // Runs off the request, so it trusts nothing it was told: the review is
201 // re-read, and only one that is still an approved top-level review is
202 // announced. Deleted or held back since, nothing fires.
203 $reviewApprovedAsyncHandler = function ($data) {
204 $reviewId = (int) \FluentCart\Framework\Support\Arr::get($data, 'review_id');
205
206 if (!$reviewId) {
207 return;
208 }
209
210 $review = \FluentCart\App\Models\ProductReview::query()->with('product')->find($reviewId);
211
212 if (!$review || $review->parent_id || $review->status !== \FluentCart\App\Helpers\Status::REVIEW_APPROVED) {
213 return;
214 }
215
216 do_action('fluent_cart/review_approved_done', [
217 'review' => $review,
218 'product' => $review->product,
219 ]);
220 };
221 add_action('fluent_cart/review_approved_async_private_handle', $reviewApprovedAsyncHandler, 1, 1);
222
223 // The settled half of a store reply — see ReviewReplied::afterDispatch().
224 // Announced only while both halves are published: the reply itself, and the
225 // review it answers. A reply to a review nobody can see is not a
226 // conversation the reviewer can be pointed at.
227 $reviewRepliedAsyncHandler = function ($data) {
228 $replyId = (int) \FluentCart\Framework\Support\Arr::get($data, 'reply_id');
229
230 if (!$replyId) {
231 return;
232 }
233
234 $reply = \FluentCart\App\Models\ProductReview::query()->with('product')->find($replyId);
235
236 if (!$reply || !$reply->parent_id || !$reply->is_admin_reply || $reply->status !== \FluentCart\App\Helpers\Status::REVIEW_APPROVED) {
237 return;
238 }
239
240 $review = \FluentCart\App\Models\ProductReview::query()->find((int) $reply->parent_id);
241
242 if (!$review || $review->parent_id || $review->status !== \FluentCart\App\Helpers\Status::REVIEW_APPROVED) {
243 return;
244 }
245
246 do_action('fluent_cart/review_replied_done', [
247 'reply' => $reply,
248 'review' => $review,
249 'product' => $reply->product,
250 ]);
251 };
252 add_action('fluent_cart/review_replied_async_private_handle', $reviewRepliedAsyncHandler, 1, 1);
253
254
255 //
256 //$app->addAction('fluent_cart/orders_filter_customer', function ($query, $filters) {
257 // return (new \FluentCart\App\Models\Order)->buildCustomerFilterQuery($query, $filters);
258 //}, 10, 2);
259
260 // require the CLI
261 if (defined('WP_CLI') && WP_CLI) {
262 \WP_CLI::add_command('fluent_cart', '\FluentCart\App\Hooks\CLI\Commands');
263
264 }
265
266 \FluentCart\App\Modules\Subscriptions\SubscriptionModule::register();
267 \FluentCart\App\Modules\Shipping\ShippingModule::register();
268 \FluentCart\App\Modules\StoreManagedRenewal\RenewalModule::register();
269 (new \FluentCart\App\Hooks\Handlers\AttributesHandler())->register();
270 (new \FluentCart\App\Hooks\Handlers\AdvancedVariationHandler())->register();
271
272 // MCP (Model Context Protocol) — operator AI tools. Ships OFF; enabled in
273 // Settings → Features & addon → MCP. See MCPInit::boot() for the bootstrap.
274 \FluentCart\App\Modules\MCP\MCPInit::boot();
275
276 $app->ready(function () use ($app) {
277 \FluentCart\App\Models\Connection\ConnectionManager::connect($this->app);
278 });
279
280
281 // Add to your theme's functions.php or a custom plugin
282 // For Elementor preview URL
283
284
285 (new \FluentCart\App\Services\Integration)->register();
286
287 $app->addAction('fluent_cart/integration/schedule_feed', function ($queueId) use ($app) {
288 (new \FluentCart\App\Modules\Integrations\GlobalNotificationHandler())->processIntegrationAction($queueId);
289 });
290
291 // Schedulers
292 (new \FluentCart\App\Hooks\Scheduler\AutoSchedules\FiveMinuteScheduler())->register();
293 (new \FluentCart\App\Hooks\Scheduler\AutoSchedules\HourlyScheduler())->register();
294 (new \FluentCart\App\Hooks\Scheduler\AutoSchedules\DailyScheduler())->register();
295
296
297 /**
298 * Theme Hooks
299 */
300
301 add_action('init', [\FluentCart\App\Modules\Templating\TemplateLoader::class, 'init']);
302 add_action('after_setup_theme', function () {
303 \FluentCart\App\Modules\Templating\TemplateLoader::registerBlockParts();
304 (new \FluentCart\App\Modules\Templating\Bricks\BricksLoader())->register();
305 });
306
307
308 /**
309 * Development Hooks
310 */
311
312 add_action('init', function () {
313 if (!is_admin()) {
314 WebRoutes::renderModalCheckout();
315 }
316 });
317