diff --git a/.env.sample b/.env.sample index bc52fd2688..b5f4d343e4 100644 --- a/.env.sample +++ b/.env.sample @@ -1,3 +1,4 @@ WP_TEST_URL="http://localhost" WP_TEST_USER="admin" WP_TEST_PASSWORD="password" +WP_TEST_PATH="/var/www/wordpress" \ No newline at end of file diff --git a/lib/config/initializer.php b/lib/config/initializer.php index b580af90e4..e14077c8b2 100644 --- a/lib/config/initializer.php +++ b/lib/config/initializer.php @@ -20,6 +20,7 @@ class Initializer { 'file' => '', 'version' => '1.0.0' )) { + $this->data = array(); $this->version = $params['version']; $this->shortname = 'mailpoet'; @@ -90,12 +91,20 @@ class Initializer { // admin menu add_action('admin_menu', array($this, 'admin_menu')); + add_action('admin_menu', array($this, 'admin_menu')); + + // widget + add_action('widgets_init', array($this, 'mailpoet_widget')); // ajax action add_action('wp_ajax_nopriv_mailpoet_ajax', array($this, 'mailpoet_ajax')); add_action('wp_ajax_mailpoet_ajax', array($this, 'mailpoet_ajax')); } + public function mailpoet_widget() { + register_widget('\MailPoet\Form\Widget'); + } + public function mailpoet_ajax() { if(!current_user_can('manage_options')) { echo json_encode(array('error' => "Access Denied")); diff --git a/lib/form/renderer.php b/lib/form/renderer.php index faca6fc490..d581d34102 100644 --- a/lib/form/renderer.php +++ b/lib/form/renderer.php @@ -1,6 +1,8 @@ widget(array(\'form\' => '.(int)$form['form'].', \'form_type\' => \'php\'));' ); return join("\n", $output); @@ -577,14 +579,14 @@ EOL; $output[] = ''; // (JS) form validation - $output[] = ''; - $output[] = ''; + $output[] = ''; + $output[] = ''; // (CSS) form validation styles - $output[] = ''; + $output[] = ''; // (JS) form submission - $output[] = ''; + $output[] = ''; // (JS) variables... $output[] = ''; $output[] = ''; - $form_widget = new MailPoetFormWidget(); + $form_widget = new Widget(); $output[] = $form_widget->widget(array( 'form' => (int)$form['form'], 'form_type' => 'php' diff --git a/lib/form/widget.php b/lib/form/widget.php new file mode 100644 index 0000000000..fe3863840d --- /dev/null +++ b/lib/form/widget.php @@ -0,0 +1,602 @@ + __("Newsletter subscription form"), + ) + ); + } + + /** + * Save the new widget's title. + */ + public function update( $new_instance, $old_instance ) { + $instance = $old_instance; + $instance['title'] = strip_tags($new_instance['title']); + $instance['form'] = (int)$new_instance['form']; + return $instance; + } + + /** + * Output the widget's option form. + */ + public function form($instance) { + + $instance = wp_parse_args( + (array)$instance, + array( + 'title' => __("Subscribe to our Newsletter") + ) + ); + + // set title + $title = isset($instance['title']) ? strip_tags($instance['title']) : ''; + + // set form + $selected_form = isset($instance['form']) ? (int)($instance['form']) : 0; + + // get forms list + // TODO: update when ORM ready + // $forms = $mailpoet->forms()->select(array( + // 'filter' => array( + // 'form_deleted_at' => NULL + // ) + // )); + $forms = array(); + + ?>

+ + +

+

+ +

+

+ +

+ + id_base + ); + + // get form + // TODO: fix when ORM is ready + // $form = $mailpoet->forms()->fetchById($instance['form']); + $form = null; + + // if the form was not found, return nothing. + if($form === null) { + return ''; + } else { + // init output + $output = ''; + + // before widget + $output .= (isset($before_widget) ? $before_widget : ''); + + if(isset($form['data'])) { + // title + $output .= (isset($before_title) ? $before_title : ''); + $output .= (isset($title) ? $title : ''); + $output .= (isset($after_title) ? $after_title : ''); + + // render form + $form_id = $this->id_base.'_'.$this->number; + if(isset($instance['form_type']) && in_array($instance['form_type'], array('html', 'php', 'iframe', 'shortcode'))) { + $form_type = $instance['form_type']; + } else { + $form_type = 'widget'; + } + + // form container + $output .= '
'; + + // form styles + $output .= MailPoetFormRendering::renderStyles($form); + + $output .= '
'; + + if(isset($_GET['mailpoet_form']) && (int)$_GET['mailpoet_form'] === $form['form']) { + // form messages (success / error) + $output .= '
'; + // success message + if(isset($_GET['mailpoet_success'])) { + $output .= '

'.strip_tags(urldecode($_GET['mailpoet_success']), '

').'

'; + } + // error message + if(isset($_GET['mailpoet_error'])) { + $output .= '

'.strip_tags(urldecode($_GET['mailpoet_error']), '

').'

'; + } + $output .= '
'; + } else { + $output .= '
'; + } + + $output .= ''; + + if(!isset($form['data']['settings']['lists_selected_by']) or (isset($form['data']['settings']['lists_selected_by']) && $form['data']['settings']['lists_selected_by'] !== 'user')) { + if(!empty($form['data']['settings']['lists'])) { + $output .= ''; + } + } + $output .= MailPoetFormRendering::renderHTML($form); + $output .= ''; + + $output .= '
'; + + // after widget + $output .= (isset($after_widget) ? $after_widget : ''); + } + + // shortcode: subscribers count + /*$subscribers_count = mailpoet_subscribers_count(); + $output = str_replace( + array('[mailpoet_subscribers_count]', '[total_subscribers]'), + array($subscribers_count, $subscribers_count), + $output + );*/ + + if($form_type === 'widget') { + echo $output; + } else { + return $output; + } + } + } +} + +// mailpoet shortcodes +// form shortcode +add_shortcode('mailpoet_form', 'mailpoet_form_shortcode'); +add_shortcode('wysija_form', 'mailpoet_form_shortcode'); + +function mailpoet_form_shortcode($params = array()) { + // IMPORTANT: this is to make sure MagicMember won't scan our form and find [user_list] as a code they should replace. + remove_shortcode('user_list'); + + if(isset($params['id']) && (int)$params['id'] > 0) { + $form_widget = new \MailPoet\Form\Widget(); + return $form_widget->widget(array( + 'form' => (int)$params['id'], + 'form_type' => 'shortcode' + )); + } +} + +/* +// subscribers count shortcode +add_shortcode('mailpoet_subscribers_count', 'mailpoet_subscribers_count'); +add_shortcode('wysija_subscribers_count', 'mailpoet_subscribers_count'); + + +function mailpoet_subscribers_count() { + $mailpoet = new MailPoetWPI(); + // return the count of subscribers (STATE_SUBSCRIBED) + $subscribers_count = $mailpoet->subscribers()->count(array( + 'filter' => array( + 'subscriber_state' => MailPoetSubscribers::STATE_SUBSCRIBED + ) + )); + + return $subscribers_count; +} + +add_action('wp_ajax_mailpoet_form_subscribe', 'mailpoet_form_subscribe'); +add_action('wp_ajax_nopriv_mailpoet_form_subscribe', 'mailpoet_form_subscribe'); +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'); + + +// set the content filter to replace the shortcode + +if(isset($_GET['mailpoet_page']) && strlen(trim($_GET['mailpoet_page'])) > 0) { + $mailpoet = new MailPoetWPI(); + + switch($_GET['mailpoet_page']) { + + case 'mailpoet_form_iframe': + $form_id = (isset($_GET['mailpoet_form']) && (int)$_GET['mailpoet_form'] > 0) ? (int)$_GET['mailpoet_form'] : null; + $form = $mailpoet->forms()->fetchById($form_id); + + if($form !== null) { + // render form + print MailPoetFormRendering::getExport('html', $form); + exit; + } + break; + + default: + // add_filter('wp_title', 'mailpoet_meta_page_title')); + add_filter('the_title', 'mailpoet_page_title', 10, 2); + add_filter('the_content', 'mailpoet_page_content', 98, 1); + break; + } +} + +function mailpoet_page_title($title = '', $id = null) { + $mailpoet = new MailPoetWPI(); + // get signup confirmation page id + $page_id = $mailpoet->settings()->get('signup_confirmation_page'); + + // check if we're on the signup confirmation page + if((int)$page_id === (int)$id) { + global $post; + + // disable comments + $post->comment_status = 'close'; + // disable password + $post->post_password = ''; + + $subscriber = null; + + // get subscriber key from url + $subscriber_digest = (isset($_GET['mailpoet_key']) && strlen(trim($_GET['mailpoet_key'])) === 32) ? trim($_GET['mailpoet_key']) : null; + + if($subscriber_digest !== null) { + // get subscriber + // TODO: change select() to selectOne() once it's implemented + $subscribers = $mailpoet->subscribers()->select(array( + 'filter' => array( + 'subscriber_digest' => $subscriber_digest + ), + 'limit' => 1 + )); + + if(!empty($subscribers)) { + $subscriber = array_shift($subscribers); + } + } + + // check if we have a subscriber record + if($subscriber === null) { + return __('Your confirmation link expired, please subscribe again.'); + } else { + // we have a subscriber, let's check its state + switch($subscriber['subscriber_state']) { + case MailPoetSubscribers::STATE_UNCONFIRMED: + case MailPoetSubscribers::STATE_UNSUBSCRIBED: + // set subscriber state as confirmed + $mailpoet->subscribers()->update(array( + 'subscriber' => $subscriber['subscriber'], + 'subscriber_state' => MailPoetSubscribers::STATE_SUBSCRIBED, + 'subscriber_confirmed_at' => time() + )); + return __("You've subscribed"); + break; + case MailPoetSubscribers::STATE_SUBSCRIBED: + return __("You've already subscribed"); + break; + } + } + } else { + return $title; + } +} + +function mailpoet_page_content($content = '') { + if(strpos($content, '[mailpoet_page]') !== FALSE) { + $content = str_replace('[mailpoet_page]', '', $content); + } + return $content; +} + +function mailpoet_signup_confirmation_email(array $subscriber, array $lists) { + $mailpoet = new MailPoetWPI(); + + $mailer = new MailPoetMailer($mailpoet->settings()->getAll()); + + // email subject & body + $email_subject = $mailpoet->settings()->get('signup_confirmation_email_subject'); + $email_body = nl2br($mailpoet->settings()->get('signup_confirmation_email_body')); + + // check for lists_to_confirm tag + if(strpos($email_body, '[lists_to_confirm]') !== FALSE) { + // gather all names from lists + $list_names = array_map(function($list) { return $list['list_name']; }, $lists); + // replace shortcode by list names in email's body + $email_body = str_replace('[lists_to_confirm]', join(', ', $list_names), $email_body); + } + + // check for activation_link tags + if(strpos($email_body, '[activation_link]') !== FALSE && strpos($email_body, '[/activation_link]') !== FALSE) { + // get confirmation page id + $confirmation_page_id = $mailpoet->settings()->get('signup_confirmation_page'); + + // generate confirmation link + $confirmation_link = add_query_arg(array( + 'mailpoet_key' => $subscriber['subscriber_digest'] + ), get_permalink($confirmation_page_id)); + + // we have both tags + $email_body = str_replace( + array('[activation_link]', '[/activation_link]'), + array('', ''), + $email_body + ); + } else { + // no activation link tags detected + // TODO... + } + + // send confirmation email + return $mailer->send(array( + 'from_email' => $mailpoet->settings()->get('signup_confirmation_from_email'), + 'from_name' => $mailpoet->settings()->get('signup_confirmation_from_name'), + 'reply_email' => $mailpoet->settings()->get('signup_confirmation_reply_email'), + 'reply_name' => $mailpoet->settings()->get('signup_confirmation_reply_name'), + 'subject' => $email_subject, + 'html' => $email_body, + 'text' => '', + 'to_email' => $subscriber['subscriber_email'], + 'to_name' => $subscriber['subscriber_email'], + )); +} + +function mailpoet_form_subscribe() { + // check to see if we're in an ajax request or post request + $doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX); + + if(isset($_GET['action']) && $_GET['action'] === 'mailpoet_form_subscribe') { + + // MailPoetWPI instance + $mailpoet = new MailPoetWPI(); + + // input data + $data = array(); + + // output errors + $errors = array(); + + // get posted data + // ajax data + $data = json_decode(file_get_contents('php://input'), true); + // -or- post data + if($data === NULL && !empty($_POST)) { $data = $_POST; } + + // define null subscriber + $subscriber = null; + + // check if email is valid + if(MailPoetMailer::isEmailAddress($data['email']) === false) { + // email invalid + $errors[] = __('Invalid email address.'); + } else { + // search for subscriber in database + $subscribers = $mailpoet->subscribers()->select(array( + 'filter' => array( + 'subscriber_email' => $data['email'] + ), + 'offset' => 0, + 'limit' => 1 + )); + + // check if we have any subscriber that matches + if(count($subscribers) > 0) { + // use existing subscriber + $subscriber = $subscribers[0]; + } + + // is signup confirmation enabled? + $needs_confirmation = (bool)$mailpoet->settings()->get('signup_confirmation'); + + if($subscriber === null) { + // create new subscriber + $subscriber = array( + 'subscriber_email' => $data['email'], + 'subscriber_firstname' => (isset($data['subscriber_firstname'])) ? $data['subscriber_firstname'] : '', + 'subscriber_lastname' => (isset($data['subscriber_lastname'])) ? $data['subscriber_lastname'] : '', + 'subscriber_state' => ($needs_confirmation === true) ? MailPoetSubscribers::STATE_UNCONFIRMED : MailPoetSubscribers::STATE_SUBSCRIBED, + 'subscriber_created_at' => time() + ); + + // set custom fields + $meta_fields = $mailpoet->getOption('mailpoet_subscriber_meta', array()); + if(!empty($meta_fields)) { + // loop through data to see if any meta field has been passed + foreach($meta_fields as $field => $field_data) { + // check if it's a mandatory field + $is_required = (isset($field_data['params']['required']) && (bool)$field_data['params']['required'] === true); + + if(array_key_exists($field, $data)) { + // check if it's a mandatory field + if($is_required === true && empty($data[$field])) { + // if it's missing, throw an error + $errors[] = sprintf(__('"%s" is required'), $field_data['name']); + } else { + // assign field to subscriber + $subscriber[$field] = $data[$field]; + } + } + } + } + + if(empty($errors)) { + // insert new subscriber + try { + $subscriber = $mailpoet->subscribers()->insert($subscriber); + } catch(Exception $e) { + $errors[] = $e->getMessage(); + } + } + } else { + // restore deleted subscriber + if($subscriber['subscriber_deleted_at'] !== NULL) { + // reset subscriber state (depends whether signup confirmation is enabled) + if($needs_confirmation === true) { + $subscriber['subscriber_state'] = MailPoetSubscribers::STATE_UNCONFIRMED; + } else { + $subscriber['subscriber_state'] = MailPoetSubscribers::STATE_SUBSCRIBED; + } + try { + // update subscriber (reset deleted_at and state) + $mailpoet->subscribers()->update(array( + 'subscriber' => $subscriber['subscriber'], + 'subscriber_state' => $subscriber['subscriber_state'], + 'subscriber_deleted_at' => NULL + )); + } catch(Exception $e) { + $errors[] = __('An error occurred. Please try again later.'); + } + } + } + } + + // check if form id has been passed + if(isset($data['form']) && (int)$data['form'] > 0) { + // get form id + $form_id = (int)$data['form']; + // get form + $form = $mailpoet->forms()->fetchById($form_id); + + if($form === null) { + $errors[] = __('This form does not exist. Please check your forms.'); + } else { + // set subscriptions + if(empty($data['lists'])) { + $errors[] = __('You need to select a list'); + } else { + // extract list ids + $list_ids = array_map('intval', explode(',', $data['lists'])); + // get lists + $lists = $mailpoet->lists()->fetchByIds($list_ids); + + // subscribe user to lists + $has_subscribed = $mailpoet->subscriptions()->addSubscriberToLists($subscriber, $lists, $form); + + // if signup confirmation is enabled and the subscriber is unconfirmed + if( $needs_confirmation === true + && $has_subscribed === true + && !empty($lists) + && !empty($subscriber['subscriber_digest']) + && $subscriber['subscriber_state'] !== MailPoetSubscribers::STATE_SUBSCRIBED + ) { + // resend confirmation email + $is_sent = mailpoet_signup_confirmation_email($subscriber, $lists); + + // error message if the email could not be sent + if($is_sent === false) { + $errors[] = __('The signup confirmation email could not be sent. Please check your settings.'); + } + } + } + } + + // get success message to display after subscription + $form_settings = (isset($form['data']['settings']) ? $form['data']['settings'] : null); + + if($subscriber !== null && empty($errors)) { + $success = true; + $message = $form_settings['success_message']; + } else { + $success = false; + $message = join('
', $errors); + } + + if($form_settings !== null) { + + // url params for non ajax requests + if($doing_ajax === false) { + // get referer + $referer = (wp_get_referer() !== false) ? wp_get_referer() : $_SERVER['HTTP_REFERER']; + + // redirection parameters + $params = array( + 'mailpoet_form' => (int)$data['form'] + ); + + // handle success/error messages + if($success === false) { + $params['mailpoet_error'] = urlencode($message); + } else { + $params['mailpoet_success'] = urlencode($message); + } + } + + switch ($form_settings['on_success']) { + case 'page': + // response depending on context + if($doing_ajax === true) { + echo json_encode(array( + 'success' => $success, + 'page' => get_permalink($form_settings['success_page']), + 'message' => $message + )); + } else { + $redirect_to = ($success === false) ? $referer : get_permalink($form_settings['success_page']); + wp_redirect(add_query_arg($params, $redirect_to)); + } + break; + + case 'message': + default: + // response depending on context + if($doing_ajax === true) { + echo json_encode(array( + 'success' => $success, + 'message' => $message + )); + } else { + // redirect to previous page + wp_redirect(add_query_arg($params, $referer)); + } + break; + } + } + } + exit(); + } +} +*/ \ No newline at end of file diff --git a/tests/unit/FormRendererCest.php b/tests/unit/FormRendererCest.php index f1640f8d22..c3dec10cbe 100644 --- a/tests/unit/FormRendererCest.php +++ b/tests/unit/FormRendererCest.php @@ -1,8 +1,8 @@ form_data = array( + 'form' => 1, 'form_name' => __("New form"), 'form_created_at' => time(), 'data' => array( @@ -51,6 +51,6 @@ class FormRendererCest { public function itCanRenderExports() { // TODO: Cannot work unless we load the WP environment - //\MailPoet\Form\Renderer::getExports($this->form_data); + \MailPoet\Form\Renderer::getExports($this->form_data); } } diff --git a/tests/unit/HostWebCest.php b/tests/unit/HostWebCest.php index 847748db37..0eb161cbfb 100644 --- a/tests/unit/HostWebCest.php +++ b/tests/unit/HostWebCest.php @@ -1,20 +1,17 @@ hosts = \MailPoet\Host\Web::getList(); - } - // tests public function itHasAListOfHosts() { - expect($this->hosts)->notEmpty(); + expect(\MailPoet\Host\Web::getList())->notEmpty(); } public function itHasValidDataForHosts() { $valid_host_count = 0; - $host_count = count($this->hosts); + $hosts = \MailPoet\Host\Web::getList(); + $host_count = count($hosts); - foreach($this->hosts as $host_key => $host_info) { + foreach($hosts as $host_key => $host_info) { if(array_key_exists('name', $host_info) && is_string($host_info['name']) && array_key_exists('emails', $host_info) @@ -40,8 +37,10 @@ class HostWebCest { } public function itShoudReturnHostLimitations() { - $host_key = array_shift(array_keys($this->hosts)); - $host = $this->hosts[$host_key]; + $hosts = \MailPoet\Host\Web::getList(); + $host_keys = array_keys($hosts); + $host_key = array_shift($host_keys); + $host = $hosts[$host_key]; $host_limitations = \MailPoet\Host\Web::getLimitations($host_key); diff --git a/tests/unit/_bootstrap.php b/tests/unit/_bootstrap.php index 3dd07019ab..ee153deae6 100644 --- a/tests/unit/_bootstrap.php +++ b/tests/unit/_bootstrap.php @@ -1,9 +1,13 @@ load(); -if(!defined('__')) { - function __($value) { - return $value; +$wordpress_path = getenv('WP_TEST_PATH'); + +if($wordpress_path) { + if(file_exists($wordpress_path.'/wp-load.php')) { + require_once(getenv('WP_TEST_PATH').'/wp-load.php'); } +} else { + throw new Exception("You need to specify the path to your WordPress installation\n`WP_TEST_PATH` in your .env file"); } \ No newline at end of file