PluginProbe
Packeta / 1.6.4
Packeta v1.6.4
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
packeta / src / Packetery / Module / Plugin.php

Plugin.php in Packeta 1.6.4, at src/Packetery/Module/Plugin.php

1,088 lines 33.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Main Packeta plugin class.
4 *
5 * @package Packetery
6 */
7
8 declare( strict_types=1 );
9
10 namespace Packetery\Module;
11
12 use Automattic\WooCommerce\Utilities\FeaturesUtil;
13 use Packetery\Core\Entity\Order as PacketeryOrder;
14 use Packetery\Core\Log\ILogger;
15 use Packetery\Module\Api;
16 use Packetery\Module\Carrier\OptionsPage;
17 use Packetery\Module\Exception\InvalidCarrierException;
18 use Packetery\Module\Log;
19 use Packetery\Module\Options;
20 use Packetery\Module\Order;
21 use Packetery\Module\Product;
22 use Packetery\Latte\Engine;
23 use Packetery\Nette\Http\Request;
24 use Packetery\Nette\Utils\Html;
25 use WC_Email;
26 use WC_Order;
27
28 /**
29 * Class Plugin
30 *
31 * @package Packetery
32 */
33 class Plugin {
34
35 public const VERSION = '1.6.4';
36 public const DOMAIN = 'packeta';
37 public const MIN_LISTENER_PRIORITY = - 9998;
38 public const PARAM_PACKETERY_ACTION = 'packetery_action';
39 public const PARAM_NONCE = '_wpnonce';
40
41 /**
42 * Options page.
43 *
44 * @var Options\Page Options page,
45 */
46 private $options_page;
47
48 /**
49 * PacketeryLatte engine.
50 *
51 * @var Engine
52 */
53 private $latte_engine;
54
55 /**
56 * Dashboard widget.
57 *
58 * @var DashboardWidget
59 */
60 private $dashboardWidget;
61
62 /**
63 * Country options page.
64 *
65 * @var OptionsPage
66 */
67 private $carrierOptionsPage;
68
69 /**
70 * Path to main plugin file.
71 *
72 * @var string Path to main plugin file.
73 */
74 private $main_file_path;
75
76 /**
77 * Admin edit order page Packeta metabox.
78 *
79 * @var Order\Metabox
80 */
81 private $order_metabox;
82
83 /**
84 * Metaboxes wrapper.
85 *
86 * @var Order\MetaboxesWrapper
87 */
88 private $metaboxesWrapper;
89
90 /**
91 * Message manager.
92 *
93 * @var MessageManager
94 */
95 private $message_manager;
96
97 /**
98 * Checkout object.
99 *
100 * @var Checkout
101 */
102 private $checkout;
103
104 /**
105 * Order BulkActions.
106 *
107 * @var Order\BulkActions
108 */
109 private $orderBulkActions;
110
111 /**
112 * Label printing.
113 *
114 * @var Order\LabelPrint
115 */
116 private $labelPrint;
117
118 /**
119 * Order collection printing.
120 *
121 * @var Order\CollectionPrint
122 */
123 private $orderCollectionPrint;
124
125 /**
126 * Order grid extender.
127 *
128 * @var Order\GridExtender
129 */
130 private $gridExtender;
131
132 /**
133 * Product tab.
134 *
135 * @var Product\DataTab
136 */
137 private $productTab;
138
139 /**
140 * Log page.
141 *
142 * @var Log\Page
143 */
144 private $logPage;
145
146 /**
147 * Log manager.
148 *
149 * @var ILogger
150 */
151 private $logger;
152
153 /**
154 * Cron service.
155 *
156 * @var CronService
157 */
158 private $cronService;
159
160 /**
161 * Order controller.
162 *
163 * @var Api\Registrar
164 */
165 private $apiRegistrar;
166
167 /**
168 * Order modal.
169 *
170 * @var Order\Modal
171 */
172 private $orderModal;
173
174 /**
175 * Options exporter.
176 *
177 * @var Options\Exporter
178 */
179 private $exporter;
180
181 /**
182 * Request.
183 *
184 * @var Request
185 */
186 private $request;
187
188 /**
189 * Order repository.
190 *
191 * @var Order\Repository
192 */
193 private $orderRepository;
194
195 /**
196 * Plugin upgrade.
197 *
198 * @var Upgrade
199 */
200 private $upgrade;
201
202 /**
203 * QueryProcessor.
204 *
205 * @var QueryProcessor
206 */
207 private $queryProcessor;
208
209 /**
210 * Options provider.
211 *
212 * @var Options\Provider
213 */
214 private $optionsProvider;
215
216 /**
217 * Packet canceller.
218 *
219 * @var Order\PacketCanceller
220 */
221 private $packetCanceller;
222
223 /**
224 * Context resolver.
225 *
226 * @var ContextResolver
227 */
228 private $contextResolver;
229
230 /**
231 * Packet submitter
232 *
233 * @var Order\PacketSubmitter
234 */
235 private $packetSubmitter;
236
237 /**
238 * Packet claim submitter
239 *
240 * @var Order\PacketClaimSubmitter
241 */
242 private $packetClaimSubmitter;
243
244 /**
245 * Category form fields.
246 *
247 * @var ProductCategory\FormFields
248 */
249 private $productCategoryFormFields;
250
251 /**
252 * Packet auto submitter.
253 *
254 * @var Order\PacketAutoSubmitter
255 */
256 private $packetAutoSubmitter;
257
258 /**
259 * Feature Flag Manager.
260 *
261 * @var Options\FeatureFlagManager
262 */
263 private $featureFlagManager;
264
265 /**
266 * API extender.
267 *
268 * @var Order\ApiExtender
269 */
270 private $apiExtender;
271
272 /**
273 * Label print.
274 *
275 * @var Order\LabelPrintModal
276 */
277 private $labelPrintModal;
278
279 /**
280 * Plugin constructor.
281 *
282 * @param Order\Metabox $order_metabox Order metabox.
283 * @param MessageManager $message_manager Message manager.
284 * @param Options\Page $options_page Options page.
285 * @param Checkout $checkout Checkout class.
286 * @param Engine $latte_engine PacketeryLatte engine.
287 * @param OptionsPage $carrierOptionsPage Carrier options page.
288 * @param Order\BulkActions $orderBulkActions Order BulkActions.
289 * @param Order\LabelPrint $labelPrint Label printing.
290 * @param Order\GridExtender $gridExtender Order grid extender.
291 * @param Product\DataTab $productTab Product tab.
292 * @param Log\Page $logPage Log page.
293 * @param ILogger $logger Log manager.
294 * @param Api\Registrar $apiRegistar API endpoints registrar.
295 * @param Order\Modal $orderModal Order modal.
296 * @param Options\Exporter $exporter Options exporter.
297 * @param Order\CollectionPrint $orderCollectionPrint Order collection print.
298 * @param Request $request HTTP request.
299 * @param Order\Repository $orderRepository Order repository.
300 * @param Upgrade $upgrade Plugin upgrade.
301 * @param QueryProcessor $queryProcessor QueryProcessor.
302 * @param Options\Provider $optionsProvider Options provider.
303 * @param CronService $cronService Cron service.
304 * @param Order\PacketCanceller $packetCanceller Packet canceller.
305 * @param ContextResolver $contextResolver Context resolver.
306 * @param DashboardWidget $dashboardWidget Dashboard widget.
307 * @param Order\PacketSubmitter $packetSubmitter Packet submitter.
308 * @param Order\PacketClaimSubmitter $packetClaimSubmitter Packet claim submitter.
309 * @param ProductCategory\FormFields $productCategoryFormFields Product category form fields.
310 * @param Order\PacketAutoSubmitter $packetAutoSubmitter Packet auto submitter.
311 * @param Options\FeatureFlagManager $featureFlagManager Feature Flag Manager.
312 * @param Order\MetaboxesWrapper $metaboxesWrapper Metaboxes wrapper.
313 * @param Order\ApiExtender $apiExtender API extender.
314 * @param Order\LabelPrintModal $labelPrintModal Label print modal.
315 */
316 public function __construct(
317 Order\Metabox $order_metabox,
318 MessageManager $message_manager,
319 Options\Page $options_page,
320 Checkout $checkout,
321 Engine $latte_engine,
322 OptionsPage $carrierOptionsPage,
323 Order\BulkActions $orderBulkActions,
324 Order\LabelPrint $labelPrint,
325 Order\GridExtender $gridExtender,
326 Product\DataTab $productTab,
327 Log\Page $logPage,
328 ILogger $logger,
329 Api\Registrar $apiRegistar,
330 Order\Modal $orderModal,
331 Options\Exporter $exporter,
332 Order\CollectionPrint $orderCollectionPrint,
333 Request $request,
334 Order\Repository $orderRepository,
335 Upgrade $upgrade,
336 QueryProcessor $queryProcessor,
337 Options\Provider $optionsProvider,
338 CronService $cronService,
339 Order\PacketCanceller $packetCanceller,
340 ContextResolver $contextResolver,
341 DashboardWidget $dashboardWidget,
342 Order\PacketSubmitter $packetSubmitter,
343 Order\PacketClaimSubmitter $packetClaimSubmitter,
344 ProductCategory\FormFields $productCategoryFormFields,
345 Order\PacketAutoSubmitter $packetAutoSubmitter,
346 Options\FeatureFlagManager $featureFlagManager,
347 Order\MetaboxesWrapper $metaboxesWrapper,
348 Order\ApiExtender $apiExtender,
349 Order\LabelPrintModal $labelPrintModal
350 ) {
351 $this->options_page = $options_page;
352 $this->latte_engine = $latte_engine;
353 $this->main_file_path = PACKETERY_PLUGIN_DIR . '/packeta.php';
354 $this->order_metabox = $order_metabox;
355 $this->message_manager = $message_manager;
356 $this->checkout = $checkout;
357 $this->carrierOptionsPage = $carrierOptionsPage;
358 $this->orderBulkActions = $orderBulkActions;
359 $this->labelPrint = $labelPrint;
360 $this->gridExtender = $gridExtender;
361 $this->productTab = $productTab;
362 $this->logPage = $logPage;
363 $this->logger = $logger;
364 $this->apiRegistrar = $apiRegistar;
365 $this->orderModal = $orderModal;
366 $this->exporter = $exporter;
367 $this->orderCollectionPrint = $orderCollectionPrint;
368 $this->request = $request;
369 $this->orderRepository = $orderRepository;
370 $this->upgrade = $upgrade;
371 $this->queryProcessor = $queryProcessor;
372 $this->optionsProvider = $optionsProvider;
373 $this->cronService = $cronService;
374 $this->packetCanceller = $packetCanceller;
375 $this->contextResolver = $contextResolver;
376 $this->dashboardWidget = $dashboardWidget;
377 $this->packetSubmitter = $packetSubmitter;
378 $this->packetClaimSubmitter = $packetClaimSubmitter;
379 $this->productCategoryFormFields = $productCategoryFormFields;
380 $this->packetAutoSubmitter = $packetAutoSubmitter;
381 $this->featureFlagManager = $featureFlagManager;
382 $this->metaboxesWrapper = $metaboxesWrapper;
383 $this->apiExtender = $apiExtender;
384 $this->labelPrintModal = $labelPrintModal;
385 }
386
387 /**
388 * Method to register hooks
389 */
390 public function run(): void {
391 add_action( 'init', [ $this, 'loadTranslation' ] );
392
393 if ( ! self::isWooCommercePluginActive() ) {
394 add_action( 'admin_notices', [ $this, 'echoInactiveWooCommerceNotice' ] );
395
396 return;
397 }
398
399 add_action( 'before_woocommerce_init', [ $this, 'declareWooCommerceCompability' ] );
400 add_action( 'init', [ $this->upgrade, 'check' ] );
401 add_action( 'init', [ $this->logger, 'register' ] );
402 add_action( 'init', [ $this->message_manager, 'init' ] );
403 add_action( 'rest_api_init', [ $this->apiRegistrar, 'registerRoutes' ] );
404
405 add_action( 'admin_enqueue_scripts', array( $this, 'enqueueAdminAssets' ) );
406 add_action( 'wp_enqueue_scripts', [ $this, 'enqueueFrontAssets' ] );
407
408 add_action(
409 'admin_notices',
410 function () {
411 $this->message_manager->render( MessageManager::RENDERER_WORDPRESS );
412 },
413 self::MIN_LISTENER_PRIORITY
414 );
415 add_action( 'init', array( $this, 'init' ) );
416
417 // TODO: deactivation_hook.
418 register_deactivation_hook(
419 $this->main_file_path,
420 static function () {
421 CronService::deactivate();
422 }
423 );
424
425 register_uninstall_hook( $this->main_file_path, array( __CLASS__, 'uninstall' ) );
426
427 $wcEmailHook = $this->optionsProvider->getEmailHook();
428 add_action( $wcEmailHook, [ $this, 'renderEmailFooter' ] );
429 add_filter( 'woocommerce_shipping_methods', array( $this, 'add_shipping_method' ) );
430
431 $orderListScreenId = 'woocommerce_page_wc-orders';
432 add_filter( 'views_edit-shop_order', [ $this->gridExtender, 'addFilterLinks' ] );
433 add_action( 'restrict_manage_posts', [ $this->gridExtender, 'renderOrderTypeSelect' ] );
434
435 $wooCommerceVersion = Helper::getWooCommerceVersion();
436 if ( null !== $wooCommerceVersion && version_compare( $wooCommerceVersion, '7.9.0', '>=' ) ) {
437 add_filter( sprintf( 'views_%s', $orderListScreenId ), [ $this->gridExtender, 'addFilterLinks' ] );
438 add_action( 'woocommerce_order_list_table_restrict_manage_orders', [ $this->gridExtender, 'renderOrderTypeSelect' ] );
439 }
440
441 $this->queryProcessor->register();
442
443 add_filter( 'manage_edit-shop_order_columns', [ $this->gridExtender, 'addOrderListColumns' ] );
444 add_filter( sprintf( 'manage_%s_columns', $orderListScreenId ), [ $this->gridExtender, 'addOrderListColumns' ] );
445 add_action( 'manage_shop_order_posts_custom_column', [ $this->gridExtender, 'fillCustomOrderListColumns' ], 10, 2 );
446 add_action( sprintf( 'manage_%s_custom_column', $orderListScreenId ), [ $this->gridExtender, 'fillCustomOrderListColumns' ], 10, 2 );
447
448 add_action( 'admin_menu', array( $this, 'add_menu_pages' ) );
449 add_action( 'admin_head', array( $this->labelPrint, 'hideFromMenus' ) );
450 add_action( 'admin_head', array( $this->orderCollectionPrint, 'hideFromMenus' ) );
451 add_action( 'admin_head', [ $this, 'renderConfirmModalTemplate' ] );
452 $this->orderModal->register();
453 $this->labelPrintModal->register();
454 $this->metaboxesWrapper->register();
455
456 $this->checkout->register_hooks();
457 $this->productTab->register();
458 $this->cronService->register();
459 $this->productCategoryFormFields->register();
460 $this->packetAutoSubmitter->register();
461 $this->apiExtender->register();
462
463 add_action( 'woocommerce_admin_order_data_after_shipping_address', [ $this, 'renderDeliveryDetail' ] );
464 add_action( 'woocommerce_order_details_after_order_table', [ $this, 'renderOrderDetail' ] );
465
466 // Adding custom actions to dropdown in admin order list.
467 add_filter( 'bulk_actions-edit-shop_order', [ $this->orderBulkActions, 'addActions' ], 20, 1 );
468 add_filter( sprintf( 'bulk_actions-%s', $orderListScreenId ), [ $this->orderBulkActions, 'addActions' ], 20, 1 );
469 // Execute the action for selected orders.
470 add_filter(
471 'handle_bulk_actions-edit-shop_order',
472 [
473 $this->orderBulkActions,
474 'handleActions',
475 ],
476 10,
477 3
478 );
479 add_filter( sprintf( 'handle_bulk_actions-%s', $orderListScreenId ), [ $this->orderBulkActions, 'handleActions' ], 10, 3 );
480 // Print packets export result.
481 add_action( 'admin_notices', [ $this->orderBulkActions, 'renderPacketsExportResult' ], self::MIN_LISTENER_PRIORITY );
482
483 add_action( 'admin_init', [ $this->labelPrint, 'outputLabelsPdf' ] );
484 add_action( 'admin_init', [ $this->orderCollectionPrint, 'print' ] );
485
486 add_action( 'admin_init', [ $this->exporter, 'outputExportTxt' ] );
487 add_action( 'admin_init', [ $this, 'handleActions' ] );
488
489 add_action( 'deleted_post', [ $this->orderRepository, 'deletedPostHook' ], 10, 2 );
490 $this->dashboardWidget->register();
491 }
492
493 /**
494 * Declares plugin compability with features.
495 *
496 * @return void
497 */
498 public function declareWooCommerceCompability(): void {
499 if ( false === class_exists( FeaturesUtil::class ) ) {
500 return;
501 }
502
503 // High-Performance Order Storage.
504 FeaturesUtil::declare_compatibility( 'custom_order_tables', $this->main_file_path );
505 }
506
507 /**
508 * Print inactive WooCommerce notice.
509 *
510 * @return void
511 */
512 public function echoInactiveWooCommerceNotice(): void {
513 if ( self::isWooCommercePluginActive() ) {
514 // When Packeta plugin is active and WooCommerce plugin is inactive.
515 // If user decides to activate WooCommerce plugin then invalid notice will not be rendered.
516 // Packeta plugin probably bootstraps twice in such case.
517 return;
518 }
519
520 $this->latte_engine->render(
521 PACKETERY_PLUGIN_DIR . '/template/admin-notice.latte',
522 [
523 'message' => [
524 'type' => 'error',
525 'message' => __( 'Packeta plugin requires WooCommerce. Please install and activate it first.', 'packeta' ),
526 ],
527 ]
528 );
529 }
530
531 /**
532 * Is WC plugin active.
533 *
534 * @return bool
535 */
536 private static function isWooCommercePluginActive(): bool {
537 return Helper::isPluginActive( 'woocommerce/woocommerce.php' );
538 }
539
540 /**
541 * Creates HTML link parts in array.
542 *
543 * @param string $href Href.
544 * @param string|null $target Target.
545 * @param string|null $class Class.
546 *
547 * @return string[]
548 */
549 public static function createLinkParts( string $href, ?string $target = null, ?string $class = null ): array {
550 $link = Html::el( 'a' )->href( $href );
551
552 if ( null !== $target ) {
553 $link->target( $target );
554 }
555
556 if ( null !== $class ) {
557 $link->class( $class );
558 }
559
560 return [ $link->startTag(), $link->endTag() ];
561 }
562
563 /**
564 * Renders delivery detail for packetery orders.
565 *
566 * @param WC_Order $order WordPress order.
567 */
568 public function renderDeliveryDetail( WC_Order $order ): void {
569 try {
570 $orderEntity = $this->orderRepository->getByWcOrder( $order );
571 } catch ( InvalidCarrierException $exception ) {
572 $orderEntity = null;
573 }
574 if ( null === $orderEntity ) {
575 return;
576 }
577
578 $carrierId = $orderEntity->getCarrier()->getId();
579 $carrierOptions = Carrier\Options::createByCarrierId( $carrierId );
580
581 $this->latte_engine->render(
582 PACKETERY_PLUGIN_DIR . '/template/order/delivery-detail.latte',
583 [
584 'pickupPoint' => $orderEntity->getPickupPoint(),
585 'validatedDeliveryAddress' => $orderEntity->getValidatedDeliveryAddress(),
586 'carrierAddressValidation' => $carrierOptions->getAddressValidation(),
587 'isExternalCarrier' => $orderEntity->isExternalCarrier(),
588 'translations' => [
589 'packeta' => __( 'Packeta', 'packeta' ),
590 'pickupPointDetail' => __( 'Pickup Point Detail', 'packeta' ),
591 'name' => __( 'Name', 'packeta' ),
592 'address' => __( 'Address', 'packeta' ),
593 'pickupPointDetailCaps' => __( 'Pickup Point Detail', 'packeta' ),
594 'addressWasNotValidated' => __( 'Address was not validated', 'packeta' ),
595 'validatedAddress' => __( 'Validated address', 'packeta' ),
596 'street' => __( 'Street', 'packeta' ),
597 'houseNumber' => __( 'House number', 'packeta' ),
598 'city' => __( 'City', 'packeta' ),
599 'zip' => __( 'Zip', 'packeta' ),
600 'county' => __( 'County', 'packeta' ),
601 'gps' => __( 'GPS', 'packeta' ),
602 ],
603 ]
604 );
605 }
606
607 /**
608 * Renders delivery detail for packetery orders, on "thank you" page and in frontend detail.
609 *
610 * @param WC_Order $wcOrder WordPress order.
611 */
612 public function renderOrderDetail( WC_Order $wcOrder ): void {
613 try {
614 $order = $this->orderRepository->getById( $wcOrder->get_id() );
615 } catch ( InvalidCarrierException $exception ) {
616 $order = null;
617 }
618 if ( null === $order ) {
619 return;
620 }
621
622 if ( $this->shouldHidePacketaInfo( $order ) ) {
623 return;
624 }
625
626 $this->latte_engine->render(
627 PACKETERY_PLUGIN_DIR . '/template/order/detail.latte',
628 [
629 'displayPickupPointInfo' => $this->shouldDisplayPickupPointInfo(),
630 'order' => $order,
631 'translations' => [
632 'packeta' => __( 'Packeta', 'packeta' ),
633 'pickupPointName' => __( 'Pickup Point Name', 'packeta' ),
634 'pickupPointDetail' => __( 'Pickup Point Detail', 'packeta' ),
635 'validatedAddress' => __( 'Validated address', 'packeta' ),
636 'address' => __( 'Address', 'packeta' ),
637 'packetTrackingOnline' => __( 'Packet tracking online', 'packeta' ),
638 ],
639 ]
640 );
641 }
642
643 /**
644 * Renders email footer.
645 *
646 * @param mixed $email Email data.
647 */
648 public function renderEmailFooter( $email ): void {
649 $wcOrder = null;
650 if ( ( $email instanceof WC_Email ) && ( $email->object instanceof WC_Order ) ) {
651 $wcOrder = $email->object;
652 }
653
654 if ( $email instanceof WC_Order ) {
655 $wcOrder = $email;
656 }
657
658 if ( null === $wcOrder ) {
659 return;
660 }
661
662 try {
663 $packeteryOrder = $this->orderRepository->getByWcOrder( $wcOrder );
664 } catch ( InvalidCarrierException $exception ) {
665 $packeteryOrder = null;
666 }
667 if ( null === $packeteryOrder ) {
668 return;
669 }
670
671 if ( $this->shouldHidePacketaInfo( $packeteryOrder ) ) {
672 return;
673 }
674
675 $templateParams = [
676 'displayPickupPointInfo' => $this->shouldDisplayPickupPointInfo(),
677 'order' => $packeteryOrder,
678 'translations' => [
679 'packeta' => __( 'Packeta', 'packeta' ),
680 'pickupPointDetail' => __( 'Pickup Point Detail', 'packeta' ),
681 'pickupPointName' => __( 'Pickup Point Name', 'packeta' ),
682 'link' => __( 'Link', 'packeta' ),
683 'pickupPointAddress' => __( 'Pickup Point Address', 'packeta' ),
684 'validatedDeliveryAddress' => __( 'validated delivery address', 'packeta' ),
685 'street' => __( 'Street', 'packeta' ),
686 'houseNumber' => __( 'House number', 'packeta' ),
687 'city' => __( 'City', 'packeta' ),
688 'zip' => __( 'Zip', 'packeta' ),
689 'county' => __( 'County', 'packeta' ),
690 'packetTrackingOnline' => __( 'Packet tracking online', 'packeta' ),
691 ],
692 ];
693 $emailHtml = $this->latte_engine->renderToString(
694 PACKETERY_PLUGIN_DIR . '/template/email/order.latte',
695 $templateParams
696 );
697 /**
698 * This filter allows you to change the HTML of e-mail footer.
699 *
700 * @since 1.5.3
701 */
702 Helper::renderString( (string) apply_filters( 'packeta_email_footer', $emailHtml, $templateParams ) );
703 }
704
705 /**
706 * Determines if a Packeta order should be displayed.
707 *
708 * @param PacketeryOrder $order Order.
709 *
710 * @return bool
711 */
712 private function shouldHidePacketaInfo( PacketeryOrder $order ): bool {
713 $isPickupPointInfoVisible = $this->shouldDisplayPickupPointInfo() && $order->getPickupPoint();
714
715 return ( ! $isPickupPointInfoVisible ) && null === $order->getValidatedDeliveryAddress() && false === $order->isExported();
716 }
717
718 /**
719 * Tells if pickup point info should be displayed.
720 *
721 * @return bool
722 */
723 public function shouldDisplayPickupPointInfo(): bool {
724 return ! $this->optionsProvider->replaceShippingAddressWithPickupPointAddress() || wc_ship_to_billing_address_only();
725 }
726
727 /**
728 * Renders confirm modal template.
729 */
730 public function renderConfirmModalTemplate(): void {
731 if ( $this->contextResolver->isPacketeryConfirmPage() ) {
732 $this->latte_engine->render(
733 PACKETERY_PLUGIN_DIR . '/template/confirm-modal-template.latte',
734 [
735 'translations' => [
736 'closeModalPanel' => __( 'Close modal panel', 'packeta' ),
737 'no' => __( 'No', 'packeta' ),
738 'yes' => __( 'Yes', 'packeta' ),
739 ],
740 ]
741 );
742 }
743 }
744
745 /**
746 * Enqueues admin JS file.
747 *
748 * @param string $name Name of script.
749 * @param string $file Relative file path.
750 * @param bool $inFooter Tells where to include script.
751 * @param array $deps Script dependencies.
752 */
753 private function enqueueScript( string $name, string $file, bool $inFooter, array $deps = [] ): void {
754 wp_enqueue_script(
755 $name,
756 plugin_dir_url( $this->main_file_path ) . $file,
757 $deps,
758 md5( (string) filemtime( PACKETERY_PLUGIN_DIR . '/' . $file ) ),
759 $inFooter
760 );
761 }
762
763 /**
764 * Enqueues CSS file.
765 *
766 * @param string $name Name of script.
767 * @param string $file Relative file path.
768 */
769 private function enqueueStyle( string $name, string $file ): void {
770 wp_enqueue_style(
771 $name,
772 plugin_dir_url( $this->main_file_path ) . $file,
773 [],
774 md5( (string) filemtime( PACKETERY_PLUGIN_DIR . '/' . $file ) )
775 );
776 }
777
778 /**
779 * Builds asset URL.
780 *
781 * @param string $asset Relative asset path without leading slash.
782 *
783 * @return string|null
784 */
785 public static function buildAssetUrl( string $asset ): ?string {
786 $url = plugin_dir_url( PACKETERY_PLUGIN_DIR . '/packeta.php' ) . $asset;
787 $filename = PACKETERY_PLUGIN_DIR . '/' . $asset;
788
789 if ( ! file_exists( $filename ) ) {
790 return null;
791 }
792
793 return add_query_arg( [ 'v' => md5( (string) filemtime( $filename ) ) ], $url );
794 }
795
796 /**
797 * Enqueues javascript files and stylesheets for checkout.
798 */
799 public function enqueueFrontAssets(): void {
800 if ( is_checkout() ) {
801 $this->enqueueStyle( 'packetery-front-styles', 'public/front.css' );
802 $this->enqueueStyle( 'packetery-custom-front-styles', 'public/custom-front.css' );
803 $this->enqueueScript( 'packetery-checkout', 'public/checkout.js', true, [ 'jquery' ] );
804 wp_localize_script( 'packetery-checkout', 'packeteryCheckoutSettings', $this->checkout->createSettings() );
805 }
806 }
807
808 /**
809 * Enqueues javascript files and stylesheets for administration.
810 */
811 public function enqueueAdminAssets(): void {
812 $page = $this->request->getQuery( 'page' );
813 $isOrderGridPage = $this->contextResolver->isOrderGridPage();
814 $isOrderDetailPage = $this->contextResolver->isOrderDetailPage();
815 $isProductCategoryPage = $this->contextResolver->isProductCategoryDetailPage() || $this->contextResolver->isProductCategoryGridPage();
816 $datePickerSettings = [
817 'deliverOnMinDate' => wp_date( \Packetery\Core\Helper::DATEPICKER_FORMAT, strtotime( 'tomorrow' ) ),
818 'dateFormat' => \Packetery\Core\Helper::DATEPICKER_FORMAT_JS,
819 ];
820
821 if ( $isOrderGridPage || $isOrderDetailPage || in_array( $page, [ Carrier\OptionsPage::SLUG, Options\Page::SLUG ], true ) ) {
822 $this->enqueueScript( 'live-form-validation-options', 'public/live-form-validation-options.js', false );
823 $this->enqueueScript( 'live-form-validation', 'public/libs/live-form-validation/live-form-validation.js', false, [ 'live-form-validation-options' ] );
824 $this->enqueueScript( 'live-form-validation-extension', 'public/live-form-validation-extension.js', false, [ 'live-form-validation' ] );
825 }
826
827 if ( Carrier\OptionsPage::SLUG === $page ) {
828 $this->enqueueStyle( 'packetery-select2-css', 'public/libs/select2-4.0.13/dist.min.css' );
829 $this->enqueueScript( 'packetery-select2', 'public/libs/select2-4.0.13/dist.min.js', true, [ 'jquery' ] );
830 $this->enqueueScript( 'packetery-multiplier', 'public/multiplier.js', true, [ 'jquery', 'live-form-validation-extension' ] );
831 $this->enqueueScript( 'packetery-admin-country-carrier', 'public/admin-country-carrier.js', true, [ 'jquery', 'packetery-multiplier', 'packetery-select2' ] );
832 }
833
834 $isProductPage = $this->contextResolver->isProductPage();
835 $screen = get_current_screen();
836 $isDashboard = ( $screen && 'dashboard' === $screen->id );
837
838 if (
839 $isOrderGridPage || $isOrderDetailPage || $isProductPage || $isProductCategoryPage || $isDashboard ||
840 in_array(
841 $page,
842 [
843 Options\Page::SLUG,
844 Carrier\OptionsPage::SLUG,
845 Log\Page::SLUG,
846 Order\labelPrint::MENU_SLUG,
847 ],
848 true
849 )
850 ) {
851 $this->enqueueStyle( 'packetery-admin-styles', 'public/admin.css' );
852 // We want to trigger the message on all pages and show it on first request.
853 $this->featureFlagManager->isSplitActive();
854 // It is placed here so that typenow in contextResolver works and there is no need to repeat the conditions.
855 if ( $this->featureFlagManager->hasSplitActivationNotice() ) {
856 add_action( 'admin_notices', [ $this->featureFlagManager, 'renderSplitActivationNotice' ] );
857 }
858 }
859
860 if ( $isOrderGridPage ) {
861 $orderGridPageSettings = [
862 'translations' => [
863 'hasToFillCustomsDeclaration' => __( 'Customs declaration has to be filled in order detail.', 'packeta' ),
864 ],
865 ];
866 $this->enqueueScript( 'packetery-admin-grid-order-edit-js', 'public/admin-grid-order-edit.js', true, [ 'jquery', 'wp-util', 'backbone' ] );
867 wp_localize_script( 'packetery-admin-grid-order-edit-js', 'datePickerSettings', $datePickerSettings );
868 wp_localize_script( 'packetery-admin-grid-order-edit-js', 'settings', $orderGridPageSettings );
869 }
870
871 $pickupPointPickerSettings = null;
872 $addressPickerSettings = null;
873
874 if ( $isOrderDetailPage ) {
875 $this->enqueueScript( 'packetery-multiplier', 'public/multiplier.js', true, [ 'jquery', 'live-form-validation-extension' ] );
876 $this->enqueueScript( 'admin-order-detail', 'public/admin-order-detail.js', true, [ 'jquery', 'packetery-multiplier', 'live-form-validation-extension' ] );
877 wp_localize_script( 'admin-order-detail', 'datePickerSettings', $datePickerSettings );
878 $pickupPointPickerSettings = $this->order_metabox->getPickupPointWidgetSettings();
879 $addressPickerSettings = $this->order_metabox->getAddressWidgetSettings();
880 }
881
882 if ( null !== $pickupPointPickerSettings || null !== $addressPickerSettings ) {
883 wp_enqueue_script( 'packetery-widget-library', 'https://widget.packeta.com/v6/www/js/library.js', [], self::VERSION, true );
884 }
885
886 if ( null !== $pickupPointPickerSettings ) {
887 $this->enqueueScript( 'packetery-admin-pickup-point-picker', 'public/admin-pickup-point-picker.js', true, [ 'jquery', 'packetery-widget-library' ] );
888 wp_localize_script( 'packetery-admin-pickup-point-picker', 'packeteryPickupPointPickerSettings', $pickupPointPickerSettings );
889 }
890
891 if ( null !== $addressPickerSettings ) {
892 $this->enqueueScript( 'packetery-admin-address-picker', 'public/admin-address-picker.js', true, [ 'jquery', 'packetery-widget-library' ] );
893 wp_localize_script( 'packetery-admin-address-picker', 'packeteryAddressPickerSettings', $addressPickerSettings );
894 }
895
896 if ( $this->contextResolver->isPacketeryConfirmPage() ) {
897 $this->enqueueScript( 'packetery-confirm', 'public/confirm.js', true, [ 'jquery', 'backbone' ] );
898 }
899 }
900
901 /**
902 * Add links to left admin menu.
903 */
904 public function add_menu_pages(): void {
905 $this->options_page->register();
906 $this->carrierOptionsPage->register();
907 $this->labelPrint->register();
908 $this->orderCollectionPrint->register();
909 $this->logPage->register();
910 }
911
912 /**
913 * Gets current locale.
914 */
915 public static function getLocale(): string {
916 /**
917 * Applies plugin_locale filters.
918 *
919 * @since 1.0.0
920 */
921 return (string) apply_filters(
922 'plugin_locale',
923 ( is_admin() ? get_user_locale() : get_locale() ),
924 self::DOMAIN
925 );
926 }
927
928 /**
929 * Loads plugin translation file by user locale.
930 */
931 public function loadTranslation(): void {
932 $domain = self::DOMAIN;
933 $locale = self::getLocale();
934
935 $moFile = PACKETERY_PLUGIN_DIR . "/languages/$domain-$locale.mo";
936 $result = load_textdomain( $domain, $moFile );
937
938 if ( false === $result ) {
939 $moFile = PACKETERY_PLUGIN_DIR . "/languages/$domain-en_US.mo";
940 load_textdomain( $domain, $moFile );
941 }
942 }
943
944 /**
945 * Inits plugin.
946 */
947 public function init(): void {
948 add_filter(
949 'plugin_action_links_' . plugin_basename( $this->main_file_path ),
950 [
951 $this,
952 'addPluginActionLinks',
953 ]
954 );
955 add_filter( 'plugin_row_meta', [ $this, 'addPluginRowMeta' ], 10, 2 );
956 }
957
958 /**
959 * Uninstalls plugin and drops custom database table.
960 * Only a static class method or function can be used in an uninstall hook.
961 */
962 public static function uninstall(): void {
963 if ( defined( 'PACKETERY_DEBUG' ) && PACKETERY_DEBUG === true ) {
964 return;
965 }
966
967 $container = require PACKETERY_PLUGIN_DIR . '/bootstrap.php';
968
969 $optionsRepository = $container->getByType( Options\Repository::class );
970 $pluginOptions = $optionsRepository->getPluginOptions();
971 foreach ( $pluginOptions as $option ) {
972 delete_option( $option->option_name );
973 }
974
975 $logRepository = $container->getByType( Log\Repository::class );
976 $logRepository->drop();
977
978 $carrierRepository = $container->getByType( Carrier\Repository::class );
979 $carrierRepository->drop();
980
981 $orderRepository = $container->getByType( Order\Repository::class );
982 $orderRepository->drop();
983 }
984
985 /**
986 * Adds action links visible at the plugin screen.
987 *
988 * @link https://developer.wordpress.org/reference/hooks/plugin_action_links_plugin_file/
989 *
990 * @param array $links Plugin Action links.
991 *
992 * @return array
993 */
994 public function addPluginActionLinks( array $links ): array {
995 $settingsLink = '<a href="' . esc_url( admin_url( 'admin.php?page=' . Options\Page::SLUG ) ) . '" aria-label="' .
996 esc_attr__( 'View the plugin documentation', 'packeta' ) . '">' .
997 esc_html__( 'Settings', 'packeta' ) . '</a>';
998
999 array_unshift( $links, $settingsLink );
1000
1001 return $links;
1002 }
1003
1004 /**
1005 * Show row meta on the plugin screen.
1006 *
1007 * @link https://developer.wordpress.org/reference/hooks/plugin_row_meta/
1008 *
1009 * @param array $links Plugin Row Meta.
1010 * @param string $pluginFileName Plugin Base file.
1011 *
1012 * @return array
1013 */
1014 public function addPluginRowMeta( array $links, string $pluginFileName ): array {
1015 if ( ! strpos( $pluginFileName, basename( $this->main_file_path ) ) ) {
1016 return $links;
1017 }
1018 $links[] = '<a href="' . esc_url( 'https://github.com/Zasilkovna/WooCommerce/wiki' ) . '" aria-label="' .
1019 esc_attr__( 'View Packeta documentation', 'packeta' ) . '">' .
1020 esc_html__( 'Documentation', 'packeta' ) . '</a>';
1021
1022 return $links;
1023 }
1024
1025 /**
1026 * Adds Packeta method to available shipping methods.
1027 *
1028 * @param array $methods Previous state.
1029 *
1030 * @return array
1031 */
1032 public function add_shipping_method( array $methods ): array {
1033 $methods[ ShippingMethod::PACKETERY_METHOD_ID ] = ShippingMethod::class;
1034
1035 return $methods;
1036 }
1037
1038 /**
1039 * Hides submenu item. Must not be called too early.
1040 *
1041 * @param string $itemSlug Item slug.
1042 */
1043 public static function hideSubmenuItem( string $itemSlug ): void {
1044 global $submenu;
1045 if ( isset( $submenu[ Options\Page::SLUG ] ) ) {
1046 foreach ( $submenu[ Options\Page::SLUG ] as $key => $menu ) {
1047 if ( $itemSlug === $menu[2] ) {
1048 unset( $submenu[ Options\Page::SLUG ][ $key ] );
1049 }
1050 }
1051 }
1052 }
1053
1054 /**
1055 * Gets software identity for Packeta APIs.
1056 *
1057 * @return string
1058 */
1059 public static function getAppIdentity(): string {
1060 return 'WordPress-' . get_bloginfo( 'version' ) . '-Woocommerce-' . WC_VERSION . '-Packeta-' . self::VERSION;
1061 }
1062
1063 /**
1064 * Check for action parameter and process wanted action.
1065 *
1066 * @return void
1067 */
1068 public function handleActions(): void {
1069 $action = $this->request->getQuery( self::PARAM_PACKETERY_ACTION );
1070
1071 if ( Order\PacketActionsCommonLogic::ACTION_SUBMIT_PACKET === $action ) {
1072 $this->packetSubmitter->processAction();
1073 }
1074
1075 if ( Order\PacketActionsCommonLogic::ACTION_SUBMIT_PACKET_CLAIM === $action ) {
1076 $this->packetClaimSubmitter->processAction();
1077 }
1078
1079 if ( Order\PacketActionsCommonLogic::ACTION_CANCEL_PACKET === $action ) {
1080 $this->packetCanceller->processAction();
1081 }
1082
1083 if ( Options\FeatureFlagManager::ACTION_HIDE_SPLIT_MESSAGE === $action ) {
1084 $this->featureFlagManager->dismissSplitActivationNotice();
1085 }
1086 }
1087 }
1088