PluginProbe
SureContact – Newsletters, Email Marketing, Automation, Revenue Tracking & CRM / 1.4.1
SureContact – Newsletters, Email Marketing, Automation, Revenue Tracking & CRM v1.4.1
1.5.4 1.5.3 1.5.2 1.5.1 trunk 0.0.2 0.0.3 0.0.4 0.0.5 1.0.0 1.1.0 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.5.0
surecontact / surecontact.php

surecontact.php in SureContact – Newsletters, Email Marketing, Automation, Revenue Tracking & CRM 1.4.1, at surecontact.php

504 lines 11.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: SureContact – Newsletters, Email Marketing, Automation, Revenue Tracking & CRM
4 * Plugin URI: https://surecontact.com
5 * Description: Send newsletters, set up email automations, manage contacts and track ecommerce revenue in a CRM for WordPress.
6 * Version: 1.4.1
7 * Author: SureContact
8 * Author URI: https://profiles.wordpress.org/brainstormforce/
9 * License: GPLv2 or later
10 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
11 * Text Domain: surecontact
12 * Domain Path: /languages
13 * Requires at least: 5.8
14 * Tested up to: 6.9
15 * Requires PHP: 7.4
16 *
17 * @since 0.0.1
18 *
19 * @package SureContact
20 */
21
22 // Exit if accessed directly.
23 if ( ! defined( 'ABSPATH' ) ) {
24 exit;
25 }
26
27 /**
28 * SaaS API Base URL constant
29 *
30 * @since 0.0.1
31 */
32 if ( ! defined( 'SURECONTACT_SAAS_API_BASE_URL' ) ) {
33 define( 'SURECONTACT_SAAS_API_BASE_URL', 'https://api.surecontact.com' );
34 }
35
36 /**
37 * SaaS SDK Base URL constant
38 *
39 * @since 0.0.1
40 */
41 if ( ! defined( 'SURECONTACT_SAAS_BASE_URL' ) ) {
42 define( 'SURECONTACT_SAAS_BASE_URL', 'https://app.surecontact.com' );
43 }
44
45 /**
46 * Main plugin class
47 *
48 * Singleton pattern implementation for SureContact plugin.
49 * Handles plugin initialization, dependency loading, and lifecycle hooks.
50 *
51 * @since 0.0.1
52 */
53 final class SureContact {
54
55 /**
56 * Plugin version
57 *
58 * @since 0.0.1
59 *
60 * @var string
61 */
62 const VERSION = '1.4.1';
63
64 /**
65 * Plugin singleton instance
66 *
67 * @since 0.0.1
68 *
69 * @var SureContact|null
70 */
71 private static $instance = null;
72
73 /**
74 * Plugin directory path
75 *
76 * @since 0.0.1
77 *
78 * @var string
79 */
80 private $plugin_path;
81
82 /**
83 * Plugin directory URL
84 *
85 * @since 0.0.1
86 *
87 * @var string
88 */
89 private $plugin_url;
90
91 /**
92 * Integrations loader instance
93 *
94 * @since 0.0.1
95 *
96 * @var SureContact\Integrations_Loader|null
97 */
98 public $integrations_loader;
99
100 /**
101 * Daily Sync Manager instance
102 *
103 * @since 0.0.1
104 *
105 * @var SureContact\Daily_Sync_Manager|null
106 */
107 private $daily_sync_manager;
108
109
110 /**
111 * Bulk Sync Service instance
112 *
113 * @since 0.0.1
114 *
115 * @var SureContact\Bulk_Sync_Service|null
116 */
117 private $bulk_sync_service;
118
119 /**
120 * Admin Menu instance
121 *
122 * @since 0.0.1
123 *
124 * @var SureContact\Admin\Admin_Menu|null
125 */
126 private $admin_menu;
127
128
129 /**
130 * Queue Manager instance
131 *
132 * @since 0.0.1
133 *
134 * @var SureContact\Queue_Manager|null
135 */
136 private $queue_manager;
137
138 /**
139 * Get singleton instance
140 *
141 * Implements lazy loading for better performance.
142 *
143 * @since 0.0.1
144 *
145 * @return SureContact
146 */
147 public static function get_instance() {
148 if ( is_null( self::$instance ) ) {
149 self::$instance = new self();
150 }
151 return self::$instance;
152 }
153
154 /**
155 * Private constructor to prevent direct instantiation
156 *
157 * @since 0.0.1
158 */
159 private function __construct() {
160 $this->define_constants();
161 $this->setup_hooks();
162 $this->load_dependencies();
163 $this->init_hooks();
164 }
165
166 /**
167 * Define plugin constants
168 *
169 * @since 0.0.1
170 *
171 * @return void
172 */
173 private function define_constants() {
174 $this->plugin_path = plugin_dir_path( __FILE__ );
175 $this->plugin_url = plugin_dir_url( __FILE__ );
176
177 define( 'SURECONTACT_VERSION', self::VERSION );
178 define( 'SURECONTACT_PLUGIN_PATH', $this->plugin_path );
179 define( 'SURECONTACT_PLUGIN_URL', $this->plugin_url );
180 define( 'SURECONTACT_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
181 }
182
183 /**
184 * Setup activation and deactivation hooks
185 *
186 * @since 0.0.1
187 *
188 * @return void
189 */
190 private function setup_hooks() {
191 register_activation_hook( __FILE__, array( $this, 'activate' ) );
192 register_deactivation_hook( __FILE__, array( $this, 'deactivate' ) );
193 }
194
195 /**
196 * Load required dependencies
197 *
198 * @since 0.0.1
199 *
200 * @return void
201 */
202 private function load_dependencies() {
203 $this->load_action_scheduler();
204
205 // Load global helper functions.
206 require_once SURECONTACT_PLUGIN_PATH . 'includes/functions.php';
207
208 $autoloader_path = SURECONTACT_PLUGIN_PATH . 'includes/class-autoloader.php';
209 if ( file_exists( $autoloader_path ) ) {
210 require_once $autoloader_path;
211 } else {
212 // Autoloader not loaded yet, use direct error_log.
213 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
214 error_log(
215 '[' . gmdate( 'Y-m-d H:i:s' ) . '] SureContact [ERROR] Plugin: Critical error - autoloader not found at ' . $autoloader_path
216 );
217 }
218 }
219
220 /**
221 * Initialize plugin components via WordPress hooks
222 *
223 * @since 0.0.1
224 *
225 * @return void
226 */
227 private function init_hooks() {
228 // Ensure database tables exist (safety check for edge cases).
229 add_action( 'plugins_loaded', array( $this, 'maybe_create_tables' ), 1 );
230
231 add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
232 add_action( 'init', array( $this, 'init_queue_manager' ), 2 );
233 add_action( 'init', array( $this, 'init_daily_sync_manager' ), 3 );
234 add_action( 'init', array( $this, 'init_bulk_sync_service' ), 5 );
235 // Load integrations early on init hook to ensure hooks are registered before plugin actions fire.
236 add_action( 'init', array( $this, 'init_integrations' ), 5 );
237 add_action( 'rest_api_init', array( $this, 'init_rest_api' ) );
238
239 SureContact\Abilities\Abilities_Loader::instance()->init();
240
241 if ( is_admin() ) {
242 add_action( 'admin_menu', array( $this, 'init_admin_menus' ) );
243 add_filter( 'plugin_action_links_' . SURECONTACT_PLUGIN_BASENAME, array( $this, 'add_action_links' ) );
244 add_filter( 'plugin_row_meta', array( $this, 'add_meta_links' ), 10, 2 );
245 }
246 }
247
248 /**
249 * Load plugin textdomain for translations
250 *
251 * @since 1.4.0
252 *
253 * @return void
254 */
255 public function load_textdomain() {
256 load_plugin_textdomain(
257 'surecontact',
258 false,
259 dirname( SURECONTACT_PLUGIN_BASENAME ) . '/languages'
260 );
261 }
262
263 /**
264 * Initialize Queue Manager.
265 *
266 * @since 0.0.1
267 *
268 * @return void
269 */
270 public function init_queue_manager() {
271 if ( is_null( $this->queue_manager ) ) {
272 $this->queue_manager = new SureContact\Queue_Manager();
273 }
274 }
275
276
277 /**
278 * Initialize Daily Sync Manager
279 *
280 * @since 0.0.1
281 *
282 * @return void
283 */
284 public function init_daily_sync_manager() {
285 if ( is_null( $this->daily_sync_manager ) ) {
286 $this->daily_sync_manager = new SureContact\Daily_Sync_Manager();
287 }
288 }
289
290
291 /**
292 * Initialize admin menus
293 *
294 * @since 0.0.1
295 *
296 * @return void
297 */
298 public function init_admin_menus() {
299 if ( is_null( $this->admin_menu ) ) {
300 $this->admin_menu = new SureContact\Admin\Admin_Menu();
301 }
302 }
303
304 /**
305 * Initialize REST API
306 *
307 * @since 0.0.1
308 *
309 * @return void
310 */
311 public function init_rest_api() {
312 $rest_controller = new SureContact\API_WP\Rest_Controller();
313 $rest_controller->register_routes();
314
315 SureContact\API_WP\Api_Init::instance();
316 }
317
318 /**
319 * Initialize Bulk Sync Service
320 *
321 * @since 0.0.1
322 *
323 * @return void
324 */
325 public function init_bulk_sync_service() {
326 if ( is_null( $this->bulk_sync_service ) ) {
327 $this->bulk_sync_service = new SureContact\Bulk_Sync_Service();
328 }
329 }
330
331 /**
332 * Initialize integrations loader
333 *
334 * @since 0.0.1
335 *
336 * @return void
337 */
338 public function init_integrations() {
339 $this->integrations_loader = new SureContact\Integrations_Loader();
340 }
341
342 /**
343 * Plugin activation handler
344 *
345 * Creates database tables and performs initial setup.
346 *
347 * @since 0.0.1
348 *
349 * @return void
350 */
351 public function activate() {
352 // Create database tables.
353 require_once SURECONTACT_PLUGIN_PATH . 'includes/database/class-api-queue-table.php';
354 require_once SURECONTACT_PLUGIN_PATH . 'includes/database/class-integrations-table.php';
355
356 SureContact\Database\API_Queue_Table::create_table();
357 SureContact\Database\Integrations_Table::create_table();
358
359 flush_rewrite_rules();
360 }
361
362 /**
363 * Maybe create or update tables and run migrations.
364 *
365 * Runs on plugins_loaded to ensure tables exist and are up to date.
366 * Each table class handles its own version checking and update logic.
367 * Handles edge cases where activation hook didn't run (multisite, manual install, etc.).
368 *
369 * @since 0.0.1
370 *
371 * @return void
372 */
373 public function maybe_create_tables() {
374 require_once SURECONTACT_PLUGIN_PATH . 'includes/database/class-api-queue-table.php';
375 require_once SURECONTACT_PLUGIN_PATH . 'includes/database/class-integrations-table.php';
376 require_once SURECONTACT_PLUGIN_PATH . 'includes/class-migration-manager.php';
377
378 SureContact\Database\API_Queue_Table::maybe_create_or_update();
379 SureContact\Database\Integrations_Table::maybe_create_or_update();
380
381 // Run data migrations after tables are ready.
382 SureContact\Migration_Manager::maybe_run_migrations();
383 }
384
385 /**
386 * Plugin deactivation handler
387 *
388 * @since 0.0.1
389 *
390 * @return void
391 */
392 public function deactivate() {
393 flush_rewrite_rules();
394
395 // Clear SureMembers expiration cron schedule.
396 $timestamp = wp_next_scheduled( 'surecontact_suremembers_check_expirations' );
397 if ( $timestamp ) {
398 wp_unschedule_event( $timestamp, 'surecontact_suremembers_check_expirations' );
399 }
400 }
401
402 /**
403 * Add action links to plugin list
404 *
405 * @since 0.0.1
406 *
407 * @param array $links Existing plugin action links.
408 * @return array Modified plugin action links.
409 */
410 public function add_action_links( $links ) {
411 $workspace_uuid = get_option( 'surecontact_workspace_uuid', '' );
412 $is_connected = ! empty( $workspace_uuid );
413
414 $link_text = $is_connected
415 ? __( 'Access Dashboard', 'surecontact' )
416 : __( 'Get Started Now', 'surecontact' );
417
418 $dashboard_link = sprintf(
419 '<a href="%s">%s</a>',
420 esc_url( admin_url( 'admin.php?page=surecontact-dashboard' ) ),
421 esc_html( $link_text )
422 );
423
424 array_unshift( $links, $dashboard_link );
425
426 return $links;
427 }
428
429 /**
430 * Add meta links to the plugin row (under description).
431 *
432 * @since 0.0.3
433 *
434 * @param array<int,string> $links Array of plugin meta links.
435 * @param string $file Plugin file path.
436 * @return array<int,string> Modified plugin meta links.
437 */
438 public function add_meta_links( array $links, string $file ): array {
439 if ( SURECONTACT_PLUGIN_BASENAME === $file ) {
440 $stars = '';
441 for ( $indx = 0; $indx < 5; $indx++ ) {
442 $stars .= '<span class="dashicons dashicons-star-filled" style="color: #ffb900; font-size: 16px; width: 16px; height: 16px; line-height: 1.2;" aria-hidden="true"></span>';
443 }
444 $links[] = sprintf(
445 '<a href="%s" target="_blank" rel="noopener noreferrer" aria-label="%s" role="button">%s</a>',
446 esc_url( 'https://wordpress.org/support/plugin/surecontact/reviews/#new-post' ),
447 esc_attr__( 'Rate our plugin', 'surecontact' ),
448 $stars
449 );
450 }
451 return $links;
452 }
453
454 /**
455 * Get plugin directory path
456 *
457 * @since 0.0.1
458 *
459 * @return string Plugin directory path.
460 */
461 public function get_plugin_path() {
462 return $this->plugin_path;
463 }
464
465 /**
466 * Get plugin directory URL
467 *
468 * @since 0.0.1
469 *
470 * @return string Plugin directory URL.
471 */
472 public function get_plugin_url() {
473 return $this->plugin_url;
474 }
475
476 /**
477 * Load Action Scheduler library
478 *
479 * @since 0.0.1
480 *
481 * @return void
482 */
483 private function load_action_scheduler() {
484 if ( function_exists( 'as_enqueue_async_action' ) ) {
485 return;
486 }
487
488 $action_scheduler_path = SURECONTACT_PLUGIN_PATH . 'lib/action-scheduler/action-scheduler.php';
489
490 if ( file_exists( $action_scheduler_path ) ) {
491 require_once $action_scheduler_path;
492 } else {
493 // Autoloader not loaded yet, use direct error_log.
494 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
495 error_log(
496 '[' . gmdate( 'Y-m-d H:i:s' ) . '] SureContact [ERROR] Plugin: Action Scheduler library not found at ' . $action_scheduler_path
497 );
498 }
499 }
500 }
501
502 // Initialize plugin.
503 $GLOBALS['surecontact'] = SureContact::get_instance();
504