PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.7.0
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.7.0
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 1.3.20 All 50 releases
← All changes | app/Hooks/actions.php +93 -5 1.3.28 → 1.7.0 View file →
@@ -25,18 +25,25 @@
25 25 (new \FluentCart\App\Hooks\Handlers\RetentionSnapshotHandler)->register();
26 26 (new \FluentCart\App\Hooks\Handlers\ReminderHandler)->register();
27 27
28 28 (new \FluentCart\App\Hooks\Handlers\ShortCodes\ShopAppHandler)->register();
29 -(new \FluentCart\App\Hooks\Handlers\ExportHandler)->register();
29 +(new \FluentCart\App\Hooks\Handlers\ShortCodes\OrderReviewShortCode)->register();
30 30
31 31 (new FluentCart\App\Hooks\Handlers\CustomCheckout\CustomCheckout())->register();
32 32
33 33 // Tax Module Init
34 -(new \FluentCart\App\Modules\Tax\TaxModule())->register();
34 +add_action('init', function () {
35 + (new \FluentCart\App\Modules\Tax\TaxModule())->register();
36 +}, 1);
35 37
36 38 // Turnstile Module Init
37 39 (new \FluentCart\App\Modules\Turnstile\TurnstileInit())->register(\FluentCart\App\App::getInstance());
38 40
41 +// Reviews Module Init
42 +(new \FluentCart\App\Modules\Reviews\ReviewModule())->register();
43 +
44 +(new \FluentCart\App\Modules\FluentPlayer\FluentPlayerAdminAssets())->register();
45 +
39 46 // Register Pro Gateways Promo
40 47 (new \FluentCart\App\Hooks\Handlers\PromoGatewaysHandler())->register();
41 48
42 49 // Register Addon Gateways
@@ -73,8 +80,9 @@
73 80 \FluentCart\App\Hooks\Handlers\BlockEditors\Buttons\BuyNowButtonBlockEditor::register();
74 81 \FluentCart\App\Hooks\Handlers\BlockEditors\Buttons\AddToCartButtonBlockEditor::register();
75 82
76 83 \FluentCart\App\Hooks\Handlers\BlockEditors\MiniCartBlockEditor::register();
84 +\FluentCart\App\Hooks\Handlers\BlockEditors\Cart\CartBlockEditor::register();
77 85 \FluentCart\App\Hooks\Handlers\BlockEditors\ProductCategoriesListBlockEditor::register();
78 86 \FluentCart\App\Hooks\Handlers\BlockEditors\RelatedProduct\RelatedProductBlockEditor::register();
79 87 \FluentCart\App\Hooks\Handlers\ShortCodes\Buttons\DirectCheckoutShortcode::register();
80 88 \FluentCart\App\Hooks\Handlers\ShortCodes\Buttons\AddToCartShortcode::register();
@@ -99,8 +107,19 @@
99 107 \FluentCart\App\Hooks\Handlers\BlockEditors\StockBlock::register();
100 108 \FluentCart\App\Hooks\Handlers\BlockEditors\SoldOutBadgeBlockEditor::register();
101 109 }
102 110
111 +if (\FluentCart\Api\ModuleSettings::isActive('reviews') && class_exists(\FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewsBlockEditor::class)) {
112 + \FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewsBlockEditor::register();
113 + \FluentCart\App\Hooks\Handlers\BlockEditors\ProductRatingBlockEditor::register();
114 + \FluentCart\App\Hooks\Handlers\BlockEditors\WriteAReviewButtonBlockEditor::register();
115 + \FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewFormBlockEditor::register();
116 + \FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewSummaryBlockEditor::register();
117 + \FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewList\ProductReviewListBlockEditor::register();
118 + \FluentCart\App\Hooks\Handlers\BlockEditors\ProductReviewSummaryGroupBlockEditor::register();
119 + \FluentCart\App\Hooks\Handlers\ShortCodes\ProductReviewsShortCode::register();
120 +}
121 +
103 122 (new \FluentCart\App\Hooks\Cart\CartLoader)->register();
104 123 (new \FluentCart\App\Hooks\Handlers\GlobalPaymentHandler)->register();
105 124
106 125 \FluentCart\App\Http\Routes\WebRoutes::register();
@@ -131,13 +150,21 @@
131 150 return;
132 151 }
133 152
134 153 $order = \FluentCart\App\Models\Order::find($orderId);
135 - if (!$order || $order->payment_status !== 'paid' || !$order->getMeta('action_scheduler_id')) {
154 + if (!$order || $order->payment_status !== 'paid') {
136 155 return;
137 156 }
138 157
139 - $order->deleteMeta('action_scheduler_id');
158 + // Claim the run by deleting the meta and branching on the affected-row count.
159 + // The Action Scheduler worker and the receipt-page AJAX nudge
160 + // (IntegrationEventListener::runOrderActionsAjax) can arrive together, so a
161 + // read-then-delete would let both pass the guard and fire order_paid_done
162 + // twice. A single DELETE is atomic: MySQL hands the row to exactly one
163 + // caller, and the loser sees 0 rows and returns.
164 + if (!$order->deleteMeta('action_scheduler_id')) {
165 + return;
166 + }
140 167
141 168 $transaction = \FluentCart\App\Models\OrderTransaction::query()
142 169 ->where('order_id', $order->id)
143 170 ->where('status', \FluentCart\App\Helpers\Status::TRANSACTION_SUCCEEDED)
@@ -160,11 +187,65 @@
160 187 do_action('fluent_cart/order_paid_done', $eventData);
161 188
162 189 };
163 190 add_action('fluent_cart/order_paid_async_private_handle', $orderPaidAsyncHandler, 1, 1);
164 -add_action('fluent_cart/order_paid_ansyc_private_handle', $orderPaidAsyncHandler, 1, 1);
165 191
192 +// The settled half of a review approval — see ReviewApproved::afterDispatch().
193 +// Runs off the request, so it trusts nothing it was told: the review is
194 +// re-read, and only one that is still an approved top-level review is
195 +// announced. Deleted or held back since, nothing fires.
196 +$reviewApprovedAsyncHandler = function ($data) {
197 + $reviewId = (int) \FluentCart\Framework\Support\Arr::get($data, 'review_id');
166 198
199 + if (!$reviewId) {
200 + return;
201 + }
202 +
203 + $review = \FluentCart\App\Models\ProductReview::query()->with('product')->find($reviewId);
204 +
205 + if (!$review || $review->parent_id || $review->status !== \FluentCart\App\Helpers\Status::REVIEW_APPROVED) {
206 + return;
207 + }
208 +
209 + do_action('fluent_cart/review_approved_done', [
210 + 'review' => $review,
211 + 'product' => $review->product,
212 + ]);
213 +};
214 +add_action('fluent_cart/review_approved_async_private_handle', $reviewApprovedAsyncHandler, 1, 1);
215 +
216 +// The settled half of a store reply — see ReviewReplied::afterDispatch().
217 +// Announced only while both halves are published: the reply itself, and the
218 +// review it answers. A reply to a review nobody can see is not a
219 +// conversation the reviewer can be pointed at.
220 +$reviewRepliedAsyncHandler = function ($data) {
221 + $replyId = (int) \FluentCart\Framework\Support\Arr::get($data, 'reply_id');
222 +
223 + if (!$replyId) {
224 + return;
225 + }
226 +
227 + $reply = \FluentCart\App\Models\ProductReview::query()->with('product')->find($replyId);
228 +
229 + if (!$reply || !$reply->parent_id || !$reply->is_admin_reply || $reply->status !== \FluentCart\App\Helpers\Status::REVIEW_APPROVED) {
230 + return;
231 + }
232 +
233 + $review = \FluentCart\App\Models\ProductReview::query()->find((int) $reply->parent_id);
234 +
235 + if (!$review || $review->parent_id || $review->status !== \FluentCart\App\Helpers\Status::REVIEW_APPROVED) {
236 + return;
237 + }
238 +
239 + do_action('fluent_cart/review_replied_done', [
240 + 'reply' => $reply,
241 + 'review' => $review,
242 + 'product' => $reply->product,
243 + ]);
244 +};
245 +add_action('fluent_cart/review_replied_async_private_handle', $reviewRepliedAsyncHandler, 1, 1);
246 +
247 +
167 248 //
168 249 //$app->addAction('fluent_cart/orders_filter_customer', function ($query, $filters) {
169 250 // return (new \FluentCart\App\Models\Order)->buildCustomerFilterQuery($query, $filters);
170 251 //}, 10, 2);
@@ -176,8 +257,15 @@
176 257 }
177 258
178 259 \FluentCart\App\Modules\Subscriptions\SubscriptionModule::register();
179 260 \FluentCart\App\Modules\Shipping\ShippingModule::register();
261 +\FluentCart\App\Modules\StoreManagedRenewal\RenewalModule::register();
262 +(new \FluentCart\App\Hooks\Handlers\AttributesHandler())->register();
263 +(new \FluentCart\App\Hooks\Handlers\AdvancedVariationHandler())->register();
264 +
265 +// MCP (Model Context Protocol) — operator AI tools. Ships OFF; enabled in
266 +// Settings → Features & addon → MCP. See MCPInit::boot() for the bootstrap.
267 +\FluentCart\App\Modules\MCP\MCPInit::boot();
180 268
181 269 $app->ready(function () use ($app) {
182 270 \FluentCart\App\Models\Connection\ConnectionManager::connect($this->app);
183 271 });