PluginProbe ʕ •ᴥ•ʔ
OttoKit: All-in-One Automation Platform / 1.1.36
OttoKit: All-in-One Automation Platform v1.1.36
1.1.36 1.1.35 1.1.34 1.1.33 1.1.32 1.1.31 1.1.30 1.1.29 1.1.28 1.1.27 1.1.9 trunk 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.20 1.0.21 1.0.22 1.0.23 1.0.24 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 1.0.39 1.0.40 1.0.41 1.0.42 1.0.43 1.0.44 1.0.45 1.0.46 1.0.47 1.0.48 1.0.49 1.0.50 1.0.51 1.0.52 1.0.53 1.0.54 1.0.55 1.0.56 1.0.57 1.0.58 1.0.59 1.0.60 1.0.61 1.0.62 1.0.63 1.0.64 1.0.65 1.0.66 1.0.67 1.0.68 1.0.69 1.0.7 1.0.70 1.0.71 1.0.72 1.0.73 1.0.74 1.0.75 1.0.76 1.0.77 1.0.78 1.0.79 1.0.8 1.0.80 1.0.81 1.0.82 1.0.83 1.0.84 1.0.85 1.0.86 1.0.87 1.0.88 1.0.89 1.0.9 1.0.90 1.1.0 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 1.1.20 1.1.21 1.1.22 1.1.23 1.1.24 1.1.25 1.1.26 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8
suretriggers / functions.php
suretriggers Last commit date
app 2 months ago assets 4 months ago languages 2 months ago src 23 hours ago autoloader.php 3 years ago changelog.txt 23 hours ago functions.php 23 hours ago readme.txt 23 hours ago suretriggers.php 23 hours ago tailwind.config.js 7 months ago
functions.php
406 lines
1 <?php
2 /**
3 * Global AutomatePlug Functions.
4 *
5 * @package Automateplug
6 */
7
8 /**
9 * Safely unserialize a value, blocking PHP object instantiation.
10 *
11 * Drop-in replacement for unserialize() / maybe_unserialize() on any data
12 * that originates from user input or external storage. Uses is_serialized()
13 * to detect serialized strings without calling unserialize(), then deserializes
14 * with allowed_classes => false so no PHP objects are ever instantiated.
15 *
16 * @param mixed $data Value to unserialize.
17 * @return mixed Unserialized value, or original value if not serialized.
18 */
19 function st_safe_unserialize( $data ) {
20 if ( ! is_string( $data ) || ! is_serialized( $data ) ) {
21 return $data;
22 }
23 // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.unserialize_optionsFound -- allowed_classes requires PHP 7.0+; WP minimum is 7.2+
24 return unserialize( $data, [ 'allowed_classes' => false ] );
25 }
26
27 /**
28 * Check whether an automation is allowed to assign the given role to a user.
29 *
30 * Role-assignment actions (WordPress "Change Role"/"Add New Role", Ultimate
31 * Member equivalents, user-creation actions, etc.) take the role as a plain
32 * string from the automation's `selected_options`. That value can originate
33 * from a hard-coded dropdown choice, but it can just as easily come from a
34 * mapped field fed by an incoming webhook, form submission, or raw REST
35 * request body — there is no reliable way at execution time to tell those
36 * apart. `administrator` is therefore blocked by default so no automation
37 * can be used, intentionally or via a spoofed payload, to escalate a user to
38 * Administrator. Site owners who deliberately need an automation to grant
39 * Administrator can restore that via the `suretriggers_blocked_user_roles`
40 * filter.
41 *
42 * @param string $role Role slug requested by the automation.
43 * @return bool True if the role may be assigned, false if it is blocked.
44 */
45 function st_is_assignable_user_role( $role ) {
46 if ( ! is_string( $role ) || '' === $role ) {
47 return false;
48 }
49
50 $blocked_roles = apply_filters( 'suretriggers_blocked_user_roles', [ 'administrator' ] );
51
52 if ( ! is_array( $blocked_roles ) ) {
53 $blocked_roles = [ 'administrator' ];
54 }
55
56 return ! in_array( strtolower( $role ), array_map( 'strtolower', $blocked_roles ), true );
57 }
58
59 /**
60 * Get or prepare user id.
61 *
62 * @return int
63 */
64 function ap_get_current_user_id() {
65
66 $user_id = get_current_user_id();
67
68 if ( $user_id ) {
69 return $user_id;
70 }
71
72 if ( ! session_id() ) { //phpcs:ignore
73 session_start(); //phpcs:ignore
74 }
75
76 if ( isset( $_SESSION['ap_user_identifier'] ) ) {
77 return $_SESSION['ap_user_identifier']; //phpcs:ignore
78 }
79
80 $ap_user_id = wp_rand( 1000000000, 9999999999 );
81 $_SESSION['ap_user_identifier'] = $ap_user_id; //phpcs:ignore
82
83 return $_SESSION['ap_user_identifier']; //phpcs:ignore
84
85 }
86
87 /**
88 * Get or prepare user id.
89 *
90 * @param string $email user email.
91 *
92 * @return int|bool
93 */
94 function ap_get_user_id_from_email( $email ) {
95
96 if ( empty( $email ) || ! email_exists( $email ) ) {
97 return false;
98 }
99
100 $get_user = get_user_by( 'email', $email );
101 if ( ! $get_user instanceof WP_User ) {
102 return false;
103 }
104 return intval( $get_user->ID );
105
106 }
107
108 add_action(
109 'in_admin_header',
110 function () {
111 if ( isset( $_GET['page'] ) && 'suretriggers' === sanitize_text_field( $_GET['page'] ) ) { // phpcs:ignore
112 remove_all_actions( 'admin_notices' );
113 remove_all_actions( 'all_admin_notices' );
114 }
115 },
116 999
117 );
118
119 add_action( 'wp_login', 'suretrigger_capture_login_time', 10, 2 );
120
121 /**
122 * Login time.
123 *
124 * @param string $user_login user login.
125 * @param object $user user.
126 * @return void
127 */
128 function suretrigger_capture_login_time( $user_login, $user ) {
129 if ( ! property_exists( $user, 'ID' ) ) {
130 return;
131 }
132 update_user_meta( $user->ID, 'st_last_login', time() );
133 }
134
135 /**
136 * Add 5-star rating display to plugin row.
137 */
138 add_filter( 'plugin_row_meta', 'suretriggers_add_plugin_rating', 10, 2 );
139
140 /**
141 * Add 5-star rating to plugin meta row.
142 *
143 * @param array $links An array of the plugin's metadata.
144 * @param string $file Path to the plugin file relative to the plugins directory.
145 * @return array Modified array of plugin metadata.
146 */
147 function suretriggers_add_plugin_rating( $links, $file ) {
148 if ( plugin_basename( SURE_TRIGGERS_FILE ) === $file ) {
149 // Check if user has already clicked the rating (stored in user meta).
150 $user_id = get_current_user_id();
151 $rating_clicked = get_user_meta( $user_id, 'suretriggers_rating_clicked', true );
152
153 // If rating has been clicked, don't show it.
154 if ( $rating_clicked ) {
155 return $links;
156 }
157
158 $rating_html = '<span class="suretriggers-rating-wrapper" id="suretriggers-rating-wrapper">';
159 $rating_html .= '<a href="https://wordpress.org/support/plugin/suretriggers/reviews/" target="_blank" class="suretriggers-rating-link" title="Rate this plugin" aria-label="Rate SureTriggers 5 stars on WordPress.org">';
160 $rating_html .= '<span class="star-rating" role="img" aria-label="5 out of 5 stars">';
161 for ( $i = 1; $i <= 5; $i++ ) {
162 $rating_html .= '<span class="star star-full" aria-hidden="true"></span>';
163 }
164 $rating_html .= '</span>';
165 $rating_html .= '<span class="screen-reader-text">Rate this plugin</span>';
166 $rating_html .= '</a>';
167 $rating_html .= '</span>';
168 $links[] = $rating_html;
169 }
170 return $links;
171 }
172
173 /**
174 * Enqueue rating styles for plugin meta row.
175 */
176 add_action( 'admin_enqueue_scripts', 'suretriggers_enqueue_rating_styles' );
177
178 /**
179 * Enqueue CSS styles for 5-star rating display.
180 * Following modular CSS organization best practices.
181 *
182 * @return void
183 */
184 function suretriggers_enqueue_rating_styles() {
185 // Only enqueue on plugins page where rating is displayed.
186 $screen = get_current_screen();
187 if ( $screen && 'plugins' === $screen->id ) {
188 wp_enqueue_style(
189 'suretriggers-rating',
190 plugin_dir_url( SURE_TRIGGERS_FILE ) . 'assets/css/st-rating.css',
191 [],
192 defined( 'SURE_TRIGGERS_VER' ) ? SURE_TRIGGERS_VER : '1.0.0'
193 );
194
195 wp_enqueue_script(
196 'suretriggers-rating-js',
197 plugin_dir_url( SURE_TRIGGERS_FILE ) . 'assets/js/st-rating.js',
198 [ 'jquery' ],
199 defined( 'SURE_TRIGGERS_VER' ) ? SURE_TRIGGERS_VER : '1.0.0',
200 true
201 );
202
203 // Localize script with AJAX URL and nonce.
204 wp_localize_script(
205 'suretriggers-rating-js',
206 'suretriggers_rating_ajax',
207 [
208 'ajax_url' => admin_url( 'admin-ajax.php' ),
209 'nonce' => wp_create_nonce( 'suretriggers_rating_nonce' ),
210 ]
211 );
212 }
213 }
214
215 /**
216 * Handle AJAX request to mark rating as clicked.
217 */
218 add_action( 'wp_ajax_suretriggers_rating_clicked', 'suretriggers_handle_rating_clicked' );
219
220 /**
221 * Mark rating as clicked for current user.
222 *
223 * @return void
224 */
225 function suretriggers_handle_rating_clicked() {
226 // Check if nonce is set and verify it.
227 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'suretriggers_rating_nonce' ) ) {
228 wp_die( 'Security check failed' );
229 }
230
231 // Mark rating as clicked for current user.
232 $user_id = get_current_user_id();
233 if ( $user_id ) {
234 update_user_meta( $user_id, 'suretriggers_rating_clicked', true );
235 wp_send_json_success( 'Rating marked as clicked' );
236 } else {
237 wp_send_json_error( 'User not logged in' );
238 }
239 }
240
241 /**
242 * SureTrigger Trigger Button shortcode.
243 *
244 * @param array $atts Attributes.
245 * @param null $content Content.
246 * @return string|bool
247 */
248 function suretrigger_button( $atts, $content = null ) {
249 $atts = shortcode_atts(
250 [
251 'id' => 0,
252 'button_label' => __( 'Click here', 'suretriggers' ),
253 'user_redirect_url' => '',
254 'visitor_redirect_url' => '',
255 'button_class' => 'suretrigger_button',
256 'button_id' => 'suretrigger_button',
257 'click_loading_label' => __( 'Clicking...', 'suretriggers' ),
258 'after_clicked_label' => __( 'Clicked!!', 'suretriggers' ),
259 'click_once' => 'true',
260 'cookie_duration' => '15',
261 ],
262 $atts,
263 'trigger_button'
264 );
265 ob_start();
266 $user_id = get_current_user_id();
267 ?>
268
269 <form method="post" class="suretrigger_button_form" id="suretrigger_button_form_<?php echo esc_attr( (string) $atts['id'] ); ?>">
270 <input type="hidden" name="st_trigger_id" value="<?php echo esc_attr( (string) $atts['id'] ); ?>" />
271 <input type="hidden" name="st_nonce" value="<?php echo esc_attr( wp_create_nonce( 'suretrigger_form' ) ); ?>"/>
272 <input type="hidden" name="st_login_url" value="<?php echo esc_attr( $atts['user_redirect_url'] ); ?>"/>
273 <input type="hidden" name="st_non_login_url" value="<?php echo esc_attr( $atts['visitor_redirect_url'] ); ?>"/>
274 <input type="hidden" name="st_click" value="<?php echo esc_attr( $atts['click_once'] ); ?>"/>
275 <input type="hidden" name="st_button_label" value="<?php echo esc_attr( $atts['button_label'] ); ?>"/>
276 <input type="hidden" name="st_loading_label" value="<?php echo esc_attr( $atts['click_loading_label'] ); ?>"/>
277 <input type="hidden" name="st_clicked_label" value="<?php echo esc_attr( $atts['after_clicked_label'] ); ?>"/>
278 <input type="hidden" name="action" value="handle_trigger_button_click"/>
279 <input type="hidden" name="st_cookie_duration" value="<?php echo esc_attr( $atts['cookie_duration'] ); ?>"/>
280 <input type="hidden" name="st_user_id" value="<?php echo esc_attr( (string) $user_id ); ?>"/>
281 <?php
282 global $post;
283 if ( ! empty( $post ) && is_object( $post ) && isset( $post->ID ) && isset( $post->post_title ) ) {
284 ?>
285 <input type="hidden" name="st_button_post_id" value="<?php echo esc_attr( $post->ID ); ?>"/>
286 <input type="hidden" name="st_button_post_title" value="<?php echo esc_attr( $post->post_title ); ?>"/>
287 <?php
288 }
289 $cookie_name = 'st_trigger_button_clicked_' . esc_attr( (string) $atts['id'] );
290 if ( isset( $_COOKIE[ $cookie_name ] ) && 'yes_' . $user_id == $_COOKIE[ $cookie_name ] ) {
291 ?>
292 <button type="button" class="<?php echo esc_attr( $atts['button_class'] ); ?>" id="<?php echo esc_attr( $atts['button_id'] ); ?>"><?php echo esc_html( $atts['after_clicked_label'] ); ?></button>
293 <?php
294 } else {
295 ?>
296 <button type="button" class="<?php echo esc_attr( $atts['button_class'] ); ?>" id="<?php echo esc_attr( $atts['button_id'] ); ?>" onclick="st_trigger_ajax(this);return false;"><?php echo esc_html( $atts['button_label'] ); ?></button>
297 <?php
298 }
299 ?>
300 </form>
301
302 <?php
303 return ob_get_clean();
304 }
305 add_shortcode( 'st_trigger_button', 'suretrigger_button' );
306
307 /**
308 * SureTrigger Trigger Button custom style.
309 *
310 * @return void
311 */
312 function suretrigger_button_custom_style() {
313 wp_enqueue_style( 'st-trigger-button-style', SURE_TRIGGERS_URL . 'assets/css/st-trigger-button.css', [], SURE_TRIGGERS_VER );
314 wp_enqueue_script( 'st-trigger-button-script', SURE_TRIGGERS_URL . 'assets/js/st-trigger-button.js', [], SURE_TRIGGERS_VER, true );
315 wp_localize_script( 'st-trigger-button-script', 'st_ajax_object', [ 'ajax_url' => admin_url( 'admin-ajax.php' ) ] );
316 }
317 add_action( 'wp_enqueue_scripts', 'suretrigger_button_custom_style' );
318
319 /**
320 * SureTrigger Trigger Button action.
321 *
322 * @return void
323 */
324 function suretrigger_trigger_button_action() {
325
326 // Trigger the custom hook before ajax response.
327 do_action( 'st_trigger_button_before_click_hook' );
328
329 if ( ! isset( $_POST['st_nonce'] ) || ! wp_verify_nonce( wp_strip_all_tags( $_POST['st_nonce'] ), 'suretrigger_form' ) ) {
330 wp_send_json_error( [ 'error' => 'Invalid nonce' ] );
331 }
332
333 if ( is_user_logged_in() ) {
334 $user_id = get_current_user_id();
335
336 if ( isset( $_POST['st_trigger_id'] ) && ! empty( $_POST['st_trigger_id'] ) ) {
337
338 $st_trigger_id = sanitize_text_field( $_POST['st_trigger_id'] );
339
340 $cookie_duration = isset( $_POST['st_cookie_duration'] ) ? sanitize_text_field( $_POST['st_cookie_duration'] ) : '';
341 $st_click = isset( $_POST['st_click'] ) ? sanitize_text_field( $_POST['st_click'] ) : '';
342
343 $post_data = [];
344
345 if ( isset( $_POST['st_button_post_id'] ) ) {
346 $post_data['parent_post_id'] = sanitize_text_field( $_POST['st_button_post_id'] );
347 }
348
349 if ( isset( $_POST['st_button_post_title'] ) ) {
350 $post_data['parent_post_title'] = sanitize_text_field( $_POST['st_button_post_title'] );
351 }
352 do_action( 'st_trigger_button_action', $st_trigger_id, $user_id, sanitize_text_field( $cookie_duration ), $st_click, $post_data );
353
354 if ( isset( $_POST['st_login_url'] ) && ! empty( $_POST['st_login_url'] ) ) {
355 wp_send_json_success( esc_url_raw( $_POST['st_login_url'] ) );
356 }
357 }
358 } else {
359 if ( isset( $_POST['st_non_login_url'] ) && ! empty( $_POST['st_non_login_url'] ) ) {
360 wp_send_json_success( esc_url_raw( $_POST['st_non_login_url'] ) );
361 } else {
362 wp_send_json_success( wp_login_url() );
363 }
364 }
365
366 // Trigger the custom hook after ajax response.
367 do_action( 'st_trigger_button_after_click_hook' );
368
369 wp_die();
370 }
371 add_action( 'wp_ajax_handle_trigger_button_click', 'suretrigger_trigger_button_action' );
372 add_action( 'wp_ajax_nopriv_handle_trigger_button_click', 'suretrigger_trigger_button_action' );
373
374 /**
375 * SureTrigger Trigger Button set cookie.
376 *
377 * @param int $st_trigger_id Trigger ID.
378 * @param int $user_id User ID.
379 * @param int $cookie_duration Cookie Duration.
380 *
381 * @return void
382 */
383 function st_trigger_button_set_cookie( $st_trigger_id, $user_id, $cookie_duration ) {
384 // Set the cookie.
385 $cookie_name = 'st_trigger_button_clicked_' . $st_trigger_id;
386 $cookie_value = 'yes_' . $user_id;
387 if ( isset( $cookie_duration ) ) {
388 $expiration = time() + 60 * 60 * 24 * intval( $cookie_duration ); // Set the expiration time as per user requested.
389 } else {
390 $expiration = time() + 60 * 60 * 24 * 15;
391 }
392
393 if ( ! defined( 'COOKIEPATH' ) ) {
394 define( 'COOKIEPATH', '/' );
395 }
396
397 if ( ! defined( 'COOKIE_DOMAIN' ) ) {
398 define( 'COOKIE_DOMAIN', false );
399 }
400
401 $secure = is_ssl();
402 setcookie( $cookie_name, $cookie_value, $expiration, COOKIEPATH, COOKIE_DOMAIN, $secure, true ); // phpcs:ignore
403
404 }
405 add_action( 'st_trigger_button_set_cookie', 'st_trigger_button_set_cookie', 10, 3 );
406