PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / src / introductions / application / delayed-premium-upsell.php

delayed-premium-upsell.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI trunk, at src/introductions/application/delayed-premium-upsell.php

165 lines 4.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Yoast\WP\SEO\Introductions\Application;
4
5 use Yoast\WP\SEO\Helpers\Current_Page_Helper;
6 use Yoast\WP\SEO\Helpers\Options_Helper;
7 use Yoast\WP\SEO\Helpers\Product_Helper;
8 use Yoast\WP\SEO\Introductions\Domain\Introduction_Interface;
9 use Yoast\WP\SEO\Introductions\Infrastructure\Introductions_Seen_Repository;
10
11 /**
12 * Represents the Premium upsell that shows on Yoast SEO pages after a delay.
13 */
14 class Delayed_Premium_Upsell implements Introduction_Interface {
15
16 public const ID = 'delayed-premium-upsell';
17 public const DELAY_DAYS = 14;
18
19 /**
20 * Holds the repository.
21 *
22 * @var Introductions_Seen_Repository
23 */
24 private $introductions_seen_repository;
25
26 /**
27 * Holds the product helper.
28 *
29 * @var Product_Helper
30 */
31 private $product_helper;
32
33 /**
34 * Holds the current page helper.
35 *
36 * @var Current_Page_Helper
37 */
38 private $current_page_helper;
39
40 /**
41 * The options helper.
42 *
43 * @var Options_Helper
44 */
45 private $options_helper;
46
47 /**
48 * Delayed_Premium_Upsell constructor.
49 *
50 * @param Current_Page_Helper $current_page_helper The current page helper.
51 * @param Introductions_Seen_Repository $introductions_seen_repository The introductions seen repository.
52 * @param Options_Helper $options_helper The options helper.
53 * @param Product_Helper $product_helper The product helper.
54 */
55 public function __construct( Current_Page_Helper $current_page_helper, Introductions_Seen_Repository $introductions_seen_repository, Options_Helper $options_helper, Product_Helper $product_helper ) {
56 $this->current_page_helper = $current_page_helper;
57 $this->introductions_seen_repository = $introductions_seen_repository;
58 $this->options_helper = $options_helper;
59 $this->product_helper = $product_helper;
60 }
61
62 /**
63 * Returns the ID.
64 *
65 * @return string The ID.
66 */
67 public function get_id(): string {
68 return self::ID;
69 }
70
71 /**
72 * Returns the requested pagination priority. Lower means earlier.
73 *
74 * @return int The priority.
75 */
76 public function get_priority(): int {
77 return 30;
78 }
79
80 /**
81 * Returns whether this introduction should show.
82 *
83 * @return bool Whether this introduction should show.
84 */
85 public function should_show(): bool {
86 // Never show when not on a Yoast SEO page or when the user has Premium activated.
87 if ( ! $this->current_page_helper->is_yoast_seo_page() || $this->product_helper->is_premium() ) {
88 return false;
89 }
90
91 return $this->should_show_after_delay();
92 }
93
94 /**
95 * Determines if the introduction should show based on the self:DELAY_DAY delay from installation or update.
96 *
97 * @return bool Whether the introduction should show after the delay.
98 */
99 private function should_show_after_delay(): bool {
100 $delay = ( self::DELAY_DAYS * \DAY_IN_SECONDS );
101 $current_time = \time();
102 $previous_version = $this->options_helper->get( 'previous_version' );
103 $first_activated_on = $this->options_helper->get( 'first_activated_on' );
104
105 // Case where the user has installed the plugin for the first time and the delay has passed.
106 if ( $previous_version === '' ) {
107 return ( $current_time - $first_activated_on ) >= $delay && $this->is_last_introduction_seen_older_than_a_week();
108 }
109
110 // Case where the user has updated the plugin and the delay has passed since the last update.
111 $last_updated_on = $this->options_helper->get( 'last_updated_on' );
112
113 $uniform_last_updated_on = \is_int( $last_updated_on ) ? $last_updated_on : 0;
114 if ( ( $current_time - $uniform_last_updated_on ) >= $delay ) {
115 return $this->is_last_introduction_seen_older_than_a_week();
116 }
117
118 return false;
119 }
120
121 /**
122 * Checks if the last introduction seen is older than a week.
123 *
124 * @return bool True if the last introduction seen is older than a week, false otherwise.
125 */
126 private function is_last_introduction_seen_older_than_a_week(): bool {
127 $seen_introductions = $this->introductions_seen_repository->get_all_introductions( \get_current_user_id() );
128 // No other introduction has been seen.
129 if ( empty( $seen_introductions ) ) {
130 return true;
131 }
132
133 $old_format_introductions = \array_filter(
134 $seen_introductions,
135 static function ( $item ) {
136 return \is_bool( $item );
137 },
138 );
139
140 if ( ! empty( $old_format_introductions ) ) {
141 // There are introductions in the old format, so we cannot determine when they were seen.
142 // To be safe, we assume the user has seen an introduction recently.
143 return false;
144 }
145
146 // Find the most recent introduction seen.
147 $most_recent_introduction = \array_reduce(
148 $seen_introductions,
149 static function ( $carry, $item ) {
150 if ( $carry === null || $item['seen_on'] > $carry['seen_on'] ) {
151 return $item;
152 }
153 return $carry;
154 },
155 );
156
157 // If the most recent introduction seen is older than a week, return true.
158 if ( ( \time() - $most_recent_introduction['seen_on'] ) >= ( 7 * \DAY_IN_SECONDS ) ) {
159 return true;
160 }
161
162 return false;
163 }
164 }
165