PluginProbe ʕ •ᴥ•ʔ
OttoKit: All-in-One Automation Platform / 1.1.27
OttoKit: All-in-One Automation Platform v1.1.27
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 / src / Loader.php
suretriggers / src Last commit date
Abilities 3 months ago Admin 2 months ago Controllers 1 month ago Integrations 1 month ago Models 2 months ago Support 1 year ago Traits 3 years ago Loader.php 1 month ago
Loader.php
1023 lines
1 <?php
2 /**
3 * Loader.
4 * php version 5.6
5 *
6 * @category Loader
7 * @package SureTriggers
8 * @author BSF <username@example.com>
9 * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3
10 * @link https://www.brainstormforce.com/
11 * @since 1.0.0
12 */
13
14 namespace SureTriggers;
15
16 use DirectoryIterator;
17 use SureTriggers\Controllers\AuthController;
18 use SureTriggers\Controllers\AutomationController;
19 use SureTriggers\Controllers\EventController;
20 use SureTriggers\Controllers\GlobalSearchController;
21 use SureTriggers\Controllers\IntegrationsController;
22 use SureTriggers\Controllers\OptionController;
23 use SureTriggers\Controllers\RestController;
24 use SureTriggers\Controllers\RoutesController;
25 use SureTriggers\Controllers\WebhookRequestsController;
26 use SureTriggers\Controllers\SettingsController;
27 use SureTriggers\Traits\SingletonLoader;
28 use SureTriggers\Models\SaasApiToken;
29 use SureTriggers\Abilities\AbilitiesController;
30 use function add_menu_page;
31 use function add_submenu_page;
32
33 /**
34 * Loader
35 *
36 * @category Loader
37 * @package SureTriggers
38 * @author BSF <username@example.com>
39 * @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3
40 * @link https://www.brainstormforce.com/
41 * @since 1.0.0
42 */
43 class Loader {
44
45
46
47 use SingletonLoader;
48
49 /**
50 * Constructor
51 *
52 * @since 1.0.0
53 */
54 public function __construct() {
55 register_activation_hook( SURE_TRIGGERS_FILE, [ $this, 'st_activate' ] );
56
57 $this->define_constants();
58 add_action( 'plugins_loaded', [ $this, 'load_textdomain' ] );
59 add_action( 'plugins_loaded', [ $this, 'initialize_core' ] );
60 // Admin Menu.
61 add_action( 'admin_menu', [ $this, 'admin_menu' ] );
62 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
63 add_action( 'admin_head', [ $this, 'add_admin_menu_styles' ] );
64 add_action( 'admin_init', [ $this, 'reset_plugin' ] );
65
66 add_filter( 'plugin_action_links_' . plugin_basename( SURE_TRIGGERS_FILE ), [ $this, 'add_settings_link' ] );
67 add_action( 'admin_init', [ $this, 'redirect_after_activation' ] );
68
69 add_action( 'admin_notices', [ $this, 'display_notice' ] );
70
71 add_action( 'all_admin_notices', [ $this, 'suretriggers_show_api_connection_error' ] );
72
73 add_action( 'wp_dashboard_setup', [ $this, 'add_dashboard_widgets' ] );
74
75 // Remove Webhook Requests retry cron and requests table.
76 register_uninstall_hook(
77 SURE_TRIGGERS_FILE,
78 [ WebhookRequestsController::class, 'suretriggers_remove_table_retry_cron' ]
79 );
80 }
81
82 /**
83 * Adding dashboard widget.
84 *
85 * @return void
86 */
87 public function add_dashboard_widgets() {
88 if ( isset( OptionController::$options['secret_key'] ) ) {
89 return;
90 }
91
92 wp_add_dashboard_widget(
93 'suretriggers_dashboard_widget',
94 __( 'Stop Doing It Manually!', 'suretriggers' ),
95 [ $this, 'dashboard_widget_display' ],
96 null,
97 null,
98 'side',
99 'high'
100 );
101 }
102
103 /**
104 * Dashboard widget callback.
105 *
106 * @return void
107 */
108 public function dashboard_widget_display() { ?>
109 <div>
110 <p> <?php esc_html_e( 'Automation That’s Easy Enough for Anyone.', 'suretriggers' ); ?></p>
111 <p>
112 <?php
113 esc_html_e(
114 'OttoKit connects all your tools - WooCommerce, Forms, CRM, and more, so your website runs smoothly while you focus on your business.
115 ',
116 'suretriggers'
117 );
118 ?>
119 </p>
120 <a href="<?php echo esc_url( admin_url( 'admin.php?page=suretriggers' ) ); ?>" class="button button-primary"> <?php esc_html_e( 'Start Automating', 'suretriggers' ); ?> </a>
121 </div>
122 <?php
123 }
124
125 /**
126 * Load Plugin Text Domain.
127 * This will load the translation textdomain depending on the file priorities.
128 * 1. Global Languages /wp-content/languages/suretriggers/ folder
129 * 2. Local directory /wp-content/plugins/suretriggers/languages/ folder
130 *
131 * @return void
132 */
133 public function load_textdomain() {
134 // Default languages directory.
135 $lang_dir = SURE_TRIGGERS_DIR . 'languages/';
136
137 /**
138 * Filters the languages directory path to use for plugin.
139 *
140 * @param string $lang_dir The languages directory path.
141 */
142 $lang_dir = apply_filters( 'suretriggers_languages_directory', $lang_dir );
143
144 // Traditional WordPress plugin locale filter.
145 global $wp_version;
146
147 $get_locale = get_locale();
148
149 if ( $wp_version >= 4.7 ) {
150 $get_locale = get_user_locale();
151 }
152
153 /**
154 * Language Locale for plugin
155 *
156 * Uses get_user_locale()` in WordPress 4.7 or greater,
157 * otherwise uses `get_locale()`.
158 */
159 $locale = apply_filters( 'plugin_locale', $get_locale, 'suretriggers' );//phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- wordpress hook
160 $mofile = sprintf( '%1$s-%2$s.mo', 'suretriggers', $locale );
161
162 // Setup paths to current locale file.
163 $mofile_global = WP_LANG_DIR . '/plugins/' . $mofile;
164 $mofile_local = $lang_dir . $mofile;
165
166 $mofile_global = wp_normalize_path( $mofile_global );
167 $mofile_local = wp_normalize_path( $mofile_local );
168
169 if ( file_exists( $mofile_global ) && wp_is_file_mod_allowed( 'load_textdomain_mofile' ) ) {
170 // Look in global /wp-content/languages/suretriggers/ folder.
171 load_textdomain( 'suretriggers', $mofile_global );
172 } elseif ( file_exists( $mofile_local ) && wp_is_file_mod_allowed( 'load_textdomain_mofile' ) && $this->st_valid_file_path( $mofile_local ) ) {
173 // Look in local /wp-content/plugins/suretriggers/languages/ folder.
174 load_textdomain( 'suretriggers', $mofile_local );
175 } else {
176 load_plugin_textdomain( 'suretriggers', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
177 }
178 }
179
180 /**
181 * Check if file is valid.
182 *
183 * @param string $file_path file_path.
184 * @return bool
185 */
186 private function st_valid_file_path( $file_path ) {
187 $allowed_dir = realpath( SURE_TRIGGERS_DIR . 'languages/' );
188 $real_file_path = realpath( $file_path );
189 return false !== $real_file_path && $allowed_dir && 0 === strpos( $real_file_path, $allowed_dir );
190 }
191
192 /**
193 * Display notice.
194 *
195 * @return void
196 */
197 public function display_notice() {
198 global $pagenow;
199 if ( isset( OptionController::$options['secret_key'] ) ) {
200 return;
201 }
202 if ( 'index.php' != $pagenow ) {
203 return;
204 }
205 ?>
206 <div class="notice notice-success" style="padding-bottom: 15px;">
207 <p>
208 <strong>
209 <?php esc_html_e( 'Automate Your WordPress Site. Save Hours. Earn More.', 'suretriggers' ); ?>
210 <span style="transform: rotate(-90deg); font-size: 15px;" class="dashicons dashicons-admin-plugins"></span>
211 </strong>
212 </p>
213 <p> <?php esc_html_e( 'OttoKit connects your plugins and favorite apps so your business runs on autopilot — while you focus on what matters most.', 'suretriggers' ); ?> </p>
214
215 <a href="<?php echo esc_url( admin_url( 'admin.php?page=suretriggers' ) ); ?>" class="button button-primary"> <?php esc_html_e( 'Start Automating', 'suretriggers' ); ?> </a>
216 <a href="https://ottokit.com/?utm_source=wpplugin&utm_medium=dashboard&utm_campaign=top+bar" class="button button-secondary"> <?php esc_html_e( 'See How It Works', 'suretriggers' ); ?> </a>
217 </div>
218 <?php
219 }
220
221 /**
222 * Show Connection Error Admin Notice.
223 *
224 * @return void
225 */
226 public function suretriggers_show_api_connection_error() {
227 global $pagenow;
228 $is_authorized = true;
229 if ( ! current_user_can( 'manage_options' ) ) {
230 $is_authorized = self::suretriggers_user_permission_check();
231 }
232 if ( 'index.php' != $pagenow || ! isset( OptionController::$options['secret_key'] ) || ! $is_authorized ) {
233 return;
234 }
235 $notice = get_option( 'suretriggers_verify_connection' );
236 // If empty option value for connection status, then verify the connection.
237 if ( empty( $notice ) || 'suretriggers_connection_successful' != $notice ) {
238 $connection_status = RestController::suretriggers_verify_wp_connection();
239 $connection_status_code = wp_remote_retrieve_response_code( $connection_status );
240 if ( is_wp_error( $connection_status ) ) {
241 update_option( 'suretriggers_verify_connection', 'suretriggers_connection_wp_error' );
242 } else {
243 if ( 200 !== $connection_status_code ) {
244 update_option( 'suretriggers_verify_connection', 'suretriggers_connection_error' );
245 } else {
246 update_option( 'suretriggers_verify_connection', 'suretriggers_connection_successful' );
247 }
248 }
249 }
250 $notice = get_option( 'suretriggers_verify_connection' );
251 if ( 'suretriggers_connection_successful' != $notice ) {
252 // If connection status is not successful, then show the notice.
253 ?>
254 <div class="notice notice-error is-dismissible">
255 <p>
256 <strong>
257 <?php esc_html_e( 'OttoKit Connection Issue', 'suretriggers' ); ?>
258 <span style="transform: rotate(-180deg); font-size: 20px;" class="dashicons dashicons-warning"></span>
259 </strong>
260 </p>
261 <p>
262 <?php esc_html_e( 'There is an issue with the established connection between WordPress and OttoKit. Please visit the OttoKit dashboard to verify and re-establish the connection if necessary.', 'suretriggers' ); ?>
263 </p>
264 <p>
265 <a href="<?php echo esc_url( admin_url( 'admin.php?page=suretriggers' ) ); ?>" class="button button-secondary"> <?php esc_html_e( 'Go To OttoKit', 'suretriggers' ); ?> </a>
266 </p>
267 </div>
268 <?php
269 }
270 }
271
272 /**
273 * Redirect user after plugin activation.
274 *
275 * @return void
276 */
277 public function redirect_after_activation() {
278 $is_redirect = get_transient( 'st-redirect-after-activation' );
279 if ( $is_redirect ) {
280 delete_transient( 'st-redirect-after-activation' );
281 $url = get_admin_url() . 'admin.php?page=suretriggers';
282 wp_safe_redirect( $url );
283 die;
284 }
285 }
286
287 /**
288 * Adding setting link.
289 *
290 * @param array $links links.
291 * @return array
292 */
293 public function add_settings_link( array $links ) {
294 $url = get_admin_url() . 'admin.php?page=suretriggers';
295 $setting_option = get_option( 'suretrigger_options' );
296 if ( isset( $setting_option ) && ! empty( $setting_option ) ) {
297 $settings_link = '<a href="' . $url . '">' . __( 'Dashboard', 'suretriggers' ) . '</a>';
298 } else {
299 $settings_link = '<a href="' . $url . '">' . __( 'Connect', 'suretriggers' ) . '</a>';
300 }
301 $links[] = $settings_link;
302
303 // Add Get OttoKit Pro link for free and pro users.
304 $verification_data = get_option( 'suretriggers_lifetime_user_plan_data' );
305 $plan_id = is_array( $verification_data ) && isset( $verification_data['plan_id'] ) ? $verification_data['plan_id'] : '';
306 if ( in_array( $plan_id, [ 'free', 'pro' ], true ) ) {
307 $button_text = ( 'free' === $plan_id ) ? __( 'Get OttoKit Pro', 'suretriggers' ) : __( 'Upgrade', 'suretriggers' );
308 $upgrade_link = '<a href="https://ottokit.com/pricing/?utm_source=wpplugin&utm_medium=plugin+list&utm_campaign=plugin+list" target="_blank" style="color: #28a745; font-weight: bold;">' . $button_text . '</a>';
309 $links[] = $upgrade_link;
310 }
311
312 return $links;
313 }
314
315 /**
316 * Define constants
317 *
318 * @return void
319 * @since 1.0.0
320 */
321 public function define_constants() {
322 $sass_url = 'https://app.ottokit.com';
323 $api_url = 'https://api.ottokit.com';
324 $webhook_url = 'https://webhook.ottokit.com';
325
326 define( 'SURE_TRIGGERS_BASE', plugin_basename( SURE_TRIGGERS_FILE ) );
327 define( 'SURE_TRIGGERS_DIR', plugin_dir_path( SURE_TRIGGERS_FILE ) );
328 define( 'SURE_TRIGGERS_URL', plugins_url( '/', SURE_TRIGGERS_FILE ) );
329 define( 'SURE_TRIGGERS_VER', '1.1.27' );
330 define( 'SURE_TRIGGERS_DB_VER', '1.1.27' );
331 define( 'SURE_TRIGGERS_REST_NAMESPACE', 'sure-triggers/v1' );
332 define( 'SURE_TRIGGERS_SASS_URL', $sass_url . '/wp-json/wp-plugs/v1/' );
333 define( 'SURE_TRIGGERS_SITE_URL', $sass_url );
334 define( 'SURE_TRIGGERS_API_SERVER_URL', $api_url );
335 define( 'SURE_TRIGGERS_WEBHOOK_SERVER_URL', $webhook_url );
336
337 define( 'SURE_TRIGGERS_PAGE', 'OttoKit' );
338 define( 'SURE_TRIGGERS_AS_GROUP', 'OttoKit' );
339
340 define( 'SURE_TRIGGERS_ACTION_ERROR_MESSAGE', 'An unexpected error occurred. Something went wrong with the action.' );
341 }
342
343 /**
344 * Flush permalink rules while plugin activation.
345 *
346 * @return void
347 */
348 public function st_activate() {
349 flush_rewrite_rules(); //phpcs:ignore
350
351 set_transient( 'st-redirect-after-activation', true, 120 );
352 }
353
354 /**
355 * SureTriggers Access for Users and User Roles.
356 *
357 * @return bool
358 */
359 private function suretriggers_user_permission_check() {
360 $current_user = wp_get_current_user();
361 $current_user_id = $current_user->ID;
362 $current_user_roles = $current_user->roles;
363
364 // Get enabled users and roles with proper default values.
365 $enabled_users = get_option( 'suretriggers_enabled_users', [] );
366 $enabled_user_roles = get_option( 'suretriggers_enabled_user_roles', [] );
367
368 $enabled_users = is_array( $enabled_users ) ? $enabled_users : [];
369 $enabled_user_roles = is_array( $enabled_user_roles ) ? $enabled_user_roles : [];
370
371 $is_authorized = in_array( $current_user_id, (array) $enabled_users ) || array_intersect( $current_user_roles, (array) $enabled_user_roles );
372
373 return $is_authorized;
374 }
375
376 /**
377 * Add main menu
378 *
379 * @since x.x.x
380 *
381 * @return void
382 */
383 public function admin_menu() {
384 $page_title = apply_filters( 'st_menu_page_title', esc_html__( 'OttoKit', 'suretriggers' ) );
385 $logo = file_get_contents( plugin_dir_path( SURE_TRIGGERS_FILE ) . 'assets/images/OttoKitLogo.svg' );
386
387 $is_authorized = true;
388 if ( ! current_user_can( 'manage_options' ) ) {
389 $is_authorized = self::suretriggers_user_permission_check();
390 }
391
392 if ( $is_authorized ) {
393 add_menu_page(
394 $page_title,
395 $page_title,
396 'read',
397 'suretriggers',
398 [ $this, 'menu_callback' ],
399 $logo ? 'data:image/svg+xml;base64,' . base64_encode( $logo ) : '',
400 30.6002
401 );
402
403 // Replace the auto-created first submenu item (which duplicates the parent title)
404 // with an explicit "Dashboard" item using the same slug.
405 add_submenu_page(
406 'suretriggers',
407 __( 'Dashboard', 'suretriggers' ),
408 __( 'Dashboard', 'suretriggers' ),
409 'read',
410 'suretriggers',
411 [ $this, 'menu_callback' ]
412 );
413
414 // Add quick-access submenu items that deep-link into the SaaS dashboard.
415 // The React app reads redirect_url from the URL and forwards it to the iframe.
416 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Standard pattern for adding direct-link submenu items.
417 global $submenu;
418 $deep_link_items = [
419 'workflows' => __( 'Workflows', 'suretriggers' ),
420 'tables' => __( 'Tables', 'suretriggers' ),
421 'forms' => __( 'Forms', 'suretriggers' ),
422 'mcp' => __( 'MCP', 'suretriggers' ),
423 'recipes' => __( 'Recipes', 'suretriggers' ),
424 'folders' => __( 'Folders', 'suretriggers' ),
425 'email-templates' => __( 'Email Templates', 'suretriggers' ),
426 'variables' => __( 'Variables', 'suretriggers' ),
427 'history' => __( 'History', 'suretriggers' ),
428 'apps' => __( 'Apps', 'suretriggers' ),
429 'members' => __( 'Members', 'suretriggers' ),
430 'settings' => __( 'Settings', 'suretriggers' ),
431 ];
432
433 foreach ( $deep_link_items as $path => $label ) {
434 // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
435 $submenu['suretriggers'][] = [
436 $label,
437 'read',
438 admin_url( 'admin.php?page=suretriggers&redirect_url=/' . $path ),
439 ];
440 }
441
442 add_submenu_page(
443 'suretriggers',
444 __( 'OttoKit Status', 'suretriggers' ),
445 __( 'Status', 'suretriggers' ),
446 'read',
447 'suretriggers-status',
448 [ $this, 'suretriggers_status_menu_callback' ]
449 );
450
451 // Add Get OttoKit Pro menu for free and pro users.
452 $verification_data = get_option( 'suretriggers_lifetime_user_plan_data' );
453 $plan_id = is_array( $verification_data ) && isset( $verification_data['plan_id'] ) ? $verification_data['plan_id'] : '';
454 if ( in_array( $plan_id, [ 'free', 'pro' ], true ) ) {
455 $button_text = ( 'free' === $plan_id ) ? __( 'Get OttoKit Pro', 'suretriggers' ) : __( 'Upgrade', 'suretriggers' );
456 add_submenu_page(
457 'suretriggers',
458 $button_text,
459 '<span class="ottokit-upgrade-btn">' . $button_text . '</span>',
460 'read',
461 'suretriggers-upgrade-plan',
462 [ $this, 'suretriggers_upgrade_plan_callback' ]
463 );
464 }
465 }
466
467 if ( isset( OptionController::$options['secret_key'] ) ) {
468 add_options_page(
469 __( 'OttoKit Settings', 'suretriggers' ),
470 __( 'OttoKit Settings', 'suretriggers' ),
471 'manage_options',
472 'ottokit-settings',
473 [ $this, 'suretriggers_render_interface_callback' ]
474 );
475 }
476 }
477
478 /**
479 * Enqueue the admin scripts
480 *
481 * @param string $hook hook.
482 * @since x.x.x
483 *
484 * @return void
485 */
486 public function enqueue_scripts( $hook = '' ) {
487 // Always enqueue admin CSS for upgrade button styling.
488 wp_enqueue_style( 'st-trigger-style', SURE_TRIGGERS_URL . 'assets/admin-css/st-admin-css.css', [], SURE_TRIGGERS_VER );
489
490 if ( ! in_array( $hook, [ 'toplevel_page_suretriggers', 'ottokit_page_suretriggers-status', 'settings_page_ottokit-settings' ], true ) ) {
491 return;
492 }
493
494 remove_all_actions( 'admin_notices' );
495
496 $file = SURE_TRIGGERS_DIR . 'app/build/main.asset.php';
497 if ( ! file_exists( $file ) ) {
498 return;
499 }
500
501 $asset = require_once $file;
502
503 if ( ! isset( $asset ) ) {
504 return;
505 }
506
507 wp_register_script(
508 'sure-trigger-admin',
509 SURE_TRIGGERS_URL . 'app/build/main.js',
510 array_merge( $asset['dependencies'], [ 'regenerator-runtime' ], [ 'wp-i18n' ] ),
511 $asset['version'],
512 true
513 );
514
515 wp_localize_script(
516 'sure-trigger-admin',
517 'sureTriggerData',
518 $this->get_localized_array()
519 );
520 wp_enqueue_script( 'sure-trigger-admin' );
521 // Set the script translations.
522 wp_set_script_translations( 'sure-trigger-admin', 'suretriggers', SURE_TRIGGERS_DIR . 'languages' );
523 wp_enqueue_style( 'sure-trigger-components', SURE_TRIGGERS_URL . 'app/build/style-main.css', [], SURE_TRIGGERS_VER );
524 wp_enqueue_style( 'sure-trigger-css', SURE_TRIGGERS_URL . 'app/build/main.css', [], SURE_TRIGGERS_VER );
525 }
526
527 /**
528 * Get localized array for sure triggers.
529 *
530 * @return array
531 */
532 private function get_localized_array() {
533 $settings_nonce = wp_create_nonce( 'suretriggers_settings_nonce_action' );
534 $current_user = wp_get_current_user();
535 global $wp_roles;
536 $is_authorized = true;
537 if ( ! current_user_can( 'manage_options' ) ) {
538 $is_authorized = self::suretriggers_user_permission_check();
539 }
540
541 $source_type = get_option( 'suretriggers_source' );
542
543 // Get enabled users and roles with proper default values.
544 $enabled_users = get_option( 'suretriggers_enabled_users', [] );
545 $enabled_user_roles = get_option( 'suretriggers_enabled_user_roles', [] );
546
547 $enabled_users = is_array( $enabled_users ) ? $enabled_users : [];
548 $enabled_user_roles = is_array( $enabled_user_roles ) ? $enabled_user_roles : [];
549
550 $data = [
551 'siteContent' => [
552 'siteUrl' => str_replace( '/wp-json/', '', get_rest_url() ),
553 'redirectUrl' => get_site_url() . '/wp-admin/themes.php?page=suretriggers',
554 'connectNonce' => wp_create_nonce( 'sure-trigger-connect' ),
555 'connectUrl' => SURE_TRIGGERS_SITE_URL . '/connect-st/connect',
556 'siteTitle' => get_bloginfo( 'name' ),
557 'resetUrl' => base64_encode( wp_nonce_url( admin_url( 'admin.php?st-reset=true' ), 'st-reset-action' ) ),
558 'sourceType' => $source_type,
559 'adminLanguage' => get_user_locale(),
560 ],
561 'user' => [
562 'name' => $current_user->display_name,
563 'email' => $current_user->user_email,
564 ],
565 'stSaasURL' => trailingslashit( SURE_TRIGGERS_SITE_URL ),
566 'stPluginURL' => plugin_dir_url( SURE_TRIGGERS_FILE ),
567 'integrations' => IntegrationsController::get_activated_integrations(),
568 'enabledIntegrations' => OptionController::get_option( 'enabled_integrations' ),
569 'verification_status' => false,
570 'projects' => [],
571 'apiSlug' => SURE_TRIGGERS_REST_NAMESPACE,
572 'reConnectSorryMsg' => (bool) OptionController::get_option( 'st_connect_notice_deprecated' ),
573 'usersRoles' => array_diff_key( $wp_roles->get_names(), [ 'administrator' => '' ] ),
574 'usersList' => get_users(
575 [
576 'fields' => [
577 'ID',
578 'display_name',
579 ],
580 'role__not_in' => [
581 'administrator',
582 ],
583 ]
584 ),
585 'enabledUsers' => $enabled_users,
586 'enabledUserRoles' => $enabled_user_roles,
587 ];
588
589 if ( $is_authorized ) {
590 $data['siteContent']['accessKey'] = SaasApiToken::get();
591 $data['siteContent']['connected_email'] = OptionController::get_option( 'connected_email_key' );
592 }
593
594 $data['settingsNonce'] = esc_js( $settings_nonce );
595 $data['ajaxurl'] = esc_url( admin_url( 'admin-ajax.php' ) );
596
597 return apply_filters( 'sure_trigger_control_localize_vars', $data );
598 }
599
600 /**
601 * Render OttoKit Interface callback.
602 *
603 * @return void
604 */
605 public function suretriggers_render_interface_callback() {
606 ?>
607 <div id="ottokit-settings-page" class="ottokit-settings"></div>
608 <?php
609 }
610
611 /**
612 * Menu callback.
613 *
614 * @since x.x.x
615 *
616 * @return void
617 */
618 public function menu_callback() {
619 // Check permalink structure first.
620 $permalink_structure = get_option( 'permalink_structure' );
621 $is_plain_permalink = empty( $permalink_structure );
622
623 // If permalink structure is "Plain" and we're trying to connect or already connected, show a prominent warning.
624 if ( $is_plain_permalink ) {
625 ?>
626 <div class="st-permalink-warning-wrapper">
627 <div class="st-permalink-warning-card">
628 <div class="st-permalink-warning-icon">
629 <span class="st-permalink-warning-icon-text">!</span>
630 </div>
631 <div class="st-permalink-warning-content">
632 <p class="st-permalink-warning-title">
633 <?php esc_html_e( '“Plain” Permalink Structure Detected', 'suretriggers' ); ?>
634 </p>
635 <p class="st-permalink-warning-message">
636 <?php esc_html_e( 'Your site is currently using the “Plain” permalink structure, which is not supported by OttoKit. Please visit', 'suretriggers' ); ?>
637 <a href="<?php echo esc_url( admin_url( 'options-permalink.php' ) ); ?>" target="_blank" class="st-permalink-warning-link">
638 <?php esc_html_e( 'Permalinks Settings', 'suretriggers' ); ?>
639 </a>
640 <?php esc_html_e( 'on your WordPress Dashboard and choose any structure other than “Plain”.', 'suretriggers' ); ?>
641 </p>
642 </div>
643 </div>
644 </div>
645 <?php
646 }
647
648 // Verify Token.
649 $response = RestController::verify_user_token();
650 $response_body = wp_remote_retrieve_body( $response );
651 $response_code = wp_remote_retrieve_response_code( $response );
652 if ( ! empty( $response_body ) ) {
653 $response_body = json_decode( $response_body, true );
654 }
655 if ( 200 === $response_code || 401 === $response_code ) {
656 if ( is_array( $response_body ) && isset( $response_body['is_iframe_enabled'] ) && 'NO' === $response_body['is_iframe_enabled'] ) {
657 ?>
658 <div class="suretriggers-nobase">
659 <div>
660 <div>
661 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-check inline-block h-8 w-8 text-green-400 mb-6" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><path d="m9 12 2 2 4-4"></path></svg>
662 <h2 class="suretriggers-info-title">
663 <?php esc_html_e( 'OttoKit is connected.', 'suretriggers' ); ?>
664 </h2>
665 <p class="suretriggers-info-content">
666 <?php esc_html_e( 'Your WordPress site is successfully connected to the OttoKit SaaS platform. However, the OttoKit interface display is currently disabled. Click below to enable it.', 'suretriggers' ); ?>
667 </p>
668 <a class="suretriggers-info-link" href="<?php echo esc_url( SURE_TRIGGERS_SITE_URL . '/apps/WordPress' ); ?>" target="_blank">
669 <?php esc_html_e( 'Access Connection Page', 'suretriggers' ); ?>
670 </a>
671 </div>
672 </div>
673 </div>
674 <?php
675 } else {
676 ?>
677 <div id="sure-triggger-entry" class="st-base"></div>
678 <?php
679 }
680 } elseif ( isset( $response ) && is_wp_error( $response ) || 200 !== $response_code ) {
681 ?>
682 <div class="suretriggers-nobase">
683 <div>
684 <div>
685 <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="30" height="24" viewBox="0 0 122.88 122.879" enable-background="new 0 0 122.88 122.879" xml:space="preserve" class="lucide lucide-circle-check inline-block h-8 w-8 text-green-400 mb-6"><g><path fill="#FF4141" d="M61.44,0c16.96,0,32.328,6.882,43.453,17.986c11.104,11.125,17.986,26.494,17.986,43.453 c0,16.961-6.883,32.328-17.986,43.453C93.769,115.998,78.4,122.879,61.44,122.879c-16.96,0-32.329-6.881-43.454-17.986 C6.882,93.768,0,78.4,0,61.439C0,44.48,6.882,29.111,17.986,17.986C29.112,6.882,44.48,0,61.44,0L61.44,0z M73.452,39.152 c2.75-2.792,7.221-2.805,9.986-0.026c2.764,2.776,2.775,7.292,0.027,10.083L71.4,61.445l12.077,12.25 c2.728,2.77,2.689,7.256-0.081,10.021c-2.772,2.766-7.229,2.758-9.954-0.012L61.445,71.541L49.428,83.729 c-2.75,2.793-7.22,2.805-9.985,0.025c-2.763-2.775-2.776-7.291-0.026-10.082L51.48,61.435l-12.078-12.25 c-2.726-2.769-2.689-7.256,0.082-10.022c2.772-2.765,7.229-2.758,9.954,0.013L61.435,51.34L73.452,39.152L73.452,39.152z M96.899,25.98C87.826,16.907,75.29,11.296,61.44,11.296c-13.851,0-26.387,5.611-35.46,14.685 c-9.073,9.073-14.684,21.609-14.684,35.459s5.611,26.387,14.684,35.459c9.073,9.074,21.609,14.686,35.46,14.686 c13.85,0,26.386-5.611,35.459-14.686c9.073-9.072,14.684-21.609,14.684-35.459S105.973,35.054,96.899,25.98L96.899,25.98z"></path></g></svg>
686 <h2 class="suretriggers-info-title">
687 <?php esc_html_e( 'OttoKit Not Connected.', 'suretriggers' ); ?>
688 </h2>
689 <p class="suretriggers-info-content">
690 <?php esc_html_e( 'It looks like your WordPress site’s connection with OttoKit has been affected because the URL used for communication has changed. The current link for your site is different from the one OttoKit was originally connected to.', 'suretriggers' ); ?>
691 </p>
692 <a class="suretriggers-info-link" href="<?php echo esc_url( SURE_TRIGGERS_SITE_URL ); ?>" target="_blank">
693 <?php esc_html_e( 'Access Dashboard', 'suretriggers' ); ?>
694 </a>
695 <a class="suretriggers-info-link" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?st-reset=true' ), 'st-reset-action' ) ); ?>">
696 <?php esc_html_e( 'Disconnect OttoKit', 'suretriggers' ); ?>
697 </a>
698 </div>
699 </div>
700 </div>
701 <?php
702 }
703 }
704
705 /**
706 * Status Menu callback.
707 *
708 * @since x.x.x
709 *
710 * @return void
711 */
712 public function suretriggers_status_menu_callback() {
713 if ( ! isset( OptionController::$options['secret_key'] ) ) {
714 ?>
715 <div class="suretriggers-nobase">
716 <div>
717 <div>
718 <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="30" height="24" viewBox="0 0 122.88 122.879" enable-background="new 0 0 122.88 122.879" xml:space="preserve" class="lucide lucide-circle-check inline-block h-8 w-8 text-green-400 mb-6"><g><path fill="#FF4141" d="M61.44,0c16.96,0,32.328,6.882,43.453,17.986c11.104,11.125,17.986,26.494,17.986,43.453 c0,16.961-6.883,32.328-17.986,43.453C93.769,115.998,78.4,122.879,61.44,122.879c-16.96,0-32.329-6.881-43.454-17.986 C6.882,93.768,0,78.4,0,61.439C0,44.48,6.882,29.111,17.986,17.986C29.112,6.882,44.48,0,61.44,0L61.44,0z M73.452,39.152 c2.75-2.792,7.221-2.805,9.986-0.026c2.764,2.776,2.775,7.292,0.027,10.083L71.4,61.445l12.077,12.25 c2.728,2.77,2.689,7.256-0.081,10.021c-2.772,2.766-7.229,2.758-9.954-0.012L61.445,71.541L49.428,83.729 c-2.75,2.793-7.22,2.805-9.985,0.025c-2.763-2.775-2.776-7.291-0.026-10.082L51.48,61.435l-12.078-12.25 c-2.726-2.769-2.689-7.256,0.082-10.022c2.772-2.765,7.229-2.758,9.954,0.013L61.435,51.34L73.452,39.152L73.452,39.152z M96.899,25.98C87.826,16.907,75.29,11.296,61.44,11.296c-13.851,0-26.387,5.611-35.46,14.685 c-9.073,9.073-14.684,21.609-14.684,35.459s5.611,26.387,14.684,35.459c9.073,9.074,21.609,14.686,35.46,14.686 c13.85,0,26.386-5.611,35.459-14.686c9.073-9.072,14.684-21.609,14.684-35.459S105.973,35.054,96.899,25.98L96.899,25.98z"></path></g></svg>
719 <h2 class="suretriggers-info-title">
720 <?php esc_html_e( 'OttoKit Not Connected.', 'suretriggers' ); ?>
721 </h2>
722 <p class="suretriggers-info-content">
723 <?php esc_html_e( 'Please connect your OttoKit account to access registered events and outgoing requests.', 'suretriggers' ); ?>
724 </p>
725 <a href="<?php echo esc_url( admin_url( 'admin.php?page=suretriggers' ) ); ?>" class="suretriggers-info-link"> <?php esc_html_e( 'Connect With OttoKit', 'suretriggers' ); ?> </a>
726 </div>
727 </div>
728 </div>
729 <?php
730 return;
731 }
732 ?>
733 <div class="wrap">
734 <?php
735 $tabs = [
736 'st_system_page' => __( 'Status', 'suretriggers' ),
737 'st_outgoing_requests' => __( 'Outgoing Requests', 'suretriggers' ),
738 'st_troubleshooting' => __( 'Troubleshooting', 'suretriggers' ),
739 ];
740 $current_tab = 'st_system_page';
741 if ( isset( $_REQUEST['tab'], $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'suretriggers_tab_nonce' ) ) {
742 if ( array_key_exists( sanitize_key( $_REQUEST['tab'] ), $tabs ) ) {
743 $current_tab = sanitize_key( $_REQUEST['tab'] );
744 }
745 }
746 ?>
747 <nav class="suretriggers-nav-tab nav-tab-wrapper">
748 <?php
749 foreach ( $tabs as $name => $label ) {
750 $tab_url = add_query_arg(
751 [
752 'tab' => $name,
753 '_wpnonce' => wp_create_nonce( 'suretriggers_tab_nonce' ),
754 ],
755 admin_url( 'admin.php?page=suretriggers-status' )
756 );
757 echo '<a href="' . esc_url( $tab_url ) . '" class="nav-tab ';
758 if ( $current_tab == $name ) {
759 echo 'nav-tab-active';
760 }
761 echo '">' . esc_html( $label ) . '</a>';
762 }
763 ?>
764 </nav>
765 <?php
766 switch ( $current_tab ) {
767 case 'st_system_page':
768 include_once __DIR__ . '/Admin/Views/st-admin-system-page.php';
769 break;
770 case 'st_outgoing_requests':
771 include_once __DIR__ . '/Admin/Views/st-admin-outgoing-req-page.php';
772 break;
773 case 'st_troubleshooting':
774 include_once __DIR__ . '/Admin/Views/st-admin-troubleshooting-page.php';
775 break;
776 }
777 ?>
778 </div>
779 <?php
780 }
781
782 /**
783 * Get OttoKit Pro Menu callback.
784 *
785 * @since x.x.x
786 *
787 * @return void
788 */
789 public function suretriggers_upgrade_plan_callback() {
790 ?>
791 <script type="text/javascript">
792 window.location.href = 'https://ottokit.com/pricing/?utm_source=wpplugin&utm_medium=menu&utm_campaign=left';
793 </script>
794 <?php
795 exit;
796 }
797
798 /**
799 * Add admin menu styles.
800 *
801 * @since x.x.x
802 *
803 * @return void
804 */
805 public function add_admin_menu_styles() {
806 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only check for menu highlighting.
807 $redirect_url_raw = isset( $_GET['redirect_url'] ) ? sanitize_text_field( wp_unslash( $_GET['redirect_url'] ) ) : '';
808 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
809 $current_page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
810
811 // Validate redirect_url against known deep-link paths to prevent CSS injection.
812 $allowed_paths = [ '/workflows', '/tables', '/forms', '/mcp', '/recipes', '/folders', '/email-templates', '/variables', '/history', '/apps', '/members', '/settings' ];
813 $redirect_url = in_array( $redirect_url_raw, $allowed_paths, true ) ? $redirect_url_raw : '';
814 ?>
815 <style>
816 <?php if ( 'suretriggers' === $current_page && '' === $redirect_url ) : ?>
817 /* Left border indicator for Dashboard when it's the active page */
818 #toplevel_page_suretriggers .wp-submenu li.wp-first-item.current a {
819 border-left: 3px solid #fff !important;
820 padding-left: 9px !important;
821 }
822 <?php endif; ?>
823 <?php if ( 'suretriggers' === $current_page && '' !== $redirect_url ) : ?>
824 /* Remove default highlight from Dashboard when a deep-link item is active */
825 #toplevel_page_suretriggers .wp-submenu li.wp-first-item.current a {
826 color: #b4b9be !important;
827 font-weight: 400 !important;
828 }
829 #toplevel_page_suretriggers .wp-submenu li.wp-first-item.current {
830 /* Keep class for WP internals but override visual */
831 }
832 /* Left border indicator for the active deep-link submenu item */
833 <?php // phpcs:disable WordPressVIPMinimum.Security.ProperEscapingFunction.hrefSrcEscUrl -- CSS attribute selector, not HTML href. Value is allowlisted. ?>
834 #toplevel_page_suretriggers .wp-submenu li a[href*="redirect_url=<?php echo esc_attr( rawurlencode( $redirect_url ) ); ?>"],
835 #toplevel_page_suretriggers .wp-submenu li a[href*="redirect_url=<?php echo esc_attr( $redirect_url ); ?>"] {
836 <?php // phpcs:enable WordPressVIPMinimum.Security.ProperEscapingFunction.hrefSrcEscUrl ?>
837 color: #fff !important;
838 font-weight: 600 !important;
839 border-left: 3px solid #fff !important;
840 padding-left: 9px !important;
841 }
842 <?php endif; ?>
843 </style>
844 <script>
845 jQuery(document).ready(function($) {
846 // Direct redirect for admin menu upgrade button.
847 $('a[href*="suretriggers-lifetime-access"]').on('click', function(e) {
848 e.preventDefault();
849 window.open('https://ottokit.com/pricing/?utm_source=wpplugin&utm_medium=menu&utm_campaign=left', '_blank');
850 return false;
851 });
852 });
853 </script>
854 <?php
855 }
856
857 /**
858 * Include all files from the folder.
859 *
860 * @param string $folder folder path.
861 * @return void
862 */
863 public function include_all_files( $folder ) {
864 $dir = new DirectoryIterator( $folder );
865 foreach ( $dir as $file ) {
866 if ( ! $file->isDot() ) {
867 if ( $file->isDir() ) {
868 $this->include_all_files( $file->getPathname() );
869 } else {
870 require_once $file->getPathname();
871 }
872 }
873 }
874 }
875
876 /**
877 * Initialize core trigger and actions.
878 *
879 * @return void
880 */
881 public function initialize_core() {
882
883 IntegrationsController::load_event_files();
884
885 EventController::get_instance();
886 IntegrationsController::get_instance();
887 GlobalSearchController::get_instance();
888 RestController::get_instance();
889 OptionController::get_instance();
890 AutomationController::get_instance();
891 AuthController::get_instance();
892 RoutesController::get_instance();
893 WebhookRequestsController::get_instance();
894 SettingsController::get_instance();
895 AbilitiesController::get_instance();
896
897 // SureTriggers Custom Filter data.
898 add_filter( 'suretriggers_get_iframe_url', [ $this, 'suretriggers_iframe_data' ] );
899 add_filter( 'suretriggers_is_user_connected', [ $this, 'suretriggers_saas_connected_data' ] );
900
901 // Create Webhook Request Log table.
902 WebhookRequestsController::suretriggers_webhook_request_log_table();
903 // Schedule the cron jon to retry failed triggers.
904 WebhookRequestsController::suretriggers_setup_custom_cron();
905
906 $this->include_all_files( SURE_TRIGGERS_DIR . 'src/Integrations/' );
907 }
908
909 /**
910 * Added option to reset plugin in case of testing.
911 *
912 * @return void
913 */
914 public function reset_plugin() {
915 $nonce = sanitize_text_field( wp_unslash( isset( $_GET['_wpnonce'] ) ? $_GET['_wpnonce'] : false ) );
916
917 if ( $nonce && wp_verify_nonce( $nonce, 'st-reset-action' ) ) {
918 $is_reset = sanitize_text_field( wp_unslash( isset( $_GET['st-reset'] ) ? $_GET['st-reset'] : false ) );
919 if ( $is_reset && current_user_can( 'manage_options' ) ) {
920 delete_option( 'suretrigger_options' );
921 self::clear_verification_cache();
922 wp_safe_redirect( admin_url( 'admin.php?page=suretriggers' ) );
923 exit();
924 }
925 }
926 }
927
928 /**
929 * Custom Filter data.
930 *
931 * @param string $site_url Optional. Site URL to include in the iframe data.
932 * @return string
933 */
934 public function suretriggers_iframe_data( $site_url = '' ) {
935 $site_url = esc_url_raw( $site_url );
936 if ( ! current_user_can( 'manage_options' ) ) {
937 return $site_url;
938 }
939 $site_content_data = [
940 'stSaasURL' => $site_url . 'wp-login',
941 'stCode' => SaasApiToken::get(),
942 'baseUrl' => str_replace( '/wp-json/', '', get_rest_url() ),
943 'resetUrl' => rtrim( base64_encode( wp_nonce_url( admin_url( 'admin.php?st-reset=true' ), 'st-reset-action' ) ), '=' ), // phpcs:ignore
944 ];
945 $params = [
946 'st-code' => $site_content_data['stCode'],
947 'base_url' => $site_content_data['baseUrl'],
948 'reset_url' => $site_content_data['resetUrl'],
949 'redirect_url' => $site_url . 'embed-login',
950 'is_embedded' => true,
951 ];
952
953 if ( filter_var( $site_url, FILTER_VALIDATE_URL ) ) {
954 $iframe_url = add_query_arg( $params, $site_content_data['stSaasURL'] );
955 } else {
956 $default_url = trailingslashit( SURE_TRIGGERS_SITE_URL ) . '?path=dashboard';
957 $iframe_url = add_query_arg( $params, $default_url );
958 }
959 return esc_url_raw( $iframe_url );
960 }
961
962
963 /**
964 * Custom Filter data to check if user is logged in iframe.
965 *
966 * @return bool
967 */
968 public function suretriggers_saas_connected_data() {
969 if ( ! current_user_can( 'manage_options' ) ) {
970 return false;
971 }
972 $token = SaasApiToken::get();
973
974 if ( '' === $token || null === $token || false === $token || 'connection-denied' === $token ) {
975 $logged_in = false;
976 } else {
977 $logged_in = true;
978 }
979 return $logged_in;
980 }
981
982 /**
983 * Check if user has lifetime plan
984 *
985 * @return bool
986 */
987 public function is_lifetime_plan() {
988 // Check if verification data is already stored in database.
989 $verification_data = get_option( 'suretriggers_lifetime_user_plan_data' );
990 // Return lifetime plan status from cached data.
991 if ( is_array( $verification_data ) && isset( $verification_data['is_lifetime_plan'] ) ) {
992 return (bool) $verification_data['is_lifetime_plan'];
993 }
994
995 return false;
996 }
997
998 /**
999 * Check if user should see upgrade button (free or pro plan)
1000 *
1001 * @return bool
1002 */
1003 public function should_show_upgrade_button() {
1004 $verification_data = get_option( 'suretriggers_lifetime_user_plan_data' );
1005
1006 if ( is_array( $verification_data ) && isset( $verification_data['plan_id'] ) ) {
1007 $plan_id = $verification_data['plan_id'];
1008 return in_array( $plan_id, [ 'free', 'pro' ], true );
1009 }
1010
1011 return false;
1012 }
1013
1014 /**
1015 * Clear cached user verification data when token changes
1016 *
1017 * @return void
1018 */
1019 public static function clear_verification_cache() {
1020 delete_option( 'suretriggers_lifetime_user_plan_data' );
1021 }
1022 }
1023