PluginProbe
HurryTimer – An Scarcity and Urgency Countdown Timer for WordPress & WooCommerce / 2.2.16
HurryTimer – An Scarcity and Urgency Countdown Timer for WordPress & WooCommerce v2.2.16
2.15.0 trunk 1.0.0 1.0.1 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.1.2 2.1.3 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 All 62 releases
← All changes | includes/Frontend.php +163 -188 trunk2.2.16 View file →
@@ -1,8 +1,10 @@
1 1 <?php
2 2
3 3 namespace Hurrytimer;
4 4
5 +use Hurrytimer\Utils\Helpers;
6 +
5 7 /**
6 8 * The public-facing functionality of the plugin.
7 9 *
8 10 * @link http://nabillemsieh.com
@@ -10,9 +12,21 @@
10 12 *
11 13 * @package Hurrytimer
12 14 * @subpackage Hurrytimer/public
13 15 */
14 -class Frontend {
16 +
17 +/**
18 + * The public-facing functionality of the plugin.
19 + *
20 + * Defines the plugin name, version, and two examples hooks for how to
21 + * enqueue the public-facing stylesheet and JavaScript.
22 + *
23 + * @package Hurrytimer
24 + * @subpackage Hurrytimer/public
25 + * @author Nabil Lemsieh <contact@nabillemsieh.com>
26 + */
27 +class Frontend
28 +{
15 29 /**
16 30 * The ID of this plugin.
17 31 *
18 32 * @since 1.0.0
@@ -33,172 +47,153 @@
33 47 /**
34 48 * Initialize the class and set its properties.
35 49 *
36 50 * @param string $plugin_name The name of the plugin.
37 - * @param string $version The version of this plugin.
51 + * @param string $version The version of this plugin.
38 52 *
39 53 * @since 1.0.0
40 54 *
41 55 */
42 - public function __construct($plugin_name, $version) {
56 + public function __construct( $plugin_name, $version )
57 + {
43 58 $this->plugin_name = $plugin_name;
44 59 $this->version = $version;
45 - }
60 + $shortcode = new CampaignShortcode();
61 + add_shortcode( 'hurrytimer', [ $shortcode, 'content' ] );
62 + add_action( 'wp_footer', [ $this, 'maybeDisplayStickyBar' ] );
63 + add_action( 'wp', [ $this, 'handleWCSingleProduct' ] );
64 + add_action( 'wp', [ $this, 'handle_actions' ] );
65 + add_action( 'wp_ajax_action_change_stock_status', [ $this, 'ajaxChangeStockStatus' ] );
66 + add_action( 'wp_ajax_nopriv_action_change_stock_status',
67 + [ $this, 'ajaxChangeStockStatus' ] );
68 + add_action( 'wp_ajax_set_timestamp', [ $this, 'bypassEvergreenDetectCookieCache' ] );
69 + add_action( 'wp_ajax_nopriv_set_timestamp', [ $this, 'bypassEvergreenDetectCookieCache' ] );
46 70
47 - function init() {
48 -
49 - // Enqueue CSS and JS.
50 - add_action('wp_enqueue_scripts', [$this, 'enqueue_styles']);
51 - add_action('wp_enqueue_scripts', [$this, 'enqueue_scripts']);
52 -
53 - // Display campaign in sticky bar.
54 - add_action('wp_footer', [$this, 'render_sticky_bar']);
55 - add_action('wp_footer', [$this, 'run_in_background']);
56 -
57 - // Display campaign on product page.
58 - add_action('wp', [$this, 'render_on_product_page']);
59 -
60 - // Log evergreen campaign start time for each visitor.
61 - add_action('wp_ajax_hurryt/update_timestamp', [$this, 'ajax_save_evergreen_start_time']);
62 - add_action('wp_ajax_nopriv_hurryt/update_timestamp', [$this, 'ajax_save_evergreen_start_time']);
63 -
64 - // Return next recurrence.
65 - add_action('wp_ajax_next_recurrence', [$this, 'ajax_next_recurrence']);
66 - add_action('wp_ajax_nopriv_next_recurrence', [$this, 'ajax_next_recurrence']);
67 -
68 - // Check before rendering campaign.
69 - add_action('hurryt_pre_render', [$this, 'pre_render_shortcode']);
70 -
71 - // Check actions for expired recurring and onetime campaigns
72 - // This only concerns shortcodes inserted in post editor.
73 - // Fallback to shortcode callback
74 - add_action('wp', [$this, 'check_post_shortcode']);
71 + add_action( 'wp_ajax_next_recurrence', [ $this, 'getNextRecurrence' ] );
72 + add_action( 'wp_ajax_nopriv_next_recurrence', [ $this, 'getNextRecurrence' ] );
75 73 }
76 74
77 - function run_in_background() {
75 + public function handle_actions()
76 + {
77 + ob_start();
78 + global $post;
79 + $pattern = get_shortcode_regex();
80 + $tag = 'hurrytimer';
81 + $ids = [];
82 + if ( ! is_admin() && $post
83 + && preg_match_all( '/' . $pattern . '/s', $post->post_content, $matches )
84 + && array_key_exists( 2, $matches )
85 + && in_array( $tag, $matches[ 2 ] )
86 + ) {
87 + foreach ( (array)$matches[ 2 ] as $key => $value ) {
88 + if ( $tag === $value ) {
89 + $ids[] = shortcode_parse_atts( $matches[ 3 ][ $key ] );
90 + }
91 + }
92 + $ids = array_map( function ( $id ) {
93 + return isset( $id[ 'id' ] ) ? $id[ 'id' ] : null;
94 + }, $ids );
95 + $ids = array_filter( $ids );
96 + $redirect = false;
97 + foreach ( $ids as $id ) {
98 + $campaign = new Campaign( $id );
99 + $isOneTimeCampaignExpired = $campaign->isRegular() && $campaign->isExpired();
100 + $isRecurringCampaignExpired = $campaign->isRecurring()
101 + && $campaign->isRecurringExpired();
78 102
79 - // At this time, all campagins with the "Expire coupon" action
80 - // should run in background.
81 - $campaigns = get_posts([
82 - 'post_type' => HURRYT_POST_TYPE,
83 - 'numberposts' => -1,
84 - 'post_status' => 'publish',
85 - ]);
86 -
87 - foreach ($campaigns as $campaign) {
88 - $campaign = new Campaign($campaign->ID);
89 -
90 - $campaign->loadSettings();
91 - $action_expire_coupon = $campaign->get_action(C::ACTION_EXPIRE_COUPON);
92 - // $action_hide_atc_button = $campaign->get_action(C::ACTION_HIDE_ADD_TO_CART_BUTTON);
93 -
94 - $run_in_background = !empty($action_expire_coupon);
95 - if ($run_in_background) {
96 - echo do_shortcode('[hurrytimer id=' . $campaign->get_id() . ' run_in_background=true]');
103 + if ( $isRecurringCampaignExpired || $isOneTimeCampaignExpired ) {
104 + foreach ( $campaign->actions as $action ) {
105 + if ( $action[ 'id' ] === C::ACTION_REDIRECT ) {
106 + $redirect = true;
107 + break;
108 + }
109 + }
110 + }
111 + if ( $redirect ) {
112 + break;
113 + }
97 114 }
98 - }
99 - }
100 115
101 - /**
102 - * Check if there is shortcode in the current post.
103 - */
104 - function check_post_shortcode() {
105 - global $post;
106 - if (
107 - is_singular() && is_a($post, 'WP_Post')
108 - && has_shortcode($post->post_content, 'hurrytimer') && !(defined('DOING_AJAX') && DOING_AJAX)
109 - ) {
110 - $campaigns_ids = hurryt_parse_campaigns($post->post_content);
111 - foreach ($campaigns_ids as $id) {
112 - do_action('hurryt_pre_render', hurryt_get_campaign($id));
116 + if ( $redirect ) {
117 + wp_redirect( $action[ 'redirectUrl' ] );
118 + exit;
113 119 }
114 120 }
115 - }
116 121
117 - /**
118 - * @param $campaign Campaign
119 - */
120 - function pre_render_shortcode($campaign) {
121 - if ($campaign->is_running() && $campaign->is_expired()) {
122 - (new ActionManager($campaign))->run();
123 - }
124 122 }
125 123
126 -
127 - public function ajax_next_recurrence() {
128 - check_ajax_referer('hurryt', 'nonce');
129 - $campaign_id = absint($_GET['id']);
130 - if (
131 - !get_post($campaign_id)
132 - || get_post_type($campaign_id) !== HURRYT_POST_TYPE
133 - ) {
134 - die(-1);
124 + public function getNextRecurrence()
125 + {
126 + check_ajax_referer( 'hurryt', 'nonce' );
127 + $campaign_id = absint( $_GET[ 'id' ] );
128 + if ( ! get_post( $campaign_id ) || get_post_type( $campaign_id ) !== HURRYT_POST_TYPE ) {
129 + die( -1 );
135 130 }
136 131
137 - $campaign = new Campaign($campaign_id);
138 - $endDate = $campaign->getRecurrenceEndDate();
139 -
140 - wp_send_json_success([
132 + $campaign = new Campaign( $campaign_id );
133 + $endDate = $campaign->getRecurringDeadline();
134 + wp_send_json_success( [
141 135 'endTimestamp' => $endDate ? $endDate->getBrowserTimestamp() : null,
142 - ]);
136 + ] );
143 137 }
144 138
145 - /**
146 - * Uses ajax to save start time for the given visitor.
147 - * This used to bypass cookie cache.
148 - */
149 - public function ajax_save_evergreen_start_time() {
150 - check_ajax_referer('hurryt', 'nonce');
151 - if (!isset($_POST['timestamp']) || !isset($_POST['cid'])) {
139 + public function bypassEvergreenDetectCookieCache()
140 + {
141 + check_ajax_referer( 'hurryt', 'nonce' );
142 + if ( ! isset( $_POST[ 'timestamp' ] ) || ! isset( $_POST[ 'cid' ] ) ) {
152 143 wp_die();
153 144 }
154 -
155 - $cid = intval($_POST['cid']);
156 - $timestamp = filter_input(INPUT_POST, 'timestamp', FILTER_VALIDATE_INT);
157 -
158 - if (!$cid || $timestamp === false || $timestamp === null) {
159 - wp_die();
160 - }
161 -
162 - // Verify the campaign exists and is of the correct type.
163 - if (!get_post($cid) || get_post_type($cid) !== HURRYT_POST_TYPE) {
164 - wp_die();
165 - }
166 -
167 - $evergreen_campaign = new EvergreenCampaign($cid);
168 - $evergreen_campaign->setEndDate($timestamp);
169 - wp_die('Success!');
145 + $ipDetection = new IPDetection();
146 + $cookieDetection = new CookieDetection();
147 + $evergreenCampaign = new EvergreenCampaign( intval( $_POST[ 'cid' ] ), $cookieDetection,
148 + $ipDetection );
149 + $evergreenCampaign->setEndDate( filter_input( INPUT_POST, 'timestamp' ) );
150 + wp_die();
170 151 }
171 152
172 - public function render_sticky_bar() {
173 - $args = [
153 + public function maybeDisplayStickyBar()
154 + {
155 + $stickyCampaigns = $posts = get_posts( [
174 156 'post_type' => HURRYT_POST_TYPE,
175 157 'numberposts' => -1,
176 158 'post_status' => 'publish',
177 159 'meta_key' => 'enable_sticky',
178 160 'meta_value' => C::YES,
179 - ];
180 -
181 - if(defined( 'ICL_SITEPRESS_VERSION' )){
182 - $args['suppress_filters'] = false;
161 + 'suppress_filters' => false,
162 + ] );
163 + foreach ( $stickyCampaigns as $post ) {
164 + echo do_shortcode( '[hurrytimer id="' . $post->ID . '"]' );
183 165 }
184 -
185 - $campaigns = get_posts($args);
186 166
187 - foreach ($campaigns as $post) {
188 - echo do_shortcode(sprintf('[hurrytimer id="%d" sticky="true" ]', $post->ID));
189 - }
190 167 }
191 168
192 169 /**
193 - * Maybe display campaign on current product page.
170 + * Apply change stock status
194 171 */
195 - public function render_on_product_page() {
172 + public function changeStockStatus()
173 + {
174 + check_ajax_referer( 'hurryt', 'ajax_nonce' );
175 + if ( isset( $_POST[ 'id' ] ) || ! isset( $_POST[ 'stockStatus' ] ) ) {
176 + die( -1 );
177 + }
178 + $id = intval( $_POST[ 'id' ] );
179 + $stockStatus = sanitize_key( $_POST[ 'stockStatus' ] );
180 + $wcCampaign = new WCCampaign();
181 + $campaign = new Campaign( $id );
182 +
183 + $wcCampaign->changeStockStatus( $campaign, $stockStatus );
184 + die();
185 + }
186 +
187 + public function handleWCSingleProduct()
188 + {
196 189 global $post;
197 - if (hurryt_is_woocommerce_activated() && is_product()) {
198 - $wc_campaign = new WCCampaign();
199 - $wc_campaign->run($post->ID);
190 +
191 + if ( Utils\Helpers::isWcActive() && is_product() ) {
192 + $wcCampaign = new WCCampaign();
193 + $wcCampaign->run( $post->ID );
200 194 }
195 +
201 196 }
202 197
203 198 /**
204 199 * Register the stylesheets for the public-facing side of the site.
@@ -204,23 +199,26 @@
204 199 * Register the stylesheets for the public-facing side of the site.
205 200 *
206 201 * @since 1.0.0
207 202 */
208 - public function enqueue_styles() {
209 - wp_enqueue_style( 'hurrytimer', CSS_Builder::get_instance()->get_css_url());
210 - }
203 + public function enqueue_styles()
204 + {
205 + $buildVersion = false;
211 206
212 - function get_custom_css(){
213 - $custom_css = get_option('hurrytimer_custom_css');
214 - if($custom_css){
215 - return $custom_css;
207 + $filePath = HURRYT_DIR . 'assets/css/hurrytimer.css';
208 + if ( file_exists( $filePath ) ) {
209 + $buildVersion = filemtime( $filePath );
216 210 }
217 - ob_start();
218 - // TODO: Minify CSS
219 - include __DIR__ . '/includes/css_template.php';
220 - $custom_css = ob_get_clean();
221 - update_option('hurrytimer_custom_css', $custom_css);
222 - return $custom_css;
211 +
212 + if ( ! $buildVersion ) {
213 + $buildVersion = time();
214 + }
215 +
216 + wp_enqueue_style(
217 + $this->plugin_name,
218 + HURRYT_URL . 'assets/css/hurrytimer.css', [], $buildVersion
219 + );
220 +
223 221 }
224 222
225 223 /**
226 224 * Register the JavaScript for the public-facing side of the site.
@@ -226,60 +224,43 @@
226 224 * Register the JavaScript for the public-facing side of the site.
227 225 *
228 226 * @since 1.0.0
229 227 */
230 - public function enqueue_scripts() {
228 + public function enqueue_scripts()
229 + {
231 230
232 - wp_enqueue_script('jquery');
233 -
234 - $deps = ['jquery', 'hurryt-countdown'];
235 -
236 - // Use woocommerce js cookie if already enqueued.
237 - // TODO: remove this dep in the future
238 - // if(! wp_script_is('js-cookie') ){
239 - wp_enqueue_script(
240 - 'hurryt-cookie',
241 - HURRYT_URL . 'assets/js/cookie.min.js',
242 - [],
243 - '3.14.1',
244 - true
245 - );
246 - $deps[] = 'hurryt-cookie';
247 - // }
248 -
249 231 wp_enqueue_script(
232 + 'hurryt-cookie',
233 + HURRYT_URL . 'assets/js/cookie.min.js',
234 + [],
235 + '2.2.0',
236 + true
237 + );
238 + wp_enqueue_script(
250 239 'hurryt-countdown',
251 240 HURRYT_URL . 'assets/js/jquery.countdown.min.js',
252 - ['jquery'],
241 + [ 'jquery' ],
253 242 '2.2.0',
254 243 true
255 244 );
256 -
257 245 wp_enqueue_script(
258 246 $this->plugin_name,
259 247 HURRYT_URL . 'assets/js/hurrytimer.js',
260 - $deps,
261 - defined('WP_DEBUG') && WP_DEBUG ? time() : $this->version,
248 + [ 'hurryt-countdown', 'hurryt-cookie' ],
249 + defined( 'WP_DEBUG' ) && WP_DEBUG ? time() : $this->version,
262 250 true
263 251 );
264 -
265 -
266 - $disable_actions = hurryt_is_admin_area() && hurryt_settings()['disable_actions'];
267 - $disable_actions = filter_var(
268 - apply_filters('hurryt_disable_actions', $disable_actions),
269 - FILTER_VALIDATE_BOOLEAN
270 - );
271 -
272 - wp_localize_script($this->plugin_name, 'hurrytimer_ajax_object', [
273 - 'ajax_url' => admin_url('admin-ajax.php'),
274 - 'ajax_nonce' => wp_create_nonce('hurryt'),
275 - 'disable_actions' => $disable_actions,
276 - 'methods' => [
277 - 'COOKIE' => C::DETECTION_METHOD_COOKIE,
278 - 'IP' => C::DETECTION_METHOD_IP,
279 - 'USER_SESSION' => C::DETECTION_METHOD_USER_SESSION,
280 - ],
281 - 'actionsOptions' => [
252 + $pluginSettings = new PluginSettings();
253 + $settings = $pluginSettings->getSettings();
254 + wp_localize_script( $this->plugin_name, 'hurrytimer_ajax_object', [
255 + 'tz' => \hurryt_tz(),
256 + 'ajax_url' => admin_url( 'admin-ajax.php' ),
257 + 'ajax_nonce' => wp_create_nonce( 'hurryt' ),
258 + 'disable_actions' => Helpers::isUsingDashboard()
259 + && $settings[ 'disable_actions' ],
260 + 'sticky_bar_hide_timeout' => apply_filters( 'hurryt_sticky_bar_hide_timeout',
261 + 7 ),
262 + 'actionsOptions' => [
282 263 'none' => C::ACTION_NONE,
283 264 'hide' => C::ACTION_HIDE,
284 265 'redirect' => C::ACTION_REDIRECT,
285 266 'stockStatus' => C::ACTION_CHANGE_STOCK_STATUS,
@@ -284,20 +265,14 @@
284 265 'redirect' => C::ACTION_REDIRECT,
285 266 'stockStatus' => C::ACTION_CHANGE_STOCK_STATUS,
286 267 'hideAddToCartButton' => C::ACTION_HIDE_ADD_TO_CART_BUTTON,
287 268 'displayMessage' => C::ACTION_DISPLAY_MESSAGE,
288 - 'expire_coupon' => C::ACTION_EXPIRE_COUPON,
289 269 ],
290 - 'restartOptions' => [
270 + 'restartOptions' => [
291 271 'none' => C::RESTART_NONE,
292 272 'immediately' => C::RESTART_IMMEDIATELY,
293 273 'afterReload' => C::RESTART_AFTER_RELOAD,
294 - 'after_duration' => C::RESTART_AFTER_DURATION,
295 274 ],
296 - 'COOKIEPATH' => defined('COOKIEPATH') ? COOKIEPATH : '',
297 - 'COOKIE_DOMAIN' => defined('COOKIE_DOMAIN') ? COOKIE_DOMAIN : '',
298 - 'redirect_no_back' => apply_filters('hurryt_redirect_no_back', true),
299 - 'expire_coupon_message' => __( 'Coupon "%s" has expired.', 'woocommerce' ),
300 - ]);
275 + 'redirect_no_back' => apply_filters( 'hurryt_redirect_no_back', true ),
276 + ] );
301 277 }
302 -
303 278 }