• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / aaea12fe12c7195d02e0f7ea5fe67d379d3e3227

12 Sep 2025 10:36AM UTC coverage: 41.602%. First build
aaea12fe12c7195d02e0f7ea5fe67d379d3e3227

Pull #22551

github

web-flow
Merge 67ccafc8d into 166ff8a05
Pull Request #22551: Add delayed premium upsell

2370 of 9166 branches covered (25.86%)

Branch coverage included in aggregate %.

15 of 89 new or added lines in 10 files covered. (16.85%)

22173 of 49829 relevant lines covered (44.5%)

4.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/introductions/application/delayed-premium-upsell.php
1
<?php
2

3

4
namespace Yoast\WP\SEO\Introductions\Application;
5

6
use Yoast\WP\SEO\Helpers\Current_Page_Helper;
7
use Yoast\WP\SEO\Helpers\Options_Helper;
8
use Yoast\WP\SEO\Helpers\Product_Helper;
9
use Yoast\WP\SEO\Introductions\Domain\Introduction_Interface;
10
use Yoast\WP\SEO\Introductions\Infrastructure\Introductions_Seen_Repository;
11

12
/**
13
 * Represents the Premium upsell that shows on Yoast SEO pages after a delay.
14
 */
15
class Delayed_Premium_Upsell implements Introduction_Interface {
16

17
        public const ID         = 'delayed-premium-upsell';
18
        public const DELAY_DAYS = 14;
19

20
        /**
21
         * Holds the repository.
22
         *
23
         * @var Introductions_Seen_Repository
24
         */
25
        private $introductions_seen_repository;
26

27
        /**
28
         * Holds the product helper.
29
         *
30
         * @var Product_Helper
31
         */
32
        private $product_helper;
33

34
        /**
35
         * Holds the current page helper.
36
         *
37
         * @var Current_Page_Helper
38
         */
39
        private $current_page_helper;
40

41
        /**
42
         * The options helper.
43
         *
44
         * @var Options_Helper
45
         */
46
        private $options_helper;
47

48
        /**
49
         * Delayed_Premium_Upsell constructor.
50
         *
51
         * @param Current_Page_Helper           $current_page_helper           The current page helper.
52
         * @param Introductions_Seen_Repository $introductions_seen_repository The introductions seen repository.
53
         * @param Options_Helper                $options_helper                The options helper.
54
         * @param Product_Helper                $product_helper                The product helper.
55
         */
NEW
56
        public function __construct( Current_Page_Helper $current_page_helper, Introductions_Seen_Repository $introductions_seen_repository, Options_Helper $options_helper, Product_Helper $product_helper ) {
×
NEW
57
                $this->current_page_helper           = $current_page_helper;
×
NEW
58
                $this->introductions_seen_repository = $introductions_seen_repository;
×
NEW
59
                $this->options_helper                = $options_helper;
×
NEW
60
                $this->product_helper                = $product_helper;
×
61
        }
62

63
        /**
64
         * Returns the ID.
65
         *
66
         * @return string The ID.
67
         */
NEW
68
        public function get_id(): string {
×
NEW
69
                return self::ID;
×
70
        }
71

72
        /**
73
         * Returns the name of the introduction.
74
         *
75
         * @return string The name.
76
         */
NEW
77
        public function get_name(): string {
×
NEW
78
                \_deprecated_function( __METHOD__, 'Yoast SEO Premium 21.6', 'Please use get_id() instead' );
×
79

NEW
80
                return self::ID;
×
81
        }
82

83
        /**
84
         * Returns the requested pagination priority. Lower means earlier.
85
         *
86
         * @return int The priority.
87
         */
NEW
88
        public function get_priority(): int {
×
NEW
89
                return 30;
×
90
        }
91

92
        /**
93
         * Returns whether this introduction should show.
94
         *
95
         * @return bool Whether this introduction should show.
96
         */
NEW
97
        public function should_show(): bool {
×
98
                // Never show when not on a Yoast SEO page or when the user has Premium activated.
NEW
99
                if ( ! $this->current_page_helper->is_yoast_seo_page() || $this->product_helper->is_premium() ) {
×
NEW
100
                        return false;
×
101
                }
102

NEW
103
                return $this->should_show_after_delay();
×
104
        }
105

106
        /**
107
         * Determines if the introduction should show based on the self:DELAY_DAY delay from installation or update.
108
         *
109
         * @return bool Whether the introduction should show after the delay.
110
         */
NEW
111
        private function should_show_after_delay(): bool {
×
NEW
112
                $delay              = ( self::DELAY_DAYS * \DAY_IN_SECONDS );
×
NEW
113
                $current_time       = \time();
×
NEW
114
                $previous_version   = $this->options_helper->get( 'previous_version' );
×
NEW
115
                $first_activated_on = $this->options_helper->get( 'first_activated_on' );
×
116

117
                // Case where the user has installed the plugin for the first time and the delay has passed.
NEW
118
                if ( $previous_version === '' ) {
×
NEW
119
                        return ( $current_time - $first_activated_on ) >= $delay && $this->is_last_introduction_seen_older_than_a_week();
×
120
                }
121

122
                // Case where the user has updated the plugin and the delay has passed since the last update.
NEW
123
                $last_updated_on = $this->options_helper->get( 'last_updated_on' );
×
124

NEW
125
                $uniform_last_updated_on = \is_int( $last_updated_on ) ? $last_updated_on : 0;
×
NEW
126
                if ( ( $current_time - $uniform_last_updated_on ) >= $delay ) {
×
NEW
127
                        return $this->is_last_introduction_seen_older_than_a_week();
×
128
                }
129

NEW
130
                return false;
×
131
        }
132

133
        /**
134
         * Checks if the last introduction seen is older than a week.
135
         *
136
         * @return bool True if the last introduction seen is older than a week, false otherwise.
137
         */
NEW
138
        private function is_last_introduction_seen_older_than_a_week(): bool {
×
NEW
139
                $seen_introductions = $this->introductions_seen_repository->get_all_introductions( \get_current_user_id() );
×
140
                // No other introduction has been seen.
NEW
141
                if ( empty( $seen_introductions ) ) {
×
NEW
142
                        return true;
×
143
                }
144

NEW
145
                $old_format_introductions = \array_filter(
×
NEW
146
                        $seen_introductions,
×
NEW
147
                        static function ( $item ) {
×
NEW
148
                                return \is_bool( $item );
×
NEW
149
                        }
×
NEW
150
                );
×
151

152
                if ( ! empty( $old_format_introductions ) ) {
153
                        // There are introductions in the old format, so we cannot determine when they were seen.
154
                        // To be safe, we assume the user has seen an introduction recently.
155
                        return false;
156
                }
157

158
                // Find the most recent introduction seen.
NEW
159
                $most_recent_introduction = \array_reduce(
×
NEW
160
                        $seen_introductions,
×
NEW
161
                        static function ( $carry, $item ) {
×
162
                                if ( $carry === null || $item['seen_on'] > $carry['seen_on'] ) {
NEW
163
                                        return $item;
×
164
                                }
165
                                return $carry;
NEW
166
                        }
×
NEW
167
                );
×
168

169
                // If the most recent introduction seen is older than a week, return true.
170
                if ( ( \time() - $most_recent_introduction['seen_on'] ) >= ( 7 * \DAY_IN_SECONDS ) ) {
171
                        return true;
172
                }
173

NEW
174
                return false;
×
175
        }
176
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc