PluginProbe ʕ •ᴥ•ʔ
Presto Player / 4.3.1
Presto Player v4.3.1
4.3.1 4.3.0 4.2.4 4.2.3 4.2.2 4.2.0 4.2.1 trunk 1.10.0 1.10.1 1.10.2 1.11.0 1.12.0 1.13.0 1.14.0 1.14.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.13 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3-beta1 2.3.0 2.3.1 2.3.2 2.3.3 3.0.0 3.0.0-beta1 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.1.0 3.1.1 3.1.2 3.1.3 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4
presto-player / inc / Services / AdminNotices.php
presto-player / inc / Services Last commit date
API 1 month ago Blocks 10 months ago License 1 month ago AdminNotice.php 3 weeks ago AdminNotices.php 3 weeks ago AjaxActions.php 3 weeks ago Blocks.php 1 year ago Compatibility.php 10 months ago Learn.php 1 month ago Menu.php 1 month ago Migrations.php 1 year ago NpsSurvey.php 5 months ago Onboarding.php 3 weeks ago Player.php 3 days ago PluginInstaller.php 1 month ago PreloadService.php 1 year ago ProCompatibility.php 1 month ago ReusableVideos.php 2 weeks ago RewriteRulesManager.php 1 year ago Scripts.php 2 weeks ago Settings.php 1 month ago Shortcodes.php 1 month ago Streamer.php 3 weeks ago Translation.php 3 weeks ago Usage.php 3 weeks ago VideoPostType.php 2 weeks ago
AdminNotices.php
307 lines
1 <?php
2 /**
3 * Admin Notices.
4 *
5 * @package PrestoPlayer\Services
6 */
7
8 namespace PrestoPlayer\Services;
9
10 use BSF_Admin_Notices;
11 use PrestoPlayer\Models\Video;
12 use PrestoPlayer\Support\Utility;
13
14 /**
15 * Admin Notices.
16 */
17 class AdminNotices {
18
19 /**
20 * NPS Survey dismiss timespan constant.
21 * Survey can be dismissed for 2 weeks before showing again.
22 *
23 * @var int
24 */
25 const NPS_SURVEY_DISMISS_TIMESPAN = 2 * WEEK_IN_SECONDS;
26
27 /**
28 * Ratings notice display delay constant.
29 * Notice displays after 7 days (604800 seconds).
30 *
31 * @var int
32 */
33 const RATINGS_NOTICE_DISPLAY_DELAY = 604800; // 7 days in seconds.
34
35 /**
36 * Nonce action shared between the dismiss link generator and dismiss() handler.
37 */
38 const DISMISS_NONCE_ACTION = 'presto-dismiss-notice';
39
40 /**
41 * Exact notice keys allowed to be dismissed via ?presto_action=dismiss_notices.
42 * Pairs with DISMISSABLE_NOTICE_PREFIXES for keys with a dynamic suffix.
43 *
44 * Allowlisting prevents an attacker (or a stray link) from polluting wp_options
45 * with arbitrary `presto_player_dismissed_notice_<anything>` keys.
46 */
47 const DISMISSABLE_NOTICES = array(
48 'nginx_rules',
49 'presto_player_reusable_notice',
50 );
51
52 /**
53 * Allowed key prefixes; the suffix must match a digits-and-dots pattern (e.g. semver).
54 */
55 const DISMISSABLE_NOTICE_PREFIXES = array(
56 'player_recommended_version_',
57 );
58
59 /**
60 * Register the admin notices.
61 *
62 * @return void
63 */
64 public function register() {
65 add_action( 'admin_init', array( $this, 'dismiss' ) );
66 add_action( 'init', array( $this, 'displayRatingsNotice' ) );
67 add_action( 'admin_footer', array( $this, 'show_nps_notice' ), 999 );
68 add_action( 'admin_head', array( $this, 'suppressForeignNotices' ) );
69 }
70
71 /**
72 * Remove third-party admin notices on PP pages.
73 *
74 * Runs on admin_head (before admin_notices fires) so we can safely
75 * unset non-PP callbacks directly from $wp_filter without re-add timing issues.
76 */
77 public function suppressForeignNotices() {
78 if ( ! Utility::isPrestoPlayerPage() ) {
79 return;
80 }
81
82 global $wp_filter;
83
84 if ( ! isset( $wp_filter['admin_notices'] ) ) {
85 return;
86 }
87
88 foreach ( $wp_filter['admin_notices']->callbacks as $priority => $hooks ) {
89 foreach ( $hooks as $id => $hook ) {
90 $cb = $hook['function'];
91 $class = null;
92
93 if ( is_array( $cb ) && is_object( $cb[0] ) ) {
94 $class = get_class( $cb[0] );
95 } elseif ( is_array( $cb ) && is_string( $cb[0] ) ) {
96 $class = $cb[0];
97 }
98
99 // Keep only PrestoPlayer\ namespace callbacks; unset everything else.
100 if ( ! $class || strncmp( $class, 'PrestoPlayer\\', 13 ) !== 0 ) {
101 unset( $wp_filter['admin_notices']->callbacks[ $priority ][ $id ] );
102 }
103 }
104 }
105 }
106
107 /**
108 * Display the ratings notice.
109 *
110 * @return void
111 */
112 public function displayRatingsNotice() {
113 require_once PRESTO_PLAYER_PLUGIN_DIR . 'vendor/brainstormforce/astra-notices/class-bsf-admin-notices.php';
114 $image_path = PRESTO_PLAYER_PLUGIN_URL . 'img/presto-player-icon-color.png';
115
116 BSF_Admin_Notices::add_notice(
117 array(
118 'id' => 'presto-player-rating',
119 'type' => '',
120 'message' => sprintf(
121 '<div class="notice-image">
122 <img src="%1$s" class="custom-logo" alt="Sidebar Manager" itemprop="logo"></div>
123 <div class="notice-content">
124 <div class="notice-heading">
125 %2$s
126 </div>
127 %3$s<br />
128 <div class="astra-review-notice-container">
129 <a href="%4$s" class="astra-notice-close astra-review-notice button-primary" target="_blank">
130 %5$s
131 </a>
132 <span class="dashicons dashicons-calendar"></span>
133 <a href="#" data-repeat-notice-after="%6$s" class="astra-notice-close astra-review-notice">
134 %7$s
135 </a>
136 <span class="dashicons dashicons-smiley"></span>
137 <a href="#" class="astra-notice-close astra-review-notice">
138 %8$s
139 </a>
140 </div>
141 </div>',
142 $image_path,
143 __( 'Thanks a ton for choosing Presto Player! We are hard at work adding more features to help you harness the power of videos.', 'presto-player' ),
144 __( 'Could you please do us a BIG favor and give us a 5-star rating on WordPress? It really boosts the motivation of our team.', 'presto-player' ),
145 'https://wordpress.org/support/plugin/presto-player/reviews/',
146 __( 'Ok, you deserve it', 'presto-player' ),
147 MONTH_IN_SECONDS,
148 __( 'Nope, maybe later', 'presto-player' ),
149 __( 'I already did', 'presto-player' )
150 ),
151 'show_if' => $this->maybeDisplayRatingsNotice(),
152 'repeat-notice-after' => MONTH_IN_SECONDS,
153 'display-notice-after' => self::RATINGS_NOTICE_DISPLAY_DELAY,
154 'priority' => 18,
155 'display-with-other-notices' => false,
156 )
157 );
158 }
159
160 /**
161 * Check whether to display notice or not.
162 *
163 * @return bool
164 */
165 public function maybeDisplayRatingsNotice() {
166 $transient_status = get_transient( 'presto-player-rating' );
167
168 if ( false !== $transient_status ) {
169 return false;
170 }
171
172 $video_count = $this->getVideosCount();
173 // Display ratings notice if video count is more than 1.
174 return 0 < $video_count ? true : false;
175 }
176
177 /**
178 * Get the videos count.
179 *
180 * @return int
181 */
182 public function getVideosCount() {
183 $video = new Video();
184 $items = $video->fetch(
185 array(
186 'per_page' => 1,
187 )
188 );
189
190 return $items->total;
191 }
192
193 /**
194 * Check if the notice is dismissed.
195 *
196 * @param string $name Notice name.
197 * @return bool
198 */
199 public static function isDismissed( $name ) {
200 return (bool) get_option( 'presto_player_dismissed_notice_' . sanitize_text_field( $name ), false );
201 }
202
203 /**
204 * Dismiss the notice.
205 *
206 * @return void
207 */
208 public function dismiss() {
209 if ( ! current_user_can( 'install_plugins' ) ) {
210 return;
211 }
212
213 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- nonce verified below.
214 if ( ! isset( $_GET['presto_action'] ) || 'dismiss_notices' !== $_GET['presto_action'] ) {
215 return;
216 }
217
218 $notice = ! empty( $_GET['presto_notice'] ) ? sanitize_text_field( wp_unslash( $_GET['presto_notice'] ) ) : '';
219 if ( ! $notice || ! self::is_dismissable_notice( $notice ) ) {
220 return;
221 }
222
223 $nonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) : '';
224 // phpcs:enable WordPress.Security.NonceVerification.Recommended
225 if ( ! wp_verify_nonce( $nonce, self::DISMISS_NONCE_ACTION ) ) {
226 return;
227 }
228
229 update_option( 'presto_player_dismissed_notice_' . $notice, 1 );
230 }
231
232 /**
233 * Whether a notice key is in the allowlist of dismissable notices.
234 *
235 * @param string $notice Notice key (already sanitized).
236 * @return bool
237 */
238 private static function is_dismissable_notice( $notice ) {
239 if ( in_array( $notice, self::DISMISSABLE_NOTICES, true ) ) {
240 return true;
241 }
242 foreach ( self::DISMISSABLE_NOTICE_PREFIXES as $prefix ) {
243 if ( 0 === strncmp( $notice, $prefix, strlen( $prefix ) ) ) {
244 $suffix = substr( $notice, strlen( $prefix ) );
245 if ( '' !== $suffix && 1 === preg_match( '/^[0-9.]+$/', $suffix ) ) {
246 return true;
247 }
248 }
249 }
250 return false;
251 }
252
253 /**
254 * Render Presto Player NPS Survey notice.
255 *
256 * @return void
257 * @since 4.0.8
258 */
259 public function show_nps_notice() {
260 if ( ! class_exists( 'Nps_Survey' ) ) {
261 return;
262 }
263
264 if ( ! Utility::isPrestoPlayerPage() ) {
265 return;
266 }
267
268 // Don't load NPS at all when show_if would be false (no videos).
269 // Avoids enqueuing NPS scripts/styles and outputting the survey div.
270 if ( $this->getVideosCount() <= 0 ) {
271 return;
272 }
273
274 \Nps_Survey::show_nps_notice(
275 'nps-survey-presto-player',
276 array(
277 'show_if' => $this->getVideosCount() > 0,
278 'dismiss_timespan' => self::NPS_SURVEY_DISMISS_TIMESPAN,
279 'display_after' => 0,
280 'plugin_slug' => 'presto-player',
281 'show_on_screens' => Utility::PRESTO_PLAYER_SCREENS,
282 'message' => array(
283 // Step 1 - Rating input.
284 'logo' => esc_url( PRESTO_PLAYER_PLUGIN_URL . 'img/presto-player-icon-color.png' ),
285 'plugin_name' => __( 'Presto Player', 'presto-player' ),
286 'nps_rating_title' => __( 'Quick Question!', 'presto-player' ),
287 'nps_rating_message' => __( 'How would you rate Presto Player? Love it, hate it, or somewhere in between? Your honest answer helps us understand how we\'re doing.', 'presto-player' ),
288 'rating_min_label' => __( 'Hate it!', 'presto-player' ),
289 'rating_max_label' => __( 'Love it!', 'presto-player' ),
290
291 // Step 2A - (rating 8-10).
292 'feedback_title' => __( 'Thanks a lot for your feedback! 😍', 'presto-player' ),
293 'feedback_content' => __( 'Thanks for being part of the Presto Player community! Got feedback or suggestions? We\'d love to hear it.', 'presto-player' ),
294
295 // Step 2B - (rating 0-7).
296 'plugin_rating_title' => __( 'Thank you for your feedback', 'presto-player' ),
297 'plugin_rating_content' => __( 'We value your input. How can we improve your experience?', 'presto-player' ),
298 ),
299 'allow_review' => false,
300 'show_overlay' => false,
301 )
302 );
303
304 wp_add_inline_style( 'nps-survey-style', '[data-id="nps-survey-presto-player"] img { width: 1.3rem !important; }' );
305 }
306 }
307