PluginProbe
Packeta / 1.6.0
Packeta v1.6.0
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.0, at src/Packetery/Module/Plugin.php

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