PluginProbe ʕ •ᴥ•ʔ
Hustle – Email Marketing, Lead Generation, Optins, Popups / 4.7.1.1
Hustle – Email Marketing, Lead Generation, Optins, Popups v4.7.1.1
7.8.14.2 7.8.14 7.8.14.1 7.8.13 7.8.13.1 trunk 3.0 3.1 3.1.1 3.1.2 3.1.3 3.1.4 4.3.2 4.4.4 4.4.5 4.4.5.1 4.4.5.4 4.6 4.6.1.1 4.6.1.4 4.7.0.2 4.7.0.3 4.7.0.7 4.7.0.9 4.7.1.0 4.7.1.1 4.8.0.0 5.0.0 5.0.1 5.0.1.1 5.0.1.2 5.1 5.1.1 5.1.2 5.1.3 5.1.3.1 5.1.3.2 5.1.4 5.1.5 6.0 6.0.1 6.0.2 6.0.3 6.0.4.2 6.0.5 6.0.6.1 6.0.7 6.0.8.1 6.0.9 7.0.0.1 7.0.2 7.0.3 7.0.4 7.1.0 7.1.1 7.2.0 7.2.1 7.3.0 7.3.1 7.3.3 7.3.5 7.3.6 7.3.7 7.4.0 7.4.1 7.4.11 7.4.13 7.4.13.1 7.4.2 7.4.3 7.4.4 7.4.5 7.4.5.1 7.4.5.2 7.4.6 7.4.7 7.5.0 7.6.0 7.6.1 7.6.3 7.6.4 7.6.6 7.7.0 7.7.1 7.8.0 7.8.1 7.8.10 7.8.10.1 7.8.10.2 7.8.11 7.8.12 7.8.12.1 7.8.2 7.8.3 7.8.4 7.8.5 7.8.6 7.8.7 7.8.8 7.8.9 7.8.9.1 7.8.9.2 7.8.9.3
wordpress-popup / inc / external / wdev-frash / module.php
wordpress-popup / inc / external / wdev-frash Last commit date
README.md 11 years ago admin.css 11 years ago admin.js 11 years ago module.php 11 years ago
module.php
457 lines
1 <?php
2 /**
3 * WPMUDEV Frash - Free Dashboard Notification module.
4 * Used by wordpress.org hosted plugins.
5 *
6 * TODO:
7 * - Form submit handler to submit email address to getdrip.com
8 * - Show the WPMUDEV logo in left side
9 *
10 * @version 1.0.0
11 * @author Incsub (Philipp Stracker)
12 */
13 if ( ! class_exists( 'WDev_Frash' ) ) {
14 class WDev_Frash {
15
16 /**
17 * The text-domain of the module.
18 *
19 * @since 1.0.0
20 */
21 const LANG = 'wdev-frash';
22
23 /**
24 * List of all registered plugins.
25 *
26 * @since 1.0.0
27 * @var array
28 */
29 protected $plugins = array();
30
31 /**
32 * Module options that are stored in database.
33 * Timestamps are stored here.
34 *
35 * Note that this option is stored in site-meta for multisite installs.
36 *
37 * @since 1.0.0
38 * @var array
39 */
40 protected $stored = array();
41
42 /**
43 * Initializes and returns the singleton instance.
44 *
45 * @since 1.0.0
46 */
47 static public function instance() {
48 static $Inst = null;
49
50 if ( null === $Inst ) {
51 $Inst = new WDev_Frash();
52 }
53
54 return $Inst;
55 }
56
57 /**
58 * Set up the WDev_Frash module. Private singleton constructor.
59 *
60 * @since 1.0.0
61 */
62 private function __construct() {
63 $this->read_stored_data();
64
65 $this->add_action( 'wdev-register-plugin', 5 );
66 $this->add_action( 'load-index.php' );
67
68 $this->add_action( 'wp_ajax_frash_act' );
69 $this->add_action( 'wp_ajax_frash_dismiss' );
70 }
71
72 /**
73 * Load persistent module-data from the WP Database.
74 *
75 * @since 1.0.0
76 */
77 protected function read_stored_data() {
78 $data = get_site_option( 'wdev-frash', false, false );
79
80 if ( ! is_array( $data ) ) {
81 $data = array();
82 }
83
84 // A list of all plugins with timestamp of first registration.
85 if ( ! isset( $data['plugins'] ) || ! is_array( $data['plugins'] ) ) {
86 $data['plugins'] = array();
87 }
88
89 // A list with pending messages and earliest timestamp for display.
90 if ( ! isset( $data['queue'] ) || ! is_array( $data['queue'] ) ) {
91 $data['queue'] = array();
92 }
93
94 // A list with all messages that were handles already.
95 if ( ! isset( $data['done'] ) || ! is_array( $data['done'] ) ) {
96 $data['done'] = array();
97 }
98
99 $this->stored = $data;
100 }
101
102 /**
103 * Save persistent module-data to the WP database.
104 *
105 * @since 1.0.0
106 */
107 protected function store_data() {
108 update_site_option( 'wdev-frash', $this->stored );
109 }
110
111 /**
112 * Action handler for 'wdev-register-plugin'
113 * Register an active plugin.
114 *
115 * @since 1.0.0
116 * @param string $plugin_id WordPress plugin-ID (see: plugin_basename).
117 * @param string $title Plugin name for display.
118 * @param string $url_wp URL to the plugin on wp.org (domain not needed)
119 * @param string $cta_email Title of the Email CTA button.
120 * @param string $drip_plugin Optional. Plugin-param for the getdrip rule.
121 */
122 public function wdev_register_plugin( $plugin_id, $title, $url_wp, $cta_email = '', $drip_plugin = '' ) {
123 // Ignore incorrectly registered plugins to avoid errors later.
124 if ( empty( $plugin_id ) ) { return; }
125 if ( empty( $title ) ) { return; }
126 if ( empty( $url_wp ) ) { return; }
127
128 if ( false === strpos( $url_wp, '://' ) ) {
129 $url_wp = 'https://wordpress.org/' . trim( $url_wp, '/' );
130 }
131
132 $this->plugins[$plugin_id] = (object) array(
133 'title' => $title,
134 'url_wp' => $url_wp,
135 'cta_email' => $cta_email,
136 'drip_plugin' => $drip_plugin,
137 );
138
139 /*
140 * When the plugin is registered the first time we store some infos
141 * in the persistent module-data that help us later to find out
142 * if/which message should be displayed.
143 */
144 if ( empty( $this->stored['plugins'][$plugin_id] ) ) {
145 // First register the plugin permanently.
146 $this->stored['plugins'][$plugin_id] = time();
147
148 // Second schedule the messages to display.
149 $hash = md5( $plugin_id . '-email' );
150 $this->stored['queue'][$hash] = array(
151 'plugin' => $plugin_id,
152 'type' => 'email',
153 'show_at' => time(), // Earliest time to display note.
154 );
155
156 $hash = md5( $plugin_id . '-rate' );
157 $this->stored['queue'][$hash] = array(
158 'plugin' => $plugin_id,
159 'type' => 'rate',
160 'show_at' => time() + 7 * DAY_IN_SECONDS,
161 );
162
163 // Finally save the details.
164 $this->store_data();
165 }
166 }
167
168 /**
169 * Ajax handler called when the user chooses the CTA button.
170 *
171 * @since 1.0.0
172 */
173 public function wp_ajax_frash_act() {
174 $plugin = $_POST['plugin_id'];
175 $type = $_POST['type'];
176
177 $this->mark_as_done( $plugin, $type, 'ok' );
178
179 echo 1;
180 exit;
181 }
182
183 /**
184 * Ajax handler called when the user chooses the dismiss button.
185 *
186 * @since 1.0.0
187 */
188 public function wp_ajax_frash_dismiss() {
189 $plugin = $_POST['plugin_id'];
190 $type = $_POST['type'];
191
192 $this->mark_as_done( $plugin, $type, 'ignore' );
193
194 echo 1;
195 exit;
196 }
197
198 /**
199 * Action handler for 'load-index.php'
200 * Set-up the Dashboard notification.
201 *
202 * @since 1.0.0
203 */
204 public function load_index_php() {
205 if ( is_super_admin() ) {
206 $this->add_action( 'all_admin_notices' );
207 }
208 }
209
210 /**
211 * Action handler for 'admin_notices'
212 * Display the Dashboard notification.
213 *
214 * @since 1.0.0
215 */
216 public function all_admin_notices() {
217 $info = $this->choose_message();
218 if ( ! $info ) { return; }
219
220 $this->render_message( $info );
221 }
222
223 /**
224 * Check to see if there is a pending message to display and returns
225 * the message details if there is.
226 *
227 * Note that this function is only called on the main Dashboard screen
228 * and only when logged in as super-admin.
229 *
230 * @since 1.0.0
231 * @return object|false
232 * string $type [rate|email] Which message type?
233 * string $plugin WordPress plugin ID?
234 */
235 protected function choose_message() {
236 $obj = false;
237 $chosen = false;
238 $earliest = false;
239
240 $now = time();
241
242 // The "current" time can be changed via $_GET to test the module.
243 if ( defined( 'WP_DEBUG' ) && WP_DEBUG && ! empty( $_GET['time'] ) ) {
244 $custom_time = $_GET['time'];
245 if ( ' ' == $custom_time[0] ) { $custom_time[0] = '+'; }
246 if ( $custom_time ) { $now = strtotime( $custom_time ); }
247 if ( ! $now ) { $now = time(); }
248 }
249
250 $tomorrow = $now + DAY_IN_SECONDS;
251
252 foreach ( $this->stored['queue'] as $hash => $item ) {
253 $show_at = intval( $item['show_at'] );
254 $is_sticky = ! empty( $item['sticky'] );
255
256 if ( ! isset( $this->plugins[ $item['plugin'] ] ) ) {
257 // Deactivated plugin before the message was displayed.
258 continue;
259 }
260 $plugin = $this->plugins[ $item['plugin'] ];
261
262 $can_display = true;
263 if ( wp_is_mobile() ) {
264 // Do not display rating message on mobile devices.
265 if ( 'rate' == $item['type'] ) {
266 $can_display = false;
267 }
268 }
269 if ( 'email' == $item['type'] ) {
270 if ( ! $plugin->drip_plugin || ! $plugin->cta_email ) {
271 // Do not display email message with missing email params.
272 $can_display = false;
273 }
274 }
275 if ( $now < $show_at ) {
276 // Do not display messages that are not due yet.
277 $can_display = false;
278 }
279
280 if ( ! $can_display ) { continue; }
281
282 if ( $is_sticky ) {
283 // If sticky item is present then choose it!
284 $chosen = $hash;
285 break;
286 } elseif ( ! $earliest || $earliest < $show_at ) {
287 $earliest = $show_at;
288 $chosen = $hash;
289 // Don't use `break` because a sticky item might follow...
290 // Find the item with the earliest schedule.
291 }
292 }
293
294 if ( $chosen ) {
295 // Make the chosen item sticky.
296 $this->stored['queue'][$chosen]['sticky'] = true;
297
298 // Re-schedule other messages that are due today.
299 foreach ( $this->stored['queue'] as $hash => $item ) {
300 $show_at = intval( $item['show_at'] );
301
302 if ( empty( $item['sticky'] ) && $tomorrow > $show_at ) {
303 $this->stored['queue'][$hash]['show_at'] = $tomorrow;
304 }
305 }
306
307 // Save the changes.
308 $this->store_data();
309
310 $obj = (object) $this->stored['queue'][$chosen];
311 }
312
313 return $obj;
314 }
315
316 /**
317 * Moves a message from the queue to the done list.
318 *
319 * @since 1.0.0
320 * @param string $plugin Plugin ID.
321 * @param string $type [rate|email] Message type.
322 * @param string $state [ok|ignore] Button clicked.
323 */
324 protected function mark_as_done( $plugin, $type, $state ) {
325 $done_item = false;
326
327 foreach ( $this->stored['queue'] as $hash => $item ) {
328 unset( $this->stored['queue'][$hash]['sticky'] );
329
330 if ( $item['plugin'] == $plugin && $item['type'] == $type ) {
331 $done_item = $item;
332 unset( $this->stored['queue'][$hash] );
333 }
334 }
335
336 if ( $done_item ) {
337 $done_item['state'] = $state;
338 $done_item['hash'] = $hash;
339 $done_item['handled_at'] = time();
340 unset( $done_item['sticky'] );
341
342 $this->stored['done'][] = $done_item;
343 $this->store_data();
344 }
345 }
346
347 /**
348 * Renders the actual Notification message.
349 *
350 * @since 1.0.0
351 */
352 protected function render_message( $info ) {
353 $plugin = $this->plugins[$info->plugin];
354 $css_url = plugin_dir_url( __FILE__ ) . '/admin.css';
355 $js_url = plugin_dir_url( __FILE__ ) . '/admin.js';
356
357 ?>
358 <link rel="stylesheet" type="text/css" href="<?php echo esc_url( $css_url ); ?>" />
359 <div class="notice frash-notice frash-notice-<?php echo esc_attr( $info->type ); ?>" style="display:none">
360 <input type="hidden" name="type" value="<?php echo esc_attr( $info->type ); ?>" />
361 <input type="hidden" name="plugin_id" value="<?php echo esc_attr( $info->plugin ); ?>" />
362 <input type="hidden" name="url_wp" value="<?php echo esc_attr( $plugin->url_wp ); ?>" />
363 <input type="hidden" name="drip_plugin" value="<?php echo esc_attr( $plugin->drip_plugin ); ?>" />
364 <?php
365 if ( 'email' == $info->type ) {
366 $this->render_email_message( $plugin );
367 } elseif ( 'rate' == $info->type ) {
368 $this->render_rate_message( $plugin );
369 }
370 ?>
371 </div>
372 <script src="<?php echo esc_url( $js_url ); ?>"></script>
373 <?php
374 }
375
376 /**
377 * Output the contents of the email message.
378 * No return value. The code is directly output.
379 *
380 * @since 1.0.0
381 */
382 protected function render_email_message( $plugin ) {
383 $admin_email = get_site_option( 'admin_email' );
384 ?>
385 <div class="frash-notice-logo"><span></span></div>
386 <div class="frash-notice-message">
387 <?php
388 printf(
389 __( "We're happy that you've chosen to install %s! Are you interested in how to make the most of this plugin? How would you like a quick 5 day email crash course with actionable advice on building your membership site? Only the info you want, no subscription!", self::LANG ),
390 '<strong>' . $plugin->title . '</strong>'
391 );
392 ?>
393 </div>
394 <div class="frash-notice-cta">
395 <input type="email" name="email" value="<?php echo esc_attr( $admin_email ); ?>" />
396 <button class="frash-notice-act button-primary" data-msg="<?php _e( 'Thanks :)', self::LANG ); ?>">
397 <?php echo esc_html( $plugin->cta_email ); ?>
398 </button>
399 <button class="frash-notice-dismiss" data-msg="<?php _e( 'Saving', self::LANG ); ?>">
400 <?php _e( 'No thanks', self::LANG ); ?>
401 </button>
402 </div>
403 <?php
404 }
405
406 /**
407 * Output the contents of the rate-this-plugin message.
408 * No return value. The code is directly output.
409 *
410 * @since 1.0.0
411 */
412 protected function render_rate_message( $plugin ) {
413 $user = wp_get_current_user();
414 $user_name = $user->display_name;
415 ?>
416 <div class="frash-notice-logo"><span></span></div>
417 <div class="frash-notice-message">
418 <?php
419 printf(
420 __( "Hey %s, you've been using %s for a while now, and we hope you're happy with it.<br />We've spent countless hours developing this free plugin for you, and we would really appreciate it if you dropped us a quick rating!", self::LANG ),
421 '<strong>' . $user_name . '</strong>',
422 '<strong>' . $plugin->title . '</strong>'
423 );
424 ?>
425 </div>
426 <div class="frash-notice-cta">
427 <button class="frash-notice-act button-primary" data-msg="<?php _e( 'Thanks :)', self::LANG ); ?>">
428 <?php
429 printf(
430 __( 'Rate %s', self::LANG ),
431 esc_html( $plugin->title )
432 ); ?>
433 </button>
434 <button class="frash-notice-dismiss" data-msg="<?php _e( 'Saving', self::LANG ); ?>">
435 <?php _e( 'No thanks', self::LANG ); ?>
436 </button>
437 </div>
438 <?php
439 }
440
441 /**
442 * Registers a new action handler. The callback function has the same
443 * name as the action hook.
444 *
445 * @since 1.0.0
446 */
447 protected function add_action( $hook, $params = 1 ) {
448 $method_name = strtolower( $hook );
449 $method_name = preg_replace( '/[^a-z0-9]/', '_', $method_name );
450 $handler = array( $this, $method_name );
451 add_action( $hook, $handler, 5, $params );
452 }
453 }
454
455 // Initialize the module.
456 WDev_Frash::instance();
457 }