PluginProbe
Packeta / 1.6.1
Packeta v1.6.1
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.1, at src/Packetery/Module/Plugin.php

1,065 lines 32.7 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.1';
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 $wcEmailHook = $this->optionsProvider->getEmailHook();
427 add_action( $wcEmailHook, [ $this, 'renderEmailFooter' ] );
428 add_filter( 'woocommerce_shipping_methods', array( $this, 'add_shipping_method' ) );
429
430 $orderListScreenId = 'woocommerce_page_wc-orders';
431 add_filter( 'views_edit-shop_order', [ $this->gridExtender, 'addFilterLinks' ] );
432 add_action( 'restrict_manage_posts', [ $this->gridExtender, 'renderOrderTypeSelect' ] );
433
434 $wooCommerceVersion = Helper::getWooCommerceVersion();
435 if ( null !== $wooCommerceVersion && version_compare( $wooCommerceVersion, '7.9.0', '>=' ) ) {
436 add_filter( sprintf( 'views_%s', $orderListScreenId ), [ $this->gridExtender, 'addFilterLinks' ] );
437 add_action( 'woocommerce_order_list_table_restrict_manage_orders', [ $this->gridExtender, 'renderOrderTypeSelect' ] );
438 }
439
440 $this->queryProcessor->register();
441
442 add_filter( 'manage_edit-shop_order_columns', [ $this->gridExtender, 'addOrderListColumns' ] );
443 add_filter( sprintf( 'manage_%s_columns', $orderListScreenId ), [ $this->gridExtender, 'addOrderListColumns' ] );
444 add_action( 'manage_shop_order_posts_custom_column', [ $this->gridExtender, 'fillCustomOrderListColumns' ], 10, 2 );
445 add_action( sprintf( 'manage_%s_custom_column', $orderListScreenId ), [ $this->gridExtender, 'fillCustomOrderListColumns' ], 10, 2 );
446
447 add_action( 'admin_menu', array( $this, 'add_menu_pages' ) );
448 add_action( 'admin_head', array( $this->labelPrint, 'hideFromMenus' ) );
449 add_action( 'admin_head', array( $this->orderCollectionPrint, 'hideFromMenus' ) );
450 add_action( 'admin_head', [ $this, 'renderConfirmModalTemplate' ] );
451 $this->orderModal->register();
452 $this->labelPrintModal->register();
453 $this->metaboxesWrapper->register();
454
455 $this->checkout->register_hooks();
456 $this->productTab->register();
457 $this->cronService->register();
458 $this->productCategoryFormFields->register();
459 $this->packetAutoSubmitter->register();
460 $this->apiExtender->register();
461
462 add_action( 'woocommerce_admin_order_data_after_shipping_address', [ $this, 'renderDeliveryDetail' ] );
463 add_action( 'woocommerce_order_details_after_order_table', [ $this, 'renderOrderDetail' ] );
464
465 // Adding custom actions to dropdown in admin order list.
466 add_filter( 'bulk_actions-edit-shop_order', [ $this->orderBulkActions, 'addActions' ], 20, 1 );
467 add_filter( sprintf( 'bulk_actions-%s', $orderListScreenId ), [ $this->orderBulkActions, 'addActions' ], 20, 1 );
468 // Execute the action for selected orders.
469 add_filter(
470 'handle_bulk_actions-edit-shop_order',
471 [
472 $this->orderBulkActions,
473 'handleActions',
474 ],
475 10,
476 3
477 );
478 add_filter( sprintf( 'handle_bulk_actions-%s', $orderListScreenId ), [ $this->orderBulkActions, 'handleActions' ], 10, 3 );
479 // Print packets export result.
480 add_action( 'admin_notices', [ $this->orderBulkActions, 'renderPacketsExportResult' ], self::MIN_LISTENER_PRIORITY );
481
482 add_action( 'admin_init', [ $this->labelPrint, 'outputLabelsPdf' ] );
483 add_action( 'admin_init', [ $this->orderCollectionPrint, 'print' ] );
484
485 add_action( 'admin_init', [ $this->exporter, 'outputExportTxt' ] );
486 add_action( 'admin_init', [ $this, 'handleActions' ] );
487
488 add_action( 'deleted_post', [ $this->orderRepository, 'deletedPostHook' ], 10, 2 );
489 $this->dashboardWidget->register();
490 }
491
492 /**
493 * Declares plugin compability with features.
494 *
495 * @return void
496 */
497 public function declareWooCommerceCompability(): void {
498 if ( false === class_exists( FeaturesUtil::class ) ) {
499 return;
500 }
501
502 // High-Performance Order Storage.
503 FeaturesUtil::declare_compatibility( 'custom_order_tables', $this->main_file_path );
504 }
505
506 /**
507 * Print inactive WooCommerce notice.
508 *
509 * @return void
510 */
511 public function echoInactiveWooCommerceNotice(): void {
512 if ( self::isWooCommercePluginActive() ) {
513 // When Packeta plugin is active and WooCommerce plugin is inactive.
514 // If user decides to activate WooCommerce plugin then invalid notice will not be rendered.
515 // Packeta plugin probably bootstraps twice in such case.
516 return;
517 }
518
519 $this->latte_engine->render(
520 PACKETERY_PLUGIN_DIR . '/template/admin-notice.latte',
521 [
522 'message' => [
523 'type' => 'error',
524 'message' => __( 'Packeta plugin requires WooCommerce. Please install and activate it first.', 'packeta' ),
525 ],
526 ]
527 );
528 }
529
530 /**
531 * Is WC plugin active.
532 *
533 * @return bool
534 */
535 private static function isWooCommercePluginActive(): bool {
536 return Helper::isPluginActive( 'woocommerce/woocommerce.php' );
537 }
538
539 /**
540 * Creates HTML link parts in array.
541 *
542 * @param string $href Href.
543 * @param string|null $target Target.
544 * @param string|null $class Class.
545 *
546 * @return string[]
547 */
548 public static function createLinkParts( string $href, ?string $target = null, ?string $class = null ): array {
549 $link = Html::el( 'a' )->href( $href );
550
551 if ( null !== $target ) {
552 $link->target( $target );
553 }
554
555 if ( null !== $class ) {
556 $link->class( $class );
557 }
558
559 return [ $link->startTag(), $link->endTag() ];
560 }
561
562 /**
563 * Renders delivery detail for packetery orders.
564 *
565 * @param WC_Order $order WordPress order.
566 */
567 public function renderDeliveryDetail( WC_Order $order ): void {
568 try {
569 $orderEntity = $this->orderRepository->getByWcOrder( $order );
570 } catch ( InvalidCarrierException $exception ) {
571 $orderEntity = null;
572 }
573 if ( null === $orderEntity ) {
574 return;
575 }
576
577 $carrierId = $orderEntity->getCarrier()->getId();
578 $carrierOptions = Carrier\Options::createByCarrierId( $carrierId );
579
580 $this->latte_engine->render(
581 PACKETERY_PLUGIN_DIR . '/template/order/delivery-detail.latte',
582 [
583 'pickupPoint' => $orderEntity->getPickupPoint(),
584 'validatedDeliveryAddress' => $orderEntity->getValidatedDeliveryAddress(),
585 'carrierAddressValidation' => $carrierOptions->getAddressValidation(),
586 'isExternalCarrier' => $orderEntity->isExternalCarrier(),
587 'translations' => [
588 'packeta' => __( 'Packeta', 'packeta' ),
589 'pickupPointDetail' => __( 'Pickup Point Detail', 'packeta' ),
590 'name' => __( 'Name', 'packeta' ),
591 'address' => __( 'Address', 'packeta' ),
592 'pickupPointDetailCaps' => __( 'Pickup Point Detail', 'packeta' ),
593 'addressWasNotValidated' => __( 'Address was not validated', 'packeta' ),
594 'validatedAddress' => __( 'Validated address', 'packeta' ),
595 'street' => __( 'Street', 'packeta' ),
596 'houseNumber' => __( 'House number', 'packeta' ),
597 'city' => __( 'City', 'packeta' ),
598 'zip' => __( 'Zip', 'packeta' ),
599 'county' => __( 'County', 'packeta' ),
600 'gps' => __( 'GPS', 'packeta' ),
601 ],
602 ]
603 );
604 }
605
606 /**
607 * Renders delivery detail for packetery orders, on "thank you" page and in frontend detail.
608 *
609 * @param WC_Order $wcOrder WordPress order.
610 */
611 public function renderOrderDetail( WC_Order $wcOrder ): void {
612 try {
613 $order = $this->orderRepository->getById( $wcOrder->get_id() );
614 } catch ( InvalidCarrierException $exception ) {
615 $order = null;
616 }
617 if ( null === $order ) {
618 return;
619 }
620
621 if ( null === $order->getPickupPoint() && null === $order->getValidatedDeliveryAddress() ) {
622 return;
623 }
624
625 $this->latte_engine->render(
626 PACKETERY_PLUGIN_DIR . '/template/order/detail.latte',
627 [
628 'displayPickupPointInfo' => $this->shouldDisplayPickupPointInfo(),
629 'order' => $order,
630 'translations' => [
631 'packeta' => __( 'Packeta', 'packeta' ),
632 'pickupPointName' => __( 'Pickup Point Name', 'packeta' ),
633 'pickupPointDetail' => __( 'Pickup Point Detail', 'packeta' ),
634 'validatedAddress' => __( 'Validated address', 'packeta' ),
635 'address' => __( 'Address', 'packeta' ),
636 'packetTrackingOnline' => __( 'Packet tracking online', 'packeta' ),
637 ],
638 ]
639 );
640 }
641
642 /**
643 * Renders email footer.
644 *
645 * @param mixed $email Email data.
646 */
647 public function renderEmailFooter( $email ): void {
648 if ( $email instanceof WC_Email || ( isset( $email->object ) && $email->object instanceof WC_Order ) ) {
649 $wcOrder = $email->object;
650 } elseif ( $email instanceof WC_Order ) {
651 $wcOrder = $email;
652 } else {
653 return;
654 }
655
656 try {
657 $packeteryOrder = $this->orderRepository->getByWcOrder( $wcOrder );
658 } catch ( InvalidCarrierException $exception ) {
659 $packeteryOrder = null;
660 }
661 if ( null === $packeteryOrder ) {
662 return;
663 }
664
665 $templateParams = [
666 'displayPickupPointInfo' => $this->shouldDisplayPickupPointInfo(),
667 'order' => $packeteryOrder,
668 'translations' => [
669 'packeta' => __( 'Packeta', 'packeta' ),
670 'pickupPointDetail' => __( 'Pickup Point Detail', 'packeta' ),
671 'pickupPointName' => __( 'Pickup Point Name', 'packeta' ),
672 'link' => __( 'Link', 'packeta' ),
673 'pickupPointAddress' => __( 'Pickup Point Address', 'packeta' ),
674 'validatedDeliveryAddress' => __( 'validated delivery address', 'packeta' ),
675 'street' => __( 'Street', 'packeta' ),
676 'houseNumber' => __( 'House number', 'packeta' ),
677 'city' => __( 'City', 'packeta' ),
678 'zip' => __( 'Zip', 'packeta' ),
679 'county' => __( 'County', 'packeta' ),
680 'packetTrackingOnline' => __( 'Packet tracking online', 'packeta' ),
681 ],
682 ];
683 $emailFooterHtml = $this->latte_engine->renderToString(
684 PACKETERY_PLUGIN_DIR . '/template/email/footer.latte',
685 $templateParams
686 );
687 /**
688 * This filter allows you to change the HTML of e-mail footer.
689 *
690 * @since 1.5.3
691 */
692 Helper::renderString( (string) apply_filters( 'packeta_email_footer', $emailFooterHtml, $templateParams ) );
693 }
694
695 /**
696 * Tells if pickup point info should be displayed.
697 *
698 * @return bool
699 */
700 public function shouldDisplayPickupPointInfo(): bool {
701 return ! $this->optionsProvider->replaceShippingAddressWithPickupPointAddress() || wc_ship_to_billing_address_only();
702 }
703
704 /**
705 * Renders confirm modal template.
706 */
707 public function renderConfirmModalTemplate(): void {
708 if ( $this->contextResolver->isPacketeryConfirmPage() ) {
709 $this->latte_engine->render(
710 PACKETERY_PLUGIN_DIR . '/template/confirm-modal-template.latte',
711 [
712 'translations' => [
713 'closeModalPanel' => __( 'Close modal panel', 'packeta' ),
714 'no' => __( 'No', 'packeta' ),
715 'yes' => __( 'Yes', 'packeta' ),
716 ],
717 ]
718 );
719 }
720 }
721
722 /**
723 * Enqueues admin JS file.
724 *
725 * @param string $name Name of script.
726 * @param string $file Relative file path.
727 * @param bool $inFooter Tells where to include script.
728 * @param array $deps Script dependencies.
729 */
730 private function enqueueScript( string $name, string $file, bool $inFooter, array $deps = [] ): void {
731 wp_enqueue_script(
732 $name,
733 plugin_dir_url( $this->main_file_path ) . $file,
734 $deps,
735 md5( (string) filemtime( PACKETERY_PLUGIN_DIR . '/' . $file ) ),
736 $inFooter
737 );
738 }
739
740 /**
741 * Enqueues CSS file.
742 *
743 * @param string $name Name of script.
744 * @param string $file Relative file path.
745 */
746 private function enqueueStyle( string $name, string $file ): void {
747 wp_enqueue_style(
748 $name,
749 plugin_dir_url( $this->main_file_path ) . $file,
750 [],
751 md5( (string) filemtime( PACKETERY_PLUGIN_DIR . '/' . $file ) )
752 );
753 }
754
755 /**
756 * Builds asset URL.
757 *
758 * @param string $asset Relative asset path without leading slash.
759 *
760 * @return string|null
761 */
762 public static function buildAssetUrl( string $asset ): ?string {
763 $url = plugin_dir_url( PACKETERY_PLUGIN_DIR . '/packeta.php' ) . $asset;
764 $filename = PACKETERY_PLUGIN_DIR . '/' . $asset;
765
766 if ( ! file_exists( $filename ) ) {
767 return null;
768 }
769
770 return add_query_arg( [ 'v' => md5( (string) filemtime( $filename ) ) ], $url );
771 }
772
773 /**
774 * Enqueues javascript files and stylesheets for checkout.
775 */
776 public function enqueueFrontAssets(): void {
777 if ( is_checkout() ) {
778 $this->enqueueStyle( 'packetery-front-styles', 'public/front.css' );
779 $this->enqueueStyle( 'packetery-custom-front-styles', 'public/custom-front.css' );
780 $this->enqueueScript( 'packetery-checkout', 'public/checkout.js', true, [ 'jquery' ] );
781 wp_localize_script( 'packetery-checkout', 'packeteryCheckoutSettings', $this->checkout->createSettings() );
782 }
783 }
784
785 /**
786 * Enqueues javascript files and stylesheets for administration.
787 */
788 public function enqueueAdminAssets(): void {
789 $page = $this->request->getQuery( 'page' );
790 $isOrderGridPage = $this->contextResolver->isOrderGridPage();
791 $isOrderDetailPage = $this->contextResolver->isOrderDetailPage();
792 $isProductCategoryPage = $this->contextResolver->isProductCategoryDetailPage() || $this->contextResolver->isProductCategoryGridPage();
793 $datePickerSettings = [
794 'deliverOnMinDate' => wp_date( \Packetery\Core\Helper::DATEPICKER_FORMAT, strtotime( 'tomorrow' ) ),
795 'dateFormat' => \Packetery\Core\Helper::DATEPICKER_FORMAT_JS,
796 ];
797
798 if ( $isOrderGridPage || $isOrderDetailPage || in_array( $page, [ Carrier\OptionsPage::SLUG, Options\Page::SLUG ], true ) ) {
799 $this->enqueueScript( 'live-form-validation-options', 'public/live-form-validation-options.js', false );
800 $this->enqueueScript( 'live-form-validation', 'public/libs/live-form-validation/live-form-validation.js', false, [ 'live-form-validation-options' ] );
801 $this->enqueueScript( 'live-form-validation-extension', 'public/live-form-validation-extension.js', false, [ 'live-form-validation' ] );
802 }
803
804 if ( Carrier\OptionsPage::SLUG === $page ) {
805 $this->enqueueStyle( 'packetery-select2-css', 'public/libs/select2-4.0.13/dist.min.css' );
806 $this->enqueueScript( 'packetery-select2', 'public/libs/select2-4.0.13/dist.min.js', true, [ 'jquery' ] );
807 $this->enqueueScript( 'packetery-multiplier', 'public/multiplier.js', true, [ 'jquery', 'live-form-validation-extension' ] );
808 $this->enqueueScript( 'packetery-admin-country-carrier', 'public/admin-country-carrier.js', true, [ 'jquery', 'packetery-multiplier', 'packetery-select2' ] );
809 }
810
811 $isProductPage = $this->contextResolver->isProductPage();
812 $screen = get_current_screen();
813 $isDashboard = ( $screen && 'dashboard' === $screen->id );
814
815 if (
816 $isOrderGridPage || $isOrderDetailPage || $isProductPage || $isProductCategoryPage || $isDashboard ||
817 in_array(
818 $page,
819 [
820 Options\Page::SLUG,
821 Carrier\OptionsPage::SLUG,
822 Log\Page::SLUG,
823 Order\labelPrint::MENU_SLUG,
824 ],
825 true
826 )
827 ) {
828 $this->enqueueStyle( 'packetery-admin-styles', 'public/admin.css' );
829 // We want to trigger the message on all pages and show it on first request.
830 $this->featureFlagManager->isSplitActive();
831 // It is placed here so that typenow in contextResolver works and there is no need to repeat the conditions.
832 if ( $this->featureFlagManager->hasSplitActivationNotice() ) {
833 add_action( 'admin_notices', [ $this->featureFlagManager, 'renderSplitActivationNotice' ] );
834 }
835 }
836
837 if ( $isOrderGridPage ) {
838 $orderGridPageSettings = [
839 'translations' => [
840 'hasToFillCustomsDeclaration' => __( 'Customs declaration has to be filled in order detail.', 'packeta' ),
841 ],
842 ];
843 $this->enqueueScript( 'packetery-admin-grid-order-edit-js', 'public/admin-grid-order-edit.js', true, [ 'jquery', 'wp-util', 'backbone' ] );
844 wp_localize_script( 'packetery-admin-grid-order-edit-js', 'datePickerSettings', $datePickerSettings );
845 wp_localize_script( 'packetery-admin-grid-order-edit-js', 'settings', $orderGridPageSettings );
846 }
847
848 $pickupPointPickerSettings = null;
849 $addressPickerSettings = null;
850
851 if ( $isOrderDetailPage ) {
852 $this->enqueueScript( 'packetery-multiplier', 'public/multiplier.js', true, [ 'jquery', 'live-form-validation-extension' ] );
853 $this->enqueueScript( 'admin-order-detail', 'public/admin-order-detail.js', true, [ 'jquery', 'packetery-multiplier', 'live-form-validation-extension' ] );
854 wp_localize_script( 'admin-order-detail', 'datePickerSettings', $datePickerSettings );
855 $pickupPointPickerSettings = $this->order_metabox->getPickupPointWidgetSettings();
856 $addressPickerSettings = $this->order_metabox->getAddressWidgetSettings();
857 }
858
859 if ( null !== $pickupPointPickerSettings || null !== $addressPickerSettings ) {
860 wp_enqueue_script( 'packetery-widget-library', 'https://widget.packeta.com/v6/www/js/library.js', [], self::VERSION, true );
861 }
862
863 if ( null !== $pickupPointPickerSettings ) {
864 $this->enqueueScript( 'packetery-admin-pickup-point-picker', 'public/admin-pickup-point-picker.js', true, [ 'jquery', 'packetery-widget-library' ] );
865 wp_localize_script( 'packetery-admin-pickup-point-picker', 'packeteryPickupPointPickerSettings', $pickupPointPickerSettings );
866 }
867
868 if ( null !== $addressPickerSettings ) {
869 $this->enqueueScript( 'packetery-admin-address-picker', 'public/admin-address-picker.js', true, [ 'jquery', 'packetery-widget-library' ] );
870 wp_localize_script( 'packetery-admin-address-picker', 'packeteryAddressPickerSettings', $addressPickerSettings );
871 }
872
873 if ( $this->contextResolver->isPacketeryConfirmPage() ) {
874 $this->enqueueScript( 'packetery-confirm', 'public/confirm.js', true, [ 'jquery', 'backbone' ] );
875 }
876 }
877
878 /**
879 * Add links to left admin menu.
880 */
881 public function add_menu_pages(): void {
882 $this->options_page->register();
883 $this->carrierOptionsPage->register();
884 $this->labelPrint->register();
885 $this->orderCollectionPrint->register();
886 $this->logPage->register();
887 }
888
889 /**
890 * Gets current locale.
891 */
892 public static function getLocale(): string {
893 /**
894 * Applies plugin_locale filters.
895 *
896 * @since 1.0.0
897 */
898 return (string) apply_filters(
899 'plugin_locale',
900 ( is_admin() ? get_user_locale() : get_locale() ),
901 self::DOMAIN
902 );
903 }
904
905 /**
906 * Loads plugin translation file by user locale.
907 */
908 public function loadTranslation(): void {
909 $domain = self::DOMAIN;
910 $locale = self::getLocale();
911
912 $moFile = PACKETERY_PLUGIN_DIR . "/languages/$domain-$locale.mo";
913 $result = load_textdomain( $domain, $moFile );
914
915 if ( false === $result ) {
916 $moFile = PACKETERY_PLUGIN_DIR . "/languages/$domain-en_US.mo";
917 load_textdomain( $domain, $moFile );
918 }
919 }
920
921 /**
922 * Inits plugin.
923 */
924 public function init(): void {
925 add_filter(
926 'plugin_action_links_' . plugin_basename( $this->main_file_path ),
927 [
928 $this,
929 'addPluginActionLinks',
930 ]
931 );
932 add_filter( 'plugin_row_meta', [ $this, 'addPluginRowMeta' ], 10, 2 );
933 }
934
935 /**
936 * Uninstalls plugin and drops custom database table.
937 * Only a static class method or function can be used in an uninstall hook.
938 */
939 public static function uninstall(): void {
940 if ( defined( 'PACKETERY_DEBUG' ) && PACKETERY_DEBUG === true ) {
941 return;
942 }
943
944 $container = require PACKETERY_PLUGIN_DIR . '/bootstrap.php';
945
946 $optionsRepository = $container->getByType( Options\Repository::class );
947 $pluginOptions = $optionsRepository->getPluginOptions();
948 foreach ( $pluginOptions as $option ) {
949 delete_option( $option->option_name );
950 }
951
952 $logRepository = $container->getByType( Log\Repository::class );
953 $logRepository->drop();
954
955 $carrierRepository = $container->getByType( Carrier\Repository::class );
956 $carrierRepository->drop();
957
958 $orderRepository = $container->getByType( Order\Repository::class );
959 $orderRepository->drop();
960 }
961
962 /**
963 * Adds action links visible at the plugin screen.
964 *
965 * @link https://developer.wordpress.org/reference/hooks/plugin_action_links_plugin_file/
966 *
967 * @param array $links Plugin Action links.
968 *
969 * @return array
970 */
971 public function addPluginActionLinks( array $links ): array {
972 $settingsLink = '<a href="' . esc_url( admin_url( 'admin.php?page=' . Options\Page::SLUG ) ) . '" aria-label="' .
973 esc_attr__( 'View the plugin documentation', 'packeta' ) . '">' .
974 esc_html__( 'Settings', 'packeta' ) . '</a>';
975
976 array_unshift( $links, $settingsLink );
977
978 return $links;
979 }
980
981 /**
982 * Show row meta on the plugin screen.
983 *
984 * @link https://developer.wordpress.org/reference/hooks/plugin_row_meta/
985 *
986 * @param array $links Plugin Row Meta.
987 * @param string $pluginFileName Plugin Base file.
988 *
989 * @return array
990 */
991 public function addPluginRowMeta( array $links, string $pluginFileName ): array {
992 if ( ! strpos( $pluginFileName, basename( $this->main_file_path ) ) ) {
993 return $links;
994 }
995 $links[] = '<a href="' . esc_url( 'https://github.com/Zasilkovna/WooCommerce/wiki' ) . '" aria-label="' .
996 esc_attr__( 'View Packeta documentation', 'packeta' ) . '">' .
997 esc_html__( 'Documentation', 'packeta' ) . '</a>';
998
999 return $links;
1000 }
1001
1002 /**
1003 * Adds Packeta method to available shipping methods.
1004 *
1005 * @param array $methods Previous state.
1006 *
1007 * @return array
1008 */
1009 public function add_shipping_method( array $methods ): array {
1010 $methods[ ShippingMethod::PACKETERY_METHOD_ID ] = ShippingMethod::class;
1011
1012 return $methods;
1013 }
1014
1015 /**
1016 * Hides submenu item. Must not be called too early.
1017 *
1018 * @param string $itemSlug Item slug.
1019 */
1020 public static function hideSubmenuItem( string $itemSlug ): void {
1021 global $submenu;
1022 if ( isset( $submenu[ Options\Page::SLUG ] ) ) {
1023 foreach ( $submenu[ Options\Page::SLUG ] as $key => $menu ) {
1024 if ( $itemSlug === $menu[2] ) {
1025 unset( $submenu[ Options\Page::SLUG ][ $key ] );
1026 }
1027 }
1028 }
1029 }
1030
1031 /**
1032 * Gets software identity for Packeta APIs.
1033 *
1034 * @return string
1035 */
1036 public static function getAppIdentity(): string {
1037 return 'WordPress-' . get_bloginfo( 'version' ) . '-Woocommerce-' . WC_VERSION . '-Packeta-' . self::VERSION;
1038 }
1039
1040 /**
1041 * Check for action parameter and process wanted action.
1042 *
1043 * @return void
1044 */
1045 public function handleActions(): void {
1046 $action = $this->request->getQuery( self::PARAM_PACKETERY_ACTION );
1047
1048 if ( Order\PacketActionsCommonLogic::ACTION_SUBMIT_PACKET === $action ) {
1049 $this->packetSubmitter->processAction();
1050 }
1051
1052 if ( Order\PacketActionsCommonLogic::ACTION_SUBMIT_PACKET_CLAIM === $action ) {
1053 $this->packetClaimSubmitter->processAction();
1054 }
1055
1056 if ( Order\PacketActionsCommonLogic::ACTION_CANCEL_PACKET === $action ) {
1057 $this->packetCanceller->processAction();
1058 }
1059
1060 if ( Options\FeatureFlagManager::ACTION_HIDE_SPLIT_MESSAGE === $action ) {
1061 $this->featureFlagManager->dismissSplitActivationNotice();
1062 }
1063 }
1064 }
1065