PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.21
ووسلام – همگام سازی ووکامرس و باسلام v1.10.21
1.10.21 1.10.19 1.10.20 1.10.18 1.10.17 1.10.15 1.10.14 1.10.13 1.10.12 1.10.10 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.2 1.9.1 1.9.0 1.8.8 1.8.5 All 54 releases
← All changes | includes/Registrar/AdminRegistrar.php +384 -114 1.10.5 → 1.10.21 View file →
@@ -15,14 +15,18 @@
15 15 use SyncBasalam\Admin\Order\OrderColumn;
16 16 use SyncBasalam\Admin\Order\OrderMetaBox;
17 17 use SyncBasalam\Admin\Components\OrderPageComponents;
18 18 use SyncBasalam\Admin\Order\OrderStatuses;
19 -use SyncBasalam\Admin\Product\ProductOperations;
20 19 use SyncBasalam\Admin\Product\Operations\ConnectProduct;
21 20 use SyncBasalam\Admin\Announcement\AnnouncementCenter;
22 21 use SyncBasalam\Admin\Onboarding\PointerTour;
22 +use SyncBasalam\Services\Products\DuplicateConnectionReport;
23 +use SyncBasalam\Services\Products\ProductConnection;
23 24 use SyncBasalam\Services\SystemResourceMonitor;
25 +use SyncBasalam\Utilities\ProductMetaKey;
24 26 use SyncBasalam\Utilities\ChatWidget;
27 +use SyncBasalam\Utilities\TicketFlashNotice;
28 +use SyncBasalam\Admin\Settings\SettingsPageHandler;
25 29 use SyncBasalam\Admin\FinancialManagement\Menu as FinancialManagementMenu;
26 30 use SyncBasalam\Admin\FinancialManagement\BalanceSettlement;
27 31 use SyncBasalam\Admin\FinancialManagement\FinancialManagementHistory;
28 32
@@ -107,12 +111,38 @@
107 111 \add_action('bulk_edit_custom_box', [$bulkEdit, 'renderFields'], 10, 2);
108 112 \add_action('admin_action_sync_basalam_bulk_edit', [$bulkEdit, 'save']);
109 113
110 114 // Product Duplicate
115 + // نسخه کپی یک محصول تازه است و نباید هیچ داده ووسلامی از محصول اصلی به ارث ببرد؛
116 + // مخصوصا شناسه اتصال، وگرنه بروزرسانی نسخه کپی، محصول اصلی را در باسلام تغییر می‌دهد.
117 + \add_filter("woocommerce_duplicate_product_exclude_meta", [self::class, "excludePluginMetaFromDuplicate"], 10, 2);
118 +
111 119 \add_action("woocommerce_product_duplicate", function ($newProduct) {
112 - ProductOperations::disconnectProduct($newProduct->get_id());
120 + if (!is_object($newProduct) || !method_exists($newProduct, "get_id")) return;
121 +
122 + ProductConnection::purgeAll($newProduct->get_id());
113 123 }, 10, 1);
114 124
125 + // Product Duplicate (third party plugins, e.g. Yoast Duplicate Post)
126 + foreach (["dp_duplicate_post", "dp_duplicate_page", "duplicate_post_post_copy"] as $duplicateHook) {
127 + \add_action($duplicateHook, function ($newPostId, $sourcePost = null) {
128 + if (!is_scalar($newPostId) || \get_post_type((int) $newPostId) !== "product") return;
129 +
130 + // اگر هوک، پست مبدا را هم بدهد مطمئنیم شناسه اول نسخه کپی است.
131 + if (is_object($sourcePost) && !empty($sourcePost->ID) && (int) $sourcePost->ID !== (int) $newPostId) {
132 + ProductConnection::purgeAll((int) $newPostId);
133 +
134 + return;
135 + }
136 +
137 + // در غیر این صورت محافظه‌کارانه عمل می‌کنیم تا داده محصول اصلی پاک نشود.
138 + ProductConnection::purgeIfCopy((int) $newPostId);
139 + }, 10, 2);
140 + }
141 +
142 + // Duplicate connection report (admin notice + dismiss handler)
143 + DuplicateConnectionReport::registerHooks();
144 +
115 145 // Order Check Buttons (HPOS)
116 146 \add_action("woocommerce_order_list_table_extra_tablenav", [OrderPageComponents::class, "renderCheckOrdersButton"], 20, 1);
117 147
118 148 // Order Check Buttons (Traditional CPT - uses same hook as product filter)
@@ -138,15 +168,162 @@
138 168 });
139 169 }
140 170
141 171
172 + /**
173 + * حذف همه متاهای ووسلام از نسخه کپی، پیش از ذخیره شدن آن توسط ووکامرس.
174 + * ووکامرس همین فهرست را روی تنوع‌های کپی شده هم اعمال می‌کند.
175 + *
176 + * @param array $excludedMeta کلیدهایی که تا اینجا برای حذف انتخاب شده‌اند.
177 + * @param array $productMetaKeys کلیدهای متای محصول اصلی.
178 + */
179 + public static function excludePluginMetaFromDuplicate($excludedMeta, $productMetaKeys = [])
180 + {
181 + $excludedMeta = is_array($excludedMeta) ? $excludedMeta : [];
182 +
183 + foreach ((array) $productMetaKeys as $metaKey) {
184 + if (ProductConnection::isPluginMetaKey($metaKey)) $excludedMeta[] = $metaKey;
185 + }
186 +
187 + // کلیدهای تنوع‌ها در فهرست متای محصول والد نیستند و باید دستی اضافه شوند.
188 + $excludedMeta = array_merge(
189 + $excludedMeta,
190 + ProductMetaKey::basalamProductMetaKeys(),
191 + [ProductMetaKey::basalamVariationId(), ProductMetaKey::DISCOUNTED]
192 + );
193 +
194 + return array_values(array_unique($excludedMeta));
195 + }
196 +
142 197 public static function assetsUrl($path = null)
143 198 {
144 199 return plugin_dir_url(dirname(__FILE__, 2)) . "assets/" . $path;
145 200 }
146 201
202 + public static function isWoosalamRelatedAdminScreen($hook = ''): bool
203 + {
204 + return self::isPluginAdminPage($hook)
205 + || self::isProductAdminScreen($hook)
206 + || self::isOrderAdminScreen($hook);
207 + }
208 +
209 + private static function isPluginAdminPage($hook = ''): bool
210 + {
211 + $page = self::currentAdminPage();
212 +
213 + if ($page !== '' && in_array($page, self::pluginAdminPages(), true)) {
214 + return true;
215 + }
216 +
217 + return is_string($hook) && strpos($hook, 'sync_basalam') !== false;
218 + }
219 +
220 + private static function isProductAdminScreen($hook = ''): bool
221 + {
222 + $screen = function_exists('get_current_screen') ? get_current_screen() : null;
223 +
224 + if ($screen && isset($screen->post_type) && $screen->post_type === 'product') {
225 + return true;
226 + }
227 +
228 + $postType = isset($_GET['post_type']) ? sanitize_key(wp_unslash($_GET['post_type'])) : '';
229 + if ($postType === 'product') {
230 + return true;
231 + }
232 +
233 + $postId = isset($_GET['post']) ? absint($_GET['post']) : 0;
234 + if ($postId > 0 && function_exists('get_post_type') && get_post_type($postId) === 'product') {
235 + return true;
236 + }
237 +
238 + return in_array((string) $hook, ['edit-product', 'product'], true);
239 + }
240 +
241 + private static function isOrderAdminScreen($hook = ''): bool
242 + {
243 + $screen = function_exists('get_current_screen') ? get_current_screen() : null;
244 +
245 + if ($screen) {
246 + $screenId = isset($screen->id) ? (string) $screen->id : '';
247 + $postType = isset($screen->post_type) ? (string) $screen->post_type : '';
248 +
249 + if ($postType === 'shop_order' || $screenId === 'woocommerce_page_wc-orders') {
250 + return true;
251 + }
252 + }
253 +
254 + $page = self::currentAdminPage();
255 + if ($page === 'wc-orders') {
256 + return true;
257 + }
258 +
259 + $postType = isset($_GET['post_type']) ? sanitize_key(wp_unslash($_GET['post_type'])) : '';
260 + if ($postType === 'shop_order') {
261 + return true;
262 + }
263 +
264 + $postId = isset($_GET['post']) ? absint($_GET['post']) : 0;
265 + if ($postId > 0 && function_exists('get_post_type') && get_post_type($postId) === 'shop_order') {
266 + return true;
267 + }
268 +
269 + return in_array((string) $hook, ['edit-shop_order', 'shop_order', 'woocommerce_page_wc-orders'], true);
270 + }
271 +
272 + private static function isProductEditScreen($hook = ''): bool
273 + {
274 + $screen = function_exists('get_current_screen') ? get_current_screen() : null;
275 +
276 + if ($screen && isset($screen->post_type, $screen->base)) {
277 + return $screen->post_type === 'product' && in_array($screen->base, ['post', 'post-new'], true);
278 + }
279 +
280 + return self::isProductAdminScreen($hook) && in_array((string) $hook, ['post.php', 'post-new.php', 'product'], true);
281 + }
282 +
283 + private static function isPluginPage(string $page): bool
284 + {
285 + return self::currentAdminPage() === $page;
286 + }
287 +
288 + private static function isTicketPage(): bool
289 + {
290 + return in_array(self::currentAdminPage(), [
291 + 'sync_basalam_tickets',
292 + 'sync_basalam_ticket',
293 + 'sync_basalam_new_ticket',
294 + ], true);
295 + }
296 +
297 + private static function currentAdminPage(): string
298 + {
299 + return isset($_GET['page']) ? sanitize_key(wp_unslash($_GET['page'])) : '';
300 + }
301 +
302 + private static function pluginAdminPages(): array
303 + {
304 + return [
305 + 'sync_basalam',
306 + 'sync_basalam_logs',
307 + 'sync_basalam_vendor_info',
308 + 'sync_basalam_help',
309 + 'sync_basalam_category_mapping',
310 + FinancialManagementMenu::PAGE_SLUG,
311 + 'basalam-onboarding',
312 + 'basalam-save-token',
313 + 'basalam-show-products',
314 + 'sync_basalam_tickets',
315 + 'sync_basalam_ticket',
316 + 'sync_basalam_new_ticket',
317 + ];
318 + }
319 +
147 320 public static function adminEnqueueStyles($hook = '')
148 321 {
322 + if (!self::isWoosalamRelatedAdminScreen($hook)) {
323 + return;
324 + }
325 +
149 326 $version = syncbasalamplugin()->getVersion();
150 327
151 328 wp_enqueue_style(
152 329 "basalam-admin-style",
@@ -159,27 +336,35 @@
159 336 self::assetsUrl("css/font.css"),
160 337 array(),
161 338 $version
162 339 );
340 + if (self::isPluginPage('sync_basalam_vendor_info')) {
341 + wp_enqueue_style(
342 + "basalam-admin-social-style",
343 + self::assetsUrl("css/social.css"),
344 + array(),
345 + $version
346 + );
347 + }
348 +
349 + if (self::isPluginPage('sync_basalam_logs')) {
350 + wp_enqueue_style(
351 + "basalam-admin-logs-style",
352 + self::assetsUrl("css/logs.css"),
353 + array(),
354 + $version
355 + );
356 + }
357 +
358 + if (self::isPluginPage('basalam-onboarding')) {
359 + wp_enqueue_style(
360 + "basalam-admin-onboarding-style",
361 + self::assetsUrl("css/onboarding.css"),
362 + array(),
363 + $version
364 + );
365 + }
163 366 wp_enqueue_style(
164 - "basalam-admin-social-style",
165 - self::assetsUrl("css/social.css"),
166 - array(),
167 - $version
168 - );
169 - wp_enqueue_style(
170 - "basalam-admin-logs-style",
171 - self::assetsUrl("css/logs.css"),
172 - array(),
173 - $version
174 - );
175 - wp_enqueue_style(
176 - "basalam-admin-onboarding-style",
177 - self::assetsUrl("css/onboarding.css"),
178 - array(),
179 - $version
180 - );
181 - wp_enqueue_style(
182 367 "basalam-admin-toast-style",
183 368 self::assetsUrl("css/toast.css"),
184 369 array(),
185 370 $version
@@ -191,11 +376,33 @@
191 376 }
192 377
193 378 public static function adminEnqueueScripts($hook = '')
194 379 {
380 + $version = syncbasalamplugin()->getVersion();
381 +
382 + if (ChatWidget::shouldLoadWidget()) {
383 + wp_enqueue_script(
384 + "basalam-chat-widget-script",
385 + self::assetsUrl("chat/widget-loader.js"),
386 + [],
387 + $version,
388 + true
389 + );
390 + }
391 +
195 392 $shouldLoadPointerTour = PointerTour::shouldLoadPointerTour((string) $hook);
196 - $version = syncbasalamplugin()->getVersion();
393 + $shouldLoadAssets = self::isWoosalamRelatedAdminScreen($hook);
197 394
395 + if (!$shouldLoadAssets && !$shouldLoadPointerTour) {
396 + return;
397 + }
398 +
399 + $isPluginPage = self::isPluginAdminPage($hook);
400 + $isMainPage = self::isPluginPage('sync_basalam');
401 + $isProductScreen = self::isProductAdminScreen($hook);
402 + $isProductEditScreen = self::isProductEditScreen($hook);
403 + $isOrderScreen = self::isOrderAdminScreen($hook);
404 +
198 405 if ($shouldLoadPointerTour) {
199 406 wp_enqueue_script('wp-pointer');
200 407 }
201 408
@@ -205,117 +412,180 @@
205 412 [],
206 413 $version,
207 414 true
208 415 );
416 +
417 + $vendorStatusScriptPath = syncbasalamplugin()->pluginPath() . '/assets/js/vendor-status.js';
418 + $vendorStatusScriptVersion = file_exists($vendorStatusScriptPath)
419 + ? $version . '-' . filemtime($vendorStatusScriptPath)
420 + : $version;
209 421 wp_enqueue_script(
210 - "basalam-admin-logs-script",
211 - self::assetsUrl("js/logs.js"),
212 - ["jquery", "basalam-admin-toast-script"],
213 - $version,
422 + "basalam-vendor-status-script",
423 + self::assetsUrl("js/vendor-status.js"),
424 + ["basalam-admin-toast-script"],
425 + $vendorStatusScriptVersion,
214 426 true
215 427 );
216 - wp_enqueue_script(
217 - "basalam-admin-help-script",
218 - self::assetsUrl("js/help.js"),
219 - ["jquery", "basalam-admin-toast-script"],
220 - $version,
221 - true
222 - );
223 - wp_enqueue_script(
224 - "basalam-admin-product-fields-script",
225 - self::assetsUrl("js/product-fields.js"),
226 - ["jquery", "basalam-admin-toast-script"],
227 - $version,
228 - true
229 - );
230 - wp_enqueue_script(
231 - "basalam-admin-manage-box-script",
232 - self::assetsUrl("js/manage-box.js"),
233 - ["jquery", "basalam-admin-toast-script"],
234 - $version,
235 - true
236 - );
237 - wp_enqueue_script(
238 - "basalam-admin-connect-modal-script",
239 - self::assetsUrl("js/connect-modal.js"),
240 - ["jquery", "basalam-admin-toast-script"],
241 - $version,
242 - true
243 - );
244 - wp_enqueue_script(
245 - "basalam-round-script",
246 - self::assetsUrl("js/round.js"),
247 - ["jquery", "basalam-admin-toast-script"],
248 - $version,
249 - true
250 - );
251 - wp_enqueue_script(
252 - "basalam-get-category-script",
253 - self::assetsUrl("js/get-category.js"),
254 - ["jquery", "basalam-admin-toast-script"],
255 - $version,
256 - true
257 - );
258 - wp_enqueue_script(
259 - "basalam-order-script",
260 - self::assetsUrl("js/order.js"),
261 - ["jquery", "basalam-admin-toast-script"],
262 - $version,
263 - true
264 - );
265 - wp_enqueue_script(
266 - "basalam-admin-script",
267 - self::assetsUrl("js/admin.js"),
268 - $shouldLoadPointerTour ? ["jquery", "wp-pointer", "basalam-admin-toast-script"] : ["jquery", "basalam-admin-toast-script"],
269 - $version,
270 - true
271 - );
272 - wp_enqueue_script(
273 - "basalam-check-sync-script",
274 - self::assetsUrl("js/check-sync.js"),
275 - ["jquery", "basalam-admin-toast-script"],
276 - $version,
277 - true
278 - );
279 - wp_enqueue_script(
280 - "basalam-map-category-option-script",
281 - self::assetsUrl("js/map-category-option.js"),
282 - ["jquery", "basalam-admin-toast-script"],
283 - $version,
284 - true
285 - );
286 428
287 - wp_enqueue_script(
288 - "basalam-generate-product-variation-script",
289 - self::assetsUrl("js/generate-product-variation.js"),
290 - ["jquery", "basalam-admin-toast-script"],
291 - $version,
292 - true
293 - );
429 + $ticketNotice = TicketFlashNotice::pull();
430 + if ($ticketNotice !== null) {
431 + wp_add_inline_script(
432 + "basalam-admin-toast-script",
433 + sprintf(
434 + 'window.addEventListener("DOMContentLoaded",function(){if(window.BasalamToast){window.BasalamToast.show(%s,%s);}});',
435 + wp_json_encode($ticketNotice['message'], JSON_UNESCAPED_UNICODE),
436 + wp_json_encode($ticketNotice['type'])
437 + ),
438 + 'after'
439 + );
440 + }
294 441
295 - wp_enqueue_script(
296 - "basalam-ticket-script",
297 - self::assetsUrl("js/ticket.js"),
298 - ["basalam-admin-toast-script"],
299 - $version,
300 - true
301 - );
442 + $settingsValidationError = SettingsPageHandler::pullValidationError();
443 + if ($settingsValidationError !== '') {
444 + wp_add_inline_script(
445 + "basalam-admin-toast-script",
446 + sprintf(
447 + 'window.addEventListener("DOMContentLoaded",function(){if(window.BasalamToast){window.BasalamToast.error(%s);}});',
448 + wp_json_encode($settingsValidationError, JSON_UNESCAPED_UNICODE)
449 + ),
450 + 'after'
451 + );
452 + }
302 453
303 - if (ChatWidget::shouldLoadWidget()) {
454 + if (self::isPluginPage('sync_basalam_logs')) {
304 455 wp_enqueue_script(
305 - "basalam-chat-widget-script",
306 - self::assetsUrl("chat/widget-loader.js"),
307 - [],
456 + "basalam-admin-logs-script",
457 + self::assetsUrl("js/logs.js"),
458 + ["jquery", "basalam-admin-toast-script"],
308 459 $version,
309 460 true
310 461 );
311 462 }
312 463
464 + if (self::isPluginPage('sync_basalam_help')) {
465 + wp_enqueue_script(
466 + "basalam-admin-help-script",
467 + self::assetsUrl("js/help.js"),
468 + ["jquery", "basalam-admin-toast-script"],
469 + $version,
470 + true
471 + );
472 + }
473 +
474 + if ($isProductEditScreen) {
475 + wp_enqueue_script(
476 + "basalam-admin-product-fields-script",
477 + self::assetsUrl("js/product-fields.js"),
478 + ["jquery", "basalam-admin-toast-script"],
479 + $version,
480 + true
481 + );
482 + wp_enqueue_script(
483 + "basalam-admin-connect-modal-script",
484 + self::assetsUrl("js/connect-modal.js"),
485 + ["jquery", "basalam-admin-toast-script"],
486 + $version,
487 + true
488 + );
489 + wp_enqueue_script(
490 + "basalam-get-category-script",
491 + self::assetsUrl("js/get-category.js"),
492 + ["jquery", "basalam-admin-toast-script"],
493 + $version,
494 + true
495 + );
496 + wp_enqueue_script(
497 + "basalam-generate-product-variation-script",
498 + self::assetsUrl("js/generate-product-variation.js"),
499 + ["jquery", "basalam-admin-toast-script"],
500 + $version,
501 + true
502 + );
503 + }
504 +
505 + if ($isMainPage || $isProductEditScreen) {
506 + wp_enqueue_script(
507 + "basalam-admin-manage-box-script",
508 + self::assetsUrl("js/manage-box.js"),
509 + ["jquery", "basalam-admin-toast-script"],
510 + $version,
511 + true
512 + );
513 + }
514 +
515 + if ($isMainPage) {
516 + wp_enqueue_script(
517 + "basalam-map-category-option-script",
518 + self::assetsUrl("js/map-category-option.js"),
519 + ["jquery", "basalam-admin-toast-script"],
520 + $version,
521 + true
522 + );
523 + }
524 +
525 + if ($isMainPage || $isProductScreen) {
526 + wp_enqueue_script(
527 + "basalam-round-script",
528 + self::assetsUrl("js/round.js"),
529 + ["jquery", "basalam-admin-toast-script"],
530 + $version,
531 + true
532 + );
533 + }
534 +
535 + if ($isOrderScreen) {
536 + wp_enqueue_script(
537 + "basalam-order-script",
538 + self::assetsUrl("js/order.js"),
539 + ["jquery", "basalam-admin-toast-script"],
540 + $version,
541 + true
542 + );
543 + }
544 +
545 + if ($isMainPage || $isOrderScreen) {
546 + wp_enqueue_script(
547 + "basalam-check-sync-script",
548 + self::assetsUrl("js/check-sync.js"),
549 + ["jquery", "basalam-admin-toast-script"],
550 + $version,
551 + true
552 + );
553 + }
554 +
555 + if ($isPluginPage || $isProductScreen || $isOrderScreen || $shouldLoadPointerTour) {
556 + $adminScriptPath = syncBasalamPlugin()->pluginPath() . '/assets/js/admin.js';
557 + $adminScriptVersion = file_exists($adminScriptPath)
558 + ? $version . '-' . filemtime($adminScriptPath)
559 + : $version;
560 + wp_enqueue_script(
561 + "basalam-admin-script",
562 + self::assetsUrl("js/admin.js"),
563 + $shouldLoadPointerTour ? ["jquery", "wp-pointer", "basalam-admin-toast-script"] : ["jquery", "basalam-admin-toast-script"],
564 + $adminScriptVersion,
565 + true
566 + );
567 + }
568 +
569 + if (self::isTicketPage()) {
570 + $ticketScriptPath = syncBasalamPlugin()->pluginPath() . '/assets/js/ticket.js';
571 + $ticketScriptVersion = file_exists($ticketScriptPath)
572 + ? $version . '-' . filemtime($ticketScriptPath)
573 + : $version;
574 + wp_enqueue_script(
575 + "basalam-ticket-script",
576 + self::assetsUrl("js/ticket.js"),
577 + ["basalam-admin-toast-script"],
578 + $ticketScriptVersion,
579 + true
580 + );
581 + }
582 +
313 583 if ($shouldLoadPointerTour) {
314 584 wp_localize_script('basalam-admin-script', 'basalamPointerTour', PointerTour::getPointerTourConfig());
315 585 }
316 586
317 - if (AnnouncementCenter::shouldLoadAnnouncement()) {
587 + if (wp_script_is('basalam-admin-script', 'enqueued') && AnnouncementCenter::shouldLoadAnnouncement()) {
318 588 wp_localize_script('basalam-admin-script', 'basalamAnnouncements', AnnouncementCenter::getConfig());
319 589 }
320 590 }
321 591