Editor
2 months ago
Embed
1 month ago
Links
2 months ago
Listing
9 months ago
Options
2 years ago
Preview
1 month ago
Renderer
4 days ago
RestApi
1 week ago
Scheduler
4 days ago
Segment
1 year ago
Sending
1 week ago
Sharing
1 month ago
Shortcodes
3 days ago
Statistics
1 week ago
ViewInBrowser
1 month ago
ApiDataSanitizer.php
3 years ago
AutomatedLatestContent.php
2 months ago
AutomaticEmailsRepository.php
3 years ago
BlockPostQuery.php
2 months ago
BulkActionController.php
1 month ago
BulkActionException.php
1 month ago
DynamicProducts.php
11 months ago
NewsletterCoupon.php
2 months ago
NewsletterDeleteController.php
2 years ago
NewsletterHtmlSanitizer.php
2 years ago
NewsletterPostsRepository.php
2 years ago
NewsletterResendController.php
4 days ago
NewsletterSaveController.php
1 month ago
NewsletterValidator.php
1 year ago
NewslettersRepository.php
2 weeks ago
StatusController.php
1 month ago
Url.php
2 months ago
index.php
3 years ago
Url.php
142 lines
| 1 | <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing |
| 2 | |
| 3 | namespace MailPoet\Newsletter; |
| 4 | |
| 5 | if (!defined('ABSPATH')) exit; |
| 6 | |
| 7 | |
| 8 | use MailPoet\Entities\NewsletterEntity; |
| 9 | use MailPoet\Entities\SendingQueueEntity; |
| 10 | use MailPoet\Entities\SubscriberEntity; |
| 11 | use MailPoet\Router\Endpoints\ViewInBrowser as ViewInBrowserEndpoint; |
| 12 | use MailPoet\Router\Router; |
| 13 | use MailPoet\Subscribers\LinkTokens; |
| 14 | use MailPoet\WP\Functions as WPFunctions; |
| 15 | |
| 16 | class Url { |
| 17 | public const PUBLIC_SHARE_PATH = '/mailpoet-email/'; |
| 18 | |
| 19 | /** @var LinkTokens */ |
| 20 | private $linkTokens; |
| 21 | |
| 22 | /** @var WPFunctions */ |
| 23 | private $wp; |
| 24 | |
| 25 | public function __construct( |
| 26 | LinkTokens $linkTokens, |
| 27 | WPFunctions $wp |
| 28 | ) { |
| 29 | $this->linkTokens = $linkTokens; |
| 30 | $this->wp = $wp; |
| 31 | } |
| 32 | |
| 33 | public function getViewInBrowserUrl( |
| 34 | ?NewsletterEntity $newsletter, |
| 35 | ?SubscriberEntity $subscriber = null, |
| 36 | ?SendingQueueEntity $queue = null, |
| 37 | bool $preview = true |
| 38 | ) { |
| 39 | $data = $this->createUrlDataObject($newsletter, $subscriber, $queue, $preview); |
| 40 | return Router::buildRequest( |
| 41 | ViewInBrowserEndpoint::ENDPOINT, |
| 42 | ViewInBrowserEndpoint::ACTION_VIEW, |
| 43 | $data |
| 44 | ); |
| 45 | } |
| 46 | |
| 47 | public function getPublicShareUrl(?NewsletterEntity $newsletter): string { |
| 48 | if (!$newsletter || !$newsletter->getHash()) { |
| 49 | return ''; |
| 50 | } |
| 51 | $identifier = $this->getPublicShareIdentifier($newsletter); |
| 52 | if ($this->usesPrettyPermalinks()) { |
| 53 | return $this->wp->homeUrl($this->getPublicSharePathPrefix() . $identifier . '/'); |
| 54 | } |
| 55 | return $this->wp->addQueryArg( |
| 56 | ['mailpoet_public_email' => $identifier], |
| 57 | $this->wp->homeUrl('/') |
| 58 | ); |
| 59 | } |
| 60 | |
| 61 | public function getPublicSharePathPrefix(): string { |
| 62 | /** |
| 63 | * Filters the URL path prefix used for the public share route. |
| 64 | * |
| 65 | * Useful when the default `/mailpoet-email/` slug collides with an |
| 66 | * existing page or you want to namespace it under another segment. |
| 67 | * |
| 68 | * @param string $prefix Default `/mailpoet-email/`. |
| 69 | */ |
| 70 | $filtered = $this->wp->applyFilters('mailpoet_public_share_url_prefix', self::PUBLIC_SHARE_PATH); |
| 71 | $prefix = is_string($filtered) ? trim($filtered, '/') : ''; |
| 72 | if ($prefix === '' || !preg_match('#^[a-zA-Z0-9_/-]+$#', $prefix)) { |
| 73 | $prefix = trim(self::PUBLIC_SHARE_PATH, '/'); |
| 74 | } |
| 75 | return '/' . $prefix . '/'; |
| 76 | } |
| 77 | |
| 78 | public function getPublicShareIdentifier(NewsletterEntity $newsletter): string { |
| 79 | $hash = $newsletter->getHash(); |
| 80 | return sprintf( |
| 81 | '%s-%s', |
| 82 | is_string($hash) ? $hash : '', |
| 83 | $this->getPublicShareSlug($newsletter) |
| 84 | ); |
| 85 | } |
| 86 | |
| 87 | public function getPublicShareSlug(NewsletterEntity $newsletter): string { |
| 88 | $slug = $this->wp->sanitizeTitle($newsletter->getCampaignNameOrSubject()); |
| 89 | return $slug ?: 'email'; |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * @return array{hash: string, slug: string|null}|null |
| 94 | */ |
| 95 | public function parsePublicShareIdentifier(string $identifier): ?array { |
| 96 | if (!preg_match('/^(?P<hash>[0-9a-f]{12})(?:-(?P<slug>[^\/]+))?$/', $identifier, $matches)) { |
| 97 | return null; |
| 98 | } |
| 99 | return [ |
| 100 | 'hash' => $matches['hash'], |
| 101 | 'slug' => $matches['slug'] ?? null, |
| 102 | ]; |
| 103 | } |
| 104 | |
| 105 | public function usesPrettyPermalinks(): bool { |
| 106 | return (string)$this->wp->getOption('permalink_structure', '') !== ''; |
| 107 | } |
| 108 | |
| 109 | public function createUrlDataObject( |
| 110 | ?NewsletterEntity $newsletter, |
| 111 | ?SubscriberEntity $subscriber, |
| 112 | ?SendingQueueEntity $queue, |
| 113 | bool $preview |
| 114 | ) { |
| 115 | $newsletterId = $newsletter && $newsletter->getId() ? $newsletter->getId() : 0; |
| 116 | $newsletterHash = $newsletter && $newsletter->getHash() ? $newsletter->getHash() : 0; |
| 117 | $sendingQueueId = $queue && $queue->getId() ? $queue->getId() : 0; |
| 118 | |
| 119 | return [ |
| 120 | $newsletterId, |
| 121 | $newsletterHash, |
| 122 | $subscriber && $subscriber->getId() ? $subscriber->getId() : 0, |
| 123 | $subscriber && $subscriber->getId() ? $this->linkTokens->getToken($subscriber) : 0, |
| 124 | $sendingQueueId, |
| 125 | (int)$preview, |
| 126 | ]; |
| 127 | } |
| 128 | |
| 129 | public function transformUrlDataObject($data) { |
| 130 | reset($data); |
| 131 | if (!is_int(key($data))) return $data; |
| 132 | $transformedData = []; |
| 133 | $transformedData['newsletter_id'] = (!empty($data[0])) ? $data[0] : false; |
| 134 | $transformedData['newsletter_hash'] = (!empty($data[1])) ? $data[1] : false; |
| 135 | $transformedData['subscriber_id'] = (!empty($data[2])) ? $data[2] : false; |
| 136 | $transformedData['subscriber_token'] = (!empty($data[3])) ? $data[3] : false; |
| 137 | $transformedData['queue_id'] = (!empty($data[4])) ? $data[4] : false; |
| 138 | $transformedData['preview'] = (!empty($data[5])) ? $data[5] : false; |
| 139 | return $transformedData; |
| 140 | } |
| 141 | } |
| 142 |