diff --git a/lib/Config/Initializer.php b/lib/Config/Initializer.php index 4332cc20d8..7b81ca950d 100644 --- a/lib/Config/Initializer.php +++ b/lib/Config/Initializer.php @@ -1,197 +1,197 @@ - '', - 'version' => '1.0.0' - )) { - Env::init($params['file'], $params['version']); - } - - function init() { - $this->setupDB(); - - register_activation_hook(Env::$file, array($this, 'runMigrator')); - register_activation_hook(Env::$file, array($this, 'runPopulator')); - - add_action('plugins_loaded', array($this, 'setup')); - add_action('init', array($this, 'onInit')); - add_action('widgets_init', array($this, 'setupWidget')); - } - - function setup() { - try { - $this->setupRenderer(); - $this->setupLocalizer(); - $this->setupMenu(); - $this->setupPermissions(); - $this->setupAnalytics(); - $this->setupChangelog(); - $this->setupShortcodes(); - $this->setupHooks(); - $this->setupImages(); - $this->runQueueSupervisor(); - } catch(\Exception $e) { - // if anything goes wrong during init - // automatically deactivate the plugin - deactivate_plugins(Env::$file); - } - } - - function onInit() { - $this->setupRouter(); - $this->setupPublicAPI(); - $this->setupPages(); - } - - function setupDB() { - \ORM::configure(Env::$db_source_name); - \ORM::configure('username', Env::$db_username); - \ORM::configure('password', Env::$db_password); - \ORM::configure('logging', WP_DEBUG); - \ORM::configure('logger', function($query, $time) { - // error_log("\n".$query."\n"); - }); - - \ORM::configure('driver_options', array( - \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', - \PDO::MYSQL_ATTR_INIT_COMMAND => - 'SET TIME_ZONE = "' . Env::$db_timezone_offset. '"' - )); - - $settings = Env::$db_prefix . 'settings'; - $segments = Env::$db_prefix . 'segments'; - $forms = Env::$db_prefix . 'forms'; - $custom_fields = Env::$db_prefix . 'custom_fields'; - $subscribers = Env::$db_prefix . 'subscribers'; - $subscriber_segment = Env::$db_prefix . 'subscriber_segment'; - $subscriber_custom_field = Env::$db_prefix . 'subscriber_custom_field'; - $newsletter_segment = Env::$db_prefix . 'newsletter_segment'; - $sending_queues = Env::$db_prefix . 'sending_queues'; - $newsletters = Env::$db_prefix . 'newsletters'; - $newsletter_templates = Env::$db_prefix . 'newsletter_templates'; - $newsletter_option_fields = Env::$db_prefix . 'newsletter_option_fields'; - $newsletter_option = Env::$db_prefix . 'newsletter_option'; - $newsletter_links = Env::$db_prefix . 'newsletter_links'; - $newsletter_posts = Env::$db_prefix . 'newsletter_posts'; - $statistics_newsletters = Env::$db_prefix . 'statistics_newsletters'; - $statistics_clicks = Env::$db_prefix . 'statistics_clicks'; - $statistics_opens = Env::$db_prefix . 'statistics_opens'; - $statistics_unsubscribes = Env::$db_prefix . 'statistics_unsubscribes'; - $statistics_forms = Env::$db_prefix . 'statistics_forms'; - - define('MP_SETTINGS_TABLE', $settings); - define('MP_SEGMENTS_TABLE', $segments); - define('MP_FORMS_TABLE', $forms); - define('MP_CUSTOM_FIELDS_TABLE', $custom_fields); - define('MP_SUBSCRIBERS_TABLE', $subscribers); - define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment); - define('MP_SUBSCRIBER_CUSTOM_FIELD_TABLE', $subscriber_custom_field); - define('MP_SENDING_QUEUES_TABLE', $sending_queues); - define('MP_NEWSLETTERS_TABLE', $newsletters); - define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates); - define('MP_NEWSLETTER_SEGMENT_TABLE', $newsletter_segment); - define('MP_NEWSLETTER_OPTION_FIELDS_TABLE', $newsletter_option_fields); - define('MP_NEWSLETTER_LINKS_TABLE', $newsletter_links); - define('MP_NEWSLETTER_POSTS_TABLE', $newsletter_posts); - define('MP_NEWSLETTER_OPTION_TABLE', $newsletter_option); - define('MP_STATISTICS_NEWSLETTERS_TABLE', $statistics_newsletters); - define('MP_STATISTICS_CLICKS_TABLE', $statistics_clicks); - define('MP_STATISTICS_OPENS_TABLE', $statistics_opens); - define('MP_STATISTICS_UNSUBSCRIBES_TABLE', $statistics_unsubscribes); - define('MP_STATISTICS_FORMS_TABLE', $statistics_forms); - } - - function runMigrator() { - $migrator = new Migrator(); - $migrator->up(); - } - - function runPopulator() { - $populator = new Populator(); - $populator->up(); - } - - function setupRenderer() { - $renderer = new Renderer(); - $this->renderer = $renderer->init(); - } - - function setupLocalizer() { - $localizer = new Localizer($this->renderer); - $localizer->init(); - } - - function setupMenu() { - $menu = new Menu($this->renderer, Env::$assets_url); - $menu->init(); - } - - function setupRouter() { - $router = new Router\Router(); - $router->init(); - } - - function setupWidget() { - $widget = new Widget($this->renderer); - $widget->init(); - } - - function setupAnalytics() { - $widget = new Analytics(); - $widget->init(); - } - - function setupPermissions() { - $permissions = new Permissions(); - $permissions->init(); - } - - function setupChangelog() { - $changelog = new Changelog(); - $changelog->init(); - } - - function setupPages() { - $pages = new \MailPoet\Settings\Pages(); - $pages->init(); - } - - function setupShortcodes() { - $shortcodes = new Shortcodes(); - $shortcodes->init(); - } - - function setupHooks() { - $hooks = new Hooks(); - $hooks->init(); - } - - function setupPublicAPI() { - $publicAPI = new PublicAPI(); - $publicAPI->init(); - } - - function runQueueSupervisor() { - if(php_sapi_name() === 'cli') return; - try { - $supervisor = new Supervisor(); - $supervisor->checkDaemon(); - } catch(\Exception $e) { - // Prevent Daemon exceptions from breaking out and breaking UI - } - } - - function setupImages() { - add_image_size('mailpoet_newsletter_max', 1320); - } -} + '', + 'version' => '1.0.0' + )) { + Env::init($params['file'], $params['version']); + } + + function init() { + $this->setupDB(); + + register_activation_hook(Env::$file, array($this, 'runMigrator')); + register_activation_hook(Env::$file, array($this, 'runPopulator')); + + add_action('plugins_loaded', array($this, 'setup')); + add_action('init', array($this, 'onInit')); + add_action('widgets_init', array($this, 'setupWidget')); + } + + function setup() { + try { + $this->setupRenderer(); + $this->setupLocalizer(); + $this->setupMenu(); + $this->setupPermissions(); + $this->setupAnalytics(); + $this->setupChangelog(); + $this->setupShortcodes(); + $this->setupHooks(); + $this->setupImages(); + $this->runQueueSupervisor(); + } catch(\Exception $e) { + // if anything goes wrong during init + // automatically deactivate the plugin + deactivate_plugins(Env::$file); + } + } + + function onInit() { + $this->setupRouter(); + $this->setupPublicAPI(); + $this->setupPages(); + } + + function setupDB() { + \ORM::configure(Env::$db_source_name); + \ORM::configure('username', Env::$db_username); + \ORM::configure('password', Env::$db_password); + \ORM::configure('logging', WP_DEBUG); + \ORM::configure('logger', function($query, $time) { + // error_log("\n".$query."\n"); + }); + + \ORM::configure('driver_options', array( + \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', + \PDO::MYSQL_ATTR_INIT_COMMAND => + 'SET TIME_ZONE = "' . Env::$db_timezone_offset. '"' + )); + + $settings = Env::$db_prefix . 'settings'; + $segments = Env::$db_prefix . 'segments'; + $forms = Env::$db_prefix . 'forms'; + $custom_fields = Env::$db_prefix . 'custom_fields'; + $subscribers = Env::$db_prefix . 'subscribers'; + $subscriber_segment = Env::$db_prefix . 'subscriber_segment'; + $subscriber_custom_field = Env::$db_prefix . 'subscriber_custom_field'; + $newsletter_segment = Env::$db_prefix . 'newsletter_segment'; + $sending_queues = Env::$db_prefix . 'sending_queues'; + $newsletters = Env::$db_prefix . 'newsletters'; + $newsletter_templates = Env::$db_prefix . 'newsletter_templates'; + $newsletter_option_fields = Env::$db_prefix . 'newsletter_option_fields'; + $newsletter_option = Env::$db_prefix . 'newsletter_option'; + $newsletter_links = Env::$db_prefix . 'newsletter_links'; + $newsletter_posts = Env::$db_prefix . 'newsletter_posts'; + $statistics_newsletters = Env::$db_prefix . 'statistics_newsletters'; + $statistics_clicks = Env::$db_prefix . 'statistics_clicks'; + $statistics_opens = Env::$db_prefix . 'statistics_opens'; + $statistics_unsubscribes = Env::$db_prefix . 'statistics_unsubscribes'; + $statistics_forms = Env::$db_prefix . 'statistics_forms'; + + define('MP_SETTINGS_TABLE', $settings); + define('MP_SEGMENTS_TABLE', $segments); + define('MP_FORMS_TABLE', $forms); + define('MP_CUSTOM_FIELDS_TABLE', $custom_fields); + define('MP_SUBSCRIBERS_TABLE', $subscribers); + define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment); + define('MP_SUBSCRIBER_CUSTOM_FIELD_TABLE', $subscriber_custom_field); + define('MP_SENDING_QUEUES_TABLE', $sending_queues); + define('MP_NEWSLETTERS_TABLE', $newsletters); + define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates); + define('MP_NEWSLETTER_SEGMENT_TABLE', $newsletter_segment); + define('MP_NEWSLETTER_OPTION_FIELDS_TABLE', $newsletter_option_fields); + define('MP_NEWSLETTER_LINKS_TABLE', $newsletter_links); + define('MP_NEWSLETTER_POSTS_TABLE', $newsletter_posts); + define('MP_NEWSLETTER_OPTION_TABLE', $newsletter_option); + define('MP_STATISTICS_NEWSLETTERS_TABLE', $statistics_newsletters); + define('MP_STATISTICS_CLICKS_TABLE', $statistics_clicks); + define('MP_STATISTICS_OPENS_TABLE', $statistics_opens); + define('MP_STATISTICS_UNSUBSCRIBES_TABLE', $statistics_unsubscribes); + define('MP_STATISTICS_FORMS_TABLE', $statistics_forms); + } + + function runMigrator() { + $migrator = new Migrator(); + $migrator->up(); + } + + function runPopulator() { + $populator = new Populator(); + $populator->up(); + } + + function setupRenderer() { + $renderer = new Renderer(); + $this->renderer = $renderer->init(); + } + + function setupLocalizer() { + $localizer = new Localizer($this->renderer); + $localizer->init(); + } + + function setupMenu() { + $menu = new Menu($this->renderer, Env::$assets_url); + $menu->init(); + } + + function setupRouter() { + $router = new Router\Router(); + $router->init(); + } + + function setupWidget() { + $widget = new Widget($this->renderer); + $widget->init(); + } + + function setupAnalytics() { + $widget = new Analytics(); + $widget->init(); + } + + function setupPermissions() { + $permissions = new Permissions(); + $permissions->init(); + } + + function setupChangelog() { + $changelog = new Changelog(); + $changelog->init(); + } + + function setupPages() { + $pages = new \MailPoet\Settings\Pages(); + $pages->init(); + } + + function setupShortcodes() { + $shortcodes = new Shortcodes(); + $shortcodes->init(); + } + + function setupHooks() { + $hooks = new Hooks(); + $hooks->init(); + } + + function setupPublicAPI() { + $publicAPI = new PublicAPI(); + $publicAPI->init(); + } + + function runQueueSupervisor() { + if(php_sapi_name() === 'cli') return; + try { + $supervisor = new Supervisor(); + $supervisor->checkDaemon(); + } catch(\Exception $e) { + // Prevent Daemon exceptions from breaking out and breaking UI + } + } + + function setupImages() { + add_image_size('mailpoet_newsletter_max', 1320); + } +} diff --git a/lib/Config/Migrator.php b/lib/Config/Migrator.php index a23cc245d6..abe3086f6e 100644 --- a/lib/Config/Migrator.php +++ b/lib/Config/Migrator.php @@ -1,360 +1,360 @@ -prefix = Env::$db_prefix; - $this->charset = Env::$db_charset; - $this->models = array( - 'segments', - 'settings', - 'custom_fields', - 'sending_queues', - 'subscribers', - 'subscriber_segment', - 'subscriber_custom_field', - 'newsletters', - 'newsletter_templates', - 'newsletter_option_fields', - 'newsletter_option', - 'newsletter_segment', - 'newsletter_links', - 'newsletter_posts', - 'forms', - 'statistics_newsletters', - 'statistics_clicks', - 'statistics_opens', - 'statistics_unsubscribes', - 'statistics_forms' - ); - } - - function up() { - global $wpdb; - - $_this = $this; - $migrate = function($model) use($_this) { - dbDelta($_this->$model()); - }; - - array_map($migrate, $this->models); - } - - function down() { - global $wpdb; - - $drop_table = function($model) use($wpdb) { - $table = $this->prefix . $model; - $wpdb->query("DROP TABLE {$table}"); - }; - - array_map($drop_table, $this->models); - } - - function segments() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'name varchar(90) NOT NULL,', - 'type varchar(90) NOT NULL DEFAULT "default",', - 'description varchar(250) NOT NULL DEFAULT "",', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'deleted_at TIMESTAMP NULL,', - 'PRIMARY KEY (id),', - 'UNIQUE KEY name (name)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function settings() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'name varchar(20) NOT NULL,', - 'value longtext,', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id),', - 'UNIQUE KEY name (name)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function custom_fields() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'name varchar(90) NOT NULL,', - 'type varchar(90) NOT NULL,', - 'params longtext NOT NULL,', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id),', - 'UNIQUE KEY name (name)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function sending_queues() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'newsletter_id mediumint(9) NOT NULL,', - 'newsletter_rendered_body longtext,', - 'newsletter_rendered_subject varchar(250) NULL DEFAULT NULL,', - 'subscribers longtext,', - 'status varchar(12) NULL DEFAULT NULL,', - 'priority mediumint(9) NOT NULL DEFAULT 0,', - 'count_total mediumint(9) NOT NULL DEFAULT 0,', - 'count_processed mediumint(9) NOT NULL DEFAULT 0,', - 'count_to_process mediumint(9) NOT NULL DEFAULT 0,', - 'count_failed mediumint(9) NOT NULL DEFAULT 0,', - 'scheduled_at TIMESTAMP NULL,', - 'processed_at TIMESTAMP NULL,', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'deleted_at TIMESTAMP NULL,', - 'PRIMARY KEY (id)', - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function subscribers() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'wp_user_id bigint(20) NULL,', - 'first_name tinytext NOT NULL DEFAULT "",', - 'last_name tinytext NOT NULL DEFAULT "",', - 'email varchar(150) NOT NULL,', - 'status varchar(12) NOT NULL DEFAULT "' . Subscriber::STATUS_UNCONFIRMED . '",', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'deleted_at TIMESTAMP NULL,', - 'PRIMARY KEY (id),', - 'UNIQUE KEY email (email)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function subscriber_segment() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'subscriber_id mediumint(9) NOT NULL,', - 'segment_id mediumint(9) NOT NULL,', - 'status varchar(12) NOT NULL DEFAULT "' . Subscriber::STATUS_SUBSCRIBED . '",', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id),', - 'UNIQUE KEY subscriber_segment (subscriber_id,segment_id)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function subscriber_custom_field() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'subscriber_id mediumint(9) NOT NULL,', - 'custom_field_id mediumint(9) NOT NULL,', - 'value varchar(255) NOT NULL DEFAULT "",', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id),', - 'UNIQUE KEY subscriber_id_custom_field_id (subscriber_id,custom_field_id)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function newsletters() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'subject varchar(250) NOT NULL DEFAULT "",', - 'type varchar(20) NOT NULL DEFAULT "standard",', - 'sender_address varchar(150) NOT NULL DEFAULT "",', - 'sender_name varchar(150) NOT NULL DEFAULT "",', - 'status varchar(20) NOT NULL DEFAULT "'.Newsletter::STATUS_DRAFT.'",', - 'reply_to_address varchar(150) NOT NULL DEFAULT "",', - 'reply_to_name varchar(150) NOT NULL DEFAULT "",', - 'preheader varchar(250) NOT NULL DEFAULT "",', - 'body longtext,', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'deleted_at TIMESTAMP NULL,', - 'PRIMARY KEY (id)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function newsletter_templates() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'name varchar(250) NOT NULL,', - 'description varchar(250) NOT NULL,', - 'body LONGTEXT,', - 'thumbnail LONGTEXT,', - 'readonly TINYINT(1) DEFAULT 0,', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function newsletter_option_fields() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'name varchar(90) NOT NULL,', - 'newsletter_type varchar(90) NOT NULL,', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id),', - 'UNIQUE KEY name_newsletter_type (newsletter_type,name)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function newsletter_option() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'newsletter_id mediumint(9) NOT NULL,', - 'option_field_id mediumint(9) NOT NULL,', - 'value varchar(255) NOT NULL DEFAULT "",', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id),', - 'UNIQUE KEY newsletter_id_option_field_id (newsletter_id,option_field_id)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function newsletter_segment() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'newsletter_id mediumint(9) NOT NULL,', - 'segment_id mediumint(9) NOT NULL,', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id),', - 'UNIQUE KEY newsletter_segment (newsletter_id,segment_id)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function newsletter_links() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'newsletter_id mediumint(9) NOT NULL,', - 'queue_id mediumint(9) NOT NULL,', - 'url varchar(255) NOT NULL,', - 'hash varchar(20) NOT NULL,', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id)', - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function newsletter_posts() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'newsletter_id mediumint(9) NOT NULL,', - 'post_id mediumint(9) NOT NULL,', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id)', - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function forms() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'name varchar(90) NOT NULL,', - 'body longtext,', - 'settings longtext,', - 'styles longtext,', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'deleted_at TIMESTAMP NULL,', - 'PRIMARY KEY (id)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function statistics_newsletters() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'newsletter_id mediumint(9) NOT NULL,', - 'subscriber_id mediumint(9) NOT NULL,', - 'queue_id mediumint(9) NOT NULL,', - 'sent_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id)', - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function statistics_clicks() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'newsletter_id mediumint(9) NOT NULL,', - 'subscriber_id mediumint(9) NOT NULL,', - 'queue_id mediumint(9) NOT NULL,', - 'link_id mediumint(9) NOT NULL,', - 'count mediumint(9) NOT NULL,', - 'created_at TIMESTAMP NULL,', - 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id)', - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function statistics_opens() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'newsletter_id mediumint(9) NOT NULL,', - 'subscriber_id mediumint(9) NOT NULL,', - 'queue_id mediumint(9) NOT NULL,', - 'created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id)', - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function statistics_unsubscribes() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'newsletter_id mediumint(9) NOT NULL,', - 'subscriber_id mediumint(9) NOT NULL,', - 'queue_id mediumint(9) NOT NULL,', - 'created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id)', - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - function statistics_forms() { - $attributes = array( - 'id mediumint(9) NOT NULL AUTO_INCREMENT,', - 'form_id mediumint(9) NOT NULL,', - 'subscriber_id mediumint(9) NOT NULL,', - 'created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,', - 'PRIMARY KEY (id),', - 'UNIQUE KEY form_subscriber (form_id,subscriber_id)' - ); - return $this->sqlify(__FUNCTION__, $attributes); - } - - private function sqlify($model, $attributes) { - $table = $this->prefix . $model; - - $sql = array(); - $sql[] = "CREATE TABLE " . $table . " ("; - $sql = array_merge($sql, $attributes); - $sql[] = ") " . $this->charset . ";"; - - return implode("\n", $sql); - } -} \ No newline at end of file +prefix = Env::$db_prefix; + $this->charset = Env::$db_charset; + $this->models = array( + 'segments', + 'settings', + 'custom_fields', + 'sending_queues', + 'subscribers', + 'subscriber_segment', + 'subscriber_custom_field', + 'newsletters', + 'newsletter_templates', + 'newsletter_option_fields', + 'newsletter_option', + 'newsletter_segment', + 'newsletter_links', + 'newsletter_posts', + 'forms', + 'statistics_newsletters', + 'statistics_clicks', + 'statistics_opens', + 'statistics_unsubscribes', + 'statistics_forms' + ); + } + + function up() { + global $wpdb; + + $_this = $this; + $migrate = function($model) use($_this) { + dbDelta($_this->$model()); + }; + + array_map($migrate, $this->models); + } + + function down() { + global $wpdb; + + $drop_table = function($model) use($wpdb) { + $table = $this->prefix . $model; + $wpdb->query("DROP TABLE {$table}"); + }; + + array_map($drop_table, $this->models); + } + + function segments() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'name varchar(90) NOT NULL,', + 'type varchar(90) NOT NULL DEFAULT "default",', + 'description varchar(250) NOT NULL DEFAULT "",', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'deleted_at TIMESTAMP NULL,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY name (name)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function settings() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'name varchar(20) NOT NULL,', + 'value longtext,', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY name (name)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function custom_fields() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'name varchar(90) NOT NULL,', + 'type varchar(90) NOT NULL,', + 'params longtext NOT NULL,', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY name (name)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function sending_queues() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'newsletter_id mediumint(9) NOT NULL,', + 'newsletter_rendered_body longtext,', + 'newsletter_rendered_subject varchar(250) NULL DEFAULT NULL,', + 'subscribers longtext,', + 'status varchar(12) NULL DEFAULT NULL,', + 'priority mediumint(9) NOT NULL DEFAULT 0,', + 'count_total mediumint(9) NOT NULL DEFAULT 0,', + 'count_processed mediumint(9) NOT NULL DEFAULT 0,', + 'count_to_process mediumint(9) NOT NULL DEFAULT 0,', + 'count_failed mediumint(9) NOT NULL DEFAULT 0,', + 'scheduled_at TIMESTAMP NULL,', + 'processed_at TIMESTAMP NULL,', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'deleted_at TIMESTAMP NULL,', + 'PRIMARY KEY (id)', + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function subscribers() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'wp_user_id bigint(20) NULL,', + 'first_name tinytext NOT NULL DEFAULT "",', + 'last_name tinytext NOT NULL DEFAULT "",', + 'email varchar(150) NOT NULL,', + 'status varchar(12) NOT NULL DEFAULT "' . Subscriber::STATUS_UNCONFIRMED . '",', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'deleted_at TIMESTAMP NULL,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY email (email)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function subscriber_segment() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'subscriber_id mediumint(9) NOT NULL,', + 'segment_id mediumint(9) NOT NULL,', + 'status varchar(12) NOT NULL DEFAULT "' . Subscriber::STATUS_SUBSCRIBED . '",', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY subscriber_segment (subscriber_id,segment_id)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function subscriber_custom_field() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'subscriber_id mediumint(9) NOT NULL,', + 'custom_field_id mediumint(9) NOT NULL,', + 'value varchar(255) NOT NULL DEFAULT "",', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY subscriber_id_custom_field_id (subscriber_id,custom_field_id)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function newsletters() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'subject varchar(250) NOT NULL DEFAULT "",', + 'type varchar(20) NOT NULL DEFAULT "standard",', + 'sender_address varchar(150) NOT NULL DEFAULT "",', + 'sender_name varchar(150) NOT NULL DEFAULT "",', + 'status varchar(20) NOT NULL DEFAULT "'.Newsletter::STATUS_DRAFT.'",', + 'reply_to_address varchar(150) NOT NULL DEFAULT "",', + 'reply_to_name varchar(150) NOT NULL DEFAULT "",', + 'preheader varchar(250) NOT NULL DEFAULT "",', + 'body longtext,', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'deleted_at TIMESTAMP NULL,', + 'PRIMARY KEY (id)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function newsletter_templates() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'name varchar(250) NOT NULL,', + 'description varchar(250) NOT NULL,', + 'body LONGTEXT,', + 'thumbnail LONGTEXT,', + 'readonly TINYINT(1) DEFAULT 0,', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function newsletter_option_fields() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'name varchar(90) NOT NULL,', + 'newsletter_type varchar(90) NOT NULL,', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY name_newsletter_type (newsletter_type,name)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function newsletter_option() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'newsletter_id mediumint(9) NOT NULL,', + 'option_field_id mediumint(9) NOT NULL,', + 'value varchar(255) NOT NULL DEFAULT "",', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY newsletter_id_option_field_id (newsletter_id,option_field_id)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function newsletter_segment() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'newsletter_id mediumint(9) NOT NULL,', + 'segment_id mediumint(9) NOT NULL,', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY newsletter_segment (newsletter_id,segment_id)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function newsletter_links() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'newsletter_id mediumint(9) NOT NULL,', + 'queue_id mediumint(9) NOT NULL,', + 'url varchar(255) NOT NULL,', + 'hash varchar(20) NOT NULL,', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id)', + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function newsletter_posts() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'newsletter_id mediumint(9) NOT NULL,', + 'post_id mediumint(9) NOT NULL,', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id)', + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function forms() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'name varchar(90) NOT NULL,', + 'body longtext,', + 'settings longtext,', + 'styles longtext,', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'deleted_at TIMESTAMP NULL,', + 'PRIMARY KEY (id)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function statistics_newsletters() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'newsletter_id mediumint(9) NOT NULL,', + 'subscriber_id mediumint(9) NOT NULL,', + 'queue_id mediumint(9) NOT NULL,', + 'sent_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id)', + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function statistics_clicks() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'newsletter_id mediumint(9) NOT NULL,', + 'subscriber_id mediumint(9) NOT NULL,', + 'queue_id mediumint(9) NOT NULL,', + 'link_id mediumint(9) NOT NULL,', + 'count mediumint(9) NOT NULL,', + 'created_at TIMESTAMP NULL,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id)', + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function statistics_opens() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'newsletter_id mediumint(9) NOT NULL,', + 'subscriber_id mediumint(9) NOT NULL,', + 'queue_id mediumint(9) NOT NULL,', + 'created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id)', + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function statistics_unsubscribes() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'newsletter_id mediumint(9) NOT NULL,', + 'subscriber_id mediumint(9) NOT NULL,', + 'queue_id mediumint(9) NOT NULL,', + 'created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id)', + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function statistics_forms() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'form_id mediumint(9) NOT NULL,', + 'subscriber_id mediumint(9) NOT NULL,', + 'created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY form_subscriber (form_id,subscriber_id)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + private function sqlify($model, $attributes) { + $table = $this->prefix . $model; + + $sql = array(); + $sql[] = "CREATE TABLE " . $table . " ("; + $sql = array_merge($sql, $attributes); + $sql[] = ") " . $this->charset . ";"; + + return implode("\n", $sql); + } +} diff --git a/lib/Config/Widget.php b/lib/Config/Widget.php index 1f363abd69..67e5a65d31 100644 --- a/lib/Config/Widget.php +++ b/lib/Config/Widget.php @@ -1,160 +1,160 @@ -renderer = $renderer; - } - } - - function init() { - $this->registerWidget(); - - if(!is_admin()) { - $this->setupDependencies(); - $this->setupIframe(); - } else { - $this->setupAdminDependencies(); - } - } - - function setupIframe() { - $form_id = (isset($_GET['mailpoet_form_iframe']) ? (int)$_GET['mailpoet_form_iframe'] : 0); - if($form_id > 0) { - $form = Form::findOne($form_id); - - if($form !== false) { - $form_widget = new \MailPoet\Form\Widget(); - $form_html = $form_widget->widget(array( - 'form' => $form_id, - 'form_type' => 'iframe' - )); - - // capture javascripts - ob_start(); - wp_print_scripts('jquery'); - wp_print_scripts('mailpoet_vendor'); - wp_print_scripts('mailpoet_public'); - $scripts = ob_get_contents(); - ob_end_clean(); - - // language attributes - $language_attributes = array(); - $is_rtl = (bool)(function_exists('is_rtl') && is_rtl()); - - if($is_rtl) { - $language_attributes[] = 'dir="rtl"'; - } - - if($lang = get_bloginfo('language')) { - if(get_option('html_type') === 'text/html') { - $language_attributes[] = "lang=\"$lang\""; - } - } - - $language_attributes = apply_filters( - 'language_attributes', implode(' ', $language_attributes) - ); - - $data = array( - 'language_attributes' => $language_attributes, - 'scripts' => $scripts, - 'form' => $form_html, - 'mailpoet_form' => array( - 'ajax_url' => admin_url('admin-ajax.php', 'absolute'), - 'is_rtl' => $is_rtl, - 'token' => Security::generateToken() - ) - ); - - echo $this->renderer->render('form/iframe.html', $data); - } - exit(); - } - } - - function registerWidget() { - register_widget('\MailPoet\Form\Widget'); - } - - function setupDependencies() { - wp_enqueue_style('mailpoet_public', Env::$assets_url.'/css/public.css'); - - wp_enqueue_script('mailpoet_vendor', - Env::$assets_url.'/js/vendor.js', - array(), - Env::$version, - true - ); - - wp_enqueue_script('mailpoet_public', - Env::$assets_url.'/js/public.js', - array(), - Env::$version, - true - ); - - wp_localize_script('mailpoet_public', 'MailPoetForm', array( - 'ajax_url' => admin_url('admin-ajax.php'), - 'is_rtl' => (function_exists('is_rtl') ? (bool)is_rtl() : false), - 'token' => Security::generateToken() - )); - } - - function setupAdminDependencies() { - if( - empty($_GET['page']) - or - isset($_GET['page']) && strpos($_GET['page'], 'mailpoet') === false - ) { - wp_enqueue_script('mailpoet_vendor', - Env::$assets_url.'/js/vendor.js', - array(), - Env::$version, - true - ); - - wp_enqueue_script('mailpoet_admin', - Env::$assets_url.'/js/mailpoet.js', - array(), - Env::$version, - true - ); - } - } - - // TODO: extract this method into an Initializer - // - the "ajax" part might probably be useless - // - the "post" (non-ajax) part needs to be redone properly - function setupActions() { - // ajax requests - add_action( - 'wp_ajax_mailpoet_form_subscribe', - 'mailpoet_form_subscribe' - ); - add_action( - 'wp_ajax_nopriv_mailpoet_form_subscribe', - 'mailpoet_form_subscribe' - ); - // post request - add_action( - 'admin_post_nopriv_mailpoet_form_subscribe', - 'mailpoet_form_subscribe' - ); - add_action( - 'admin_post_mailpoet_form_subscribe', - 'mailpoet_form_subscribe' - ); - add_action( - 'init', - 'mailpoet_form_subscribe' - ); - } -} +renderer = $renderer; + } + } + + function init() { + $this->registerWidget(); + + if(!is_admin()) { + $this->setupDependencies(); + $this->setupIframe(); + } else { + $this->setupAdminDependencies(); + } + } + + function setupIframe() { + $form_id = (isset($_GET['mailpoet_form_iframe']) ? (int)$_GET['mailpoet_form_iframe'] : 0); + if($form_id > 0) { + $form = Form::findOne($form_id); + + if($form !== false) { + $form_widget = new \MailPoet\Form\Widget(); + $form_html = $form_widget->widget(array( + 'form' => $form_id, + 'form_type' => 'iframe' + )); + + // capture javascripts + ob_start(); + wp_print_scripts('jquery'); + wp_print_scripts('mailpoet_vendor'); + wp_print_scripts('mailpoet_public'); + $scripts = ob_get_contents(); + ob_end_clean(); + + // language attributes + $language_attributes = array(); + $is_rtl = (bool)(function_exists('is_rtl') && is_rtl()); + + if($is_rtl) { + $language_attributes[] = 'dir="rtl"'; + } + + if($lang = get_bloginfo('language')) { + if(get_option('html_type') === 'text/html') { + $language_attributes[] = "lang=\"$lang\""; + } + } + + $language_attributes = apply_filters( + 'language_attributes', implode(' ', $language_attributes) + ); + + $data = array( + 'language_attributes' => $language_attributes, + 'scripts' => $scripts, + 'form' => $form_html, + 'mailpoet_form' => array( + 'ajax_url' => admin_url('admin-ajax.php', 'absolute'), + 'is_rtl' => $is_rtl, + 'token' => Security::generateToken() + ) + ); + + echo $this->renderer->render('form/iframe.html', $data); + } + exit(); + } + } + + function registerWidget() { + register_widget('\MailPoet\Form\Widget'); + } + + function setupDependencies() { + wp_enqueue_style('mailpoet_public', Env::$assets_url.'/css/public.css'); + + wp_enqueue_script('mailpoet_vendor', + Env::$assets_url.'/js/vendor.js', + array(), + Env::$version, + true + ); + + wp_enqueue_script('mailpoet_public', + Env::$assets_url.'/js/public.js', + array(), + Env::$version, + true + ); + + wp_localize_script('mailpoet_public', 'MailPoetForm', array( + 'ajax_url' => admin_url('admin-ajax.php'), + 'is_rtl' => (function_exists('is_rtl') ? (bool)is_rtl() : false), + 'token' => Security::generateToken() + )); + } + + function setupAdminDependencies() { + if( + empty($_GET['page']) + or + isset($_GET['page']) && strpos($_GET['page'], 'mailpoet') === false + ) { + wp_enqueue_script('mailpoet_vendor', + Env::$assets_url.'/js/vendor.js', + array(), + Env::$version, + true + ); + + wp_enqueue_script('mailpoet_admin', + Env::$assets_url.'/js/mailpoet.js', + array(), + Env::$version, + true + ); + } + } + + // TODO: extract this method into an Initializer + // - the "ajax" part might probably be useless + // - the "post" (non-ajax) part needs to be redone properly + function setupActions() { + // ajax requests + add_action( + 'wp_ajax_mailpoet_form_subscribe', + 'mailpoet_form_subscribe' + ); + add_action( + 'wp_ajax_nopriv_mailpoet_form_subscribe', + 'mailpoet_form_subscribe' + ); + // post request + add_action( + 'admin_post_nopriv_mailpoet_form_subscribe', + 'mailpoet_form_subscribe' + ); + add_action( + 'admin_post_mailpoet_form_subscribe', + 'mailpoet_form_subscribe' + ); + add_action( + 'init', + 'mailpoet_form_subscribe' + ); + } +} diff --git a/lib/Mailer/Mailer.php b/lib/Mailer/Mailer.php index 90ead39aff..627ec3ba97 100644 --- a/lib/Mailer/Mailer.php +++ b/lib/Mailer/Mailer.php @@ -1,143 +1,143 @@ -mailer = $this->getMailer($mailer); - $this->sender = $this->getSender($sender); - $this->reply_to = $this->getReplyTo($reply_to); - $this->mailer_instance = $this->buildMailer(); - } - - function send($newsletter, $subscriber) { - $subscriber = $this->transformSubscriber($subscriber); - return $this->mailer_instance->send($newsletter, $subscriber); - } - - function buildMailer() { - switch($this->mailer['method']) { - case 'AmazonSES': - $mailer_instance = new $this->mailer['class']( - $this->mailer['region'], - $this->mailer['access_key'], - $this->mailer['secret_key'], - $this->sender, - $this->reply_to - ); - break; - case 'ElasticEmail': - $mailer_instance = new $this->mailer['class']( - $this->mailer['api_key'], - $this->sender, - $this->reply_to - ); - break; - case 'MailGun': - $mailer_instance = new $this->mailer['class']( - $this->mailer['domain'], - $this->mailer['api_key'], - $this->sender, - $this->reply_to - ); - break; - case 'MailPoet': - $mailer_instance = new $this->mailer['class']( - $this->mailer['mailpoet_api_key'], - $this->sender, - $this->reply_to - ); - break; - case 'SendGrid': - $mailer_instance = new $this->mailer['class']( - $this->mailer['api_key'], - $this->sender, - $this->reply_to - ); - break; - case 'PHPMail': - $mailer_instance = new $this->mailer['class']( - $this->sender, - $this->reply_to - ); - break; - case 'SMTP': - $mailer_instance = new $this->mailer['class']( - $this->mailer['host'], - $this->mailer['port'], - $this->mailer['authentication'], - $this->mailer['login'], - $this->mailer['password'], - $this->mailer['encryption'], - $this->sender, - $this->reply_to - ); - break; - default: - throw new \Exception(__('Mailing method does not exist.')); - } - return $mailer_instance; - } - - function getMailer($mailer = false) { - if(!$mailer) { - $mailer = Setting::getValue('mta'); - if(!$mailer || !isset($mailer['method'])) throw new \Exception(__('Mailer is not configured.')); - } - $mailer['class'] = 'MailPoet\\Mailer\\Methods\\' . $mailer['method']; - return $mailer; - } - - function getSender($sender = false) { - if(empty($sender)) { - $sender = Setting::getValue('sender', array()); - if(empty($sender['address'])) throw new \Exception(__('Sender name and email are not configured.')); - } - return array( - 'from_name' => $sender['name'], - 'from_email' => $sender['address'], - 'from_name_email' => sprintf('%s <%s>', $sender['name'], $sender['address']) - ); - } - - function getReplyTo($reply_to = false) { - if(!$reply_to) { - $reply_to = Setting::getValue('reply_to', null); - if(!$reply_to) { - $reply_to = array( - 'name' => $this->sender['from_name'], - 'address' => $this->sender['from_email'] - ); - } - } - if(empty($reply_to['address'])) { - $reply_to['address'] = $this->sender['from_email']; - } - return array( - 'reply_to_name' => $reply_to['name'], - 'reply_to_email' => $reply_to['address'], - 'reply_to_name_email' => sprintf('%s <%s>', $reply_to['name'], $reply_to['address']) - ); - } - - function transformSubscriber($subscriber) { - if(!is_array($subscriber)) return $subscriber; - if(isset($subscriber['address'])) $subscriber['email'] = $subscriber['address']; - $first_name = (isset($subscriber['first_name'])) ? $subscriber['first_name'] : ''; - $last_name = (isset($subscriber['last_name'])) ? $subscriber['last_name'] : ''; - if(!$first_name && !$last_name) return $subscriber['email']; - $subscriber = sprintf('%s %s <%s>', $first_name, $last_name, $subscriber['email']); - $subscriber = trim(preg_replace('!\s\s+!', ' ', $subscriber)); - return $subscriber; - } -} \ No newline at end of file +mailer = $this->getMailer($mailer); + $this->sender = $this->getSender($sender); + $this->reply_to = $this->getReplyTo($reply_to); + $this->mailer_instance = $this->buildMailer(); + } + + function send($newsletter, $subscriber) { + $subscriber = $this->transformSubscriber($subscriber); + return $this->mailer_instance->send($newsletter, $subscriber); + } + + function buildMailer() { + switch($this->mailer['method']) { + case 'AmazonSES': + $mailer_instance = new $this->mailer['class']( + $this->mailer['region'], + $this->mailer['access_key'], + $this->mailer['secret_key'], + $this->sender, + $this->reply_to + ); + break; + case 'ElasticEmail': + $mailer_instance = new $this->mailer['class']( + $this->mailer['api_key'], + $this->sender, + $this->reply_to + ); + break; + case 'MailGun': + $mailer_instance = new $this->mailer['class']( + $this->mailer['domain'], + $this->mailer['api_key'], + $this->sender, + $this->reply_to + ); + break; + case 'MailPoet': + $mailer_instance = new $this->mailer['class']( + $this->mailer['mailpoet_api_key'], + $this->sender, + $this->reply_to + ); + break; + case 'SendGrid': + $mailer_instance = new $this->mailer['class']( + $this->mailer['api_key'], + $this->sender, + $this->reply_to + ); + break; + case 'PHPMail': + $mailer_instance = new $this->mailer['class']( + $this->sender, + $this->reply_to + ); + break; + case 'SMTP': + $mailer_instance = new $this->mailer['class']( + $this->mailer['host'], + $this->mailer['port'], + $this->mailer['authentication'], + $this->mailer['login'], + $this->mailer['password'], + $this->mailer['encryption'], + $this->sender, + $this->reply_to + ); + break; + default: + throw new \Exception(__('Mailing method does not exist.')); + } + return $mailer_instance; + } + + function getMailer($mailer = false) { + if(!$mailer) { + $mailer = Setting::getValue('mta'); + if(!$mailer || !isset($mailer['method'])) throw new \Exception(__('Mailer is not configured.')); + } + $mailer['class'] = 'MailPoet\\Mailer\\Methods\\' . $mailer['method']; + return $mailer; + } + + function getSender($sender = false) { + if(empty($sender)) { + $sender = Setting::getValue('sender', array()); + if(empty($sender['address'])) throw new \Exception(__('Sender name and email are not configured.')); + } + return array( + 'from_name' => $sender['name'], + 'from_email' => $sender['address'], + 'from_name_email' => sprintf('%s <%s>', $sender['name'], $sender['address']) + ); + } + + function getReplyTo($reply_to = false) { + if(!$reply_to) { + $reply_to = Setting::getValue('reply_to', null); + if(!$reply_to) { + $reply_to = array( + 'name' => $this->sender['from_name'], + 'address' => $this->sender['from_email'] + ); + } + } + if(empty($reply_to['address'])) { + $reply_to['address'] = $this->sender['from_email']; + } + return array( + 'reply_to_name' => $reply_to['name'], + 'reply_to_email' => $reply_to['address'], + 'reply_to_name_email' => sprintf('%s <%s>', $reply_to['name'], $reply_to['address']) + ); + } + + function transformSubscriber($subscriber) { + if(!is_array($subscriber)) return $subscriber; + if(isset($subscriber['address'])) $subscriber['email'] = $subscriber['address']; + $first_name = (isset($subscriber['first_name'])) ? $subscriber['first_name'] : ''; + $last_name = (isset($subscriber['last_name'])) ? $subscriber['last_name'] : ''; + if(!$first_name && !$last_name) return $subscriber['email']; + $subscriber = sprintf('%s %s <%s>', $first_name, $last_name, $subscriber['email']); + $subscriber = trim(preg_replace('!\s\s+!', ' ', $subscriber)); + return $subscriber; + } +} diff --git a/lib/Models/Model.php b/lib/Models/Model.php index c85c2b65f7..31d89c8be6 100644 --- a/lib/Models/Model.php +++ b/lib/Models/Model.php @@ -1,160 +1,160 @@ -_errors = array(); - parent::__construct(); - } - - static function create() { - return parent::create(); - } - - function getErrors() { - if(empty($this->_errors)) { - return false; - } else { - return $this->_errors; - } - } - - function setError($error = '') { - if(!empty($error)) { - if(is_array($error)) { - $this->_errors = array_merge($this->_errors, $error); - $this->_errors = array_unique($this->_errors); - } else { - $this->_errors[] = $error; - } - } - } - - function save() { - $this->setTimestamp(); - try { - parent::save(); - } catch(\Sudzy\ValidationException $e) { - $this->setError($e->getValidationErrors()); - } catch(\PDOException $e) { - switch($e->getCode()) { - case 23000: - preg_match("/for key \'(.*?)\'/i", $e->getMessage(), $matches); - if(isset($matches[1])) { - $column = $matches[1]; - $this->setError( - sprintf( - __('Another record already exists. Please specify a different "%1$s".'), - $column - ) - ); - } else { - $this->setError($e->getMessage()); - } - break; - default: - $this->setError($e->getMessage()); - } - } - return $this; - } - - function trash() { - return $this->set_expr('deleted_at', 'NOW()')->save(); - } - - static function bulkTrash($orm) { - $model = get_called_class(); - return self::bulkAction($orm, function($ids) use($model) { - self::rawExecute(join(' ', array( - 'UPDATE `'.$model::$_table.'`', - 'SET `deleted_at` = NOW()', - 'WHERE `id` IN ('.rtrim(str_repeat('?,', count($ids)), ',').')' - )), - $ids - ); - }); - } - - static function bulkDelete($orm) { - $model = get_called_class(); - return self::bulkAction($orm, function($ids) use($model) { - $model::whereIn('id', $ids)->deleteMany(); - }); - } - - function restore() { - return $this->set_expr('deleted_at', 'NULL')->save(); - } - - static function bulkRestore($orm) { - $model = get_called_class(); - return self::bulkAction($orm, function($ids) use($model) { - self::rawExecute(join(' ', array( - 'UPDATE `'.$model::$_table.'`', - 'SET `deleted_at` = NULL', - 'WHERE `id` IN ('.rtrim(str_repeat('?,', count($ids)), ',').')' - )), - $ids - ); - }); - } - - static function bulkAction($orm, $callback = false) { - $total = $orm->count(); - - if($total === 0) return false; - - $rows = $orm->select(static::$_table.'.id') - ->offset(null) - ->limit(null) - ->findArray(); - - $ids = array_map(function($model) { - return (int)$model['id']; - }, $rows); - - if($callback !== false) { - $callback($ids); - } - - // get number of affected rows - return $orm->get_last_statement()->rowCount(); - } - - function duplicate($data = array()) { - $model = get_called_class(); - $model_data = array_merge($this->asArray(), $data); - unset($model_data['id']); - - $duplicate = $model::create(); - $duplicate->hydrate($model_data); - $duplicate->set_expr('created_at', 'NOW()'); - $duplicate->set_expr('updated_at', 'NOW()'); - $duplicate->set_expr('deleted_at', 'NULL'); - - if($duplicate->save()) { - return $duplicate; - } else { - return false; - } - } - - private function setTimestamp() { - if($this->created_at === null) { - $this->set_expr('created_at', 'NOW()'); - } - } - - static function getPublished() { - return static::whereNull('deleted_at'); - } - - static function getTrashed() { - return static::whereNotNull('deleted_at'); - } -} +_errors = array(); + parent::__construct(); + } + + static function create() { + return parent::create(); + } + + function getErrors() { + if(empty($this->_errors)) { + return false; + } else { + return $this->_errors; + } + } + + function setError($error = '') { + if(!empty($error)) { + if(is_array($error)) { + $this->_errors = array_merge($this->_errors, $error); + $this->_errors = array_unique($this->_errors); + } else { + $this->_errors[] = $error; + } + } + } + + function save() { + $this->setTimestamp(); + try { + parent::save(); + } catch(\Sudzy\ValidationException $e) { + $this->setError($e->getValidationErrors()); + } catch(\PDOException $e) { + switch($e->getCode()) { + case 23000: + preg_match("/for key \'(.*?)\'/i", $e->getMessage(), $matches); + if(isset($matches[1])) { + $column = $matches[1]; + $this->setError( + sprintf( + __('Another record already exists. Please specify a different "%1$s".'), + $column + ) + ); + } else { + $this->setError($e->getMessage()); + } + break; + default: + $this->setError($e->getMessage()); + } + } + return $this; + } + + function trash() { + return $this->set_expr('deleted_at', 'NOW()')->save(); + } + + static function bulkTrash($orm) { + $model = get_called_class(); + return self::bulkAction($orm, function($ids) use($model) { + self::rawExecute(join(' ', array( + 'UPDATE `'.$model::$_table.'`', + 'SET `deleted_at` = NOW()', + 'WHERE `id` IN ('.rtrim(str_repeat('?,', count($ids)), ',').')' + )), + $ids + ); + }); + } + + static function bulkDelete($orm) { + $model = get_called_class(); + return self::bulkAction($orm, function($ids) use($model) { + $model::whereIn('id', $ids)->deleteMany(); + }); + } + + function restore() { + return $this->set_expr('deleted_at', 'NULL')->save(); + } + + static function bulkRestore($orm) { + $model = get_called_class(); + return self::bulkAction($orm, function($ids) use($model) { + self::rawExecute(join(' ', array( + 'UPDATE `'.$model::$_table.'`', + 'SET `deleted_at` = NULL', + 'WHERE `id` IN ('.rtrim(str_repeat('?,', count($ids)), ',').')' + )), + $ids + ); + }); + } + + static function bulkAction($orm, $callback = false) { + $total = $orm->count(); + + if($total === 0) return false; + + $rows = $orm->select(static::$_table.'.id') + ->offset(null) + ->limit(null) + ->findArray(); + + $ids = array_map(function($model) { + return (int)$model['id']; + }, $rows); + + if($callback !== false) { + $callback($ids); + } + + // get number of affected rows + return $orm->get_last_statement()->rowCount(); + } + + function duplicate($data = array()) { + $model = get_called_class(); + $model_data = array_merge($this->asArray(), $data); + unset($model_data['id']); + + $duplicate = $model::create(); + $duplicate->hydrate($model_data); + $duplicate->set_expr('created_at', 'NOW()'); + $duplicate->set_expr('updated_at', 'NOW()'); + $duplicate->set_expr('deleted_at', 'NULL'); + + if($duplicate->save()) { + return $duplicate; + } else { + return false; + } + } + + private function setTimestamp() { + if($this->created_at === null) { + $this->set_expr('created_at', 'NOW()'); + } + } + + static function getPublished() { + return static::whereNull('deleted_at'); + } + + static function getTrashed() { + return static::whereNotNull('deleted_at'); + } +} diff --git a/lib/Models/Newsletter.php b/lib/Models/Newsletter.php index 03f05f298c..8ffa745a43 100644 --- a/lib/Models/Newsletter.php +++ b/lib/Models/Newsletter.php @@ -1,526 +1,526 @@ -addValidations('type', array( - 'required' => __('Please specify a type.') - )); - } - - function save() { - if(is_string($this->deleted_at) && strlen(trim($this->deleted_at)) === 0) { - $this->set_expr('deleted_at', 'NULL'); - } - - $this->set('body', - is_array($this->body) - ? json_encode($this->body) - : $this->body - ); - return parent::save(); - } - - function setStatus($status = null) { - if(in_array($status, array( - self::STATUS_DRAFT, - self::STATUS_SCHEDULED, - self::STATUS_SENDING, - self::STATUS_SENT, - self::STATUS_ACTIVE - ))) { - $this->set('status', $status); - $this->save(); - } - return $this; - } - - function duplicate($data = array()) { - // get current newsletter's data as an array - $newsletter_data = $this->asArray(); - - // remove id so that it creates a new record - unset($newsletter_data['id']); - - // merge data with newsletter data (allows override) - $data = array_merge($newsletter_data, $data); - - $duplicate = self::create(); - $duplicate->hydrate($data); - - // reset timestamps - $duplicate->set_expr('created_at', 'NOW()'); - $duplicate->set_expr('updated_at', 'NOW()'); - $duplicate->set_expr('deleted_at', 'NULL'); - - // reset status - $duplicate->set('status', self::STATUS_DRAFT); - - $duplicate->save(); - - if($duplicate->getErrors() === false) { - // create relationships between duplicate and segments - $segments = $this->segments()->findArray(); - - if(!empty($segments)) { - foreach($segments as $segment) { - $relation = NewsletterSegment::create(); - $relation->segment_id = $segment['id']; - $relation->newsletter_id = $duplicate->id; - $relation->save(); - } - } - - // duplicate options - $options = NewsletterOption::where('newsletter_id', $this->id) - ->findArray(); - - if(!empty($options)) { - foreach($options as $option) { - $relation = NewsletterOption::create(); - $relation->newsletter_id = $duplicate->id; - $relation->option_field_id = $option['option_field_id']; - $relation->value = $option['value']; - $relation->save(); - } - } - } - - return $duplicate; - } - - function asArray() { - $model = parent::asArray(); - - if(isset($model['body'])) { - $model['body'] = json_decode($model['body'], true); - } - return $model; - } - - function delete() { - // delete all relations to segments - NewsletterSegment::where('newsletter_id', $this->id)->deleteMany(); - - return parent::delete(); - } - - function segments() { - return $this->has_many_through( - __NAMESPACE__.'\Segment', - __NAMESPACE__.'\NewsletterSegment', - 'newsletter_id', - 'segment_id' - ); - } - - function withSegments() { - $this->segments = $this->segments()->findArray(); - return $this; - } - - function options() { - return $this->has_many_through( - __NAMESPACE__.'\NewsletterOptionField', - __NAMESPACE__.'\NewsletterOption', - 'newsletter_id', - 'option_field_id' - )->select_expr(MP_NEWSLETTER_OPTION_TABLE.'.value'); - } - - function getQueue() { - return SendingQueue::where('newsletter_id', $this->id) - ->orderByDesc('updated_at') - ->findOne(); - } - - function withSendingQueue() { - $queue = $this->getQueue(); - if($queue === false) { - $this->queue = false; - } else { - $this->queue = $queue->asArray(); - } - return $this; - } - - function withOptions() { - $options = $this->options()->findArray(); - if(empty($options)) { - $this->options = array(); - } else { - $this->options = Helpers::arrayColumn($options, 'value', 'name'); - } - return $this; - } - - function withTotalSent() { - // total of subscribers who received the email - $this->total_sent = (int)SendingQueue::where('newsletter_id', $this->id) - ->where('status', SendingQueue::STATUS_COMPLETED) - ->sum('count_processed'); - return $this; - } - - function withStatistics() { - $statistics = $this->getStatistics(); - if($statistics === false) { - $this->statistics = false; - } else { - $this->statistics = $statistics->asArray(); - } - - return $this; - } - - function getStatistics() { - if($this->queue === false) { - return false; - } - return SendingQueue::tableAlias('queues') - ->selectExpr( - 'COUNT(DISTINCT(clicks.subscriber_id)) as clicked, ' . - 'COUNT(DISTINCT(opens.subscriber_id)) as opened, ' . - 'COUNT(DISTINCT(unsubscribes.subscriber_id)) as unsubscribed ' - ) - ->leftOuterJoin( - MP_STATISTICS_CLICKS_TABLE, - 'queues.id = clicks.queue_id', - 'clicks' - ) - ->leftOuterJoin( - MP_STATISTICS_OPENS_TABLE, - 'queues.id = opens.queue_id', - 'opens' - ) - ->leftOuterJoin( - MP_STATISTICS_UNSUBSCRIBES_TABLE, - 'queues.id = unsubscribes.queue_id', - 'unsubscribes' - ) - ->where('queues.id', $this->queue['id']) - ->findOne(); - } - - static function search($orm, $search = '') { - if(strlen(trim($search)) > 0) { - $orm->whereLike('subject', '%' . $search . '%'); - } - return $orm; - } - - static function filters($data = array()) { - $segments = Segment::orderByAsc('name')->findMany(); - $segment_list = array(); - $segment_list[] = array( - 'label' => __('All Lists'), - 'value' => '' - ); - - foreach($segments as $segment) { - $newsletters = $segment->newsletters() - ->filter('filterType', $data['tab']) - ->filter('groupBy', $data); - - $newsletters_count = $newsletters->count(); - - if($newsletters_count > 0) { - $segment_list[] = array( - 'label' => sprintf('%s (%d)', $segment->name, $newsletters_count), - 'value' => $segment->id - ); - } - } - - $filters = array( - 'segment' => $segment_list - ); - - return $filters; - } - - static function filterBy($orm, $data = array()) { - $type = isset($data['tab']) ? $data['tab'] : null; - - if(!empty($data['filter'])) { - foreach($data['filter'] as $key => $value) { - if($key === 'segment') { - $segment = Segment::findOne($value); - if($segment !== false) { - $orm = $segment->newsletters()->filter('filterType', $type); - } - } - } - } - return $orm; - } - - static function filterWithOptions($orm) { - $orm = $orm->select(MP_NEWSLETTERS_TABLE.'.*'); - $optionFields = NewsletterOptionField::findArray(); - foreach($optionFields as $optionField) { - $orm = $orm->select_expr( - 'IFNULL(GROUP_CONCAT(CASE WHEN ' . - MP_NEWSLETTER_OPTION_FIELDS_TABLE . '.id=' . $optionField['id'] . ' THEN ' . - MP_NEWSLETTER_OPTION_TABLE . '.value END), NULL) as "' . $optionField['name'].'"'); - } - $orm = $orm - ->left_outer_join( - MP_NEWSLETTER_OPTION_TABLE, - array( - MP_NEWSLETTERS_TABLE.'.id', - '=', - MP_NEWSLETTER_OPTION_TABLE.'.newsletter_id' - ) - ) - ->left_outer_join( - MP_NEWSLETTER_OPTION_FIELDS_TABLE, - array( - MP_NEWSLETTER_OPTION_FIELDS_TABLE.'.id', - '=', - MP_NEWSLETTER_OPTION_TABLE.'.option_field_id' - ) - ) - ->group_by(MP_NEWSLETTERS_TABLE.'.id'); - return $orm; - } - - static function groups($data = array()) { - $type = isset($data['tab']) ? $data['tab'] : null; - - $groups = array( - array( - 'name' => 'all', - 'label' => __('All'), - 'count' => Newsletter::getPublished() - ->filter('filterType', $type) - ->count() - ) - ); - - switch($type) { - case self::TYPE_STANDARD: - $groups = array_merge($groups, array( - array( - 'name' => self::STATUS_DRAFT, - 'label' => __('Draft'), - 'count' => Newsletter::getPublished() - ->filter('filterType', $type) - ->filter('filterStatus', self::STATUS_DRAFT) - ->count() - ), - array( - 'name' => self::STATUS_SCHEDULED, - 'label' => __('Scheduled'), - 'count' => Newsletter::getPublished() - ->filter('filterType', $type) - ->filter('filterStatus', self::STATUS_SCHEDULED) - ->count() - ), - array( - 'name' => self::STATUS_SENDING, - 'label' => __('Sending'), - 'count' => Newsletter::getPublished() - ->filter('filterType', $type) - ->filter('filterStatus', self::STATUS_SENDING) - ->count() - ), - array( - 'name' => self::STATUS_SENT, - 'label' => __('Sent'), - 'count' => Newsletter::getPublished() - ->filter('filterType', $type) - ->filter('filterStatus', self::STATUS_SENT) - ->count() - ) - )); - break; - - case self::TYPE_WELCOME: - case self::TYPE_NOTIFICATION: - $groups = array_merge($groups, array( - array( - 'name' => self::STATUS_ACTIVE, - 'label' => __('Active'), - 'count' => Newsletter::getPublished() - ->filter('filterType', $type) - ->filter('filterStatus', self::STATUS_ACTIVE) - ->count() - ), - array( - 'name' => self::STATUS_DRAFT, - 'label' => __('Not active'), - 'count' => Newsletter::getPublished() - ->filter('filterType', $type) - ->filter('filterStatus', self::STATUS_DRAFT) - ->count() - ) - )); - break; - } - - $groups[] = array( - 'name' => 'trash', - 'label' => __('Trash'), - 'count' => Newsletter::getTrashed() - ->filter('filterType', $type) - ->count() - ); - - return $groups; - } - - static function groupBy($orm, $data = array()) { - $group = (!empty($data['group'])) ? $data['group'] : 'all'; - - switch($group) { - case self::STATUS_DRAFT: - case self::STATUS_SCHEDULED: - case self::STATUS_SENDING: - case self::STATUS_SENT: - case self::STATUS_ACTIVE: - $orm - ->whereNull('deleted_at') - ->filter('filterStatus', $group); - break; - - case 'trash': - $orm->whereNotNull('deleted_at'); - break; - - default: - $orm->whereNull('deleted_at'); - } - return $orm; - } - - static function filterStatus($orm, $status = false) { - if(in_array($status, array( - self::STATUS_DRAFT, - self::STATUS_SCHEDULED, - self::STATUS_SENDING, - self::STATUS_SENT, - self::STATUS_ACTIVE - ))) { - $orm->where('status', $status); - } - return $orm; - } - - static function filterType($orm, $type = false) { - if(in_array($type, array( - self::TYPE_STANDARD, - self::TYPE_WELCOME, - self::TYPE_NOTIFICATION - ))) { - $orm->where('type', $type); - } - return $orm; - } - - static function listingQuery($data = array()) { - return self::select(array( - 'id', - 'subject', - 'type', - 'status', - 'updated_at', - 'deleted_at' - )) - ->filter('filterType', $data['tab']) - ->filter('filterBy', $data) - ->filter('groupBy', $data) - ->filter('search', $data['search']); - } - - static function createOrUpdate($data = array()) { - $newsletter = false; - - if(isset($data['id']) && (int)$data['id'] > 0) { - $newsletter = self::findOne((int)$data['id']); - } - - if($newsletter === false) { - $newsletter = self::create(); - - // set default sender based on settings - if(empty($data['sender'])) { - $sender = Setting::getValue('sender', array()); - $data['sender_name'] = ( - !empty($sender['name']) - ? $sender['name'] - : '' - ); - $data['sender_address'] = ( - !empty($sender['address']) - ? $sender['address'] - : '' - ); - } - - // set default reply_to based on settings - if(empty($data['reply_to'])) { - $reply_to = Setting::getValue('reply_to', array()); - $data['reply_to_name'] = ( - !empty($reply_to['name']) - ? $reply_to['name'] - : '' - ); - $data['reply_to_address'] = ( - !empty($reply_to['address']) - ? $reply_to['address'] - : '' - ); - } - - $newsletter->hydrate($data); - } else { - unset($data['id']); - $newsletter->set($data); - } - - $newsletter->save(); - return $newsletter; - } - - static function getWelcomeNotificationsForSegments($segments) { - return NewsletterOption::table_alias('options') - ->select('options.newsletter_id') - ->select('options.value', 'segment_id') - ->join( - self::$_table, - 'newsletters.id = options.newsletter_id', - 'newsletters' - ) - ->join( - MP_NEWSLETTER_OPTION_FIELDS_TABLE, - 'option_fields.id = options.option_field_id', - 'option_fields' - ) - ->whereNull('newsletters.deleted_at') - ->where('newsletters.type', 'welcome') - ->where('option_fields.name', 'segment') - ->whereIn('options.value', $segments) - ->findMany(); - } -} +addValidations('type', array( + 'required' => __('Please specify a type.') + )); + } + + function save() { + if(is_string($this->deleted_at) && strlen(trim($this->deleted_at)) === 0) { + $this->set_expr('deleted_at', 'NULL'); + } + + $this->set('body', + is_array($this->body) + ? json_encode($this->body) + : $this->body + ); + return parent::save(); + } + + function setStatus($status = null) { + if(in_array($status, array( + self::STATUS_DRAFT, + self::STATUS_SCHEDULED, + self::STATUS_SENDING, + self::STATUS_SENT, + self::STATUS_ACTIVE + ))) { + $this->set('status', $status); + $this->save(); + } + return $this; + } + + function duplicate($data = array()) { + // get current newsletter's data as an array + $newsletter_data = $this->asArray(); + + // remove id so that it creates a new record + unset($newsletter_data['id']); + + // merge data with newsletter data (allows override) + $data = array_merge($newsletter_data, $data); + + $duplicate = self::create(); + $duplicate->hydrate($data); + + // reset timestamps + $duplicate->set_expr('created_at', 'NOW()'); + $duplicate->set_expr('updated_at', 'NOW()'); + $duplicate->set_expr('deleted_at', 'NULL'); + + // reset status + $duplicate->set('status', self::STATUS_DRAFT); + + $duplicate->save(); + + if($duplicate->getErrors() === false) { + // create relationships between duplicate and segments + $segments = $this->segments()->findArray(); + + if(!empty($segments)) { + foreach($segments as $segment) { + $relation = NewsletterSegment::create(); + $relation->segment_id = $segment['id']; + $relation->newsletter_id = $duplicate->id; + $relation->save(); + } + } + + // duplicate options + $options = NewsletterOption::where('newsletter_id', $this->id) + ->findArray(); + + if(!empty($options)) { + foreach($options as $option) { + $relation = NewsletterOption::create(); + $relation->newsletter_id = $duplicate->id; + $relation->option_field_id = $option['option_field_id']; + $relation->value = $option['value']; + $relation->save(); + } + } + } + + return $duplicate; + } + + function asArray() { + $model = parent::asArray(); + + if(isset($model['body'])) { + $model['body'] = json_decode($model['body'], true); + } + return $model; + } + + function delete() { + // delete all relations to segments + NewsletterSegment::where('newsletter_id', $this->id)->deleteMany(); + + return parent::delete(); + } + + function segments() { + return $this->has_many_through( + __NAMESPACE__.'\Segment', + __NAMESPACE__.'\NewsletterSegment', + 'newsletter_id', + 'segment_id' + ); + } + + function withSegments() { + $this->segments = $this->segments()->findArray(); + return $this; + } + + function options() { + return $this->has_many_through( + __NAMESPACE__.'\NewsletterOptionField', + __NAMESPACE__.'\NewsletterOption', + 'newsletter_id', + 'option_field_id' + )->select_expr(MP_NEWSLETTER_OPTION_TABLE.'.value'); + } + + function getQueue() { + return SendingQueue::where('newsletter_id', $this->id) + ->orderByDesc('updated_at') + ->findOne(); + } + + function withSendingQueue() { + $queue = $this->getQueue(); + if($queue === false) { + $this->queue = false; + } else { + $this->queue = $queue->asArray(); + } + return $this; + } + + function withOptions() { + $options = $this->options()->findArray(); + if(empty($options)) { + $this->options = array(); + } else { + $this->options = Helpers::arrayColumn($options, 'value', 'name'); + } + return $this; + } + + function withTotalSent() { + // total of subscribers who received the email + $this->total_sent = (int)SendingQueue::where('newsletter_id', $this->id) + ->where('status', SendingQueue::STATUS_COMPLETED) + ->sum('count_processed'); + return $this; + } + + function withStatistics() { + $statistics = $this->getStatistics(); + if($statistics === false) { + $this->statistics = false; + } else { + $this->statistics = $statistics->asArray(); + } + + return $this; + } + + function getStatistics() { + if($this->queue === false) { + return false; + } + return SendingQueue::tableAlias('queues') + ->selectExpr( + 'COUNT(DISTINCT(clicks.subscriber_id)) as clicked, ' . + 'COUNT(DISTINCT(opens.subscriber_id)) as opened, ' . + 'COUNT(DISTINCT(unsubscribes.subscriber_id)) as unsubscribed ' + ) + ->leftOuterJoin( + MP_STATISTICS_CLICKS_TABLE, + 'queues.id = clicks.queue_id', + 'clicks' + ) + ->leftOuterJoin( + MP_STATISTICS_OPENS_TABLE, + 'queues.id = opens.queue_id', + 'opens' + ) + ->leftOuterJoin( + MP_STATISTICS_UNSUBSCRIBES_TABLE, + 'queues.id = unsubscribes.queue_id', + 'unsubscribes' + ) + ->where('queues.id', $this->queue['id']) + ->findOne(); + } + + static function search($orm, $search = '') { + if(strlen(trim($search)) > 0) { + $orm->whereLike('subject', '%' . $search . '%'); + } + return $orm; + } + + static function filters($data = array()) { + $segments = Segment::orderByAsc('name')->findMany(); + $segment_list = array(); + $segment_list[] = array( + 'label' => __('All Lists'), + 'value' => '' + ); + + foreach($segments as $segment) { + $newsletters = $segment->newsletters() + ->filter('filterType', $data['tab']) + ->filter('groupBy', $data); + + $newsletters_count = $newsletters->count(); + + if($newsletters_count > 0) { + $segment_list[] = array( + 'label' => sprintf('%s (%d)', $segment->name, $newsletters_count), + 'value' => $segment->id + ); + } + } + + $filters = array( + 'segment' => $segment_list + ); + + return $filters; + } + + static function filterBy($orm, $data = array()) { + $type = isset($data['tab']) ? $data['tab'] : null; + + if(!empty($data['filter'])) { + foreach($data['filter'] as $key => $value) { + if($key === 'segment') { + $segment = Segment::findOne($value); + if($segment !== false) { + $orm = $segment->newsletters()->filter('filterType', $type); + } + } + } + } + return $orm; + } + + static function filterWithOptions($orm) { + $orm = $orm->select(MP_NEWSLETTERS_TABLE.'.*'); + $optionFields = NewsletterOptionField::findArray(); + foreach($optionFields as $optionField) { + $orm = $orm->select_expr( + 'IFNULL(GROUP_CONCAT(CASE WHEN ' . + MP_NEWSLETTER_OPTION_FIELDS_TABLE . '.id=' . $optionField['id'] . ' THEN ' . + MP_NEWSLETTER_OPTION_TABLE . '.value END), NULL) as "' . $optionField['name'].'"'); + } + $orm = $orm + ->left_outer_join( + MP_NEWSLETTER_OPTION_TABLE, + array( + MP_NEWSLETTERS_TABLE.'.id', + '=', + MP_NEWSLETTER_OPTION_TABLE.'.newsletter_id' + ) + ) + ->left_outer_join( + MP_NEWSLETTER_OPTION_FIELDS_TABLE, + array( + MP_NEWSLETTER_OPTION_FIELDS_TABLE.'.id', + '=', + MP_NEWSLETTER_OPTION_TABLE.'.option_field_id' + ) + ) + ->group_by(MP_NEWSLETTERS_TABLE.'.id'); + return $orm; + } + + static function groups($data = array()) { + $type = isset($data['tab']) ? $data['tab'] : null; + + $groups = array( + array( + 'name' => 'all', + 'label' => __('All'), + 'count' => Newsletter::getPublished() + ->filter('filterType', $type) + ->count() + ) + ); + + switch($type) { + case self::TYPE_STANDARD: + $groups = array_merge($groups, array( + array( + 'name' => self::STATUS_DRAFT, + 'label' => __('Draft'), + 'count' => Newsletter::getPublished() + ->filter('filterType', $type) + ->filter('filterStatus', self::STATUS_DRAFT) + ->count() + ), + array( + 'name' => self::STATUS_SCHEDULED, + 'label' => __('Scheduled'), + 'count' => Newsletter::getPublished() + ->filter('filterType', $type) + ->filter('filterStatus', self::STATUS_SCHEDULED) + ->count() + ), + array( + 'name' => self::STATUS_SENDING, + 'label' => __('Sending'), + 'count' => Newsletter::getPublished() + ->filter('filterType', $type) + ->filter('filterStatus', self::STATUS_SENDING) + ->count() + ), + array( + 'name' => self::STATUS_SENT, + 'label' => __('Sent'), + 'count' => Newsletter::getPublished() + ->filter('filterType', $type) + ->filter('filterStatus', self::STATUS_SENT) + ->count() + ) + )); + break; + + case self::TYPE_WELCOME: + case self::TYPE_NOTIFICATION: + $groups = array_merge($groups, array( + array( + 'name' => self::STATUS_ACTIVE, + 'label' => __('Active'), + 'count' => Newsletter::getPublished() + ->filter('filterType', $type) + ->filter('filterStatus', self::STATUS_ACTIVE) + ->count() + ), + array( + 'name' => self::STATUS_DRAFT, + 'label' => __('Not active'), + 'count' => Newsletter::getPublished() + ->filter('filterType', $type) + ->filter('filterStatus', self::STATUS_DRAFT) + ->count() + ) + )); + break; + } + + $groups[] = array( + 'name' => 'trash', + 'label' => __('Trash'), + 'count' => Newsletter::getTrashed() + ->filter('filterType', $type) + ->count() + ); + + return $groups; + } + + static function groupBy($orm, $data = array()) { + $group = (!empty($data['group'])) ? $data['group'] : 'all'; + + switch($group) { + case self::STATUS_DRAFT: + case self::STATUS_SCHEDULED: + case self::STATUS_SENDING: + case self::STATUS_SENT: + case self::STATUS_ACTIVE: + $orm + ->whereNull('deleted_at') + ->filter('filterStatus', $group); + break; + + case 'trash': + $orm->whereNotNull('deleted_at'); + break; + + default: + $orm->whereNull('deleted_at'); + } + return $orm; + } + + static function filterStatus($orm, $status = false) { + if(in_array($status, array( + self::STATUS_DRAFT, + self::STATUS_SCHEDULED, + self::STATUS_SENDING, + self::STATUS_SENT, + self::STATUS_ACTIVE + ))) { + $orm->where('status', $status); + } + return $orm; + } + + static function filterType($orm, $type = false) { + if(in_array($type, array( + self::TYPE_STANDARD, + self::TYPE_WELCOME, + self::TYPE_NOTIFICATION + ))) { + $orm->where('type', $type); + } + return $orm; + } + + static function listingQuery($data = array()) { + return self::select(array( + 'id', + 'subject', + 'type', + 'status', + 'updated_at', + 'deleted_at' + )) + ->filter('filterType', $data['tab']) + ->filter('filterBy', $data) + ->filter('groupBy', $data) + ->filter('search', $data['search']); + } + + static function createOrUpdate($data = array()) { + $newsletter = false; + + if(isset($data['id']) && (int)$data['id'] > 0) { + $newsletter = self::findOne((int)$data['id']); + } + + if($newsletter === false) { + $newsletter = self::create(); + + // set default sender based on settings + if(empty($data['sender'])) { + $sender = Setting::getValue('sender', array()); + $data['sender_name'] = ( + !empty($sender['name']) + ? $sender['name'] + : '' + ); + $data['sender_address'] = ( + !empty($sender['address']) + ? $sender['address'] + : '' + ); + } + + // set default reply_to based on settings + if(empty($data['reply_to'])) { + $reply_to = Setting::getValue('reply_to', array()); + $data['reply_to_name'] = ( + !empty($reply_to['name']) + ? $reply_to['name'] + : '' + ); + $data['reply_to_address'] = ( + !empty($reply_to['address']) + ? $reply_to['address'] + : '' + ); + } + + $newsletter->hydrate($data); + } else { + unset($data['id']); + $newsletter->set($data); + } + + $newsletter->save(); + return $newsletter; + } + + static function getWelcomeNotificationsForSegments($segments) { + return NewsletterOption::table_alias('options') + ->select('options.newsletter_id') + ->select('options.value', 'segment_id') + ->join( + self::$_table, + 'newsletters.id = options.newsletter_id', + 'newsletters' + ) + ->join( + MP_NEWSLETTER_OPTION_FIELDS_TABLE, + 'option_fields.id = options.option_field_id', + 'option_fields' + ) + ->whereNull('newsletters.deleted_at') + ->where('newsletters.type', 'welcome') + ->where('option_fields.name', 'segment') + ->whereIn('options.value', $segments) + ->findMany(); + } +} diff --git a/lib/Models/NewsletterTemplate.php b/lib/Models/NewsletterTemplate.php index 28fc4484a8..bb7730c6ef 100644 --- a/lib/Models/NewsletterTemplate.php +++ b/lib/Models/NewsletterTemplate.php @@ -1,46 +1,46 @@ -addValidations('name', array( - 'required' => __('Please specify a name.') - )); - $this->addValidations('body', array( - 'required' => __('The template body cannot be empty.') - )); - } - - function asArray() { - $template = parent::asArray(); - if(isset($template['body'])) { - $template['body'] = json_decode($template['body'], true); - } - return $template; - } - - static function createOrUpdate($data = array()) { - $template = false; - - if(isset($data['id']) && (int)$data['id'] > 0) { - $template = self::findOne((int)$data['id']); - } - - if($template === false) { - $template = self::create(); - $template->hydrate($data); - } else { - unset($data['id']); - $template->set($data); - } - - $template->save(); - return $template; - } -} +addValidations('name', array( + 'required' => __('Please specify a name.') + )); + $this->addValidations('body', array( + 'required' => __('The template body cannot be empty.') + )); + } + + function asArray() { + $template = parent::asArray(); + if(isset($template['body'])) { + $template['body'] = json_decode($template['body'], true); + } + return $template; + } + + static function createOrUpdate($data = array()) { + $template = false; + + if(isset($data['id']) && (int)$data['id'] > 0) { + $template = self::findOne((int)$data['id']); + } + + if($template === false) { + $template = self::create(); + $template->hydrate($data); + } else { + unset($data['id']); + $template->set($data); + } + + $template->save(); + return $template; + } +} diff --git a/lib/Models/Setting.php b/lib/Models/Setting.php index c4ff939812..ba48ab6bff 100644 --- a/lib/Models/Setting.php +++ b/lib/Models/Setting.php @@ -1,160 +1,160 @@ -addValidations('name', array( - 'required' => __('Please specify a name.') - )); - } - - public static function getDefaults() { - if(self::$defaults === null) { - self::loadDefaults(); - } - return self::$defaults; - } - - public static function loadDefaults() { - self::$defaults = array( - 'mta_group' => self::DEFAULT_SENDING_METHOD_GROUP, - 'mta' => array( - 'method' => self::DEFAULT_SENDING_METHOD, - 'frequency' => array( - 'emails' => self::DEFAULT_SENDING_FREQUENCY_EMAILS, - 'interval' => self::DEFAULT_SENDING_FREQUENCY_INTERVAL - ) - ), - 'signup_confirmation' => array( - 'enabled' => true, - 'subject' => sprintf(__('Confirm your subscription to %1$s'), get_option('blogname')), - 'body' => __("Hello!\n\nHurray! You've subscribed to our site.\n\nPlease confirm your subscription to the list(s): [lists_to_confirm] by clicking the link below: \n\n[activation_link]Click here to confirm your subscription.[/activation_link]\n\nThank you,\n\nThe Team") - ), - 'tracking' => array( - 'enabled' => true - ) - ); - } - - public static function getValue($key, $default = null) { - $keys = explode('.', $key); - $defaults = self::getDefaults(); - - if(count($keys) === 1) { - $setting = Setting::where('name', $key)->findOne(); - if($setting === false) { - if($default === null && array_key_exists($key, $defaults)) { - return $defaults[$key]; - } else { - return $default; - } - } else { - if(is_serialized($setting->value)) { - $value = unserialize($setting->value); - } else { - $value = $setting->value; - } - if(is_array($value) && array_key_exists($key, $defaults)) { - return array_replace_recursive($defaults[$key], $value); - } else { - return $value; - } - } - } else { - $main_key = array_shift($keys); - - $setting = static::getValue($main_key, $default); - - if($setting !== $default) { - for($i = 0, $count = count($keys); $i < $count; $i++) { - if(!is_array($setting)) { - $setting = array(); - } - if(array_key_exists($keys[$i], $setting)) { - $setting = $setting[$keys[$i]]; - } else { - return $default; - } - } - } - return $setting; - } - } - - public static function setValue($key, $value) { - $keys = explode('.', $key); - - if(count($keys) === 1) { - if(is_array($value)) { - $value = serialize($value); - } - - $setting = Setting::createOrUpdate(array( - 'name' => $key, - 'value' => $value - )); - return ($setting->id() > 0 && $setting->getErrors() === false); - } else { - $main_key = array_shift($keys); - - $setting_value = static::getValue($main_key, array()); - $current_value = &$setting_value; - $last_key = array_pop($keys); - - foreach($keys as $key) { - $current_value =& $current_value[$key]; - } - if(is_scalar($current_value)) { - $current_value = array(); - } - $current_value[$last_key] = $value; - - return static::setValue($main_key, $setting_value); - } - } - - public static function getAll() { - $settingsCollection = self::findMany(); - $settings = array(); - if(!empty($settingsCollection)) { - foreach($settingsCollection as $setting) { - $value = (is_serialized($setting->value) - ? unserialize($setting->value) - : $setting->value - ); - $settings[$setting->name] = $value; - } - } - return array_replace_recursive(self::getDefaults(), $settings); - } - - public static function createOrUpdate($data = array()) { - $setting = false; - - if(isset($data['name'])) { - $setting = self::where('name', $data['name'])->findOne(); - } - - if($setting === false) { - $setting = self::create(); - $setting->hydrate($data); - } else { - $setting->value = $data['value']; - } - - return $setting->save(); - } -} +addValidations('name', array( + 'required' => __('Please specify a name.') + )); + } + + public static function getDefaults() { + if(self::$defaults === null) { + self::loadDefaults(); + } + return self::$defaults; + } + + public static function loadDefaults() { + self::$defaults = array( + 'mta_group' => self::DEFAULT_SENDING_METHOD_GROUP, + 'mta' => array( + 'method' => self::DEFAULT_SENDING_METHOD, + 'frequency' => array( + 'emails' => self::DEFAULT_SENDING_FREQUENCY_EMAILS, + 'interval' => self::DEFAULT_SENDING_FREQUENCY_INTERVAL + ) + ), + 'signup_confirmation' => array( + 'enabled' => true, + 'subject' => sprintf(__('Confirm your subscription to %1$s'), get_option('blogname')), + 'body' => __("Hello!\n\nHurray! You've subscribed to our site.\n\nPlease confirm your subscription to the list(s): [lists_to_confirm] by clicking the link below: \n\n[activation_link]Click here to confirm your subscription.[/activation_link]\n\nThank you,\n\nThe Team") + ), + 'tracking' => array( + 'enabled' => true + ) + ); + } + + public static function getValue($key, $default = null) { + $keys = explode('.', $key); + $defaults = self::getDefaults(); + + if(count($keys) === 1) { + $setting = Setting::where('name', $key)->findOne(); + if($setting === false) { + if($default === null && array_key_exists($key, $defaults)) { + return $defaults[$key]; + } else { + return $default; + } + } else { + if(is_serialized($setting->value)) { + $value = unserialize($setting->value); + } else { + $value = $setting->value; + } + if(is_array($value) && array_key_exists($key, $defaults)) { + return array_replace_recursive($defaults[$key], $value); + } else { + return $value; + } + } + } else { + $main_key = array_shift($keys); + + $setting = static::getValue($main_key, $default); + + if($setting !== $default) { + for($i = 0, $count = count($keys); $i < $count; $i++) { + if(!is_array($setting)) { + $setting = array(); + } + if(array_key_exists($keys[$i], $setting)) { + $setting = $setting[$keys[$i]]; + } else { + return $default; + } + } + } + return $setting; + } + } + + public static function setValue($key, $value) { + $keys = explode('.', $key); + + if(count($keys) === 1) { + if(is_array($value)) { + $value = serialize($value); + } + + $setting = Setting::createOrUpdate(array( + 'name' => $key, + 'value' => $value + )); + return ($setting->id() > 0 && $setting->getErrors() === false); + } else { + $main_key = array_shift($keys); + + $setting_value = static::getValue($main_key, array()); + $current_value = &$setting_value; + $last_key = array_pop($keys); + + foreach($keys as $key) { + $current_value =& $current_value[$key]; + } + if(is_scalar($current_value)) { + $current_value = array(); + } + $current_value[$last_key] = $value; + + return static::setValue($main_key, $setting_value); + } + } + + public static function getAll() { + $settingsCollection = self::findMany(); + $settings = array(); + if(!empty($settingsCollection)) { + foreach($settingsCollection as $setting) { + $value = (is_serialized($setting->value) + ? unserialize($setting->value) + : $setting->value + ); + $settings[$setting->name] = $value; + } + } + return array_replace_recursive(self::getDefaults(), $settings); + } + + public static function createOrUpdate($data = array()) { + $setting = false; + + if(isset($data['name'])) { + $setting = self::where('name', $data['name'])->findOne(); + } + + if($setting === false) { + $setting = self::create(); + $setting->hydrate($data); + } else { + $setting->value = $data['value']; + } + + return $setting->save(); + } +} diff --git a/lib/Newsletter/Links/Links.php b/lib/Newsletter/Links/Links.php index 754a8611ff..6f2249151c 100644 --- a/lib/Newsletter/Links/Links.php +++ b/lib/Newsletter/Links/Links.php @@ -1,132 +1,132 @@ -]+' - . '[.]' - # conditionally match everything except for special characters after . - . '(?:' - . '\([\w\d]+\)|' - . '(?:' - . '[^`!()\[\]{}:;\'".,<>«»“”‘’\s]|' - . '(?:[:]\d+)?/?' - . ')+' - . ')' - . ')\\1#'; - // extract shortcodes with [link:*] format - $shortcodes = new Shortcodes(); - $shortcodes = $shortcodes->extract($content, $categories = array('link')); - $extracted_links = array_map(function($shortcode) { - return array( - 'html' => $shortcode, - 'link' => $shortcode - ); - }, $shortcodes); - // extract urls with href="url" format - preg_match_all($regex, $content, $matched_urls); - $matched_urls_count = count($matched_urls[0]); - if($matched_urls_count) { - for($index = 0; $index < $matched_urls_count; $index++) { - $extracted_links[] = array( - 'html' => $matched_urls[0][$index], - 'link' => $matched_urls[2][$index] - ); - } - } - return array_unique($extracted_links, SORT_REGULAR); - } - - static function process($content) { - $extracted_links = self::extract($content); - $processed_links = array(); - foreach($extracted_links as $extracted_link) { - $hash = Security::generateRandomString(self::HASH_LENGTH); - $processed_links[] = array( - 'hash' => $hash, - 'url' => $extracted_link['link'] - ); - $params = array( - 'mailpoet' => '', - 'endpoint' => 'track', - 'action' => 'click', - 'data' => self::DATA_TAG . '-' . $hash - ); - $tracked_link = add_query_arg($params, home_url()); - // first, replace URL in the extracted HTML source with encoded link - $tracked_link_html_source = str_replace( - $extracted_link['link'], $tracked_link, - $extracted_link['html'] - ); - // second, replace original extracted HTML source with tracked URL source - $content = str_replace( - $extracted_link['html'], $tracked_link_html_source, $content - ); - // third, replace text version URL with tracked link: [description](url) - // regex is used to avoid replacing description URLs that are wrapped in round brackets - // i.e., (http://google.com) => [(http://google.com)](http://tracked_link) - $regex_escaped_extracted_link = preg_quote($extracted_link['link'], '/'); - $content = preg_replace( - '/\[(' . $regex_escaped_extracted_link . ')\](\(' . $regex_escaped_extracted_link . '\))/', - '[$1](' . $tracked_link . ')', - $content - ); - } - return array( - $content, - $processed_links - ); - } - - static function replaceSubscriberData( - $newsletter_id, - $subscriber_id, - $queue_id, - $content - ) { - $regex = sprintf('/data=(%s(?:-\w+)?)/', preg_quote(self::DATA_TAG)); - preg_match_all($regex, $content, $links); - foreach($links[1] as $link) { - $hash = null; - if(preg_match('/-/', $link)) { - list(, $hash) = explode('-', $link); - } - $data = array( - 'newsletter' => $newsletter_id, - 'subscriber' => $subscriber_id, - 'queue' => $queue_id, - 'hash' => $hash - ); - $data = rtrim(base64_encode(serialize($data)), '='); - $content = str_replace($link, $data, $content); - } - return $content; - } - - static function save(array $links, $newsletter_id, $queue_id) { - foreach($links as $link) { - if(empty($link['hash'] || empty($link['url']))) continue; - $newsletter_link = NewsletterLink::create(); - $newsletter_link->newsletter_id = $newsletter_id; - $newsletter_link->queue_id = $queue_id; - $newsletter_link->hash = $link['hash']; - $newsletter_link->url = $link['url']; - $newsletter_link->save(); - } - } -} \ No newline at end of file +]+' + . '[.]' + # conditionally match everything except for special characters after . + . '(?:' + . '\([\w\d]+\)|' + . '(?:' + . '[^`!()\[\]{}:;\'".,<>«»“”‘’\s]|' + . '(?:[:]\d+)?/?' + . ')+' + . ')' + . ')\\1#'; + // extract shortcodes with [link:*] format + $shortcodes = new Shortcodes(); + $shortcodes = $shortcodes->extract($content, $categories = array('link')); + $extracted_links = array_map(function($shortcode) { + return array( + 'html' => $shortcode, + 'link' => $shortcode + ); + }, $shortcodes); + // extract urls with href="url" format + preg_match_all($regex, $content, $matched_urls); + $matched_urls_count = count($matched_urls[0]); + if($matched_urls_count) { + for($index = 0; $index < $matched_urls_count; $index++) { + $extracted_links[] = array( + 'html' => $matched_urls[0][$index], + 'link' => $matched_urls[2][$index] + ); + } + } + return array_unique($extracted_links, SORT_REGULAR); + } + + static function process($content) { + $extracted_links = self::extract($content); + $processed_links = array(); + foreach($extracted_links as $extracted_link) { + $hash = Security::generateRandomString(self::HASH_LENGTH); + $processed_links[] = array( + 'hash' => $hash, + 'url' => $extracted_link['link'] + ); + $params = array( + 'mailpoet' => '', + 'endpoint' => 'track', + 'action' => 'click', + 'data' => self::DATA_TAG . '-' . $hash + ); + $tracked_link = add_query_arg($params, home_url()); + // first, replace URL in the extracted HTML source with encoded link + $tracked_link_html_source = str_replace( + $extracted_link['link'], $tracked_link, + $extracted_link['html'] + ); + // second, replace original extracted HTML source with tracked URL source + $content = str_replace( + $extracted_link['html'], $tracked_link_html_source, $content + ); + // third, replace text version URL with tracked link: [description](url) + // regex is used to avoid replacing description URLs that are wrapped in round brackets + // i.e., (http://google.com) => [(http://google.com)](http://tracked_link) + $regex_escaped_extracted_link = preg_quote($extracted_link['link'], '/'); + $content = preg_replace( + '/\[(' . $regex_escaped_extracted_link . ')\](\(' . $regex_escaped_extracted_link . '\))/', + '[$1](' . $tracked_link . ')', + $content + ); + } + return array( + $content, + $processed_links + ); + } + + static function replaceSubscriberData( + $newsletter_id, + $subscriber_id, + $queue_id, + $content + ) { + $regex = sprintf('/data=(%s(?:-\w+)?)/', preg_quote(self::DATA_TAG)); + preg_match_all($regex, $content, $links); + foreach($links[1] as $link) { + $hash = null; + if(preg_match('/-/', $link)) { + list(, $hash) = explode('-', $link); + } + $data = array( + 'newsletter' => $newsletter_id, + 'subscriber' => $subscriber_id, + 'queue' => $queue_id, + 'hash' => $hash + ); + $data = rtrim(base64_encode(serialize($data)), '='); + $content = str_replace($link, $data, $content); + } + return $content; + } + + static function save(array $links, $newsletter_id, $queue_id) { + foreach($links as $link) { + if(empty($link['hash'] || empty($link['url']))) continue; + $newsletter_link = NewsletterLink::create(); + $newsletter_link->newsletter_id = $newsletter_id; + $newsletter_link->queue_id = $queue_id; + $newsletter_link->hash = $link['hash']; + $newsletter_link->url = $link['url']; + $newsletter_link->save(); + } + } +} diff --git a/lib/Newsletter/Renderer/PostProcess/OpenTracking.php b/lib/Newsletter/Renderer/PostProcess/OpenTracking.php index 92dc3b007d..613db18cfa 100644 --- a/lib/Newsletter/Renderer/PostProcess/OpenTracking.php +++ b/lib/Newsletter/Renderer/PostProcess/OpenTracking.php @@ -1,27 +1,27 @@ -parseStr($template); - $template = $DOM->query('body'); - $open_tracking_image = sprintf( - '', - home_url(), - esc_attr('?mailpoet&endpoint=track&action=open&data=' . Links::DATA_TAG) - ); - $template->html($template->html() . $open_tracking_image); - return $DOM->__toString(); - } - - static function addTrackingImage() { - add_filter(Renderer::POST_PROCESS_FILTER, function ($template) { - return OpenTracking::process($template); - }); - return true; - } -} \ No newline at end of file +parseStr($template); + $template = $DOM->query('body'); + $open_tracking_image = sprintf( + '', + home_url(), + esc_attr('?mailpoet&endpoint=track&action=open&data=' . Links::DATA_TAG) + ); + $template->html($template->html() . $open_tracking_image); + return $DOM->__toString(); + } + + static function addTrackingImage() { + add_filter(Renderer::POST_PROCESS_FILTER, function ($template) { + return OpenTracking::process($template); + }); + return true; + } +} diff --git a/lib/Newsletter/Shortcodes/Categories/Date.php b/lib/Newsletter/Shortcodes/Categories/Date.php index 4c77d1456e..0a1e72beb9 100644 --- a/lib/Newsletter/Shortcodes/Categories/Date.php +++ b/lib/Newsletter/Shortcodes/Categories/Date.php @@ -1,17 +1,17 @@ - $date->format('d'), - 'dordinal' => $date->format('dS'), - 'dtext' => $date->format('D'), - 'm' => $date->format('m'), - 'mtext' => $date->format('F'), - 'y' => $date->format('Y') - ); - return (isset($actions[$action])) ? $actions[$action] : false; - } -} + $date->format('d'), + 'dordinal' => $date->format('dS'), + 'dtext' => $date->format('D'), + 'm' => $date->format('m'), + 'mtext' => $date->format('F'), + 'y' => $date->format('Y') + ); + return (isset($actions[$action])) ? $actions[$action] : false; + } +} diff --git a/lib/Newsletter/Shortcodes/Categories/Newsletter.php b/lib/Newsletter/Shortcodes/Categories/Newsletter.php index cdf60563c6..fc5b226f2c 100644 --- a/lib/Newsletter/Shortcodes/Categories/Newsletter.php +++ b/lib/Newsletter/Shortcodes/Categories/Newsletter.php @@ -1,57 +1,57 @@ -where('status', 'completed') - ->count(); - return ++$sent_newsletters; - - default: - return false; - } - } - - private static function getLatestWPPost($post_ids) { - $posts = new \WP_Query( - array( - 'post__in' => $post_ids, - 'posts_per_page' => 1, - 'ignore_sticky_posts' => true, - 'orderby' => 'post_date', - 'order' => 'DESC' - ) - ); - return (count($posts)) ? - $posts->posts[0]->to_array() : - false; - } -} +where('status', 'completed') + ->count(); + return ++$sent_newsletters; + + default: + return false; + } + } + + private static function getLatestWPPost($post_ids) { + $posts = new \WP_Query( + array( + 'post__in' => $post_ids, + 'posts_per_page' => 1, + 'ignore_sticky_posts' => true, + 'orderby' => 'post_date', + 'order' => 'DESC' + ) + ); + return (count($posts)) ? + $posts->posts[0]->to_array() : + false; + } +} diff --git a/lib/Newsletter/Shortcodes/Shortcodes.php b/lib/Newsletter/Shortcodes/Shortcodes.php index ab0661dcc7..cff19f7c58 100644 --- a/lib/Newsletter/Shortcodes/Shortcodes.php +++ b/lib/Newsletter/Shortcodes/Shortcodes.php @@ -1,97 +1,97 @@ -newsletter = (is_object($newsletter)) ? - $newsletter->asArray() : - $newsletter; - $this->subscriber = (is_object($subscriber)) ? - $subscriber->asArray() : - $subscriber; - $this->queue = (is_object($queue)) ? - $queue->asArray() : - $queue; - } - - function extract($content, $categories = false) { - $categories = (is_array($categories)) ? implode('|', $categories) : false; - $regex = sprintf( - '/\[%s:.*?\]/ism', - ($categories) ? '(?:' . $categories . ')' : '(?:\w+)' - ); - preg_match_all($regex, $content, $shortcodes); - $shortcodes = $shortcodes[0]; - return (count($shortcodes)) ? - array_unique($shortcodes) : - false; - } - - function match($shortcode) { - preg_match( - '/\[(?P\w+)?:(?P\w+)(?:.*?\|.*?default:(?P.*?))?\]/', - $shortcode, - $match - ); - return $match; - } - - function process($shortcodes, $content = false) { - $processed_shortcodes = array_map( - function($shortcode) use ($content) { - $shortcode_details = $this->match($shortcode); - $shortcode_category = !empty($shortcode_details['category']) ? - ucfirst($shortcode_details['category']) : - false; - $shortcode_action = !empty($shortcode_details['action']) ? - $shortcode_details['action'] : - false; - $shortcode_class = - self::SHORTCODE_CATEGORY_NAMESPACE . $shortcode_category; - $shortcode_default_value = !empty($shortcode_details['default']) ? - $shortcode_details['default'] : - false; - if(!class_exists($shortcode_class)) { - $custom_shortcode = apply_filters( - 'mailpoet_newsletter_shortcode', - $shortcode, - $this->newsletter, - $this->subscriber, - $this->queue, - $content - ); - return ($custom_shortcode === $shortcode) ? - false : - $custom_shortcode; - } - return $shortcode_class::process( - $shortcode_action, - $shortcode_default_value, - $this->newsletter, - $this->subscriber, - $this->queue, - $content - ); - }, $shortcodes); - return $processed_shortcodes; - } - - function replace($content, $categories = false) { - $shortcodes = $this->extract($content, $categories); - if(!$shortcodes) { - return $content; - } - $processed_shortcodes = $this->process($shortcodes, $content); - $shortcodes = array_intersect_key($shortcodes, $processed_shortcodes); - return str_replace($shortcodes, $processed_shortcodes, $content); - } -} \ No newline at end of file +newsletter = (is_object($newsletter)) ? + $newsletter->asArray() : + $newsletter; + $this->subscriber = (is_object($subscriber)) ? + $subscriber->asArray() : + $subscriber; + $this->queue = (is_object($queue)) ? + $queue->asArray() : + $queue; + } + + function extract($content, $categories = false) { + $categories = (is_array($categories)) ? implode('|', $categories) : false; + $regex = sprintf( + '/\[%s:.*?\]/ism', + ($categories) ? '(?:' . $categories . ')' : '(?:\w+)' + ); + preg_match_all($regex, $content, $shortcodes); + $shortcodes = $shortcodes[0]; + return (count($shortcodes)) ? + array_unique($shortcodes) : + false; + } + + function match($shortcode) { + preg_match( + '/\[(?P\w+)?:(?P\w+)(?:.*?\|.*?default:(?P.*?))?\]/', + $shortcode, + $match + ); + return $match; + } + + function process($shortcodes, $content = false) { + $processed_shortcodes = array_map( + function($shortcode) use ($content) { + $shortcode_details = $this->match($shortcode); + $shortcode_category = !empty($shortcode_details['category']) ? + ucfirst($shortcode_details['category']) : + false; + $shortcode_action = !empty($shortcode_details['action']) ? + $shortcode_details['action'] : + false; + $shortcode_class = + self::SHORTCODE_CATEGORY_NAMESPACE . $shortcode_category; + $shortcode_default_value = !empty($shortcode_details['default']) ? + $shortcode_details['default'] : + false; + if(!class_exists($shortcode_class)) { + $custom_shortcode = apply_filters( + 'mailpoet_newsletter_shortcode', + $shortcode, + $this->newsletter, + $this->subscriber, + $this->queue, + $content + ); + return ($custom_shortcode === $shortcode) ? + false : + $custom_shortcode; + } + return $shortcode_class::process( + $shortcode_action, + $shortcode_default_value, + $this->newsletter, + $this->subscriber, + $this->queue, + $content + ); + }, $shortcodes); + return $processed_shortcodes; + } + + function replace($content, $categories = false) { + $shortcodes = $this->extract($content, $categories); + if(!$shortcodes) { + return $content; + } + $processed_shortcodes = $this->process($shortcodes, $content); + $shortcodes = array_intersect_key($shortcodes, $processed_shortcodes); + return str_replace($shortcodes, $processed_shortcodes, $content); + } +} diff --git a/lib/Router/Router.php b/lib/Router/Router.php index a99b86edfa..19ec99672d 100644 --- a/lib/Router/Router.php +++ b/lib/Router/Router.php @@ -1,103 +1,103 @@ -verifyToken(); - $this->checkPermissions(); - return $this->processRoute(); - } - - function setupPublic() { - $this->verifyToken(); - return $this->processRoute(); - } - - function processRoute() { - $class = ucfirst($_POST['endpoint']); - $endpoint = __NAMESPACE__ . "\\" . $class; - $method = $_POST['method']; - - $doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX); - - if($doing_ajax) { - $data = isset($_POST['data']) ? stripslashes_deep($_POST['data']) : array(); - } else { - $data = $_POST; - } - - if(is_array($data) && !empty($data)) { - // filter out reserved keywords from data - $reserved_keywords = array( - 'token', - 'endpoint', - 'method', - 'mailpoet_redirect' - ); - $data = array_diff_key($data, array_flip($reserved_keywords)); - } - - try { - $endpoint = new $endpoint(); - $response = $endpoint->$method($data); - wp_send_json($response); - } catch(\Exception $e) { - error_log($e->getMessage()); - exit; - } - } - - function setToken() { - $global = ''; - echo $global; - } - - function checkPermissions() { - if(!current_user_can('manage_options')) { - die(); - } - } - - function verifyToken() { - if( - empty($_POST['token']) - || - !wp_verify_nonce($_POST['token'], 'mailpoet_token') - ) { - die(); - } - } -} +verifyToken(); + $this->checkPermissions(); + return $this->processRoute(); + } + + function setupPublic() { + $this->verifyToken(); + return $this->processRoute(); + } + + function processRoute() { + $class = ucfirst($_POST['endpoint']); + $endpoint = __NAMESPACE__ . "\\" . $class; + $method = $_POST['method']; + + $doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX); + + if($doing_ajax) { + $data = isset($_POST['data']) ? stripslashes_deep($_POST['data']) : array(); + } else { + $data = $_POST; + } + + if(is_array($data) && !empty($data)) { + // filter out reserved keywords from data + $reserved_keywords = array( + 'token', + 'endpoint', + 'method', + 'mailpoet_redirect' + ); + $data = array_diff_key($data, array_flip($reserved_keywords)); + } + + try { + $endpoint = new $endpoint(); + $response = $endpoint->$method($data); + wp_send_json($response); + } catch(\Exception $e) { + error_log($e->getMessage()); + exit; + } + } + + function setToken() { + $global = ''; + echo $global; + } + + function checkPermissions() { + if(!current_user_can('manage_options')) { + die(); + } + } + + function verifyToken() { + if( + empty($_POST['token']) + || + !wp_verify_nonce($_POST['token'], 'mailpoet_token') + ) { + die(); + } + } +} diff --git a/lib/Router/Settings.php b/lib/Router/Settings.php index 5bbcf7ff0a..6378b3bf6d 100644 --- a/lib/Router/Settings.php +++ b/lib/Router/Settings.php @@ -1,26 +1,26 @@ - $value) { - Setting::setValue($name, $value); - } - return true; - } - } -} + $value) { + Setting::setValue($name, $value); + } + return true; + } + } +}