Файловый менеджер - Редактировать - /home/tuudkjt/globeasy/wp-includes/ID3/mailchimp-for-wp.tar
Назад
config/default-form-content.php 0000777 00000001034 15251522663 0012573 0 ustar 00 <?php $email_label = esc_html__('Email address', 'mailchimp-for-wp'); $email_placeholder_attr = esc_attr__('Your email address', 'mailchimp-for-wp'); $signup_button_value = esc_attr__('Sign up', 'mailchimp-for-wp'); $content = "<p>\n\t<label for=\"email\">{$email_label}: \n"; $content .= "\t\t<input type=\"email\" id=\"email\" name=\"EMAIL\" placeholder=\"{$email_placeholder_attr}\" required>\n\t</label>\n</p>\n\n"; $content .= "<p>\n\t<input type=\"submit\" value=\"{$signup_button_value}\">\n</p>"; return $content; config/default-form-settings.php 0000777 00000000561 15251522663 0012765 0 ustar 00 <?php return [ 'css' => 0, 'double_optin' => 1, 'hide_after_success' => 0, 'lists' => [], 'redirect' => '', 'replace_interests' => 1, 'required_fields' => '', 'update_existing' => 0, 'subscriber_tags' => '', 'remove_subscriber_tags' => '', 'email_typo_check' => 0, ]; config/default-settings.php 0000777 00000000172 15251522663 0012022 0 ustar 00 <?php return [ 'api_key' => '', 'debug_log_level' => 'warning', 'email_on_error' => '', ]; config/default-form-messages.php 0000777 00000003221 15251522663 0012730 0 ustar 00 <?php return [ 'subscribed' => [ 'type' => 'success', 'text' => esc_html__('Thank you, your sign-up request was successful! Please check your email inbox to confirm.', 'mailchimp-for-wp'), ], 'updated' => [ 'type' => 'success', 'text' => esc_html__('Thank you, your records have been updated!', 'mailchimp-for-wp'), ], 'unsubscribed' => [ 'type' => 'success', 'text' => esc_html__('You were successfully unsubscribed.', 'mailchimp-for-wp'), ], 'not_subscribed' => [ 'type' => 'notice', 'text' => esc_html__('Given email address is not subscribed.', 'mailchimp-for-wp'), ], 'error' => [ 'type' => 'error', 'text' => esc_html__('Oops. Something went wrong. Please try again later.', 'mailchimp-for-wp'), ], 'invalid_email' => [ 'type' => 'error', 'text' => esc_html__('Please provide a valid email address.', 'mailchimp-for-wp'), ], 'already_subscribed' => [ 'type' => 'notice', 'text' => esc_html__('Given email address is already subscribed, thank you!', 'mailchimp-for-wp'), ], 'required_field_missing' => [ 'type' => 'error', 'text' => esc_html__('Please fill in the required fields.', 'mailchimp-for-wp'), ], 'no_lists_selected' => [ 'type' => 'error', 'text' => esc_html__('Please select at least one list.', 'mailchimp-for-wp'), ], 'spam' => [ 'type' => 'error', 'text' => esc_html__('Your submission was marked as spam.', 'mailchimp-for-wp'), ], ]; SECURITY.md 0000777 00000000757 15251522663 0006364 0 ustar 00 # Security Policy The Mailchimp for WordPress team and community take potential security issues in our software seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions. ## Reporting a Vulnerability To report a security issue, please email us at support@mc4wp.com or use the GitHub Security Advisory "[Report a Vulnerability](https://github.com/ibericode/mailchimp-for-wordpress/security/advisories/new)" tab. includes/class-list-data-mapper.php 0000777 00000014133 15251522663 0013352 0 ustar 00 <?php /** * Class MC4WP_Field_Map * * @access private * @since 4.0 * @ignore */ class MC4WP_List_Data_Mapper { /** * @var array */ private $data = []; /** * @var array */ private $list_ids = []; /** * @var MC4WP_Field_Formatter */ private $formatter; /** * @var MC4WP_MailChimp */ private $mailchimp; /** * @param array $data * @param array $list_ids */ public function __construct(array $data, array $list_ids) { $this->data = array_change_key_case($data, CASE_UPPER); if (! isset($this->data['EMAIL'])) { throw new InvalidArgumentException('Data needs at least an EMAIL key.'); } $this->list_ids = $list_ids; $this->formatter = new MC4WP_Field_Formatter(); $this->mailchimp = new MC4WP_MailChimp(); } /** * @return MC4WP_MailChimp_Subscriber[] */ public function map() { $map = []; foreach ($this->list_ids as $list_id) { $map[ "$list_id" ] = $this->map_list($list_id); } return $map; } /** * @param string $list_id * @return MC4WP_MailChimp_Subscriber * @throws Exception */ protected function map_list($list_id) { $subscriber = new MC4WP_MailChimp_Subscriber(); $subscriber->email_address = $this->data['EMAIL']; // find merge fields $merge_fields = $this->mailchimp->get_list_merge_fields($list_id); foreach ($merge_fields as $merge_field) { // skip EMAIL field as that is handled separately (see above) if ($merge_field->tag === 'EMAIL') { continue; } // use empty() here to skip empty field values if (empty($this->data[ $merge_field->tag ])) { continue; } // format field value $value = $this->data[ $merge_field->tag ]; $value = $this->format_merge_field_value($merge_field, $value); // add to map $subscriber->merge_fields[ $merge_field->tag ] = $value; } // find interest categories if (! empty($this->data['INTERESTS'])) { $interest_categories = $this->mailchimp->get_list_interest_categories($list_id); foreach ($interest_categories as $interest_category) { foreach ($interest_category->interests as $interest_id => $interest_name) { // straight lookup by ID as key with value copy. if (isset($this->data['INTERESTS'][ $interest_id ])) { $subscriber->interests[ $interest_id ] = $this->formatter->boolean($this->data['INTERESTS'][ $interest_id ]); } // straight lookup by ID as top-level value if (in_array($interest_id, $this->data['INTERESTS'], false)) { $subscriber->interests[ $interest_id ] = true; } // look in array with category ID as key. if (isset($this->data['INTERESTS'][ $interest_category->id ])) { $value = $this->data['INTERESTS'][ $interest_category->id ]; $values = is_array($value) ? $value : array_map('trim', explode('|', $value)); // find by category ID + interest ID if (in_array($interest_id, $values, false)) { $subscriber->interests[ $interest_id ] = true; } // find by category ID + interest name if (in_array($interest_name, $values, true)) { $subscriber->interests[ $interest_id ] = true; } } } } } // add GDPR marketing permissions if (! empty($this->data['MARKETING_PERMISSIONS'])) { $values = $this->data['MARKETING_PERMISSIONS']; $values = is_array($values) ? $values : explode(',', $values); $values = array_map('trim', $values); $marketing_permissions = $this->mailchimp->get_list_marketing_permissions($list_id); foreach ($marketing_permissions as $mp) { if (in_array($mp->marketing_permission_id, $values, true) || in_array($mp->text, $values, true)) { $subscriber->marketing_permissions[] = (object) [ 'marketing_permission_id' => $mp->marketing_permission_id, 'enabled' => true, ]; } } } // find language /* @see http://kb.mailchimp.com/lists/managing-subscribers/view-and-edit-subscriber-languages?utm_source=mc-api&utm_medium=docs&utm_campaign=apidocs&_ga=1.211519638.2083589671.1469697070 */ if (! empty($this->data['MC_LANGUAGE'])) { $subscriber->language = $this->formatter->language($this->data['MC_LANGUAGE']); } return $subscriber; } /** * @param object $merge_field * @param string $value * * @return mixed */ private function format_merge_field_value($merge_field, $value) { $field_type = strtolower($merge_field->type); // Convert arrays to comma-separated strings for all non-address fields if (is_array($value) && $field_type == 'text') { $value = join(', ', $value); } if (method_exists($this->formatter, $field_type)) { $value = call_user_func([ $this->formatter, $field_type ], $value, $merge_field->options); } /** * Filters the value of a field after it is formatted. * * Use this to format a field value according to the field type (in Mailchimp). * * @since 3.0 * @param string $value The value * @param string $field_type The type of the field (in Mailchimp) */ $value = apply_filters('mc4wp_format_field_value', $value, $field_type); return $value; } } includes/class-field-guesser.php 0000777 00000006754 15251522663 0012756 0 ustar 00 <?php /** * Class MC4WP_Field_Guesser * * @access private * @ignore */ class MC4WP_Field_Guesser { /** * @var array */ protected $fields; /** * @param array $fields */ public function __construct(array $fields) { $fields = array_change_key_case($fields, CASE_UPPER); $this->fields = $fields; } /** * Get all data which is namespaced with a given namespace * * @param string $namespace * * @return array */ public function namespaced($namespace = 'mc4wp-') { $prefix = strtoupper($namespace); $return = []; $length = strlen($prefix); foreach ($this->fields as $key => $value) { if (strpos($key, $prefix) === 0) { $new_key = substr($key, $length); $return[ $new_key ] = $value; } } return $return; } /** * Guess values for the following fields * - EMAIL * - NAME * - FNAME * - LNAME * * @return array */ public function guessed() { $guessed = []; foreach ($this->fields as $field => $value) { // transform value into array to support 1-level arrays $sub_fields = is_array($value) ? $value : [ $value ]; foreach ($sub_fields as $sub_field_value) { // poor man's urldecode, to get Enfold theme's contact element to work. $sub_field_value = str_replace('%40', '@', $sub_field_value); // is this an email value? if so, assume it's the EMAIL field if (empty($guessed['EMAIL']) && is_string($sub_field_value) && is_email($sub_field_value)) { $guessed['EMAIL'] = $sub_field_value; continue 2; } // remove special characters from field name $simple_key = str_replace([ '-', '_', ' ' ], '', $field); if (empty($guessed['FNAME']) && $this->string_contains($simple_key, [ 'FIRSTNAME', 'FNAME', 'GIVENNAME', 'FORENAME' ])) { // find first name field $guessed['FNAME'] = $sub_field_value; } elseif (empty($guessed['LNAME']) && $this->string_contains($simple_key, [ 'LASTNAME', 'LNAME', 'SURNAME', 'FAMILYNAME' ])) { // find last name field $guessed['LNAME'] = $sub_field_value; } elseif (empty($guessed['NAME']) && $this->string_contains($simple_key, 'NAME')) { // find name field $guessed['NAME'] = $sub_field_value; } } } return $guessed; } /** * @param $methods * * @return array */ public function combine(array $methods) { $combined = []; foreach ($methods as $method) { if (method_exists($this, $method)) { $combined = array_merge($combined, call_user_func([ $this, $method ])); } } return $combined; } /** * @param string $haystack * @param string|array $needles * * @return bool */ private function string_contains($haystack, $needles) { if (! is_array($needles)) { $needles = [ $needles ]; } foreach ($needles as $needle) { if (strpos($haystack, $needle) !== false) { return true; } } return false; } } includes/class-queue-job.php 0000777 00000001031 15251522663 0012073 0 ustar 00 <?php /** * Class MC4WP_Queue_Job * * @ignore */ class MC4WP_Queue_Job { /** * @var string */ public $id; /** * @var mixed */ public $data; /** * @var int */ public $max_attempts = 1; /** * @var int */ public $attempts = 0; /** * MC4WP_Queue_Job constructor. * * @param mixed $data */ public function __construct($data) { $this->id = (string) microtime(true) . rand(1, 10000); $this->data = $data; } } includes/class-field-formatter.php 0000777 00000010513 15251522663 0013270 0 ustar 00 <?php /** * Class MC4WP_Field_Formatter * * Formats values based on what the Mailchimp API expects or accepts for the given field types. */ class MC4WP_Field_Formatter { /** * @param mixed $value * @param object $options * @return array */ public function address($value, $options = null) { // auto-format if this is a string if (is_string($value)) { // addr1, addr2, city, state, zip, country $address_pieces = explode(',', $value); $address_pieces = array_filter($address_pieces); $address_pieces = array_values($address_pieces); // try to fill it.... this is a long shot $value = [ 'addr1' => $address_pieces[0], 'city' => isset($address_pieces[1]) ? $address_pieces[1] : '', 'state' => isset($address_pieces[2]) ? $address_pieces[2] : '', 'zip' => isset($address_pieces[3]) ? $address_pieces[3] : '', ]; if (! empty($address_pieces[4])) { $value['country'] = $address_pieces[4]; } } elseif (is_array($value)) { // merge with array of empty defaults to allow skipping certain fields $default = array_fill_keys([ 'addr1', 'city', 'state', 'zip' ], ''); $value = array_merge($default, $value); } return $value; } /** * @param mixed $value * @param object $options * @return string */ public function birthday($value, $options = null) { $format = is_object($options) && isset($options->date_format) ? $options->date_format : 'MM/DD'; if (is_array($value)) { // allow for "day" and "month" fields if (isset($value['month']) && isset($value['day'])) { $value = $value['month'] . '/' . $value['day']; } else { // if other array, just join together $value = join('/', $value); } } $value = trim($value); if (empty($value)) { return $value; } // always use slashes as delimiter, so next part works $value = str_replace([ '.', '-' ], '/', $value); // if format = DD/MM OR if first part is definitely a day value (>12), then flip order // this allows `strtotime` to understand `dd/mm` values $values = explode('/', $value); if ($format === 'DD/MM' || ( $values[0] > 12 && $values[0] <= 31 && isset($values[1]) && $values[1] <= 12 )) { $values = array_reverse($values); $value = join('/', $values); } // Mailchimp expects a MM/DD format, regardless of their display preference $value = (string) gmdate('m/d', strtotime($value)); return $value; } /** * @param mixed $value * @param object $options * @return string */ public function date($value, $options = null) { if (is_array($value)) { // allow for "year", "month" and "day" keys if (isset($value['year']) && isset($value['month']) && isset($value['day'])) { $value = $value['year'] . '/' . $value['month'] . '/' . $value['day']; } else { // if other array, just join together $value = join('/', $value); } } $value = trim($value); if (empty($value)) { return $value; } // Mailchimp expects a Y-m-d format no matter the display preference return (string) gmdate('Y-m-d', strtotime($value)); } /** * @param string $value * @param object $options * @return string */ public function language($value, $options = null) { $value = trim($value); $exceptions = [ 'pt_PT', 'es_ES', 'fr_CA', ]; if (! in_array($value, $exceptions, true)) { $value = substr($value, 0, 2); } return $value; } /** * @param mixed $value * @param object $options * @return bool */ public function boolean($value, $options = null) { $falsey = [ 'false', '0' ]; if (in_array($value, $falsey, true)) { return false; } // otherwise, just cast. return (bool) $value; } } includes/class-debug-log.php 0000777 00000014704 15251522663 0012057 0 ustar 00 <?php /** * Class MC4WP_Debug_Log * * Simple logging class which writes to a file, loosely based on PSR-3. */ class MC4WP_Debug_Log { /** * Detailed debug information */ public const DEBUG = 100; /** * Interesting events * * Examples: Visitor subscribed */ public const INFO = 200; /** * Exceptional occurrences that are not errors * * Examples: User already subscribed */ public const WARNING = 300; /** * Runtime errors */ public const ERROR = 400; /** * Logging levels from syslog protocol defined in RFC 5424 * * @var array $levels Logging levels */ protected static $levels = [ self::DEBUG => 'DEBUG', self::INFO => 'INFO', self::WARNING => 'WARNING', self::ERROR => 'ERROR', ]; /** * @var string The file to which messages should be written. */ public $file; /** * @var int Only write messages with this level or higher */ public $level; /** * @var resource */ protected $stream; /** * MC4WP_Debug_Log constructor. * * @param string $file * @param mixed $level; */ public function __construct($file, $level = self::DEBUG) { $this->file = $file; $this->level = self::to_level($level); } /** * @param mixed $level * @param string $message * @return boolean */ public function log($level, $message) { $level = self::to_level($level); // only log if message level is higher than log level if ($level < $this->level) { return false; } // obfuscate email addresses in log message since log might be public. $message = mc4wp_obfuscate_email_addresses((string) $message); // first, get rid of everything between "invisible" tags $message = preg_replace('/<(?:style|script|head)>.+?<\/(?:style|script|head)>/is', '', $message); // then, strip tags (while retaining content of these tags) $message = strip_tags($message); $message = trim($message); /** * Modifies the message that is written to the debug log. * Return an empty string to skip logging this message altogether. * * @param string $message */ $message = apply_filters('mc4wp_debug_log_message', $message); if (empty($message)) { return false; } // generate line $level_name = self::get_level_name($level); $datetime = gmdate('Y-m-d H:i:s', time() + ( get_option('gmt_offset', 0) * HOUR_IN_SECONDS )); $message = sprintf('[%s] %s: %s', $datetime, $level_name, $message) . PHP_EOL; // did we open stream yet? if (! is_resource($this->stream)) { // attempt to open stream $this->stream = @fopen($this->file, 'c+'); if (! is_resource($this->stream)) { return false; } // make sure first line of log file is a PHP tag + exit statement (to prevent direct file access) $line = fgets($this->stream); $php_exit_string = '<?php exit; ?>'; if (strpos($line, $php_exit_string) !== 0) { rewind($this->stream); fwrite($this->stream, $php_exit_string . PHP_EOL . $line); } // place pointer at end of file fseek($this->stream, 0, SEEK_END); } // lock file while we write, ignore errors (not much we can do) flock($this->stream, LOCK_EX); // write the message to the file fwrite($this->stream, $message); // unlock file again, but don't close it for remainder of this request flock($this->stream, LOCK_UN); // Maybe send email on level errors and up if ($level >= self::ERROR) { $opts = mc4wp_get_options(); if (! empty($opts['email_on_error'])) { $last_sent = get_transient('mc4wp_error_email_sent'); if (! $last_sent) { $subject = sprintf('[%s] MC4WP Error on your site', get_bloginfo('name')); $body = sprintf('A MC4WP error occurred on your site: %s', $message); wp_mail($opts['email_on_error'], $subject, $body); set_transient('mc4wp_error_email_sent', time(), DAY_IN_SECONDS); } } } return true; } /** * @param string $message * @return boolean */ public function warning($message) { return $this->log(self::WARNING, $message); } /** * @param string $message * @return boolean */ public function info($message) { return $this->log(self::INFO, $message); } /** * @param string $message * @return boolean */ public function error($message) { return $this->log(self::ERROR, $message); } /** * @param string $message * @return boolean */ public function debug($message) { return $this->log(self::DEBUG, $message); } /** * Converts PSR-3 levels to local ones if necessary * * @param string|int Level number or name (PSR-3) * @return int */ public static function to_level($level) { if (is_string($level)) { $level = strtoupper($level); if (defined(__CLASS__ . '::' . $level)) { return constant(__CLASS__ . '::' . $level); } throw new InvalidArgumentException('Level "' . $level . '" is not defined, use one of: ' . implode(', ', array_keys(self::$levels))); } return $level; } /** * Gets the name of the logging level. * * @param int $level * @return string */ public static function get_level_name($level) { if (! isset(self::$levels[ $level ])) { throw new InvalidArgumentException('Level "' . $level . '" is not defined, use one of: ' . implode(', ', array_keys(self::$levels))); } return self::$levels[ $level ]; } /** * Tests if the log file is writable * * @return bool */ public function test() { $handle = @fopen($this->file, 'a'); $writable = false; if (is_resource($handle)) { $writable = true; fclose($handle); } return $writable; } } includes/class-dynamic-content-tags.php 0000777 00000017130 15251522663 0014236 0 ustar 00 <?php /** * Class MC4WP_Dynamic_Content_Tags * * @access private * @ignore */ abstract class MC4WP_Dynamic_Content_Tags { /** * @var string The escape function for replacement values. */ protected $escape_function = 'esc_html'; /** * @var array Array of registered dynamic content tags */ protected $tags = []; /** * Register template tags */ protected function register() { // Global tags can go here $this->tags['cookie'] = [ 'description' => __('Data from a cookie.', 'mailchimp-for-wp'), 'callback' => [ $this, 'get_cookie' ], 'example' => "cookie name='my_cookie' default='Default Value'", ]; $this->tags['email'] = [ 'description' => __('The email address of the current visitor (if known).', 'mailchimp-for-wp'), 'callback' => [ $this, 'get_email' ], ]; $this->tags['current_url'] = [ 'description' => __('The URL of the page.', 'mailchimp-for-wp'), 'callback' => 'mc4wp_get_request_url', ]; $this->tags['current_path'] = [ 'description' => __('The path of the page.', 'mailchimp-for-wp'), 'callback' => 'mc4wp_get_request_path', ]; $this->tags['date'] = [ 'description' => sprintf(__('The current date. Example: %s.', 'mailchimp-for-wp'), '<strong>' . gmdate('Y/m/d', time() + ( get_option('gmt_offset') * HOUR_IN_SECONDS )) . '</strong>'), 'replacement' => gmdate('Y/m/d', time() + ( get_option('gmt_offset') * HOUR_IN_SECONDS )), ]; $this->tags['time'] = [ 'description' => sprintf(__('The current time. Example: %s.', 'mailchimp-for-wp'), '<strong>' . gmdate('H:i:s', time() + ( get_option('gmt_offset') * HOUR_IN_SECONDS )) . '</strong>'), 'replacement' => gmdate('H:i:s', time() + ( get_option('gmt_offset') * HOUR_IN_SECONDS )), ]; $this->tags['language'] = [ 'description' => sprintf(__('The site\'s language. Example: %s.', 'mailchimp-for-wp'), '<strong>' . get_locale() . '</strong>'), 'callback' => 'get_locale', ]; $this->tags['ip'] = [ 'description' => sprintf(__('The visitor\'s IP address. Example: %s.', 'mailchimp-for-wp'), '<strong>' . mc4wp_get_request_ip_address() . '</strong>'), 'callback' => 'mc4wp_get_request_ip_address', ]; $this->tags['user'] = [ 'description' => __('The property of the currently logged-in user.', 'mailchimp-for-wp'), 'callback' => [ $this, 'get_user_property' ], 'example' => "user property='user_email'", ]; $this->tags['post'] = [ 'description' => __('Property of the current page or post.', 'mailchimp-for-wp'), 'callback' => [ $this, 'get_post_property' ], 'example' => "post property='ID'", ]; } /** * @return array */ public function all() { if (count($this->tags) === 0) { $this->register(); } return $this->tags; } /** * @param array $matches * * @return string */ protected function replace_tag(array $matches) { $tags = $this->all(); $tag = $matches[1]; if (isset($tags[ $tag ])) { $config = $tags[ $tag ]; $replacement = ''; if (isset($config['replacement'])) { $replacement = $config['replacement']; } elseif (isset($config['callback'])) { // parse attributes $attributes = []; if (isset($matches[2])) { $attribute_string = $matches[2]; $attributes = shortcode_parse_atts($attribute_string); } // call function $replacement = call_user_func($config['callback'], $attributes); } // escape replacement value, unless it's configured as providing raw HTML (like {response}) if (!isset($config['raw_html']) || !$config['raw_html']) { $replacement = call_user_func($this->escape_function, $replacement); } return $replacement; } // default to not replacing it return $matches[0]; } /** * @param string $string The string containing dynamic content tags. * @param string $escape_function Escape mode for the replacement value. * @return string */ private function replace($string, $escape_function = 'esc_html') { // first, replace inside attributes $this->escape_function = 'esc_attr'; $string = preg_replace_callback('/\=[\'"]?[^\'"]*\{(\w+)(\ +(?:(?!\{)[^}\n])+)*\ }/', [ $this, 'replace_tag' ], $string); $this->escape_function = $escape_function; // replace strings like this: {tagname attr="value"} $string = preg_replace_callback('/\{(\w+)(\ +(?:(?!\{)[^}\n])+)*\ }/', [ $this, 'replace_tag' ], $string); // call again to take care of nested variables $string = preg_replace_callback('/\{(\w+)(\ +(?:(?!\{)[^}\n])+)*\}/', [ $this, 'replace_tag' ], $string); return $string; } /** * @param string $string * * @return string */ protected function replace_in_html($string) { return $this->replace($string, 'esc_html'); } /** * @param string $string * * @return string */ protected function replace_in_attributes($string) { return $this->replace($string, 'esc_attr'); } /** * @param string $string * * @return string */ protected function replace_in_url($string) { return $this->replace($string, 'urlencode'); } /** * Gets data variable from cookie. * * @param array $args * * @return string */ protected function get_cookie($args = []) { if (empty($args['name'])) { return ''; } $name = $args['name']; $default = isset($args['default']) ? $args['default'] : ''; if (isset($_COOKIE[ $name ])) { return $_COOKIE[ $name ]; } return $default; } /* * Get property of currently logged-in user * * @param array $args * * @return string */ protected function get_user_property($args = []) { $property = empty($args['property']) ? 'user_email' : $args['property']; $default = isset($args['default']) ? $args['default'] : ''; $user = wp_get_current_user(); if ($user instanceof WP_User && isset($user->{$property})) { return $user->{$property}; } return $default; } /* * Get property of viewed post * * @param array $args * * @return string */ protected function get_post_property($args = []) { global $post; $property = empty($args['property']) ? 'ID' : $args['property']; $default = isset($args['default']) ? $args['default'] : ''; if ($post instanceof WP_Post && isset($post->{$property})) { return $post->{$property}; } return $default; } /** * @return string */ protected function get_email() { if (! empty($_REQUEST['EMAIL'])) { return sanitize_email($_REQUEST['EMAIL']); } // then , try logged-in user if (is_user_logged_in()) { $user = wp_get_current_user(); return $user->user_email; } // TODO: Read from cookie? Or add $_COOKIE support to {data} tag? return ''; } } includes/class-plugin.php 0000777 00000002677 15251522663 0011516 0 ustar 00 <?php /** * Class MC4WP_Plugin * * Helper class for easy access to information like the plugin file or plugin directory. * Used in MC4WP Premium. * * @access public * @ignore */ class MC4WP_Plugin { /** * @var string The plugin version. */ protected $version; /** * @var string The main plugin file. */ protected $file; /** * @param string $file The plugin version. * @param string $version The main plugin file. */ public function __construct($file, $version) { $this->file = $file; $this->version = $version; } /** * Get the main plugin file. * * @return string */ public function file() { return $this->file; } /** * Get the plugin version. * * @return string */ public function version() { return $this->version; } /** * Gets the directory the plugin lives in. * * @param string $path * * @return string */ public function dir($path = '') { // ensure path has leading slash if ('' !== $path) { $path = '/' . ltrim($path, '/'); } return dirname($this->file) . $path; } /** * Gets the URL to the plugin files. * * @param string $path * * @return string */ public function url($path = '') { return plugins_url($path, $this->file); } } includes/class-tools.php 0000777 00000020743 15251522663 0011352 0 ustar 00 <?php /** * Class MC4WP_Tools * * @access private * @ignore */ class MC4WP_Tools { /** * @return array */ public static function get_countries() { return [ 'AF' => 'Afghanistan', 'AX' => 'Aland Islands', 'AL' => 'Albania', 'DZ' => 'Algeria', 'AS' => 'American Samoa', 'AD' => 'Andorra', 'AO' => 'Angola', 'AI' => 'Anguilla', 'AQ' => 'Antarctica', 'AG' => 'Antigua and Barbuda', 'AR' => 'Argentina', 'AM' => 'Armenia', 'AW' => 'Aruba', 'AU' => 'Australia', 'AT' => 'Austria', 'AZ' => 'Azerbaijan', 'BS' => 'Bahamas', 'BH' => 'Bahrain', 'BD' => 'Bangladesh', 'BB' => 'Barbados', 'BY' => 'Belarus', 'BE' => 'Belgium', 'BZ' => 'Belize', 'BJ' => 'Benin', 'BM' => 'Bermuda', 'BT' => 'Bhutan', 'BO' => 'Bolivia', 'BQ' => 'Bonaire, Saint Eustatius and Saba', 'BA' => 'Bosnia and Herzegovina', 'BW' => 'Botswana', 'BV' => 'Bouvet Island', 'BR' => 'Brazil', 'IO' => 'British Indian Ocean Territory', 'VG' => 'British Virgin Islands', 'BN' => 'Brunei', 'BG' => 'Bulgaria', 'BF' => 'Burkina Faso', 'BI' => 'Burundi', 'KH' => 'Cambodia', 'CM' => 'Cameroon', 'CA' => 'Canada', 'CV' => 'Cape Verde', 'KY' => 'Cayman Islands', 'CF' => 'Central African Republic', 'TD' => 'Chad', 'CL' => 'Chile', 'CN' => 'China', 'CX' => 'Christmas Island', 'CC' => 'Cocos Islands', 'CO' => 'Colombia', 'KM' => 'Comoros', 'CK' => 'Cook Islands', 'CR' => 'Costa Rica', 'HR' => 'Croatia', 'CU' => 'Cuba', 'CW' => 'Curacao', 'CY' => 'Cyprus', 'CZ' => 'Czech Republic', 'CD' => 'Democratic Republic of the Congo', 'DK' => 'Denmark', 'DJ' => 'Djibouti', 'DM' => 'Dominica', 'DO' => 'Dominican Republic', 'TL' => 'East Timor', 'EC' => 'Ecuador', 'EG' => 'Egypt', 'SV' => 'El Salvador', 'GQ' => 'Equatorial Guinea', 'ER' => 'Eritrea', 'EE' => 'Estonia', 'ET' => 'Ethiopia', 'FK' => 'Falkland Islands', 'FO' => 'Faroe Islands', 'FJ' => 'Fiji', 'FI' => 'Finland', 'FR' => 'France', 'GF' => 'French Guiana', 'PF' => 'French Polynesia', 'TF' => 'French Southern Territories', 'GA' => 'Gabon', 'GM' => 'Gambia', 'GE' => 'Georgia', 'DE' => 'Germany', 'GH' => 'Ghana', 'GI' => 'Gibraltar', 'GR' => 'Greece', 'GL' => 'Greenland', 'GD' => 'Grenada', 'GP' => 'Guadeloupe', 'GU' => 'Guam', 'GT' => 'Guatemala', 'GG' => 'Guernsey', 'GN' => 'Guinea', 'GW' => 'Guinea-Bissau', 'GY' => 'Guyana', 'HT' => 'Haiti', 'HM' => 'Heard Island and McDonald Islands', 'HN' => 'Honduras', 'HK' => 'Hong Kong', 'HU' => 'Hungary', 'IS' => 'Iceland', 'IN' => 'India', 'ID' => 'Indonesia', 'IR' => 'Iran', 'IQ' => 'Iraq', 'IE' => 'Ireland', 'IM' => 'Isle of Man', 'IL' => 'Israel', 'IT' => 'Italy', 'CI' => 'Ivory Coast', 'JM' => 'Jamaica', 'JP' => 'Japan', 'JE' => 'Jersey', 'JO' => 'Jordan', 'KZ' => 'Kazakhstan', 'KE' => 'Kenya', 'KI' => 'Kiribati', 'XK' => 'Kosovo', 'KW' => 'Kuwait', 'KG' => 'Kyrgyzstan', 'LA' => 'Laos', 'LV' => 'Latvia', 'LB' => 'Lebanon', 'LS' => 'Lesotho', 'LR' => 'Liberia', 'LY' => 'Libya', 'LI' => 'Liechtenstein', 'LT' => 'Lithuania', 'LU' => 'Luxembourg', 'MO' => 'Macao', 'MK' => 'Macedonia', 'MG' => 'Madagascar', 'MW' => 'Malawi', 'MY' => 'Malaysia', 'MV' => 'Maldives', 'ML' => 'Mali', 'MT' => 'Malta', 'MH' => 'Marshall Islands', 'MQ' => 'Martinique', 'MR' => 'Mauritania', 'MU' => 'Mauritius', 'YT' => 'Mayotte', 'MX' => 'Mexico', 'FM' => 'Micronesia', 'MD' => 'Moldova', 'MC' => 'Monaco', 'MN' => 'Mongolia', 'ME' => 'Montenegro', 'MS' => 'Montserrat', 'MA' => 'Morocco', 'MZ' => 'Mozambique', 'MM' => 'Myanmar', 'NA' => 'Namibia', 'NR' => 'Nauru', 'NP' => 'Nepal', 'NL' => 'Netherlands', 'NC' => 'New Caledonia', 'NZ' => 'New Zealand', 'NI' => 'Nicaragua', 'NE' => 'Niger', 'NG' => 'Nigeria', 'NU' => 'Niue', 'NF' => 'Norfolk Island', 'KP' => 'North Korea', 'MP' => 'Northern Mariana Islands', 'NO' => 'Norway', 'OM' => 'Oman', 'PK' => 'Pakistan', 'PW' => 'Palau', 'PS' => 'Palestinian Territory', 'PA' => 'Panama', 'PG' => 'Papua New Guinea', 'PY' => 'Paraguay', 'PE' => 'Peru', 'PH' => 'Philippines', 'PN' => 'Pitcairn', 'PL' => 'Poland', 'PT' => 'Portugal', 'PR' => 'Puerto Rico', 'QA' => 'Qatar', 'CG' => 'Republic of the Congo', 'RE' => 'Reunion', 'RO' => 'Romania', 'RU' => 'Russia', 'RW' => 'Rwanda', 'BL' => 'Saint Barthelemy', 'SH' => 'Saint Helena', 'KN' => 'Saint Kitts and Nevis', 'LC' => 'Saint Lucia', 'MF' => 'Saint Martin', 'PM' => 'Saint Pierre and Miquelon', 'VC' => 'Saint Vincent and the Grenadines', 'WS' => 'Samoa', 'SM' => 'San Marino', 'ST' => 'Sao Tome and Principe', 'SA' => 'Saudi Arabia', 'SN' => 'Senegal', 'RS' => 'Serbia', 'SC' => 'Seychelles', 'SL' => 'Sierra Leone', 'SG' => 'Singapore', 'SX' => 'Sint Maarten', 'SK' => 'Slovakia', 'SI' => 'Slovenia', 'SB' => 'Solomon Islands', 'SO' => 'Somalia', 'ZA' => 'South Africa', 'GS' => 'South Georgia and the South Sandwich Islands', 'KR' => 'South Korea', 'SS' => 'South Sudan', 'ES' => 'Spain', 'LK' => 'Sri Lanka', 'SD' => 'Sudan', 'SR' => 'Suriname', 'SJ' => 'Svalbard and Jan Mayen', 'SZ' => 'Swaziland', 'SE' => 'Sweden', 'CH' => 'Switzerland', 'SY' => 'Syria', 'TW' => 'Taiwan', 'TJ' => 'Tajikistan', 'TZ' => 'Tanzania', 'TH' => 'Thailand', 'TG' => 'Togo', 'TK' => 'Tokelau', 'TO' => 'Tonga', 'TT' => 'Trinidad and Tobago', 'TN' => 'Tunisia', 'TR' => 'Turkey', 'TM' => 'Turkmenistan', 'TC' => 'Turks and Caicos Islands', 'TV' => 'Tuvalu', 'VI' => 'U.S. Virgin Islands', 'UG' => 'Uganda', 'UA' => 'Ukraine', 'AE' => 'United Arab Emirates', 'GB' => 'United Kingdom', 'US' => 'United States', 'UM' => 'United States Minor Outlying Islands', 'UY' => 'Uruguay', 'UZ' => 'Uzbekistan', 'VU' => 'Vanuatu', 'VA' => 'Vatican', 'VE' => 'Venezuela', 'VN' => 'Vietnam', 'WF' => 'Wallis and Futuna', 'EH' => 'Western Sahara', 'YE' => 'Yemen', 'ZM' => 'Zambia', 'ZW' => 'Zimbabwe', ]; } } includes/class-mailchimp-subscriber.php 0000777 00000003331 15251522663 0014310 0 ustar 00 <?php class MC4WP_MailChimp_Subscriber { /** * @var string Email address for this subscriber. */ public $email_address = ''; /** * @var array The key of this object’s properties is the ID of the interest in question. */ public $interests = []; /** * @var array An individual merge var and value for a member. */ public $merge_fields = []; /** * @var string Subscriber’s status. */ public $status = 'pending'; /** * @var string Type of email this member asked to get (‘html’ or ‘text’). */ public $email_type = 'html'; /** * @var string IP address the subscriber signed up from. */ public $ip_signup; /** * @var string The subscriber's language */ public $language; /** * @var boolean VIP status for subscriber. */ public $vip; /** * @var array The tags applied to this member. */ public $tags = []; /** * @var array The marketing permissions for the subscriber. */ public $marketing_permissions = []; /** * Retrieves member data as an array, without null values. * * @return array */ public function to_array() { $all = get_object_vars($this); $array = []; foreach ($all as $key => $value) { // skip null values if ($value === null) { continue; } // skip empty marketing_permissions property if ($key === 'marketing_permissions' && empty($value)) { continue; } // otherwise, add to final array $array[ $key ] = $value; } return $array; } } includes/class-personal-data-exporter.php 0000777 00000006426 15251522663 0014614 0 ustar 00 <?php /** * Class MC4WP_Exporter */ class MC4WP_Personal_Data_Exporter { /** * Registers the personal data exporter for comments. * * @param array[] $exporters An array of personal data exporters. * @return array[] An array of personal data exporters. */ public static function add_mailchimp_to_privacy_export($exporters) { $exporters['mailchimp-subscriptions'] = [ 'exporter_friendly_name' => __('Mailchimp Subscriptions'), 'callback' => [self::class, 'get_mailchimp_subscription_data'] ]; return $exporters; } /** * Retrieves the Mailchimp subscription data for a given email address. * * This method uses the Mailchimp for WordPress (MC4WP) API to search for members based on the provided * email address and returns a list of Mailchimp lists the user is subscribed to, if any. * * @param string $email_address The email address of the user to search for. * * @return array An array containing the user's Mailchimp subscription data: * - 'data' (array): The subscription information, including: * - 'group_id' (string): The group identifier for Mailchimp. * - 'group_label' (string): The label for the group ('Mailchimp Subscriptions'). * - 'item_id' (string): The item identifier ('mailchimp-subscriptions'). * - 'data' (array): The subscription details, with: * - 'name' (string): The label ('Mailchimp List'). * - 'value' (string): A comma-separated list of Mailchimp lists the user is subscribed to. * - 'done' (bool): Indicates the completion of the process (always true). */ public static function get_mailchimp_subscription_data($email_address) { $api = mc4wp_get_api_v3(); $client = $api->get_client(); $data = $client->get('search-members?query=' . urlencode($email_address)); // Parse the API response to get the lists the user is subscribed to. $subscribed_lists = []; $data_to_export = []; if (!empty($data->exact_matches->members)) { $lists = $api->get_lists(); foreach ($data->exact_matches->members as $member) { // Fetch the user's subscribed lists. if (isset($member->list_id)) { foreach ($lists as $list) { if ($list->id == $member->list_id) { $subscribed_lists[] = $list->name; continue; } } } } } if ($subscribed_lists) { $data_to_export[] = [ 'group_id' => 'mailchimp', 'group_label' => __('Mailchimp Subscriptions', 'mailchimp-for-wp'), 'item_id' => 'mailchimp-subscriptions', 'data' => [ [ 'name' => __('Mailchimp Lists', 'mailchimp-for-wp'), 'value' => implode(', ', $subscribed_lists), ] ] ]; } return [ 'data' => $data_to_export, 'done' => true, ]; } } includes/class-queue.php 0000777 00000010022 15251522663 0011323 0 ustar 00 <?php /** * Class MC4WP_Queue * * @ignore */ class MC4WP_Queue { /** * @var MC4WP_Queue_Job[] */ protected $jobs; /** * @var string */ protected $option_name; /** * @var bool */ protected $dirty = false; /** * @var int */ private const MAX_JOB_COUNT = 1000; /** * MC4WP_Ecommerce_Queue constructor. * * @param string $option_name */ public function __construct($option_name) { $this->option_name = $option_name; register_shutdown_function([ $this, 'save' ]); } /** * Load jobs from option */ protected function load() { if (! is_null($this->jobs)) { return; } $jobs = get_option($this->option_name, []); if (! is_array($jobs)) { $jobs = []; } else { $valid_jobs = []; foreach ($jobs as $i => $obj) { // filter invalid data from array if (! is_object($obj) || empty($obj->data)) { continue; } // make sure each job is instance of MC4WP_Queue_Job if ($obj instanceof MC4WP_Queue_Job) { $job = $obj; } else { $job = new MC4WP_Queue_Job($obj->data); $job->id = $obj->id; } $valid_jobs[] = $job; } $jobs = $valid_jobs; } $this->jobs = $jobs; } /** * Get all jobs in the queue * * @return MC4WP_Queue_Job[] Array of jobs */ public function all() { $this->load(); return $this->jobs; } /** * Add job to queue * * @param mixed $data * @return boolean */ public function put($data) { $this->load(); // check if we already have a job with same data foreach ($this->jobs as $job) { if ($job->data === $data) { return false; } } // if we have more than MAX_JOB_COUNT jobs, remove first job item. // this protects against an ever-growing job list, but also potentially loses jobs if the queue is not processed soon enough. if (count($this->jobs) > self::MAX_JOB_COUNT) { array_shift($this->jobs); } // add job to end of jobs array $job = new MC4WP_Queue_Job($data); $this->jobs[] = $job; $this->dirty = true; return true; } /** * Get all jobs in the queue * * @return MC4WP_Queue_Job|false */ public function get() { $this->load(); // do we have jobs? if (count($this->jobs) === 0) { return false; } // return first element return reset($this->jobs); } /** * @param MC4WP_Queue_Job $job */ public function delete(MC4WP_Queue_Job $job) { $this->load(); $index = array_search($job, $this->jobs, true); // check for "false" here, as 0 is a valid index. if ($index !== false) { unset($this->jobs[ $index ]); $this->jobs = array_values($this->jobs); $this->dirty = true; } } /** * @param MC4WP_Queue_Job $job */ public function reschedule(MC4WP_Queue_Job $job) { $this->load(); // delete job from start of queue $this->delete($job); // add job to end of queue $this->jobs[] = $job; $this->dirty = true; } /** * Reset queue */ public function reset() { $this->jobs = []; $this->dirty = true; } /** * Save the queue */ public function save() { if (! $this->dirty || is_null($this->jobs)) { return false; } $success = update_option($this->option_name, $this->jobs, false); if ($success) { $this->dirty = false; } return $success; } } includes/default-filters.php 0000777 00000001602 15251522663 0012172 0 ustar 00 <?php defined('ABSPATH') or exit; add_filter('mc4wp_form_data', 'mc4wp_add_name_data', 60); add_filter('mc4wp_integration_data', 'mc4wp_add_name_data', 60); add_filter('mctb_data', '_mc4wp_update_groupings_data', PHP_INT_MAX); add_filter('mc4wp_form_data', '_mc4wp_update_groupings_data', PHP_INT_MAX); add_filter('mc4wp_integration_data', '_mc4wp_update_groupings_data', PHP_INT_MAX); add_filter('mailchimp_sync_user_data', '_mc4wp_update_groupings_data', PHP_INT_MAX); add_filter('mc4wp_use_sslverify', '_mc4wp_use_sslverify', 1); add_filter('wp_privacy_personal_data_exporters', [MC4WP_Personal_Data_Exporter::class, 'add_mailchimp_to_privacy_export']); mc4wp_apply_deprecated_filters('mc4wp_merge_vars', 'mc4wp_form_data'); mc4wp_apply_deprecated_filters('mc4wp_form_merge_vars', 'mc4wp_form_data'); mc4wp_apply_deprecated_filters('mc4wp_integration_merge_vars', 'mc4wp_integration_data'); includes/class-container.php 0000777 00000006016 15251522663 0012171 0 ustar 00 <?php /** * Class MC4WP_Service_Container * * @access private * @ignore */ class MC4WP_Container implements ArrayAccess { /** * @var array */ protected $services = []; /** * @var array */ protected $resolved_services = []; /** * @param string $name * @return boolean */ public function has($name) { return isset($this->services[ $name ]); } /** * @param string $name * * @return mixed * @throws Exception */ public function get($name) { if (! $this->has($name)) { throw new Exception(sprintf('No service named %s was registered.', $name)); } $service = $this->services[ $name ]; // is this a resolvable service? if (is_callable($service)) { // resolve service if it's not resolved yet if (! isset($this->resolved_services[ $name ])) { $this->resolved_services[ $name ] = call_user_func($service); } return $this->resolved_services[ $name ]; } return $this->services[ $name ]; } /** * (PHP 5 >= 5.0.0)<br/> * Whether a offset exists * @link http://php.net/manual/en/arrayaccess.offsetexists.php * * @param mixed $offset <p> * An offset to check for. * </p> * * @return boolean true on success or false on failure. * </p> * <p> * The return value will be casted to boolean if non-boolean was returned. */ #[\ReturnTypeWillChange] public function offsetExists($offset) { return $this->has($offset); } /** * (PHP 5 >= 5.0.0)<br/> * Offset to retrieve * @link http://php.net/manual/en/arrayaccess.offsetget.php * * @param mixed $offset <p> * The offset to retrieve. * </p> * * @return mixed Can return all value types. */ #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->get($offset); } /** * (PHP 5 >= 5.0.0)<br/> * Offset to set * @link http://php.net/manual/en/arrayaccess.offsetset.php * * @param mixed $offset <p> * The offset to assign the value to. * </p> * @param mixed $value <p> * The value to set. * </p> * * @return void */ #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { $this->services[ $offset ] = $value; } /** * (PHP 5 >= 5.0.0)<br/> * Offset to unset * @link http://php.net/manual/en/arrayaccess.offsetunset.php * * @param mixed $offset <p> * The offset to unset. * </p> * * @return void */ #[\ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->services[ $offset ]); } } includes/integrations/class-integration-tags.php 0000777 00000002755 15251522663 0016202 0 ustar 00 <?php /** * Class MC4WP_Integration_Tags * * @ignore * @access private */ class MC4WP_Integration_Tags extends MC4WP_Dynamic_Content_Tags { /** * @var MC4WP_Integration */ protected $integration; /** * Add hooks */ public function add_hooks() { add_filter('mc4wp_integration_checkbox_label', [ $this, 'replace_in_checkbox_label' ], 10, 2); } /** * Register template tags for integrations */ public function register() { parent::register(); $this->tags['subscriber_count'] = [ 'description' => __('Replaced with the number of subscribers on the selected list(s)', 'mailchimp-for-wp'), 'callback' => [ $this, 'get_subscriber_count' ], ]; } /** * @hooked `mc4wp_integration_checkbox_label` * @param string $string * @param MC4WP_Integration $integration * @return string */ public function replace_in_checkbox_label($string, MC4WP_Integration $integration) { $this->integration = $integration; return $this->replace_in_html($string); } /** * Returns the number of subscribers on the selected lists (for the form context) * * @return int */ public function get_subscriber_count() { $mailchimp = new MC4WP_MailChimp(); $list_ids = $this->integration->get_lists(); $count = $mailchimp->get_subscriber_count($list_ids); return number_format($count); } } includes/integrations/class-integration.php 0000777 00000041442 15251522663 0015242 0 ustar 00 <?php /** * Class MC4WP_Integration * * Base class for all integrations. * * Extend this class and implement the `add_hooks` method to get a settings page. * * @access public * @since 3.0 * @abstract */ abstract class MC4WP_Integration { /** * @var string Name of this integration. */ public $name = ''; /** * @var string Description */ public $description = ''; /** * @var string Slug, used as an unique identifier for this integration. */ public $slug = ''; /** * @var array Array of settings */ public $options = []; /** * @var string Name attribute for the checkbox element. Will be created from slug if empty. */ protected $checkbox_name = ''; /** * @var string[] */ public $checkbox_classes = []; /** * @var string[] */ public $wrapper_classes = []; /** * Constructor * * @param string $slug * @param array $options */ public function __construct($slug, array $options) { $this->slug = $slug; $this->options = $this->parse_options($options); // if checkbox name is not set, set a good custom value if ($this->checkbox_name === '') { $this->checkbox_name = '_mc4wp_subscribe_' . $this->slug; } } /** * Return array of default options * * @return array */ protected function get_default_options() { return [ 'css' => 0, 'double_optin' => 1, 'enabled' => 0, 'implicit' => 0, 'label' => __('Sign me up for the newsletter!', 'mailchimp-for-wp'), 'lists' => [], 'precheck' => 0, 'replace_interests' => 0, 'update_existing' => 0, 'wrap_p' => 1, ]; } /** * @param array $options * * @return array */ protected function parse_options(array $options) { $slug = $this->slug; $default_options = $this->get_default_options(); $options = array_merge($default_options, $options); /** * Filters options for a specific integration * * The dynamic portion of the hook, `$slug`, refers to the slug of the ingration. * * @param array $integration_options */ return (array) apply_filters('mc4wp_integration_' . $slug . '_options', $options); } /** * Initialize the integration */ public function initialize() { $this->add_required_hooks(); $this->add_hooks(); } /** * Adds the required hooks for core functionality, like adding checkbox reset CSS. */ protected function add_required_hooks() { if ($this->options['css'] && ! $this->options['implicit']) { add_action('wp_head', [ $this, 'print_css_reset' ]); } } /** * Was integration triggered? * * Will always return true when integration is implicit. Otherwise, will check value of checkbox. * * @param int $object_id Useful when overriding method. (optional) * @return bool */ public function triggered($object_id = null) { return $this->options['implicit'] || $this->checkbox_was_checked(); } /** * Adds the hooks which are specific to this integration */ abstract protected function add_hooks(); /** * Print CSS reset * * @hooked `wp_head` */ public function print_css_reset() { $css = file_get_contents(MC4WP_PLUGIN_DIR . '/assets/css/checkbox-reset.css'); // replace selector by integration specific selector so the css affects just this checkbox $css = str_ireplace('__INTEGRATION_SLUG__', $this->slug, $css); printf('<style>%s</style>', $css); } /** * Get the text for the label element * * @return string */ public function get_label_text() { $integration = $this; $label = $this->options['label']; if (empty($label)) { $default_options = $this->get_default_options(); $label = $default_options['label']; } // run saved value through gettext filter // this allows people to use a plugin like Loco Translate to translate this message // without updating the setting itself $label = __($label, 'mailchimp-for-wp'); /** * Filters the checkbox label * * @since 3.0 * * @param string $label * @param MC4WP_Integration $integration * @ignore */ $label = (string) apply_filters('mc4wp_integration_checkbox_label', $label, $integration); return $label; } /** * Was the integration checkbox checked? * * @return bool */ public function checkbox_was_checked() { $data = $this->get_data(); return isset($data[ $this->checkbox_name ]) && (int) $data[ $this->checkbox_name ] === 1; } /** * Get a string of attributes for the HTML element wrapping the checkbox + label * * @return string */ protected function get_wrapper_attributes() { $classes = join(' ', $this->wrapper_classes); $html_attrs = [ 'class' => "mc4wp-checkbox mc4wp-checkbox-{$this->slug} $classes", ]; return $this->array_to_attr_string($html_attrs); } /** * Get a string of attributes for the checkbox element. * * @return string */ protected function get_checkbox_attributes() { $integration = $this; $slug = $this->slug; $attributes = []; if ($this->options['precheck']) { $attributes['checked'] = 'checked'; } if (! empty($this->checkbox_classes)) { $attributes['class'] = join(' ', $this->checkbox_classes); } /** * Filters the attributes array. * * @param array $attributes * @param MC4WP_Integration $integration * @ignore */ $attributes = (array) apply_filters('mc4wp_integration_checkbox_attributes', $attributes, $integration); /** * Filters the attributes array. * * The dynamic portion of the hook, `$slug`, refers to the slug for this integration. * * @param array $attributes * @param MC4WP_Integration $integration * @ignore */ $attributes = (array) apply_filters('mc4wp_integration_' . $slug . '_checkbox_attributes', $attributes, $integration); return $this->array_to_attr_string($attributes); } /** * Outputs a checkbox */ public function output_checkbox() { echo $this->get_checkbox_html(); } /** * Get HTML string for the checkbox row (incl. wrapper, label, etc.) * * @return string */ public function get_checkbox_html() { $show_checkbox = empty($this->options['implicit']); $integration_slug = $this->slug; /** * Filters whether to show the sign-up checkbox for this integration. * * @param bool $show_checkbox * @param string $integration_slug */ $show_checkbox = (bool) apply_filters('mc4wp_integration_show_checkbox', $show_checkbox, $integration_slug); if (! $show_checkbox) { return ''; } ob_start(); echo '<!-- Mailchimp for WordPress v', MC4WP_VERSION,' - https://www.mc4wp.com/ -->'; /** @ignore */ do_action('mc4wp_integration_before_checkbox_wrapper', $this); /** @ignore */ do_action('mc4wp_integration_' . $this->slug . '_before_checkbox_wrapper', $this); $wrapper_tag = $this->options['wrap_p'] ? 'p' : 'span'; $wrapper_attrs = $this->get_wrapper_attributes(); // Hidden field to make sure "0" is sent to server echo '<input type="hidden" name="', esc_attr($this->checkbox_name), '" value="0" />'; echo "<$wrapper_tag $wrapper_attrs>"; echo '<label>'; echo '<input type="checkbox" name="', esc_attr($this->checkbox_name), '" value="1" ', $this->get_checkbox_attributes(), '>'; echo '<span>', $this->get_label_text(), '</span>'; echo '</label>'; echo "</$wrapper_tag>"; /** @ignore */ do_action('mc4wp_integration_after_checkbox_wrapper', $this); /** @ignore */ do_action('mc4wp_integration_' . $this->slug . '_after_checkbox_wrapper', $this); echo '<!-- / Mailchimp for WordPress -->'; $html = ob_get_clean(); return $html; } /** * Get the selected Mailchimp lists * * @return array Array of List ID's */ public function get_lists() { $data = $this->get_data(); $integration = $this; $slug = $this->slug; // get checkbox lists options $lists = $this->options['lists']; // get lists from request, if set. if (! empty($data['_mc4wp_lists'])) { $lists = $data['_mc4wp_lists']; // ensure lists is an array if (! is_array($lists)) { $lists = explode(',', $lists); $lists = array_map('trim', $lists); } } /** * Allow plugins to filter final lists value. This filter is documented elsewhere. * * @since 2.0 * @see MC4WP_Form::get_lists * @ignore */ $lists = (array) apply_filters('mc4wp_lists', $lists); /** * Filters the Mailchimp lists this integration should subscribe to * * @since 3.0 * * @param array $lists * @param MC4WP_Integration $integration */ $lists = (array) apply_filters('mc4wp_integration_lists', $lists, $integration); /** * Filters the Mailchimp lists a specific integration should subscribe to * * The dynamic portion of the hook, `$slug`, refers to the slug of the integration. * * @since 3.0 * * @param array $lists * @param MC4WP_Integration $integration */ $lists = (array) apply_filters('mc4wp_integration_' . $slug . '_lists', $lists, $integration); return $lists; } /** * Makes a subscription request * * @param array $data * @param int $related_object_id * * @return boolean */ protected function subscribe(array $data, $related_object_id = 0) { $integration = $this; $slug = $this->slug; $mailchimp = new MC4WP_MailChimp(); $log = $this->get_log(); $list_ids = $this->get_lists(); /** @var MC4WP_MailChimp_Subscriber $subscriber */ $subscriber = null; $result = false; // validate lists if (empty($list_ids)) { $log->warning(sprintf('%s > No Mailchimp lists were selected', $this->name)); return false; } /** * Filters data for integration requests. * * @param array $data */ $data = apply_filters('mc4wp_integration_data', $data); /** * Filters data for a specific integration request. * * The dynamic portion of the hook, `$slug`, refers to the integration slug. * * @param array $data * @param int $related_object_id */ $data = apply_filters("mc4wp_integration_{$slug}_data", $data, $related_object_id); $email_type = mc4wp_get_email_type(); $mapper = new MC4WP_List_Data_Mapper($data, $list_ids); /** @var MC4WP_MailChimp_Subscriber[] $map */ $map = $mapper->map(); foreach ($map as $list_id => $subscriber) { $subscriber->status = $this->options['double_optin'] ? 'pending' : 'subscribed'; $subscriber->email_type = $email_type; $subscriber->ip_signup = mc4wp_get_request_ip_address(); /** @ignore (documented elsewhere) */ $subscriber = apply_filters('mc4wp_subscriber_data', $subscriber); if (! $subscriber instanceof MC4WP_MailChimp_Subscriber) { continue; } /** * Filters subscriber data before it is sent to Mailchimp. Only fires for integration requests. * * @param MC4WP_MailChimp_Subscriber $subscriber */ $subscriber = apply_filters('mc4wp_integration_subscriber_data', $subscriber); if (! $subscriber instanceof MC4WP_MailChimp_Subscriber) { continue; } /** * Filters subscriber data before it is sent to Mailchimp. Only fires for integration requests. * * The dynamic portion of the hook, `$slug`, refers to the integration slug. * * @param MC4WP_MailChimp_Subscriber $subscriber * @param int $related_object_id */ $subscriber = apply_filters("mc4wp_integration_{$slug}_subscriber_data", $subscriber, $related_object_id); if (! $subscriber instanceof MC4WP_MailChimp_Subscriber) { continue; } $result = $mailchimp->list_subscribe($list_id, $subscriber->email_address, $subscriber->to_array(), $this->options['update_existing'], $this->options['replace_interests']); } // if result failed, show error message if (! $result) { // log error if ((int) $mailchimp->get_error_code() === 214) { $log->warning(sprintf('%s > %s is already subscribed to the selected list(s)', $this->name, $subscriber->email_address)); } else { $log->error(sprintf('%s > Mailchimp API Error: %s', $this->name, $mailchimp->get_error_message())); } // bail return false; } $log->info(sprintf('%s > Successfully subscribed %s', $this->name, $subscriber->email_address)); /** * Runs right after someone is subscribed using an integration * * @since 3.0 * * @param MC4WP_Integration $integration * @param string $email_address * @param array $merge_vars * @param MC4WP_MailChimp_Subscriber[] $subscriber_data * @param int $related_object_id */ do_action('mc4wp_integration_subscribed', $integration, $subscriber->email_address, $subscriber->merge_fields, $map, $related_object_id); return true; } /** * Are the required dependencies for this integration installed? * * @return bool */ public function is_installed() { return false; } /** * Which UI elements should we show on the settings page for this integration? * * @return array */ public function get_ui_elements() { return array_keys($this->options); } /** * Does integration have the given UI element? * * @param string $element * @return bool */ public function has_ui_element($element) { $elements = $this->get_ui_elements(); return in_array($element, $elements, true); } /** * Return a string to the admin settings page for this object (if any) * * @param int $object_id * @return string */ public function get_object_link($object_id) { return ''; } /** * Get the data for this integration request * * By default, this will return a combination of all $_GET and $_POST parameters. * Override this method if you need data from somewhere else. * * This data should contain the value of the checkbox (required) * and the lists to which should be subscribed (optional) * * @see MC4WP_Integration::$checkbox_name * @see MC4WP_Integration::get_lists * @see MC4WP_Integration::checkbox_was_checked * * @return array */ public function get_data() { return array_merge((array) $_GET, (array) $_POST); } /** * Converts an array to an attribute string (foo="bar" bar="foo") with escaped values. * * @param array $attrs * @return string */ protected function array_to_attr_string(array $attrs) { $str = ''; foreach ($attrs as $key => $value) { $str .= $key; $str .= '="'; $str .= esc_attr($value); $str .= '"'; } return $str; } /** * @return MC4WP_Debug_Log */ protected function get_log() { return mc4wp('log'); } /** * @return MC4WP_API_V3 */ protected function get_api() { return mc4wp('api'); } } includes/integrations/class-integration-manager.php 0000777 00000010634 15251522663 0016651 0 ustar 00 <?php /** * Class MC4WP_Integration_Manager * * @ignore * @access private */ class MC4WP_Integration_Manager { /** * @var MC4WP_Integration_Fixture[] */ protected $integrations = []; /** * @var MC4WP_Integration_Tags */ protected $tags; /** * Constructor */ public function __construct() { $this->tags = new MC4WP_Integration_Tags(); } /** * Add hooks */ public function add_hooks() { add_action('after_setup_theme', [ $this, 'initialize' ]); $this->tags->add_hooks(); } /** * Add hooks */ public function initialize() { /*** @var MC4WP_Integration_Fixture $integration */ $enabled_integrations = $this->get_enabled_integrations(); foreach ($enabled_integrations as $integration) { $integration->load()->initialize(); } } /** * Get an integration instance * * @return MC4WP_Integration_Fixture[] * @throws Exception */ public function get_all() { return $this->integrations; } /** * Get an integration instance * * @param string $slug * @return MC4WP_Integration * @throws Exception */ public function get($slug) { if (! isset($this->integrations[ $slug ])) { throw new Exception(sprintf('No integration with slug %s has been registered.', $slug)); } return $this->integrations[ $slug ]->load(); } /** * Register a new integration class * * @param string $slug * @param string $class * @param bool $enabled */ public function register_integration($slug, $class, $enabled = false) { $raw_options = $this->get_integration_options($slug); $this->integrations[ $slug ] = new MC4WP_Integration_Fixture($slug, $class, $enabled, $raw_options); } /** * Deregister an integration class * * @param string $slug */ public function deregister_integration($slug) { if (isset($this->integrations[ $slug ])) { unset($this->integrations[ $slug ]); } } /** * Checks whether a certain integration is enabled (in the settings) * * This is decoupled from the integration class itself as checking an array is way "cheaper" than instantiating an object * * @param MC4WP_Integration_Fixture $integration * * @return bool */ public function is_enabled(MC4WP_Integration_Fixture $integration) { return $integration->enabled; } /** * @param MC4WP_Integration $integration * @return bool */ public function is_installed($integration) { return $integration->is_installed(); } /** * Get the integrations which are enabled * * - Some integrations are always enabled because they need manual work * - Other integrations can be enabled in the settings page * - Only returns installed integrations * * @return array */ public function get_enabled_integrations() { // get all enabled integrations $enabled_integrations = array_filter($this->integrations, [ $this, 'is_enabled' ]); // remove duplicate values, for whatever reason.. $enabled_integrations = array_unique($enabled_integrations); // filter out integrations which are not installed $installed_enabled_integrations = array_filter($enabled_integrations, [ $this, 'is_installed' ]); return $installed_enabled_integrations; } /** * Gets all integration options in a keyed array * * @return array */ private function load_options() { $options = (array) get_option('mc4wp_integrations', []); /** * Filters global integration options * * This array holds ALL integration settings * * @since 3.0 * @param array $options * @ignore */ return (array) apply_filters('mc4wp_integration_options', $options); } /** * Gets the raw options for an integration * * @param $slug * @return array */ public function get_integration_options($slug) { static $options; if ($options === null) { $options = $this->load_options(); } return isset($options[ $slug ]) ? $options[ $slug ] : []; } } includes/integrations/class-integration-fixture.php 0000777 00000003610 15251522663 0016721 0 ustar 00 <?php /** * Class MC4WP_Integration_Fixture * * @since 3.0 * @ignore */ class MC4WP_Integration_Fixture { /** * @var string */ public $slug; /** * @var string */ public $class; /** * @var bool */ public $enabled; /** * @var bool */ public $enabled_by_default; /** * @var MC4WP_Integration */ public $instance; /** * @var array */ public $options; /** * @param string $slug * @param string $class * @param bool $enabled_by_default * @param array $options */ public function __construct($slug, $class, $enabled_by_default, array $options) { $this->slug = $slug; $this->class = $class; $this->enabled_by_default = $enabled_by_default; $this->enabled = $enabled_by_default; $this->options = $options; if (! empty($options['enabled'])) { $this->enabled = true; } } /** * Returns the actual instance * * @return MC4WP_Integration */ public function load() { if (! $this->instance instanceof MC4WP_Integration) { $this->instance = new $this->class($this->slug, $this->options); } return $this->instance; } /** * Tunnel everything to MC4WP_Integration class * * @param string $name * @param array $arguments * * @return MC4WP_Integration */ public function __call($name, $arguments) { return call_user_func_array([ $this->load(), $name ], $arguments); } /** * @param string $name * * @return string */ public function __get($name) { return $this->load()->$name; } /** * @return string */ public function __toString() { return $this->slug; } } includes/integrations/class-admin.php 0000777 00000012237 15251522663 0014007 0 ustar 00 <?php /** * Class MC4WP_Integration_Admin * * @ignore * @access private */ class MC4WP_Integration_Admin { /** * @var MC4WP_Integration_Manager */ protected $integrations; /** * @var MC4WP_Admin_Messages */ protected $messages; /** * @param MC4WP_Integration_Manager $integrations * @param MC4WP_Admin_Messages $messages */ public function __construct(MC4WP_Integration_Manager $integrations, MC4WP_Admin_Messages $messages) { $this->integrations = $integrations; $this->messages = $messages; } /** * Add hooks */ public function add_hooks() { add_action('admin_init', [ $this, 'register_setting' ]); add_action('mc4wp_admin_enqueue_assets', [ $this, 'enqueue_assets' ], 10, 2); add_filter('mc4wp_admin_menu_items', [ $this, 'add_menu_item' ]); } /** * Register settings */ public function register_setting() { register_setting('mc4wp_integrations_settings', 'mc4wp_integrations', [ $this, 'save_integration_settings' ]); } /** * Enqueue assets * * @param string $suffix * @param string $page * * @return void */ public function enqueue_assets($suffix, $page) { // only load on integrations pages if ($page !== 'integrations') { return; } wp_register_script('mc4wp-integrations-admin', mc4wp_plugin_url('assets/js/integrations-admin.js'), [ 'mc4wp-admin' ], MC4WP_VERSION, true); wp_enqueue_script('mc4wp-integrations-admin'); } /** * @param array $items * * @return array */ public function add_menu_item($items) { $items[] = [ 'title' => esc_html__('Integrations', 'mailchimp-for-wp'), 'text' => esc_html__('Integrations', 'mailchimp-for-wp'), 'slug' => 'integrations', 'callback' => [ $this, 'show_integrations_page' ], 'position' => 20, ]; return $items; } /** * @param array $new_settings * @return array */ public function save_integration_settings(array $new_settings) { $integrations = $this->integrations->get_all(); $current_settings = (array) get_option('mc4wp_integrations', []); $settings = []; foreach ($integrations as $slug => $integration) { $settings[ $slug ] = $this->parse_integration_settings($slug, $current_settings, $new_settings); } return $settings; } /** * @since 3.0 * @param string $slug * @param array $current * @param array $new * * @return array */ protected function parse_integration_settings($slug, $current, $new) { $settings = []; // start with current settings if (! empty($current[ $slug ])) { $settings = $current[ $slug ]; } // if no new settings were given, return current settings. if (empty($new[ $slug ])) { return $settings; } // merge new settings with currents (to allow passing partial setting arrays) $settings = array_merge($settings, $new[ $slug ]); // sanitize settings $settings = $this->sanitize_integration_settings($settings); return $settings; } /** * @param array $settings * @return array */ protected function sanitize_integration_settings($settings) { // filter null values from lists setting if (! empty($settings['lists'])) { $settings['lists'] = array_filter($settings['lists']); } else { $settings['lists'] = []; } $settings['label'] = strip_tags($settings['label'], '<strong><b><br><a><script><u><em><i><span><img>'); if (! current_user_can('unfiltered_html')) { $settings['label'] = mc4wp_kses($settings['label']); } return $settings; } /** * Show the Integration Settings page * * @internal */ public function show_integrations_page() { if (! empty($_GET['integration'])) { $this->show_integration_settings_page($_GET['integration']); return; } // get all installed & enabled integrations $enabled_integrations = $this->integrations->get_enabled_integrations(); // get all integrations but remove enabled integrations from the resulting array $integrations = $this->integrations->get_all(); require __DIR__ . '/views/integrations.php'; } /** * @param string $slug * * @internal */ public function show_integration_settings_page($slug) { try { $integration = $this->integrations->get($slug); } catch (Exception $e) { echo sprintf('<h3>Integration not found.</h3><p>No integration with slug <strong>%s</strong> was found.</p>', esc_html($slug)); return; } $opts = $integration->options; $mailchimp = new MC4WP_MailChimp(); $lists = $mailchimp->get_lists(); require __DIR__ . '/views/integration-settings.php'; } } includes/integrations/views/integration-settings.php 0000777 00000045564 15251522663 0017143 0 ustar 00 <?php defined('ABSPATH') or exit; /** @var MC4WP_Integration $integration */ /** @var array $opts */ ?> <div id="mc4wp-admin" class="wrap mc4wp-settings"> <p class="mc4wp-breadcrumbs"> <span class="prefix"><?php echo esc_html__('You are here: ', 'mailchimp-for-wp'); ?></span> <a href="<?php echo esc_url(admin_url('admin.php?page=mailchimp-for-wp')); ?>">Mailchimp for WordPress</a> › <a href="<?php echo esc_url(admin_url('admin.php?page=mailchimp-for-wp-integrations')); ?>"><?php echo esc_html__('Integrations', 'mailchimp-for-wp'); ?></a> › <span class="current-crumb"><strong><?php echo esc_html($integration->name); ?></strong></span> </p> <div class="mc4wp-row"> <div class="main-content mc4wp-col"> <h1 class="mc4wp-page-title"> <?php printf(esc_html__('%s integration', 'mailchimp-for-wp'), esc_html($integration->name)); ?> </h1> <h2 style="display: none;"></h2> <?php settings_errors(); ?> <div id="notice-additional-fields" class="notice notice-warning" style="display: none;"> <p><?php echo esc_html__('The selected Mailchimp audience requires custom fields, which may prevent this integration from working.', 'mailchimp-for-wp'); ?></p> <p><?php echo sprintf(wp_kses(__('Please ensure you <a href="%1$s">configure the plugin to send all required fields</a> or <a href="%2$s">log into your Mailchimp account</a> and make sure only the email & name fields are marked as required fields for the selected audiences.', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ] ]), 'https://www.mc4wp.com/kb/send-additional-fields-from-integrations/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=integrations-page', 'https://admin.mailchimp.com/lists/'); ?></p> </div> <p> <?php echo esc_html($integration->description); ?> </p> <form method="post" action="<?php echo admin_url('options.php'); ?>"> <?php settings_fields('mc4wp_integrations_settings'); ?> <?php do_action('mc4wp_admin_before_integration_settings', $integration, $opts); do_action('mc4wp_admin_before_' . $integration->slug . '_integration_settings', $integration, $opts); ?> <table class="form-table"> <?php if ($integration->has_ui_element('enabled')) { ?> <tbody> <tr valign="top"> <th scope="row"><?php echo esc_html__('Enabled?', 'mailchimp-for-wp'); ?></th> <td class="nowrap integration-toggles-wrap"> <label><input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][enabled]" value="1" <?php checked($opts['enabled'], 1); ?> /> <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?></label> <label><input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][enabled]" value="0" <?php checked($opts['enabled'], 0); ?> /> <?php echo esc_html__('No', 'mailchimp-for-wp'); ?></label> <p class="description"><?php echo sprintf(esc_html__('Enable the %s integration? This will add a sign-up checkbox to the form.', 'mailchimp-for-wp'), $integration->name); ?></p> </td> </tr> </tbody> <?php } ?> <?php $config = [ 'element' => 'mc4wp_integrations[' . $integration->slug . '][enabled]', 'value' => '1', 'hide' => false, ]; ?> <tbody class="integration-toggled-settings" data-showif="<?php echo esc_attr(json_encode($config)); ?>"> <?php if ($integration->has_ui_element('implicit')) { ?> <tr valign="top"> <th scope="row"><?php echo esc_html__('Implicit?', 'mailchimp-for-wp'); ?></th> <td class="nowrap"> <label><input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][implicit]" value="1" <?php checked($opts['implicit'], 1); ?> /> <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?></label> <label><input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][implicit]" value="0" <?php checked($opts['implicit'], 0); ?> /> <?php echo esc_html__('No', 'mailchimp-for-wp'); ?> <?php echo '<em>', esc_html__('(recommended)', 'mailchimp-for-wp'), '</em>'; ?> </label> <p class="description"> <?php echo esc_html__('Select "yes" if you want to subscribe people without asking them explicitly.', 'mailchimp-for-wp'); echo '<br />'; echo sprintf( wp_kses( __('<strong>Warning: </strong> enabling this may affect your <a href="%s">GDPR compliance</a>.', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ], 'strong' => [], ] ), 'https://www.mc4wp.com/kb/gdpr-compliance/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=integrations-page' ); ?> </p> </td> </tr> <?php } ?> <?php if ($integration->has_ui_element('lists')) { ?> <?php // hidden input to make sure a value is sent to the server when no checkboxes were selected ?> <input type="hidden" name="mc4wp_integrations[<?php echo $integration->slug; ?>][lists][]" value="" /> <tr valign="top"> <th scope="row"><?php echo esc_html__('Mailchimp audiences', 'mailchimp-for-wp'); ?></th> <?php if (! empty($lists)) { echo '<td>'; echo '<ul style="margin-bottom: 20px; max-height: 300px; overflow-y: auto;">'; foreach ($lists as $list) { $checked = checked(in_array($list->id, $opts['lists'], true), true, false); $value = esc_attr($list->id); echo '<li><label>'; echo "<input type=\"checkbox\" name=\"mc4wp_integrations[{$integration->slug}][lists][]\" value=\"{$value}\" class=\"mc4wp-list-input\" {$checked}> "; echo esc_html($list->name); echo '</label></li>'; } echo '</ul>'; echo '<p class="description">'; echo esc_html__('Select the audiences to which people who check the checkbox should be subscribed.', 'mailchimp-for-wp'); echo '</p>'; echo '</td>'; } else { echo '<td>', sprintf(wp_kses(__('No audiences found, <a href="%s">are you connected to Mailchimp</a>?', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ] ]), esc_url(admin_url('admin.php?page=mailchimp-for-wp'))), '</td>'; } ?> </tr> <?php } // end if UI has lists ?> <?php if ($integration->has_ui_element('label')) { $config = [ 'element' => 'mc4wp_integrations[' . $integration->slug . '][implicit]', 'value' => 0, ]; ?> <tr valign="top" data-showif="<?php echo esc_attr(json_encode($config)); ?>"> <th scope="row"><label for="mc4wp_checkbox_label"><?php echo esc_html__('Checkbox label text', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" id="mc4wp_checkbox_label" name="mc4wp_integrations[<?php echo $integration->slug; ?>][label]" value="<?php echo esc_attr($opts['label']); ?>" required /> <p class="description"><?php printf(esc_html__('HTML tags like %s are allowed in the label text.', 'mailchimp-for-wp'), '<code>' . esc_html('<strong><em><a>') . '</code>'); ?></p> </td> </tr> <?php } // end if UI label ?> <?php if ($integration->has_ui_element('precheck')) { $config = [ 'element' => 'mc4wp_integrations[' . $integration->slug . '][implicit]', 'value' => 0, ]; ?> <tr valign="top" data-showif="<?php echo esc_attr(json_encode($config)); ?>"> <th scope="row"><?php echo esc_html__('Pre-check the checkbox?', 'mailchimp-for-wp'); ?></th> <td class="nowrap"> <label><input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][precheck]" value="1" <?php checked($opts['precheck'], 1); ?> /> <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?></label> <label><input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][precheck]" value="0" <?php checked($opts['precheck'], 0); ?> /> <?php echo esc_html__('No', 'mailchimp-for-wp'); ?> <?php echo '<em>' . __('(recommended)', 'mailchimp-for-wp') . '</em>'; ?></label> <p class="description"> <?php echo esc_html__('Select "yes" if the checkbox should be pre-checked.', 'mailchimp-for-wp'); echo '<br />'; echo sprintf( wp_kses( __('<strong>Warning: </strong> enabling this may affect your <a href="%s">GDPR compliance</a>.', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ], 'strong' => [], ] ), 'https://www.mc4wp.com/kb/gdpr-compliance/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=integrations-page' ); ?> </p> </td> <?php } // end if UI precheck ?> <?php if ($integration->has_ui_element('css')) { $config = [ 'element' => 'mc4wp_integrations[' . $integration->slug . '][implicit]', 'value' => 0, ]; ?> <tr valign="top" data-showif="<?php echo esc_attr(json_encode($config)); ?>"> <th scope="row"><?php echo esc_html__('Load some default CSS?', 'mailchimp-for-wp'); ?></th> <td class="nowrap"> <label><input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][css]" value="1" <?php checked($opts['css'], 1); ?> />‏ <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?></label> <label><input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][css]" value="0" <?php checked($opts['css'], 0); ?> />‏ <?php echo esc_html__('No', 'mailchimp-for-wp'); ?></label> <p class="description"><?php echo esc_html__('Select "yes" if the checkbox appears in a weird place.', 'mailchimp-for-wp'); ?></p> </td> </tr> <?php } // end if UI css ?> <?php if ($integration->has_ui_element('double_optin')) { ?> <tr valign="top"> <th scope="row"><?php echo esc_html__('Double opt-in?', 'mailchimp-for-wp'); ?></th> <td class="nowrap"> <label> <input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][double_optin]" value="1" <?php checked($opts['double_optin'], 1); ?> />‏ <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?> </label> <label> <input type="radio" id="mc4wp_checkbox_double_optin_0" name="mc4wp_integrations[<?php echo $integration->slug; ?>][double_optin]" value="0" <?php checked($opts['double_optin'], 0); ?> />‏ <?php echo esc_html__('No', 'mailchimp-for-wp'); ?> </label> <p class="description"> <?php echo esc_html__('Select "yes" if you want people to confirm their email address before being subscribed (recommended)', 'mailchimp-for-wp'); ?> </p> </td> </tr> <?php } // end if UI double_optin ?> <?php if ($integration->has_ui_element('update_existing')) { ?> <tr valign="top"> <th scope="row"><?php echo esc_html__('Update existing subscribers?', 'mailchimp-for-wp'); ?></th> <td class="nowrap"> <label> <input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][update_existing]" value="1" <?php checked($opts['update_existing'], 1); ?> />‏ <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?> </label> <label> <input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][update_existing]" value="0" <?php checked($opts['update_existing'], 0); ?> />‏ <?php echo esc_html__('No', 'mailchimp-for-wp'); ?> </label> <p class="description"><?php echo esc_html__('Select "yes" if you want to update existing subscribers with the data that is sent.', 'mailchimp-for-wp'); ?></p> </td> </tr> <?php } // end if UI update_existing ?> <?php if ($integration->has_ui_element('replace_interests')) { $config = [ 'element' => 'mc4wp_integrations[' . $integration->slug . '][update_existing]', 'value' => 1, ]; ?> <tr valign="top" data-showif="<?php echo esc_attr(json_encode($config)); ?>"> <th scope="row"><?php echo esc_html__('Replace interest groups?', 'mailchimp-for-wp'); ?></th> <td class="nowrap"> <label> <input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][replace_interests]" value="1" <?php checked($opts['replace_interests'], 1); ?> />‏ <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?> </label> <label> <input type="radio" name="mc4wp_integrations[<?php echo $integration->slug; ?>][replace_interests]" value="0" <?php checked($opts['replace_interests'], 0); ?> />‏ <?php echo esc_html__('No', 'mailchimp-for-wp'); ?> </label> <p class="description"> <?php echo esc_html__('Select "no" if you want to add the selected interests to any previously selected interests when updating a subscriber.', 'mailchimp-for-wp'); ?> <?php echo sprintf('<a href="%s" target="_blank">' . esc_html__('What does this do?', 'mailchimp-for-wp') . '</a>', 'https://www.mc4wp.com/kb/what-does-replace-groupings-mean/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=integrations-page'); ?> </p> </td> </tr> <?php } // end if UI replace_interests ?> </tbody> </table> <?php do_action('mc4wp_admin_after_integration_settings', $integration, $opts); do_action('mc4wp_admin_after_' . $integration->slug . '_integration_settings', $integration, $opts); ?> <?php if (count($integration->get_ui_elements()) > 0) { submit_button(); } ?> </form> </div> <div class="mc4wp-sidebar mc4wp-col"> <?php require MC4WP_PLUGIN_DIR . '/includes/views/parts/admin-sidebar.php'; ?> </div> </div> </div> includes/integrations/views/integrations.php 0000777 00000010717 15251522663 0015460 0 ustar 00 <?php defined('ABSPATH') or exit; /** @var MC4WP_Integration_Fixture[] $enabled_integrations */ /** @var MC4WP_Integration_Fixture[] $available_integrations */ /** @var MC4WP_Integration_Fixture $integration */ function _mc4wp_integrations_table_row($integration) { $style_attr = ! $integration->is_installed() ? 'style="opacity: 0.6;"' : ''; ?> <tr <?php echo $style_attr; ?>> <td> <?php if ($integration->is_installed()) { $href = esc_attr(add_query_arg([ 'integration' => $integration->slug ])); $title = esc_attr__('Configure this integration', 'mailchimp-for-wp'); echo "<strong><a href=\"{$href}\" title=\"{$title}\">{$integration->name}</a></strong>"; } else { echo esc_html($integration->name); } ?> </td> <td class="desc"> <?php echo esc_html($integration->description); ?> </td> <td> <?php if ($integration->enabled && $integration->is_installed()) { echo '<span class="mc4wp-status positive">', esc_html__('Active', 'mailchimp-for-wp'), '</span>'; } elseif ($integration->is_installed()) { echo '<span class="mc4wp-status neutral">', esc_html__('Inactive', 'mailchimp-for-wp'), '</span>'; } else { echo '<span>', esc_html__('Not installed', 'mailchimp-for-wp'), '</span>'; } ?> </td> </tr> <?php } /** * Render a table with integrations * * @param $integrations * @ignore */ function _mc4wp_integrations_table($integrations) { ?> <table class="mc4wp-table widefat striped"> <thead> <tr> <th><?php echo esc_html__('Name', 'mailchimp-for-wp'); ?></th> <th><?php echo esc_html__('Description', 'mailchimp-for-wp'); ?></th> <th><?php echo esc_html__('Status', 'mailchimp-for-wp'); ?></th> </tr> </thead> <tbody> <?php // active & enabled integrations first foreach ($integrations as $integration) { if ($integration->is_installed() && $integration->enabled) { _mc4wp_integrations_table_row($integration); } } // active & disabled integrations next foreach ($integrations as $integration) { if ($integration->is_installed() && ! $integration->enabled) { _mc4wp_integrations_table_row($integration); } } // rest foreach ($integrations as $integration) { if (! $integration->is_installed()) { _mc4wp_integrations_table_row($integration); } } ?> </tbody> </table> <?php } ?> <div id="mc4wp-admin" class="wrap mc4wp-settings"> <p class="mc4wp-breadcrumbs"> <span class="prefix"><?php echo esc_html__('You are here: ', 'mailchimp-for-wp'); ?></span> <a href="<?php echo admin_url('admin.php?page=mailchimp-for-wp'); ?>">Mailchimp for WordPress</a> › <span class="current-crumb"><strong><?php echo esc_html__('Integrations', 'mailchimp-for-wp'); ?></strong></span> </p> <div class="mc4wp-row"> <div class="mc4wp-col mc4wp-col-4"> <h1 class="mc4wp-page-title">Mailchimp for WordPress: <?php echo esc_html__('Integrations', 'mailchimp-for-wp'); ?></h1> <h2 style="display: none;"></h2> <?php settings_errors(); ?> <p> <?php echo esc_html__('The table below shows all available integrations.', 'mailchimp-for-wp'); ?> <?php echo esc_html__('Click on the name of an integration to edit all settings specific to that integration.', 'mailchimp-for-wp'); ?> </p> <form action="<?php echo admin_url('options.php'); ?>" method="post"> <?php settings_fields('mc4wp_integrations_settings'); ?> <h3><?php echo esc_html__('Integrations', 'mailchimp-for-wp'); ?></h3> <?php _mc4wp_integrations_table($integrations); ?> <p><?php echo esc_html__('Greyed out integrations will become available after installing & activating the corresponding plugin.', 'mailchimp-for-wp'); ?></p> </form> </div> <div class="mc4wp-sidebar mc4wp-col"> <?php require MC4WP_PLUGIN_DIR . '/includes/views/parts/admin-sidebar.php'; ?> </div> </div> </div> includes/integrations/functions.php 0000777 00000002052 15251522663 0013616 0 ustar 00 <?php /** * Gets an array of all registered integrations * * @since 3.0 * @access public * * @return MC4WP_Integration[] */ function mc4wp_get_integrations() { return mc4wp('integrations')->get_all(); } /** * Get an instance of a registered integration class * * @since 3.0 * @access public * * @param string $slug * * @return MC4WP_Integration */ function mc4wp_get_integration($slug) { return mc4wp('integrations')->get($slug); } /** * Register a new integration with Mailchimp for WordPress * * @since 3.0 * @access public * * @param string $slug * @param string $class * * @param bool $always_enabled */ function mc4wp_register_integration($slug, $class, $always_enabled = false) { return mc4wp('integrations')->register_integration($slug, $class, $always_enabled); } /** * Deregister a previously registered integration with Mailchimp for WordPress * * @since 3.0 * @access public * @param string $slug */ function mc4wp_deregister_integration($slug) { mc4wp('integrations')->deregister_integration($slug); } includes/integrations/class-user-integration.php 0000777 00000002561 15251522663 0016215 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_User_Integration * * @access public * @since 2.0 */ abstract class MC4WP_User_Integration extends MC4WP_Integration { /** * @param WP_User $user * * @return array */ protected function user_merge_vars(WP_User $user) { // start with user_login as name, since that's always known $data = [ 'EMAIL' => $user->user_email, 'NAME' => $user->user_login, ]; if ('' !== $user->first_name) { $data['NAME'] = $user->first_name; $data['FNAME'] = $user->first_name; } if ('' !== $user->last_name) { $data['LNAME'] = $user->last_name; } if ('' !== $user->first_name && '' !== $user->last_name) { $data['NAME'] = sprintf('%s %s', $user->first_name, $user->last_name); } /** * @use mc4wp_integration_user_data * @since 3.0 * @deprecated 4.0 * @ignore */ $data = (array) apply_filters('mc4wp_user_merge_vars', $data, $user); /** * Filters the data for user-related integrations * @since 4.2 * @param array $data * @param WP_User $user */ $data = (array) apply_filters('mc4wp_integration_user_data', $data, $user); return $data; } } includes/admin/class-admin-texts.php 0000777 00000005314 15251522663 0013534 0 ustar 00 <?php /** * Class MC4WP_Admin_Texts * * @ignore * @since 3.0 */ class MC4WP_Admin_Texts { /** * @var string */ protected $plugin_file; /** * @param string $plugin_file */ public function __construct($plugin_file) { $this->plugin_file = $plugin_file; } /** * Add hooks */ public function add_hooks() { global $pagenow; add_filter('admin_footer_text', [ $this, 'footer_text' ]); // Hooks for Plugins overview page if ($pagenow === 'plugins.php') { add_filter('plugin_action_links_' . $this->plugin_file, [ $this, 'add_plugin_settings_link' ], 10, 2); add_filter('plugin_row_meta', [ $this, 'add_plugin_meta_links' ], 10, 2); } } /** * Ask for a plugin review in the WP Admin footer, if this is one of the plugin pages. * * @param string $text * * @return string */ public function footer_text($text) { if (! empty($_GET['page']) && strpos($_GET['page'], 'mailchimp-for-wp') === 0) { $text = sprintf('If you enjoy using <strong>Mailchimp for WordPress</strong>, please <a href="%s" target="_blank">leave us a ★★★★★ plugin review on WordPress.org</a>.', 'https://wordpress.org/support/plugin/mailchimp-for-wp/reviews/#new-post'); } return $text; } /** * Add the settings link to the Plugins overview * * @param array $links * @param $file * * @return array */ public function add_plugin_settings_link($links, $file) { if ($file !== $this->plugin_file) { return $links; } $settings_link = sprintf('<a href="%s">%s</a>', admin_url('admin.php?page=mailchimp-for-wp'), esc_html__('Settings', 'mailchimp-for-wp')); array_unshift($links, $settings_link); return $links; } /** * Adds meta links to the plugin in the WP Admin > Plugins screen * * @param array $links * @param string $file * * @return array */ public function add_plugin_meta_links($links, $file) { if ($file !== $this->plugin_file) { return $links; } $links[] = '<a href="https://www.mc4wp.com/kb/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=plugins-page">' . esc_html__('Documentation', 'mailchimp-for-wp') . '</a>'; /** * Filters meta links shown on the Plugins overview page * * This takes an array of strings * * @since 3.0 * @param array $links * @ignore */ $links = apply_filters('mc4wp_admin_plugin_meta_links', $links); return $links; } } includes/admin/class-upgrade-routines.php 0000777 00000003536 15251522663 0014600 0 ustar 00 <?php /** * Class MC4WP_DB_Upgrader * * This class takes care of loading migration files from the specified migrations directory. * Migration files should only use default WP functions and NOT use code which might not be there in the future. * * @ignore */ class MC4WP_Upgrade_Routines { /** * @var float */ protected $version_from = 0; /** * @var float */ protected $version_to = 0; /** * @var string */ protected $migrations_dir = ''; /** * @param float $from * @param float $to */ public function __construct($from, $to, $migrations_dir) { $this->version_from = $from; $this->version_to = $to; $this->migrations_dir = $migrations_dir; } /** * Run the various upgrade routines, all the way up to the latest version */ public function run() { $migrations = $this->find_migrations(); // run in sub-function for scope array_map([ $this, 'run_migration' ], $migrations); } /** * @return array */ public function find_migrations() { $files = glob(rtrim($this->migrations_dir, '/') . '/*.php'); $migrations = []; // return empty array when glob returns non-array value. if (! is_array($files)) { return $migrations; } foreach ($files as $file) { $migration = basename($file); $parts = explode('-', $migration); $version = $parts[0]; if (version_compare($this->version_from, $version, '<')) { $migrations[] = $file; } } return $migrations; } /** * Include a migration file and runs it. * * @param string $file */ protected function run_migration($file) { include $file; } } includes/admin/migrations/3.0.0-form-2-options.php 0000777 00000003331 15251522663 0015574 0 ustar 00 <?php defined('ABSPATH') or exit; $global_options = (array) get_option('mc4wp_form', []); // find all form posts $posts = get_posts( [ 'post_type' => 'mc4wp-form', 'post_status' => 'publish', 'numberposts' => -1, ] ); $css_map = [ 'default' => 'basic', 'custom' => 'styles-builder', 'light' => 'theme-light', 'dark' => 'theme-dark', 'red' => 'theme-red', 'green' => 'theme-green', 'blue' => 'theme-blue', 'custom-color' => 'theme-custom-color', ]; $stylesheets = []; foreach ($posts as $post) { // get form options from post meta directly $options = (array) get_post_meta($post->ID, '_mc4wp_settings', true); // store all global options in scoped form settings // do this BEFORE changing css key, so we take that as well. foreach ($global_options as $key => $value) { if (strlen($value) > 0 && ( ! isset($options[ $key ]) || strlen($options[ $key ]) == 0 )) { $options[ $key ] = $value; } } // update "css" option value if (isset($options['css']) && isset($css_map[ $options['css'] ])) { $options['css'] = $css_map[ $options['css'] ]; } // create stylesheets option if (! empty($options['css'])) { $stylesheet = $options['css']; if (strpos($stylesheet, 'theme-') === 0) { $stylesheet = 'themes'; } if (! in_array($stylesheet, $stylesheets)) { $stylesheets[] = $stylesheet; } } update_post_meta($post->ID, '_mc4wp_settings', $options); } // update stylesheets option update_option('mc4wp_form_stylesheets', $stylesheets); // delete old options delete_option('mc4wp_form'); includes/admin/migrations/4.0.7-rename-debug-log-file.php 0000777 00000001700 15251522663 0017036 0 ustar 00 <?php defined('ABSPATH') or exit; // get old log filename $upload_dir = wp_upload_dir(null, false); $old_filename = trailingslashit($upload_dir['basedir']) . 'mc4wp-debug.log'; $new_filename = trailingslashit($upload_dir['basedir']) . 'mc4wp-debug-log.php'; // check if old default log file exists if (! file_exists($old_filename)) { return; } // rename to new file. @rename($old_filename, $new_filename); // if success, insert php exit tag as first line if (file_exists($new_filename)) { $handle = fopen($new_filename, 'r+'); if (is_resource($handle)) { // make sure first line of log file is a PHP tag + exit statement (to prevent direct file access) $line = fgets($handle); $php_exit_string = '<?php exit; ?>'; if (strpos($line, $php_exit_string) !== 0) { rewind($handle); fwrite($handle, $php_exit_string . PHP_EOL . $line); } fclose($handle); } } includes/admin/migrations/3.0.0-form-1-post-type.php 0000777 00000003733 15251522663 0016052 0 ustar 00 <?php defined('ABSPATH') or exit; // get options $form_options = get_option('mc4wp_lite_form', []); // bail if there are no previous options if (empty($form_options)) { return; } // bail if there are Pro forms already $has_forms = get_posts( [ 'post_type' => 'mc4wp-form', 'post_status' => 'publish', 'numberposts' => 1, ] ); // There are forms already, don't continue. if (! empty($has_forms)) { // delete option as it apparently exists. delete_option('mc4wp_lite_form'); return; } // create post type for form $id = wp_insert_post( [ 'post_type' => 'mc4wp-form', 'post_status' => 'publish', 'post_title' => __('Default sign-up form', 'mailchimp-for-wp'), 'post_content' => ( empty($form_options['markup']) ) ? '' : $form_options['markup'], ] ); // set default_form_id update_option('mc4wp_default_form_id', $id); // set form settings $setting_keys = [ 'css', 'custom_theme_color', 'double_optin', 'update_existing', 'replace_interests', 'send_welcome', 'redirect', 'hide_after_success', ]; $settings = []; foreach ($setting_keys as $setting_key) { // use isset to account for "0" settings if (isset($form_options[ $setting_key ])) { $settings[ $setting_key ] = $form_options[ $setting_key ]; } } // get only keys of lists setting if (isset($form_options['lists'])) { $settings['lists'] = array_keys($form_options['lists']); } update_post_meta($id, '_mc4wp_settings', $settings); // set form message texts $message_keys = [ 'text_subscribed', 'text_error', 'text_invalid_email', 'text_already_subscribed', 'text_required_field_missing', 'text_unsubscribed', 'text_not_subscribed', ]; foreach ($message_keys as $message_key) { if (! empty($form_options[ $message_key ])) { update_post_meta($id, $message_key, $form_options[ $message_key ]); } } // delete old option delete_option('mc4wp_lite_form'); includes/admin/migrations/4.0.0-hidden-fields-value-delimiter.php 0000777 00000001340 15251522663 0020565 0 ustar 00 <?php defined('ABSPATH') or exit; /** @ignore */ function _mc4wp_400_replace_comma_with_pipe($matches) { $old = $matches[1]; $new = str_replace(',', '|', $old); return str_replace($old, $new, $matches[0]); } // get all forms $posts = get_posts( [ 'post_type' => 'mc4wp-form', 'numberposts' => -1, ] ); foreach ($posts as $post) { // find hidden field values in form and pass through replace function $old = $post->post_content; $new = preg_replace_callback('/type="hidden" .* value="(.*)"/i', '_mc4wp_400_replace_comma_with_pipe', $old); // update post if we replaced something if ($new != $old) { $post->post_content = $new; wp_update_post($post); } } includes/admin/migrations/4.6.0-remove-lists-from-options.php 0000777 00000000163 15251522663 0020073 0 ustar 00 <?php global $wpdb; $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE 'mc4wp_mailchimp_list_%'"); includes/admin/migrations/3.0.0-widget-base-id.php 0000777 00000002160 15251522663 0015565 0 ustar 00 <?php defined('ABSPATH') or exit; $section_widgets = get_option('sidebars_widgets', []); $replaced = false; foreach ($section_widgets as $section => $widgets) { // WP has an "array_version" key that is not an array... if (! is_array($widgets)) { continue; } // loop through widget ID's foreach ($widgets as $key => $widget_id) { // does this widget ID start with "mc4wp_widget"? if (strpos($widget_id, 'mc4wp_widget') === 0) { // replace "mc4wp_widget" with "mc4wp_form_widget" $new_widget_id = str_replace('mc4wp_widget', 'mc4wp_form_widget', $widget_id); $section_widgets[ $section ][ $key ] = $new_widget_id; $replaced = true; } } } // update option if we made changes if ($replaced) { update_option('sidebars_widgets', $section_widgets); } // update widget options $options = get_option('widget_mc4wp_widget', false); if ($options) { update_option('widget_mc4wp_form_widget', $options); // delete old option delete_option('widget_mc4wp_widget'); } includes/admin/migrations/3.0.0-general-options.php 0000777 00000000552 15251522663 0016111 0 ustar 00 <?php defined('ABSPATH') or exit; // transfer option $options = (array) get_option('mc4wp_lite', []); // merge options, with Pro options taking precedence $pro_options = (array) get_option('mc4wp', []); $options = array_merge($options, $pro_options); // update options update_option('mc4wp', $options); // delete old option delete_option('mc4wp_lite'); includes/admin/migrations/3.0.0-styles-builder.php 0000777 00000001735 15251522663 0015756 0 ustar 00 <?php defined('ABSPATH') or exit; // move stylebuilders file to bundle $file = (string) get_option('mc4wp_custom_css_file', ''); if (empty($file)) { return; } $uploads = wp_upload_dir(); // figure out absolute file path $prefix = str_replace('http:', '', $uploads['baseurl']); $relative_path = str_replace($prefix, '', $file); // get part before ? if (strpos($relative_path, '?') !== false) { $parts = explode('?', $relative_path); $relative_path = array_shift($parts); } // This is the absolute path to the file, he he.. $file = $uploads['basedir'] . $relative_path; if (file_exists($file)) { // create directory, if necessary $dir = $uploads['basedir'] . '/mc4wp-stylesheets'; if (! file_exists($dir)) { @mkdir($dir, 0755); } @chmod($dir, 0755); // Move file to new location $new_file = $dir . '/bundle.css'; $success = rename($file, $new_file); } // remove old option delete_option('mc4wp_custom_css_file'); includes/admin/migrations/3.0.0-form-3-messages.php 0000777 00000001647 15251522663 0015721 0 ustar 00 <?php defined('ABSPATH') or exit; // find all form posts $posts = get_posts( [ 'post_type' => 'mc4wp-form', 'post_status' => 'publish', 'numberposts' => -1, ] ); // set form message texts $message_keys = [ 'text_subscribed', 'text_error', 'text_invalid_email', 'text_already_subscribed', 'text_required_field_missing', 'text_unsubscribed', 'text_not_subscribed', ]; foreach ($posts as $post) { $settings = get_post_meta($post->ID, '_mc4wp_settings', true); foreach ($message_keys as $key) { if (empty($settings[ $key ])) { continue; } $message = $settings[ $key ]; // move message setting over to post meta update_post_meta($post->ID, $key, $message); unset($settings[ $key ]); } // update post meta with unset message keys update_post_meta($post->ID, '_mc4wp_settings', $settings); } includes/admin/migrations/4.0.0-groupings-to-interests.php 0000777 00000005133 15251522663 0017457 0 ustar 00 <?php defined('ABSPATH') or exit; /** * @ignore * @return object */ function _mc4wp_400_find_grouping_for_interest_category($groupings, $interest_category) { foreach ($groupings as $grouping) { // cast to stdClass because of missing class $grouping = (object) (array) $grouping; if ($grouping->name === $interest_category->title) { return $grouping; } } return null; } /** * @ignore * @return object */ function _mc4wp_400_find_group_for_interest($groups, $interest) { foreach ($groups as $group_id => $group_name) { if ($group_name === $interest->name) { return (object) [ 'name' => $group_name, 'id' => $group_id, ]; } } return null; } // in case the migration is _very_ late to the party if (! class_exists('MC4WP_API_V3')) { return; } $options = get_option('mc4wp', []); if (empty($options['api_key'])) { return; } // get current state from transient $lists = get_transient('mc4wp_mailchimp_lists_fallback'); if (empty($lists)) { return; } @set_time_limit(600); $api_v3 = new MC4WP_API_V3($options['api_key']); $map = []; foreach ($lists as $list) { // cast to stdClass because of missing classes $list = (object) (array) $list; // no groupings? easy! if (empty($list->groupings)) { continue; } // fetch (new) interest categories for this list try { $interest_categories = $api_v3->get_list_interest_categories($list->id); } catch (MC4WP_API_Exception $e) { continue; } foreach ($interest_categories as $interest_category) { // compare interest title with grouping name, if it matches, get new id. $grouping = _mc4wp_400_find_grouping_for_interest_category($list->groupings, $interest_category); if (! $grouping) { continue; } $groups = []; try { $interests = $api_v3->get_list_interest_category_interests($list->id, $interest_category->id); } catch (MC4WP_API_Exception $e) { continue; } foreach ($interests as $interest) { $group = _mc4wp_400_find_group_for_interest($grouping->groups, $interest); if ($group) { $groups[ $group->id ] = $interest->id; $groups[ $group->name ] = $interest->id; } } $map[ (string) $grouping->id ] = [ 'id' => $interest_category->id, 'groups' => $groups, ]; } } if (! empty($map)) { update_option('mc4wp_groupings_map', $map); } includes/admin/migrations/3.1.6-woocommerce-position-prefix.php 0000777 00000000507 15251522663 0020466 0 ustar 00 <?php defined('ABSPATH') or exit; $options = get_option('mc4wp_integrations', []); if (! empty($options['woocommerce']) && ! empty($options['woocommerce']['position'])) { $options['woocommerce']['position'] = sprintf('checkout_%s', $options['woocommerce']['position']); } update_option('mc4wp_integrations', $options); includes/admin/migrations/4.1.2-flush-list-cache.php 0000777 00000000500 15251522663 0016133 0 ustar 00 <?php defined('ABSPATH') or exit; if (function_exists('mc4wp_refresh_mailchimp_lists')) { mc4wp_refresh_mailchimp_lists(); } delete_transient('mc4wp_mailchimp_lists_v3'); delete_option('mc4wp_mailchimp_lists_v3_fallback'); wp_schedule_event(strtotime('tomorrow 3 am'), 'daily', 'mc4wp_refresh_mailchimp_lists'); includes/admin/migrations/3.0.0-integration-options.php 0000777 00000003054 15251522663 0017017 0 ustar 00 <?php defined('ABSPATH') or exit; $old_options = get_option('mc4wp_lite_checkbox', []); $pro_options = get_option('mc4wp_checkbox', []); if (! empty($pro_options)) { $old_options = array_merge($old_options, $pro_options); } // do we have to do something? if (empty($old_options)) { return; } // find activated integrations (show_at_xxx options) $new_options = []; $map = [ 'comment_form' => 'wp-comment-form', 'registration_form' => 'wp-registration-form', 'buddypress_form' => 'buddypress', 'bbpres_forms' => 'bbpress', 'woocommerce_checkout' => 'woocommerce', 'edd_checkout' => 'easy-digital-downloads', ]; $option_keys = [ 'label', 'precheck', 'css', 'lists', 'double_optin', 'update_existing', 'replace_interests', 'send_welcome', ]; foreach ($map as $old_integration_slug => $new_integration_slug) { // check if integration is enabled using its old slug $show_key = sprintf('show_at_%s', $old_integration_slug); if (empty($old_options[ $show_key ])) { continue; } $options = [ 'enabled' => 1, ]; foreach ($option_keys as $option_key) { if (isset($old_options[ $option_key ])) { $options[ $option_key ] = $old_options[ $option_key ]; } } // add to new options $new_options[ $new_integration_slug ] = $options; } // save new settings update_option('mc4wp_integrations', $new_options); // delete old options delete_option('mc4wp_lite_checkbox'); delete_option('mc4wp_checkbox'); includes/admin/migrations/4.8.2-move-debug-log-to-subdirectory.php 0000777 00000000755 15251522663 0020770 0 ustar 00 <?php defined('ABSPATH') or exit; // get old filename $upload_dir = wp_upload_dir(null, false); $old_filename = trailingslashit($upload_dir['basedir']) . 'mc4wp-debug-log.php'; // if old file exists, move it to new location if (is_file($old_filename)) { $new_filename = $upload_dir['basedir'] . '/mailchimp-for-wp/debug-log.php'; $dir = dirname($new_filename); if (! is_dir($dir)) { mkdir($dir, 0755, true); } rename($old_filename, $new_filename); } includes/admin/migrations/4.1.3-reschedule-event.php 0000777 00000000410 15251522663 0016243 0 ustar 00 <?php defined('ABSPATH') or exit; wp_clear_scheduled_hook('mc4wp_refresh_mailchimp_lists'); $time_string = sprintf('tomorrow %d:%d%d am', rand(1, 6), rand(0, 5), rand(0, 9)); wp_schedule_event(strtotime($time_string), 'daily', 'mc4wp_refresh_mailchimp_lists'); includes/admin/class-admin-tools.php 0000777 00000003114 15251522663 0013521 0 ustar 00 <?php class MC4WP_Admin_Tools { /** * @return string */ public function get_plugin_page() { if (empty($_GET['page'])) { return ''; } $prefix = 'mailchimp-for-wp'; $page = ltrim(substr($_GET['page'], strlen($prefix)), '-'); return $page; } /** * @param string $page * * @return bool */ public function on_plugin_page($page = null) { // any settings page if (is_null($page)) { return isset($_GET['page']) && strpos($_GET['page'], 'mailchimp-for-wp') === 0; } // specific page return $this->get_plugin_page() === $page; } /** * Does the logged-in user have the required capability? * * @return bool */ public function is_user_authorized() { return current_user_can($this->get_required_capability()); } /** * Get required capability to access settings page and view dashboard widgets. * * @return string */ public function get_required_capability() { $capability = 'manage_options'; /** * Filters the required user capability to access the Mailchimp for WordPress' settings pages, view the dashboard widgets. * * Defaults to `manage_options` * * @since 3.0 * @param string $capability * @see https://codex.wordpress.org/Roles_and_Capabilities */ $capability = (string) apply_filters('mc4wp_admin_required_capability', $capability); return $capability; } } includes/admin/class-admin-messages.php 0000777 00000003045 15251522663 0014173 0 ustar 00 <?php /** * Class MC4WP_Admin_Messages * * @ignore * @since 3.0 */ class MC4WP_Admin_Messages { /** * @var array */ protected $bag; /** * @var bool */ protected $dirty = false; /** * Add hooks */ public function add_hooks() { add_action('admin_notices', [ $this, 'show' ]); register_shutdown_function([ $this, 'save' ]); } private function load() { if (is_null($this->bag)) { $this->bag = get_option('mc4wp_flash_messages', []); } } // empty flash bag private function reset() { $this->bag = []; $this->dirty = true; } /** * Flash a message (shows on next pageload) * * @param $message * @param string $type */ public function flash($message, $type = 'success') { $this->load(); $this->bag[] = [ 'text' => $message, 'type' => $type, ]; $this->dirty = true; } /** * Show queued flash messages */ public function show() { $this->load(); foreach ($this->bag as $message) { echo sprintf('<div class="notice notice-%s is-dismissible"><p>%s</p></div>', $message['type'], $message['text']); } $this->reset(); } /** * Save queued messages * * @hooked `shutdown` */ public function save() { if ($this->dirty) { update_option('mc4wp_flash_messages', $this->bag, false); } } } includes/admin/class-review-notice.php 0000777 00000005722 15251522663 0014062 0 ustar 00 <?php /** * Class MC4WP_Admin_Review_Notice * * @ignore */ class MC4WP_Admin_Review_Notice { /** * @var MC4WP_Admin_Tools */ protected $tools; /** * @var string */ protected $meta_key_dismissed = '_mc4wp_review_notice_dismissed'; /** * MC4WP_Admin_Review_Notice constructor. * * @param MC4WP_Admin_Tools $tools */ public function __construct(MC4WP_Admin_Tools $tools) { $this->tools = $tools; } /** * Add action & filter hooks. */ public function add_hooks() { add_action('admin_notices', [ $this, 'show' ]); add_action('mc4wp_admin_dismiss_review_notice', [ $this, 'dismiss' ]); } /** * Set flag in user meta so notice won't be shown. */ public function dismiss() { $user = wp_get_current_user(); update_user_meta($user->ID, $this->meta_key_dismissed, 1); } /** * @return bool */ public function show() { // only show on Mailchimp for WordPress' pages. if (! $this->tools->on_plugin_page()) { return false; } // only show if 2 weeks have passed since first use. $two_weeks_in_seconds = ( 60 * 60 * 24 * 14 ); if ($this->time_since_first_use() <= $two_weeks_in_seconds) { return false; } // only show if user did not dismiss before $user = wp_get_current_user(); if (get_user_meta($user->ID, $this->meta_key_dismissed, true)) { return false; } echo '<div class="notice notice-info mc4wp-is-dismissible" id="mc4wp-review-notice">'; echo '<p>'; echo esc_html__('You\'ve been using Mailchimp for WordPress for some time now; we hope you love it!', 'mailchimp-for-wp'), ' <br />'; echo sprintf(wp_kses(__('If you do, please <a href="%s">leave us a 5★ rating on WordPress.org</a>. It would be of great help to us.', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ] ]), 'https://wordpress.org/support/view/plugin-reviews/mailchimp-for-wp?rate=5#new-post'); echo '</p>'; echo '<form method="POST" id="mc4wp-dismiss-review-form"><button type="submit" class="notice-dismiss"><span class="screen-reader-text">', esc_html__('Dismiss this notice.', 'mailchimp-for-wp'), '</span></button><input type="hidden" name="_mc4wp_action" value="dismiss_review_notice" />', wp_nonce_field('_mc4wp_action', '_wpnonce', true, false), '</form>'; echo '</div>'; return true; } /** * @return int */ private function time_since_first_use() { $options = get_option('mc4wp', []); if (! is_array($options)) { $options = []; } // option was never added before, do it now. if (empty($options['first_activated_on'])) { $options['first_activated_on'] = time(); update_option('mc4wp', $options); } return time() - $options['first_activated_on']; } } includes/admin/class-admin-ajax.php 0000777 00000003367 15251522663 0013316 0 ustar 00 <?php class MC4WP_Admin_Ajax { /** * @var MC4WP_Admin_Tools */ protected $tools; /** * MC4WP_Admin_Ajax constructor. * * @param MC4WP_Admin_Tools $tools */ public function __construct(MC4WP_Admin_Tools $tools) { $this->tools = $tools; } /** * Hook AJAX actions */ public function add_hooks() { add_action('wp_ajax_mc4wp_get_list_details', [ $this, 'get_list_details' ]); } /** * Retrieve details (merge fields and interest categories) for one or multiple lists in Mailchimp * @throws MC4WP_API_Exception */ public function get_list_details() { if (! $this->tools->is_user_authorized()) { wp_send_json_error(); return; } $list_ids = (array) explode(',', $_GET['ids']); $data = []; $mailchimp = new MC4WP_MailChimp(); foreach ($list_ids as $list_id) { $data[] = (object) [ 'id' => $list_id, 'merge_fields' => $mailchimp->get_list_merge_fields($list_id), 'interest_categories' => $mailchimp->get_list_interest_categories($list_id), 'marketing_permissions' => $mailchimp->get_list_marketing_permissions($list_id), ]; } if (isset($_GET['format']) && $_GET['format'] === 'html') { $merge_fields = $data[0]->merge_fields; $interest_categories = $data[0]->interest_categories; $marketing_permissions = $data[0]->marketing_permissions; require MC4WP_PLUGIN_DIR . '/includes/views/parts/lists-overview-details.php'; } else { wp_send_json($data); } exit; } } includes/admin/class-admin.php 0000777 00000041057 15251522663 0012373 0 ustar 00 <?php /** * Class MC4WP_Admin * * @ignore * @access private */ class MC4WP_Admin { /** * @var string The relative path to the main plugin file from the plugins dir */ protected $plugin_file; /** * @var MC4WP_Admin_Messages */ protected $messages; /** * @var MC4WP_Admin_Ads */ protected $ads; /** * @var MC4WP_Admin_Tools */ protected $tools; /** * @var MC4WP_Admin_Review_Notice */ protected $review_notice; /** * Constructor * * @param MC4WP_Admin_Tools $tools * @param MC4WP_Admin_Messages $messages */ public function __construct(MC4WP_Admin_Tools $tools, MC4WP_Admin_Messages $messages) { $this->tools = $tools; $this->messages = $messages; $this->plugin_file = plugin_basename(MC4WP_PLUGIN_FILE); $this->ads = new MC4WP_Admin_Ads(); $this->review_notice = new MC4WP_Admin_Review_Notice($tools); } /** * Registers all hooks */ public function add_hooks() { // Actions used globally throughout WP Admin add_action('admin_menu', [ $this, 'build_menu' ]); add_action('admin_init', [ $this, 'initialize' ]); add_action('current_screen', [ $this, 'customize_admin_texts' ]); add_action('wp_dashboard_setup', [ $this, 'register_dashboard_widgets' ]); add_action('mc4wp_admin_empty_lists_cache', [ $this, 'renew_lists_cache' ]); add_action('mc4wp_admin_empty_debug_log', [ $this, 'empty_debug_log' ]); add_action('admin_notices', [ $this, 'show_api_key_notice' ]); add_action('mc4wp_admin_dismiss_api_key_notice', [ $this, 'dismiss_api_key_notice' ]); add_action('admin_enqueue_scripts', [ $this, 'enqueue_assets' ]); $this->ads->add_hooks(); $this->messages->add_hooks(); $this->review_notice->add_hooks(); } /** * Initializes various stuff used in WP Admin * * - Registers settings */ public function initialize() { // register settings register_setting('mc4wp_settings', 'mc4wp', [ $this, 'save_general_settings' ]); // Load upgrader $this->init_upgrade_routines(); // listen for custom actions $this->listen_for_actions(); } /** * Listen for `_mc4wp_action` requests */ public function listen_for_actions() { // do nothing if _mc4wp_action was not in the request parameters if (! isset($_REQUEST['_mc4wp_action'])) { return; } // check if user is authorized if (! $this->tools->is_user_authorized()) { return; } // verify nonce if (! isset($_REQUEST['_wpnonce']) || false === wp_verify_nonce($_REQUEST['_wpnonce'], '_mc4wp_action')) { wp_nonce_ays('_mc4wp_action'); exit; } $action = (string) $_REQUEST['_mc4wp_action']; /** * Allows you to hook into requests containing `_mc4wp_action` => action name. * * The dynamic portion of the hook name, `$action`, refers to the action name. * * By the time this hook is fired, the user is already authorized. After processing all the registered hooks, * the request is redirected back to the referring URL. * * @since 3.0 */ do_action('mc4wp_admin_' . $action); // redirect back to where we came from (to prevent double submit) if (isset($_POST['_redirect_to'])) { $redirect_url = $_POST['_redirect_to']; } elseif (isset($_GET['_redirect_to'])) { $redirect_url = $_GET['_redirect_to']; } else { $redirect_url = remove_query_arg('_mc4wp_action'); } wp_safe_redirect($redirect_url); exit; } /** * Register dashboard widgets */ public function register_dashboard_widgets() { if (! $this->tools->is_user_authorized()) { return; } /** * Setup dashboard widget, users are authorized by now. * * Use this hook to register your own dashboard widgets for users with the required capability. * * @since 3.0 * @ignore */ do_action('mc4wp_dashboard_setup'); } /** * Upgrade routine */ private function init_upgrade_routines() { // upgrade routine for upgrade routine.... $previous_version = get_option('mc4wp_lite_version', 0); if ($previous_version) { delete_option('mc4wp_lite_version'); update_option('mc4wp_version', $previous_version); } $previous_version = get_option('mc4wp_version', 0); // Ran upgrade routines before? if (empty($previous_version)) { update_option('mc4wp_version', MC4WP_VERSION); // if we have at least one form, we're going to run upgrade routine for v3 => v4 anyway. $posts = get_posts( [ 'post_type' => 'mc4wp-form', 'posts_per_page' => 1, ] ); if (empty($posts)) { return; } $previous_version = '3.9'; } // This means we're good! if (version_compare($previous_version, MC4WP_VERSION, '>=')) { return; } define('MC4WP_DOING_UPGRADE', true); $upgrade_routines = new MC4WP_Upgrade_Routines($previous_version, MC4WP_VERSION, __DIR__ . '/migrations'); $upgrade_routines->run(); update_option('mc4wp_version', MC4WP_VERSION); } /** * Renew Mailchimp lists cache */ public function renew_lists_cache() { // try getting new lists to fill cache again $mailchimp = new MC4WP_MailChimp(); $lists = $mailchimp->refresh_lists(); if (! empty($lists)) { $this->messages->flash(esc_html__('Success! The cached configuration for your Mailchimp lists has been renewed.', 'mailchimp-for-wp')); } } /** * Customize texts throughout WP Admin */ public function customize_admin_texts() { $texts = new MC4WP_Admin_Texts($this->plugin_file); $texts->add_hooks(); } /** * Validates the General settings * @param array $settings * @return array */ public function save_general_settings(array $settings) { $current = mc4wp_get_options(); // merge with current settings to allow passing partial arrays to this method $settings = array_merge($current, $settings); // Make sure not to use obfuscated key if (strpos($settings['api_key'], '*') !== false) { $settings['api_key'] = $current['api_key']; } // Sanitize API key $settings['api_key'] = sanitize_text_field($settings['api_key']); // if API key changed, empty Mailchimp cache if ($settings['api_key'] !== $current['api_key']) { delete_transient('mc4wp_mailchimp_lists'); } /** * Runs right before general settings are saved. * * @param array $settings The updated settings array * @param array $current The old settings array */ do_action('mc4wp_save_settings', $settings, $current); return $settings; } /** * Load scripts and stylesheet on Mailchimp for WP Admin pages */ public function enqueue_assets() { if (! $this->tools->on_plugin_page()) { return; } $opts = mc4wp_get_options(); $page = $this->tools->get_plugin_page(); $mailchimp = new MC4WP_MailChimp(); // css wp_register_style('mc4wp-admin', mc4wp_plugin_url('assets/css/admin.css'), [], MC4WP_VERSION); wp_enqueue_style('mc4wp-admin'); // js wp_register_script('mc4wp-admin', mc4wp_plugin_url('assets/js/admin.js'), [], MC4WP_VERSION, true); wp_enqueue_script('mc4wp-admin'); $connected = ! empty($opts['api_key']); $mailchimp_lists = $connected ? $mailchimp->get_lists() : []; wp_localize_script( 'mc4wp-admin', 'mc4wp_vars', [ 'ajaxurl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('mc4wp-ajax'), 'mailchimp' => [ 'api_connected' => $connected, 'lists' => $mailchimp_lists, ], 'countries' => MC4WP_Tools::get_countries(), 'i18n' => [ 'invalid_api_key' => __('The given value does not look like a valid Mailchimp API key.', 'mailchimp-for-wp'), 'pro_only' => __('This is a premium feature. Please upgrade to Mailchimp for WordPress Premium to be able to use it.', 'mailchimp-for-wp'), ], ] ); /** * Hook to enqueue your own custom assets on the Mailchimp for WordPress setting pages. * * @since 3.0 * * @param string $suffix * @param string $page */ do_action('mc4wp_admin_enqueue_assets', '', $page); } /** * Register the setting pages and their menu items */ public function build_menu() { $required_cap = $this->tools->get_required_capability(); $menu_items = [ [ 'title' => esc_html__('Mailchimp API Settings', 'mailchimp-for-wp'), 'text' => 'Mailchimp', 'slug' => '', 'callback' => [ $this, 'show_generals_setting_page' ], 'position' => 0, ], [ 'title' => esc_html__('Other Settings', 'mailchimp-for-wp'), 'text' => esc_html__('Other', 'mailchimp-for-wp'), 'slug' => 'other', 'callback' => [ $this, 'show_other_setting_page' ], 'position' => 90, ], ]; /** * Filters the menu items to appear under the main menu item. * * To add your own item, add an associative array in the following format. * * $menu_items[] = array( * 'title' => 'Page title', * 'text' => 'Menu text', * 'slug' => 'Page slug', * 'callback' => 'my_page_function', * 'position' => 50 * ); * * @param array $menu_items * @since 3.0 */ $menu_items = (array) apply_filters('mc4wp_admin_menu_items', $menu_items); // add top menu item $icon = file_get_contents(MC4WP_PLUGIN_DIR . '/assets/img/icon.svg'); add_menu_page('Mailchimp for WP', 'MC4WP', $required_cap, 'mailchimp-for-wp', [ $this, 'show_generals_setting_page' ], 'data:image/svg+xml;base64,' . base64_encode($icon), '99.68491'); // sort submenu items by 'position' usort($menu_items, [ $this, 'sort_menu_items_by_position' ]); // add sub-menu items foreach ($menu_items as $item) { $this->add_menu_item($item); } } /** * @param array $item */ public function add_menu_item(array $item) { // generate menu slug $slug = 'mailchimp-for-wp'; if (! empty($item['slug'])) { $slug .= '-' . $item['slug']; } // provide some defaults $parent_slug = ! empty($item['parent_slug']) ? $item['parent_slug'] : 'mailchimp-for-wp'; $capability = ! empty($item['capability']) ? $item['capability'] : $this->tools->get_required_capability(); // register page $hook = add_submenu_page($parent_slug, $item['title'] . ' - Mailchimp for WordPress', $item['text'], $capability, $slug, $item['callback']); // register callback for loading this page, if given if (array_key_exists('load_callback', $item)) { add_action('load-' . $hook, $item['load_callback']); } } /** * Show the API Settings page */ public function show_generals_setting_page() { $opts = mc4wp_get_options(); $api_key = mc4wp_get_api_key(); $lists = []; $connected = ! empty($api_key); if ($connected) { try { $connected = $this->get_api()->is_connected(); $mailchimp = new MC4WP_MailChimp(); $lists = $mailchimp->get_lists(); } catch (MC4WP_API_Connection_Exception $e) { $message = sprintf('<strong>%s</strong> %s %s ', esc_html__('Error connecting to Mailchimp:', 'mailchimp-for-wp'), $e->getCode(), $e->getMessage()); if (is_object($e->response_data) && ! empty($e->response_data->ref_no)) { $message .= '<br />' . sprintf(esc_html__('Looks like your server is blocked by Mailchimp\'s firewall. Please contact Mailchimp support and include the following reference number: %s', 'mailchimp-for-wp'), $e->response_data->ref_no); } $message .= '<br /><br />' . sprintf('<a href="%s">' . esc_html__('Here\'s some info on solving common connectivity issues.', 'mailchimp-for-wp') . '</a>', 'https://www.mc4wp.com/kb/solving-connectivity-issues/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=settings-notice'); $this->messages->flash($message, 'error'); $connected = false; } catch (MC4WP_API_Exception $e) { $message = sprintf('<strong>%s</strong><br /> %s', esc_html__('Mailchimp returned the following error:', 'mailchimp-for-wp'), nl2br((string) $e)); $this->messages->flash($message, 'error'); $connected = false; } } $obfuscated_api_key = mc4wp_obfuscate_string($api_key); $is_procaptcha_configured = MC4WP_Procaptcha::get_instance()->is_enabled(); require MC4WP_PLUGIN_DIR . '/includes/views/general-settings.php'; } /** * Show the Other Settings page */ public function show_other_setting_page() { $opts = mc4wp_get_options(); $log = $this->get_log(); $log_reader = new MC4WP_Debug_Log_Reader($log->file); require MC4WP_PLUGIN_DIR . '/includes/views/other-settings.php'; } /** * @param $a * @param $b * * @return int */ public function sort_menu_items_by_position($a, $b) { $pos_a = isset($a['position']) ? $a['position'] : 80; $pos_b = isset($b['position']) ? $b['position'] : 90; return $pos_a < $pos_b ? -1 : 1; } /** * Empties the log file */ public function empty_debug_log() { $log = $this->get_log(); file_put_contents($log->file, ''); $this->messages->flash(esc_html__('Log successfully emptied.', 'mailchimp-for-wp')); } /** * Shows a notice when API key is not set. */ public function show_api_key_notice() { // don't show if on settings page already if ($this->tools->on_plugin_page('')) { return; } // only show to user with proper permissions if (! $this->tools->is_user_authorized()) { return; } // don't show if dismissed if (get_transient('mc4wp_api_key_notice_dismissed')) { return; } // don't show if api key is set already $api_key = mc4wp_get_api_key(); if (! empty($api_key)) { return; } echo '<div class="notice notice-warning mc4wp-is-dismissible">'; echo '<p>', sprintf(wp_kses(__('To get started with Mailchimp for WordPress, please <a href="%s">enter your Mailchimp API key on the settings page of the plugin</a>.', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ] ]), admin_url('admin.php?page=mailchimp-for-wp')), '</p>'; echo '<form method="post">'; wp_nonce_field('_mc4wp_action', '_wpnonce'); echo '<input type="hidden" name="_mc4wp_action" value="dismiss_api_key_notice" />'; echo '<button type="submit" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span></button>'; echo '</form>'; echo '</div>'; } /** * Dismisses the API key notice for 1 week */ public function dismiss_api_key_notice() { set_transient('mc4wp_api_key_notice_dismissed', 1, 3600 * 24 * 7); } /** * @return MC4WP_Debug_Log */ protected function get_log() { return mc4wp('log'); } /** * @return MC4WP_API_V3 */ protected function get_api() { return mc4wp('api'); } } includes/admin/class-ads.php 0000777 00000016061 15251522663 0012047 0 ustar 00 <?php /** * Class MC4WP_Admin_Ads * * @ignore * @access private */ class MC4WP_Admin_Ads { /** * @return bool Adds hooks */ public function add_hooks() { // don't hook if Premium is activated if (defined('MC4WP_PREMIUM_VERSION')) { return false; } add_filter('mc4wp_admin_plugin_meta_links', [ $this, 'plugin_meta_links' ]); add_action('mc4wp_admin_form_after_behaviour_settings_rows', [ $this, 'after_form_settings_rows' ]); add_action('mc4wp_admin_form_after_appearance_settings_rows', [ $this, 'after_form_appearance_settings_rows' ]); add_action('mc4wp_admin_sidebar', [ $this, 'admin_sidebar' ]); add_action('mc4wp_admin_footer', [ $this, 'admin_footer' ]); add_action('mc4wp_admin_other_settings', [ $this, 'ecommerce' ], 90); add_filter('mc4wp_admin_menu_items', [ $this, 'add_menu_item' ]); add_action('mc4wp_admin_after_woocommerce_integration_settings', [ $this, 'ecommerce' ]); return true; } public function add_menu_item($items) { $items['extensions'] = [ 'title' => __('Add-ons', 'mailchimp-for-wp'), 'text' => __('Add-ons', 'mailchimp-for-wp'), 'slug' => 'extensions', 'callback' => [ $this, 'show_extensions_page' ], 'position' => 100, ]; return $items; } /** * Add text row to "Form > Appearance" tab. */ public function after_form_appearance_settings_rows() { echo '<tr>'; echo '<td colspan="2">'; echo '<p class="description">'; echo sprintf(__('Want to customize the style of your form? <a href="%s">Try our Styles Builder</a> & edit the look of your forms with just a few clicks.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=form-settings-link'); echo '</p>'; echo '</td>'; echo '</tr>'; } /** * Add text row to "Form > Settings" tab. */ public function after_form_settings_rows() { echo '<tr>'; echo '<td colspan="2">'; echo '<p class="description">'; if (rand(1, 2) === 1) { echo sprintf(__('Be notified whenever someone subscribes? <a href="%s">Mailchimp for WordPress Premium</a> allows you to set up email notifications for your forms.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=footer-link'); } else { echo sprintf(__('Increased conversions? <a href="%s">Mailchimp for WordPress Premium</a> submits forms without reloading the entire page, resulting in a much better experience for your visitors.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=form-settings-link'); } echo '</p>'; echo '</td>'; echo '</tr>'; } /** * @param array $links * * @return array */ public function plugin_meta_links($links) { $links[] = '<a href="https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=plugins-upgrade-link">' . __('Upgrade to Premium', 'mailchimp-for-wp') . '</a>'; return $links; } /** * Add several texts to admin footer. */ public function admin_footer() { if (isset($_GET['view']) && $_GET['view'] === 'edit-form') { // WPML & Polylang specific message if (defined('ICL_LANGUAGE_CODE')) { echo '<p class="description">' . sprintf(__('Do you want translated forms for all of your languages? <a href="%s">Try Mailchimp for WordPress Premium</a>, which does just that plus more.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=footer-link') . '</p>'; return; } // General "edit form" message echo '<p class="description">' . sprintf(__('Do you want to create more than one form? Our Premium add-on does just that! <a href="%s">Have a look at all Premium benefits</a>.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=footer-link') . '</p>'; return; } // General message echo '<p class="description">' . sprintf(__('Are you enjoying this plugin? The Premium add-on unlocks several powerful features. <a href="%s">Find out about all benefits now</a>.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=footer-link') . '</p>'; } /** * Add email opt-in form to sidebar */ public function admin_sidebar() { echo '<style>.mc4wp-premium-box { background: #fff8c5; border: 1px solid #d4a72c66; padding: 1em; }</style>'; echo '<div class="mc4wp-box">'; echo '<div class="mc4wp-premium-box">'; echo '<h3>Mailchimp for WordPress Premium</h3>'; echo '<p>'; echo 'You are currently using the free version of Mailchimp for WordPress. '; echo '</p>'; echo '<p>'; echo 'There is a Premium version of this plugin that adds several powerful features. Like multiple and improved sign-up forms, an easier way to visually enhance those forms, advanced e-commerce integration and keeping track of all sign-up attempts in your local WordPress database.'; echo '</p>'; echo '<p>You can have all those benefits for a small yearly fee. <a href="https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=upgrade-box">Take a look at Mailchimp for WordPress Premium here</a>.</p>'; echo '</div>'; echo '</div>'; } /** * Show notice about E-Commerce integration in Premium. */ public function ecommerce() { // detect whether WooCommerce is installed & activated. if (! class_exists('WooCommerce')) { return; } echo '<div class="mc4wp-margin-m">'; echo '<h3>Advanced WooCommerce integration for Mailchimp</h3>'; echo '<p>'; echo __('Do you want to track all WooCommerce orders in Mailchimp so you can send emails based on the purchase activity of your subscribers?', 'mailchimp-for-wp'); echo '</p>'; echo '<p>'; echo sprintf(__('<a href="%1$s">Upgrade to Mailchimp for WordPress Premium</a> or <a href="%2$s">read more about Mailchimp\'s E-Commerce features</a>.', 'mailchimp-for-wp') . '</p>', 'https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=other-settings-link', 'https://www.mc4wp.com/kb/what-is-ecommerce360/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=other-settings-link'); echo '</p>'; echo '</div>'; } public function show_extensions_page() { require MC4WP_PLUGIN_DIR . '/includes/views/extensions.php'; } } includes/default-actions.php 0000777 00000000162 15251522663 0012162 0 ustar 00 <?php defined('ABSPATH') or exit; add_action('mc4wp_refresh_mailchimp_lists', 'mc4wp_refresh_mailchimp_lists'); includes/functions.php 0000777 00000035553 15251522663 0011124 0 ustar 00 <?php /** * Get a service by its name * * _Example:_ * * $forms = mc4wp('forms'); * $api = mc4wp('api'); * * When no service parameter is given, the entire container will be returned. * * @ignore * @access private * * @param null|string $service (optional) * @return mixed * * @throws Exception when service is not found */ function mc4wp($service = null) { static $mc4wp = null; if (null === $mc4wp) { $mc4wp = new MC4WP_Container(); } if (null !== $service) { return $mc4wp->get($service); } return $mc4wp; } /** * Gets the Mailchimp for WP options from the database * Uses default values to prevent undefined index notices. * * @since 1.0 * @access public * @static array $options * @return array */ function mc4wp_get_options() { $defaults = require MC4WP_PLUGIN_DIR . '/config/default-settings.php'; $options = (array) get_option('mc4wp', []); $options = array_merge($defaults, $options); /** * Filters the Mailchimp for WordPress settings (general). * * @param array $options */ return apply_filters('mc4wp_settings', $options); } /** * @return array */ function mc4wp_get_settings() { return mc4wp_get_options(); } /** * @since 4.2.6 * @return string */ function mc4wp_get_api_key() { // try to get from constant if (defined('MC4WP_API_KEY') && constant('MC4WP_API_KEY') !== '') { return MC4WP_API_KEY; } // get from options $opts = mc4wp_get_options(); return $opts['api_key']; } /** * Gets the Mailchimp for WP API class (v3) and injects it with the API key * * @since 4.0 * @access public * * @return MC4WP_API_V3 */ function mc4wp_get_api_v3() { $api_key = mc4wp_get_api_key(); return new MC4WP_API_V3($api_key); } /** * Creates a new instance of the Debug Log * * @return MC4WP_Debug_Log */ function mc4wp_get_debug_log() { $opts = mc4wp_get_options(); // get default log file location $upload_dir = wp_upload_dir(null, false); $file = $upload_dir['basedir'] . '/mailchimp-for-wp/debug-log.php'; $default_file = $file; /** * Filters the log file to write to. * * @param string $file The log file location. Default: /wp-content/uploads/mailchimp-for-wp/mc4wp-debug.log */ $file = apply_filters('mc4wp_debug_log_file', $file); if ($file === $default_file) { $dir = dirname($file); if (! is_dir($dir)) { mkdir($dir, 0755, true); } if (! is_file($dir . '/.htaccess')) { $lines = [ '<IfModule !authz_core_module>', 'Order deny,allow', 'Deny from all', '</IfModule>', '<IfModule authz_core_module>', 'Require all denied', '</IfModule>', ]; file_put_contents($dir . '/.htaccess', join(PHP_EOL, $lines)); } if (! is_file($dir . '/index.html')) { file_put_contents($dir . '/index.html', ''); } } /** * Filters the minimum level to log messages. * * @see MC4WP_Debug_Log * * @param string|int $level The minimum level of messages which should be logged. */ $level = apply_filters('mc4wp_debug_log_level', $opts['debug_log_level']); return new MC4WP_Debug_Log($file, $level); } /** * Get URL to a file inside the plugin directory * * @since 4.8.3 * @param string $path * @return string */ function mc4wp_plugin_url($path) { static $base = null; if ($base === null) { $base = plugins_url('/', MC4WP_PLUGIN_FILE); } return $base . $path; } /** * Get current URL (full) * * @return string */ function mc4wp_get_request_url() { global $wp; // get requested url from global $wp object $site_request_uri = $wp->request; // fix for IIS servers using index.php in the URL if (false !== strpos($_SERVER['REQUEST_URI'], '/index.php/' . $site_request_uri)) { $site_request_uri = 'index.php/' . $site_request_uri; } // concatenate request url to home url $url = home_url($site_request_uri); $url = trailingslashit($url); return esc_url($url); } /** * Get current URL path. * * @return string */ function mc4wp_get_request_path() { return $_SERVER['REQUEST_URI']; } /** * Get IP address for client making current request * * @return string|null */ function mc4wp_get_request_ip_address() { if (isset($_SERVER['X-Forwarded-For'])) { $ip_address = $_SERVER['X-Forwarded-For']; } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip_address = $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif (isset($_SERVER['REMOTE_ADDR'])) { $ip_address = $_SERVER['REMOTE_ADDR']; } if (isset($ip_address)) { if (! is_array($ip_address)) { $ip_address = explode(',', $ip_address); } // use first IP in list $ip_address = trim($ip_address[0]); // if IP address is not valid, simply return null if (! filter_var($ip_address, FILTER_VALIDATE_IP)) { return null; } return $ip_address; } return null; } /** * Strips all HTML tags from all values in a mixed variable, then trims the result. * * @access public * @param mixed $value * * @return mixed */ function mc4wp_sanitize_deep($value) { if (is_scalar($value)) { // strip all HTML tags & whitespace $value = trim(strip_tags($value)); // convert & back to & $value = html_entity_decode($value, ENT_NOQUOTES); } elseif (is_array($value)) { $value = array_map('mc4wp_sanitize_deep', $value); } elseif (is_object($value)) { $vars = get_object_vars($value); foreach ($vars as $key => $data) { $value->{$key} = mc4wp_sanitize_deep($data); } } return $value; } /** * * @since 4.0 * @ignore * * @param array $data * @return array */ function _mc4wp_update_groupings_data($data = []) { // data still has old "GROUPINGS" key? if (empty($data['GROUPINGS'])) { return $data; } // prepare new key if (! isset($data['INTERESTS'])) { $data['INTERESTS'] = []; } $map = get_option('mc4wp_groupings_map', []); foreach ($data['GROUPINGS'] as $grouping_id => $groups) { // for compatibility with expanded grouping arrays $grouping_key = $grouping_id; if (is_array($groups) && isset($groups['id']) && isset($groups['groups'])) { $grouping_id = $groups['id']; $groups = $groups['groups']; } // do we have transfer data for this grouping id? if (! isset($map[ $grouping_id ])) { continue; } // if we get a string, explode on delimiter(s) if (is_string($groups)) { // for BC with 3.x: explode on comma's $groups = join('|', explode(',', $groups)); // explode on current delimiter $groups = explode('|', $groups); } // loop through groups and find interest ID $migrated = 0; foreach ($groups as $key => $group_name_or_id) { // do we know the new interest ID? if (empty($map[ $grouping_id ]['groups'][ $group_name_or_id ])) { continue; } $interest_id = $map[ $grouping_id ]['groups'][ $group_name_or_id ]; // add to interests data if (! in_array($interest_id, $data['INTERESTS'], false)) { ++$migrated; $data['INTERESTS'][] = $interest_id; } } // remove old grouping ID if we migrated all groups. if ($migrated === count($groups)) { unset($data['GROUPINGS'][ $grouping_key ]); } } // if everything went well, this is now empty & moved to new INTERESTS key. if (empty($data['GROUPINGS'])) { unset($data['GROUPINGS']); } // is this empty? just unset it then. if (empty($data['INTERESTS'])) { unset($data['INTERESTS']); } return $data; } /** * Guesses merge vars based on given data & current request. * * @since 3.0 * @access public * * @param array $data * * @return array */ function mc4wp_add_name_data($data) { // Guess first and last name if (! empty($data['NAME']) && empty($data['FNAME']) && empty($data['LNAME'])) { $data['NAME'] = trim($data['NAME']); $strpos = strpos($data['NAME'], ' '); if ($strpos !== false) { $data['FNAME'] = trim(substr($data['NAME'], 0, $strpos)); $data['LNAME'] = trim(substr($data['NAME'], $strpos)); } else { $data['FNAME'] = $data['NAME']; } } // Set name value if (empty($data['NAME']) && ! empty($data['FNAME']) && ! empty($data['LNAME'])) { $data['NAME'] = sprintf('%s %s', $data['FNAME'], $data['LNAME']); } return $data; } /** * Gets the "email type" for new subscribers. * * Possible return values are either "html" or "text" * * @access public * @since 3.0 * * @return string */ function mc4wp_get_email_type() { $email_type = 'html'; /** * Filters the email type preference for this new subscriber. * * @param string $email_type */ $email_type = (string) apply_filters('mc4wp_email_type', $email_type); return $email_type; } /** * * @ignore * @return bool */ function _mc4wp_use_sslverify() { // Disable for all transports other than CURL if (! function_exists('curl_version')) { return false; } $curl = curl_version(); // Disable if OpenSSL is not installed if (empty($curl['ssl_version'])) { return false; } // Disable if on WP 4.4, see https://core.trac.wordpress.org/ticket/34935 if ($GLOBALS['wp_version'] === '4.4') { return false; } return true; } /** * This will replace the first half of a string with "*" characters. * * @param string $string * @return string */ function mc4wp_obfuscate_string($string) { if (strlen($string) <= 2) { return $string; } $length = strlen($string); $keep = floor(strlen($string) / 3); $keep = min($keep, 4); return substr($string, 0, $keep) . str_repeat('*', $length - ($keep * 2)) . substr($string, -$keep); } /** * @internal * @ignore */ function _mc4wp_obfuscate_email_addresses_callback($m) { $one = $m[1] . str_repeat('*', strlen($m[2])); $two = $m[3] . str_repeat('*', strlen($m[4])); $three = $m[5]; return sprintf('%s@%s.%s', $one, $two, $three); } /** * Obfuscates email addresses in a string. * * @param $string String possibly containing email address * @return string */ function mc4wp_obfuscate_email_addresses($string) { return preg_replace_callback('/([\w\.]{1,4})([\w\.]*)\@(\w{1,2})(\w*)\.(\w+)/', '_mc4wp_obfuscate_email_addresses_callback', $string); } /** * Refreshes Mailchimp lists. This can take a while if the connected Mailchimp account has many lists. * * @return void */ function mc4wp_refresh_mailchimp_lists() { $mailchimp = new MC4WP_MailChimp(); $mailchimp->refresh_lists(); } /** * Get element from array, allows for dot notation eg: "foo.bar" * * @param array $array * @param string $key * @param mixed $default * @return mixed */ function mc4wp_array_get($array, $key, $default = null) { if (is_null($key)) { return $array; } if (isset($array[ $key ])) { return $array[ $key ]; } foreach (explode('.', $key) as $segment) { if (! is_array($array) || ! array_key_exists($segment, $array)) { return $default; } $array = $array[ $segment ]; } return $array; } /** * Filters string and strips out all HTML tags and attributes, except what's in our whitelist. * * @param string $string The string to apply KSES whitelist on * @return string * @since 4.8.8 */ function mc4wp_kses($string) { $always_allowed_attr = array_fill_keys( [ 'aria-describedby', 'aria-details', 'aria-label', 'aria-labelledby', 'aria-hidden', 'class', 'id', 'style', 'title', 'role', 'data-*', 'tabindex', ], true ); $input_allowed_attr = array_merge( $always_allowed_attr, array_fill_keys( [ 'type', 'required', 'placeholder', 'value', 'name', 'step', 'min', 'max', 'checked', 'width', 'autocomplete', 'autofocus', 'minlength', 'maxlength', 'size', 'pattern', 'disabled', 'readonly', ], true ) ); $allowed = [ 'p' => $always_allowed_attr, 'label' => array_merge($always_allowed_attr, [ 'for' => true ]), 'input' => $input_allowed_attr, 'button' => $input_allowed_attr, 'fieldset' => $always_allowed_attr, 'legend' => $always_allowed_attr, 'ul' => $always_allowed_attr, 'ol' => $always_allowed_attr, 'li' => $always_allowed_attr, 'select' => array_merge($input_allowed_attr, [ 'multiple' => true ]), 'option' => array_merge($input_allowed_attr, [ 'selected' => true ]), 'optgroup' => [ 'disabled' => true, 'label' => true, ], 'textarea' => array_merge( $input_allowed_attr, [ 'rows' => true, 'cols' => true, ] ), 'div' => $always_allowed_attr, 'strong' => $always_allowed_attr, 'b' => $always_allowed_attr, 'i' => $always_allowed_attr, 'br' => [], 'em' => $always_allowed_attr, 'span' => $always_allowed_attr, 'a' => array_merge($always_allowed_attr, [ 'href' => true ]), 'img' => array_merge( $always_allowed_attr, [ 'src' => true, 'alt' => true, 'width' => true, 'height' => true, 'srcset' => true, 'sizes' => true, 'referrerpolicy' => true, ] ), 'u' => $always_allowed_attr, ]; return wp_kses($string, $allowed); } /** * Helper function for safely deprecating a changed filter hook. * * @param string $old_hook * @param string $new_hook * * @return void */ function mc4wp_apply_deprecated_filters($old_hook, $new_hook) { add_filter($new_hook, function ($value, $a = null, $b = null, $c = null) use ($new_hook, $old_hook) { return apply_filters_deprecated($old_hook, [ $value, $a, $b, $c ], '4.9.0', $new_hook); }, 10, 3); } includes/deprecated-functions.php 0000777 00000000006 15251522663 0013203 0 ustar 00 <?php includes/class-mailchimp.php 0000777 00000041363 15251522663 0012156 0 ustar 00 <?php /** * Helper class for dealing with common API requests. */ class MC4WP_MailChimp { /** * @var string */ public $error_code = ''; /** * @var string */ public $error_message = ''; /** * * Sends a subscription request to the Mailchimp API * * @param string $list_id The list id to subscribe to * @param string $email_address The email address to subscribe * @param array $args * @param bool $update_existing Update information if this email is already on list? * @param bool $replace_interests Replace interest groupings, only if update_existing is true. * * @return object * @throws Exception */ public function list_subscribe($list_id, $email_address, array $args = [], $update_existing = false, $replace_interests = true) { $this->reset_error(); $default_args = [ 'status' => 'pending', 'email_address' => $email_address, ]; $existing_member_data = null; // setup default args $args = array_merge($default_args, $args); $api = $this->get_api(); // first, check if subscriber is already on the given list try { $existing_member_data = $api->get_list_member($list_id, $email_address); if ($existing_member_data->status === 'subscribed') { // if we're not supposed to update, bail. if (! $update_existing) { $this->error_code = 214; $this->error_message = 'That subscriber already exists.'; return null; } $args['status'] = 'subscribed'; // this key only exists if list actually has interests if (isset($existing_member_data->interests)) { $existing_interests = (array) $existing_member_data->interests; // if replace, assume all existing interests disabled if ($replace_interests) { $existing_interests = array_fill_keys(array_keys($existing_interests), false); } $args['interests'] = array_replace($existing_interests, $args['interests']); } } elseif ($args['status'] === 'pending' && $existing_member_data->status === 'pending') { // this ensures that a new double opt-in email is send out $api->update_list_member( $list_id, $email_address, [ 'status' => 'unsubscribed', ] ); } } catch (MC4WP_API_Resource_Not_Found_Exception $e) { // subscriber does not exist (not an issue in this case) } catch (MC4WP_API_Exception $e) { // other errors. $this->error_code = $e->getCode(); $this->error_message = $e; return null; } try { // Extract tags from args before subscriber creation/update $tags = []; if (isset($args['tags']) && is_array($args['tags'])) { $tags = $args['tags']; unset($args['tags']); } if ($existing_member_data) { $data = $api->update_list_member($list_id, $email_address, $args); $data->was_already_on_list = $existing_member_data->status === 'subscribed'; } else { $data = $api->add_new_list_member($list_id, $args); $data->was_already_on_list = false; } // update subscriber tags, if supplied $this->update_subscriber_tags($list_id, $email_address, $tags); } catch (MC4WP_API_Exception $e) { $this->error_code = $e->getCode(); $this->error_message = $e; return null; } return $data; } /** * Format tags to send to Mailchimp. * * @param $tags array new tags to add * @return array * @since 4.7.9 */ private function merge_and_format_member_tags($tags) { $formatted_tags = []; foreach ($tags as $tag) { if (is_string($tag)) { $formatted_tags[] = [ 'name' => $tag, 'status' => 'active' ]; } elseif (is_array($tag) && isset($tag['name'])) { $formatted_tags[] = [ 'name' => $tag['name'], 'status' => isset($tag['status']) ? $tag['status'] : 'active' ]; } } return $formatted_tags; } /** * Post the tags on a list member. * * @param $mailchimp_list_id string The list id to subscribe to * @param $email_address Email of the Mailchimp susbcriber * @param $tags array tags to set for the user (can include 'status' key) * @return bool * @throws Exception * @since 4.10.10 */ private function update_subscriber_tags($mailchimp_list_id, $email_address, array $tags) { // do nothing if no tags given if (count($tags) === 0) { return true; } $api = $this->get_api(); $data = [ 'tags' => $this->merge_and_format_member_tags($tags), ]; try { $api->update_list_member_tags($mailchimp_list_id, $email_address, $data); } catch (MC4WP_API_Exception $ex) { // fail silently return false; } return true; } /** * Changes the subscriber status to "unsubscribed" * * @param string $list_id * @param string $email_address * * @return boolean */ public function list_unsubscribe($list_id, $email_address) { $this->reset_error(); try { $this->get_api()->update_list_member($list_id, $email_address, [ 'status' => 'unsubscribed' ]); } catch (MC4WP_API_Resource_Not_Found_Exception $e) { // if email wasn't even on the list: great. return true; } catch (MC4WP_API_Exception $e) { $this->error_code = $e->getCode(); $this->error_message = $e; return false; } return true; } /** * Checks if an email address is on a given list with status "subscribed" * * @param string $list_id * @param string $email_address * * @return boolean * @throws Exception */ public function list_has_subscriber($list_id, $email_address) { try { $data = $this->get_api()->get_list_member($list_id, $email_address); } catch (MC4WP_API_Resource_Not_Found_Exception $e) { return false; } return ! empty($data->id) && $data->status === 'subscribed'; } /** * @param string $list_id * * @return array * @throws Exception */ public function get_list_merge_fields($list_id) { $transient_key = "mc4wp_list_{$list_id}_mf"; $cached = get_transient($transient_key); if (is_array($cached)) { return $cached; } $api = $this->get_api(); try { // fetch list merge fields $merge_fields = $api->get_list_merge_fields( $list_id, [ 'count' => 100, 'fields' => 'merge_fields.name,merge_fields.tag,merge_fields.type,merge_fields.required,merge_fields.default_value,merge_fields.options,merge_fields.public', ] ); } catch (MC4WP_API_Exception $e) { return []; } // add EMAIL field array_unshift( $merge_fields, (object) [ 'tag' => 'EMAIL', 'name' => __('Email address', 'mailchimp-for-wp'), 'required' => true, 'type' => 'email', 'options' => [], 'public' => true, ] ); set_transient($transient_key, $merge_fields, HOUR_IN_SECONDS * 24); return $merge_fields; } /** * @param string $list_id * * @return array * @throws Exception */ public function get_list_interest_categories($list_id) { $transient_key = "mc4wp_list_{$list_id}_ic"; $cached = get_transient($transient_key); if (is_array($cached)) { return $cached; } $api = $this->get_api(); try { // fetch list interest categories $interest_categories = $api->get_list_interest_categories( $list_id, [ 'count' => 100, 'fields' => 'categories.id,categories.title,categories.type', ] ); } catch (MC4WP_API_Exception $e) { return []; } foreach ($interest_categories as $interest_category) { $interest_category->interests = []; try { // fetch groups for this interest $interests_data = $api->get_list_interest_category_interests( $list_id, $interest_category->id, [ 'count' => 100, 'fields' => 'interests.id,interests.name', ] ); foreach ($interests_data as $interest_data) { $interest_category->interests[ (string) $interest_data->id ] = $interest_data->name; } } catch (MC4WP_API_Exception $e) { // ignore } } set_transient($transient_key, $interest_categories, HOUR_IN_SECONDS * 24); return $interest_categories; } /** * Gets marketing permissions from a Mailchimp list. * The list needs to have at least 1 member for this to work. * * @param string $list_id * * @return array * @throws Exception */ public function get_list_marketing_permissions($list_id) { $transient_key = "mc4wp_list_{$list_id}_mp"; $cached = get_transient($transient_key); if (is_array($cached)) { return $cached; } try { $api = $this->get_api(); $data = $api->get_list_members( $list_id, [ 'fields' => [ 'members.marketing_permissions' ], 'count' => 1, ] ); $marketing_permissions = []; if (count($data->members) > 0 && isset($data->members[0]->marketing_permissions)) { foreach ($data->members[0]->marketing_permissions as $mp) { $marketing_permissions[] = (object) [ 'marketing_permission_id' => $mp->marketing_permission_id, 'text' => $mp->text, ]; } } } catch (MC4WP_API_Exception $e) { return []; } set_transient($transient_key, $marketing_permissions, HOUR_IN_SECONDS * 24); return $marketing_permissions; } /** * Get Mailchimp lists, from cache or remote API. * * @param boolean $skip_cache Whether to force a result by hitting Mailchimp API * * @return array */ public function get_lists($skip_cache = false) { $cache_key = 'mc4wp_mailchimp_lists'; $cached = get_transient($cache_key); if (is_array($cached) && ! $skip_cache) { return $cached; } $lists = $this->fetch_lists(); /** * Filters the cache time for Mailchimp lists configuration, in seconds. Defaults to 24 hours. */ $cache_ttl = (int) apply_filters('mc4wp_lists_count_cache_time', HOUR_IN_SECONDS * 24); // make sure cache ttl is not lower than 60 seconds $cache_ttl = max(60, $cache_ttl); set_transient($cache_key, $lists, $cache_ttl); return $lists; } private function fetch_lists() { $client = $this->get_api()->get_client(); $lists_data = []; $offset = 0; $count = 10; $exceptions_skipped = 0; // increase total time limit to 3 minutes @set_time_limit(180); // increase HTTP timeout to 30s as MailChimp is super slow to calculate dynamic fields add_filter( 'mc4wp_http_request_args', function ($args) { $args['timeout'] = 30; return $args; } ); // collect all lists in separate HTTP requests do { try { $data = $client->get( '/lists', [ 'count' => $count, 'offset' => $offset, 'fields' => 'total_items,lists.id,lists.name,lists.web_id,lists.stats.member_count,lists.marketing_permissions', ] ); $lists_data = array_merge($lists_data, $data->lists); $offset += $count; } catch (MC4WP_API_Connection_Exception $e) { // ignore timeout errors as this is likely due to mailchimp being slow to calculate the lists.stats.member_count property // keep going so we can at least pull-in all other lists $offset += $count; ++$exceptions_skipped; // failsafe against infinite loop // bail after 5 skipped exceptions if ($exceptions_skipped >= 5) { break; } continue; } catch (MC4WP_API_Exception $e) { // break on other errors, like "API key missing"etc. break; } } while ($data->total_items >= $offset); // key by list ID $lists = []; foreach ($lists_data as $list_data) { $lists["$list_data->id"] = $list_data; } return $lists; } /** * @param string $list_id * * @return object|null */ public function get_list($list_id) { $lists = $this->get_lists(); return isset($lists["$list_id"]) ? $lists["$list_id"] : null; } /** * Fetch lists data from Mailchimp. */ public function refresh_lists() { $lists = $this->get_lists(true); foreach ($lists as $list_id => $list) { // delete cached merge fields delete_transient("mc4wp_list_{$list_id}_mf"); // delete cached interest categories delete_transient("mc4wp_list_{$list_id}_ic"); // delete cached marketing permissions delete_transient("mc4wp_list_{$list_id}_mp"); } return ! empty($lists); } /** * Returns number of subscribers on given lists. * * @param array|string $list_ids Array of list ID's, or single string. * * @return int Total # subscribers for given lists. */ public function get_subscriber_count($list_ids) { // make sure we're getting an array if (! is_array($list_ids)) { $list_ids = [ $list_ids ]; } // if we got an empty array, return 0 if (empty($list_ids)) { return 0; } $lists = $this->get_lists(); // start calculating subscribers count for all given list ID's combined $count = 0; foreach ($list_ids as $list_id) { if (! isset($lists["$list_id"])) { continue; } $list = $lists["$list_id"]; $count += $list->stats->member_count; } /** * Filters the total subscriber_count for the given List ID's. * * @param string $count * @param array $list_ids * * @since 2.0 */ return apply_filters('mc4wp_subscriber_count', $count, $list_ids); } /** * Resets error properties. */ public function reset_error() { $this->error_message = ''; $this->error_code = ''; } /** * @return bool */ public function has_error() { return ! empty($this->error_code); } /** * @return string */ public function get_error_message() { return $this->error_message; } /** * @return string */ public function get_error_code() { return $this->error_code; } /** * @return MC4WP_API_V3 * @throws Exception */ private function get_api() { return mc4wp('api'); } } includes/api/class-resource-not-found-exception.php 0000777 00000000230 15251522663 0016502 0 ustar 00 <?php class MC4WP_API_Resource_Not_Found_Exception extends MC4WP_API_Exception { // Thrown when a requested resource does not exist in Mailchimp } includes/api/class-connection-exception.php 0000777 00000000114 15251522663 0015104 0 ustar 00 <?php class MC4WP_API_Connection_Exception extends MC4WP_API_Exception { } includes/api/class-exception.php 0000777 00000007230 15251522663 0012755 0 ustar 00 <?php /** * Class MC4WP_API_Exception * * @property string $title * @property string $detail * @property array $errors */ class MC4WP_API_Exception extends Exception { /** * @var object */ public $response = []; /** * @var object */ public $request = []; /** * @var array */ public $response_data = []; /** * MC4WP_API_Exception constructor. * * @param string $message * @param int $code * @param array $request * @param array $response * @param object $data */ public function __construct($message, $code, $request = null, $response = null, $data = null) { parent::__construct($message, $code); $this->request = $request; $this->response = $response; $this->response_data = $data; } /** * Backwards compatibility for direct property access. * @param string $property * @return mixed */ public function __get($property) { if (in_array($property, [ 'title', 'detail', 'errors' ], true)) { if (! empty($this->response_data) && isset($this->response_data->{$property})) { return $this->response_data->{$property}; } return ''; } } /** * @return string */ public function __toString() { $string = $this->message . '.'; // add errors from response data returned by Mailchimp if (! empty($this->response_data)) { if (! empty($this->response_data->title) && $this->response_data->title !== $this->getMessage()) { $string .= ' ' . $this->response_data->title . '.'; } // add detail message if (! empty($this->response_data->detail)) { $string .= ' ' . $this->response_data->detail; } // add field specific errors if (! empty($this->response_data->errors) && isset($this->response_data->errors[0]->field)) { // strip off obsolete msg $string = str_replace('For field-specific details, see the \'errors\' array.', '', $string); // generate list of field errors $field_errors = []; foreach ($this->response_data->errors as $error) { if (! empty($error->field)) { $field_errors[] = sprintf('- %s : %s', $error->field, $error->message); } else { $field_errors[] = sprintf('- %s', $error->message); } } $string .= " \n" . join("\n", $field_errors); } } // Add request data if (! empty($this->request) && is_array($this->request)) { $string .= "\n\n" . sprintf("Request: \n%s %s\n", $this->request['method'], $this->request['url']); // foreach ( $this->request['headers'] as $key => $value ) { // $string .= sprintf( "%s: %s\n", $key, $value ); // } if (! empty($this->request['body'])) { $string .= "\n" . $this->request['body']; } } // Add response data if (! empty($this->response) && is_array($this->response)) { $response_code = wp_remote_retrieve_response_code($this->response); $response_message = wp_remote_retrieve_response_message($this->response); $response_body = wp_remote_retrieve_body($this->response); $string .= "\n\n" . sprintf("Response: \n%d %s\n%s", $response_code, $response_message, $response_body); } return $string; } } includes/api/class-api-v3-client.php 0000777 00000014670 15251522663 0013340 0 ustar 00 <?php class MC4WP_API_V3_Client { /** * @var string */ private $api_key; /** * @var string */ private $api_url = 'https://api.mailchimp.com/3.0/'; /** * @var array */ private $last_response; /** * @var array */ private $last_request; /** * Constructor * * @param string $api_key */ public function __construct($api_key) { $this->api_key = $api_key; $dash_position = strpos($api_key, '-'); if ($dash_position !== false) { $this->api_url = str_replace('//api.', '//' . substr($api_key, $dash_position + 1) . '.api.', $this->api_url); } } /** * @param string $resource * @param array $args * * @return mixed * @throws MC4WP_API_Exception */ public function get($resource, array $args = []) { return $this->request('GET', $resource, $args); } /** * @param string $resource * @param array $data * * @return mixed * @throws MC4WP_API_Exception */ public function post($resource, array $data) { return $this->request('POST', $resource, $data); } /** * @param string $resource * @param array $data * @return mixed * @throws MC4WP_API_Exception */ public function put($resource, array $data) { return $this->request('PUT', $resource, $data); } /** * @param string $resource * @param array $data * @return mixed * @throws MC4WP_API_Exception */ public function patch($resource, array $data) { return $this->request('PATCH', $resource, $data); } /** * @param string $resource * @return mixed * @throws MC4WP_API_Exception */ public function delete($resource) { return $this->request('DELETE', $resource); } /** * @param string $method * @param string $resource * @param array $data * * @return mixed * * @throws MC4WP_API_Exception */ private function request($method, $resource, array $data = []) { $this->reset(); // don't bother if no API key was given. if (empty($this->api_key)) { throw new MC4WP_API_Exception('Missing API key', 001); } $method = strtoupper(trim($method)); $url = $this->api_url . ltrim($resource, '/'); $args = [ 'method' => $method, 'headers' => $this->get_headers(), 'timeout' => 20, 'sslverify' => apply_filters('mc4wp_use_sslverify', true), ]; if (! empty($data)) { if (in_array($method, [ 'GET', 'DELETE' ], true)) { $url = add_query_arg($data, $url); } else { $args['headers']['Content-Type'] = 'application/json'; $args['body'] = json_encode($data); } } /** * Filter the request arguments for all requests generated by this class * * @param array $args */ $args = apply_filters('mc4wp_http_request_args', $args, $url); // perform request $response = wp_remote_request($url, $args); // store request & response $args['url'] = $url; $this->last_request = $args; $this->last_response = $response; // parse response $data = $this->parse_response($response); return $data; } /** * @return array */ private function get_headers() { global $wp_version; $headers = [ 'Authorization' => sprintf('Basic %s', base64_encode('mc4wp:' . $this->api_key)), 'User-Agent' => sprintf('mc4wp/%s; WordPress/%s; %s', MC4WP_VERSION, $wp_version, home_url()), ]; // Copy Accept-Language from browser headers if (! empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $headers['Accept-Language'] = $_SERVER['HTTP_ACCEPT_LANGUAGE']; } return $headers; } /** * @param array|WP_Error $response * * @return mixed * * @throws MC4WP_API_Connection_Exception|MC4WP_API_Resource_Not_Found_Exception|MC4WP_API_Exception */ private function parse_response($response) { if ($response instanceof WP_Error) { throw new MC4WP_API_Connection_Exception($response->get_error_message(), (int) $response->get_error_code(), $this->last_request); } // decode response body $code = (int) wp_remote_retrieve_response_code($response); $message = wp_remote_retrieve_response_message($response); $body = wp_remote_retrieve_body($response); // set body to "true" in case Mailchimp returned No Content if ($code < 300 && empty($body)) { $body = 'true'; } $data = json_decode($body); if ($code >= 400) { // check for akamai errors // {"type":"akamai_error_message","title":"akamai_503","status":503,"ref_no":"Reference Number: 00.950e16c3.1498559813.1450dbe2"} if (is_object($data) && isset($data->type) && $data->type === 'akamai_error_message') { throw new MC4WP_API_Connection_Exception($message, $code, $this->last_request, $this->last_response, $data); } if ($code === 404) { throw new MC4WP_API_Resource_Not_Found_Exception($message, $code, $this->last_request, $this->last_response, $data); } // mailchimp returned an error.. throw new MC4WP_API_Exception($message, $code, $this->last_request, $this->last_response, $data); } // throw exception if unable to decode response if ($data === null) { throw new MC4WP_API_Exception($message, $code, $this->last_request, $this->last_response); } return $data; } /** * Empties all data from previous response */ private function reset() { $this->last_response = null; $this->last_request = null; } /** * @return string */ public function get_last_response_body() { return wp_remote_retrieve_body($this->last_response); } /** * @return array */ public function get_last_response_headers() { return wp_remote_retrieve_headers($this->last_response); } /** * @return array|WP_Error */ public function get_last_response() { return $this->last_response; } } includes/api/class-api-v3.php 0000777 00000134047 15251522663 0012065 0 ustar 00 <?php /** * Class MC4WP_API_V3 */ class MC4WP_API_V3 { /** * @var MC4WP_API_V3_Client */ protected $client; /** * Constructor * * @param string $api_key */ public function __construct($api_key) { $this->client = new MC4WP_API_V3_Client($api_key); } /** * Gets the API client to perform raw API calls. * * @return MC4WP_API_V3_Client */ public function get_client() { return $this->client; } /** * Pings the Mailchimp API to see if we're connected * * @return boolean * @throws MC4WP_API_Exception */ public function is_connected() { $data = $this->client->get('/', [ 'fields' => 'account_id' ]); $connected = is_object($data) && isset($data->account_id); return $connected; } /** * @param $email_address * * @return string */ public function get_subscriber_hash($email_address) { return md5(strtolower(trim($email_address))); } /** * Get recent daily, aggregated activity stats for a list. * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/activity/#read-get_lists_list_id_activity * * @param string $list_id * @param array $args * * @return array * @throws MC4WP_API_Exception */ public function get_list_activity($list_id, array $args = []) { $resource = sprintf('/lists/%s/activity', $list_id); $data = $this->client->get($resource, $args); if (is_object($data) && isset($data->activity)) { return $data->activity; } return []; } /** * Gets the interest categories for a given List * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/interest-categories/#read-get_lists_list_id_interest_categories * * @param string $list_id * @param array $args * * @return array * @throws MC4WP_API_Exception */ public function get_list_interest_categories($list_id, array $args = []) { $resource = sprintf('/lists/%s/interest-categories', $list_id); $data = $this->client->get($resource, $args); if (is_object($data) && isset($data->categories)) { return $data->categories; } return []; } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/interest-categories/interests/#read-get_lists_list_id_interest_categories_interest_category_id_interests * * @param string $list_id * @param string $interest_category_id * @param array $args * * @return array * @throws MC4WP_API_Exception */ public function get_list_interest_category_interests($list_id, $interest_category_id, array $args = []) { $resource = sprintf('/lists/%s/interest-categories/%s/interests', $list_id, $interest_category_id); $data = $this->client->get($resource, $args); if (is_object($data) && isset($data->interests)) { return $data->interests; } return []; } /** * Get merge vars for a given list * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/merge-fields/#read-get_lists_list_id_merge_fields * * @param string $list_id * @param array $args * * @return array * @throws MC4WP_API_Exception */ public function get_list_merge_fields($list_id, array $args = []) { $resource = sprintf('/lists/%s/merge-fields', $list_id); $data = $this->client->get($resource, $args); if (is_object($data) && isset($data->merge_fields)) { return $data->merge_fields; } return []; } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/#read-get_lists_list_id * * @param string $list_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_list($list_id, array $args = []) { $resource = sprintf('/lists/%s', $list_id); $data = $this->client->get($resource, $args); return $data; } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/#read-get_lists * * @param array $args * * @return array * @throws MC4WP_API_Exception */ public function get_lists(array $args = []) { $resource = '/lists'; $data = $this->client->get($resource, $args); if (is_object($data) && isset($data->lists)) { return $data->lists; } return []; } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/ * * @param string $list_id * @param string $email_address * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_list_member($list_id, $email_address, array $args = []) { $subscriber_hash = $this->get_subscriber_hash($email_address); $resource = sprintf('/lists/%s/members/%s', $list_id, $subscriber_hash); $data = $this->client->get($resource, $args); return $data; } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/ * @since 4.8.12 * @param string $list_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_list_members($list_id, array $args = []) { $resource = sprintf('/lists/%s/members', $list_id); return $this->client->get($resource, $args); } /** * Batch subscribe / unsubscribe list members. * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/#create-post_lists_list_id * * @param string $list_id * @param array $args * @return object * @throws MC4WP_API_Exception */ public function add_list_members($list_id, array $args) { $resource = sprintf('/lists/%s', $list_id); return $this->client->post($resource, $args); } /** * Add a new member to a Mailchimp list. * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#create-post_lists_list_id_members * * @param string $list_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function add_new_list_member($list_id, array $args) { $resource = sprintf('/lists/%s/members', $list_id); // make sure we're sending an object as the Mailchimp schema requires this if (isset($args['merge_fields'])) { $args['merge_fields'] = (object) $args['merge_fields']; } if (isset($args['interests'])) { $args['interests'] = (object) $args['interests']; } if (isset($args['marketing_permissions'])) { $args['marketing_permissions'] = (array) $args['marketing_permissions']; } return $this->client->post($resource, $args); } /** * Add or update (!) a member to a Mailchimp list. * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#create-post_lists_list_id_members * * @param string $list_id * @param array $args * @param bool $skip_merge_validation Allow subscribing users without all required MERGE fields * * @return object * @throws MC4WP_API_Exception */ public function add_list_member($list_id, array $args, $skip_merge_validation = false) { $subscriber_hash = $this->get_subscriber_hash($args['email_address']); $resource = sprintf('/lists/%s/members/%s', $list_id, $subscriber_hash); if ($skip_merge_validation) { $resource = add_query_arg([ 'skip_merge_validation' => 'true' ], $resource); } // make sure we're sending an object as the Mailchimp schema requires this if (isset($args['merge_fields'])) { $args['merge_fields'] = (object) $args['merge_fields']; } if (isset($args['interests'])) { $args['interests'] = (object) $args['interests']; } if (isset($args['marketing_permissions'])) { $args['marketing_permissions'] = (array) $args['marketing_permissions']; } // "put" updates the member if it's already on the list... take notice return $this->client->put($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#edit-patch_lists_list_id_members_subscriber_hash * * @param $list_id * @param $email_address * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function update_list_member($list_id, $email_address, array $args) { $subscriber_hash = $this->get_subscriber_hash($email_address); $resource = sprintf('/lists/%s/members/%s', $list_id, $subscriber_hash); // make sure we're sending an object as the Mailchimp schema requires this if (isset($args['merge_fields'])) { $args['merge_fields'] = (object) $args['merge_fields']; } if (isset($args['interests'])) { $args['interests'] = (object) $args['interests']; } if (isset($args['marketing_permissions'])) { $args['marketing_permissions'] = (array) $args['marketing_permissions']; } return $this->client->patch($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/ * * @param string $list_id * @param string $email_address * * @return bool * @throws MC4WP_API_Exception */ public function delete_list_member($list_id, $email_address) { $subscriber_hash = $this->get_subscriber_hash($email_address); $resource = sprintf('/lists/%s/members/%s', $list_id, $subscriber_hash); $data = $this->client->delete($resource); return ! ! $data; } /** * Get the tags on a list member. * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/tags/#create-post_lists_list_id_members_subscriber_hash_tags * @param string $list_id * @param string $email_address * @return object * @throws MC4WP_API_Exception */ public function get_list_member_tags($list_id, $email_address) { $subscriber_hash = $this->get_subscriber_hash($email_address); $resource = sprintf('/lists/%s/members/%s/tags', $list_id, $subscriber_hash); return $this->client->get($resource); } /** * Add or remove tags from a list member. If a tag that does not exist is passed in and set as ‘active’, a new tag will be created. * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/tags/#read-get_lists_list_id_members_subscriber_hash_tags * @param string $list_id * @param string $email_address * @param array $data * @return object * @throws MC4WP_API_Exception */ public function update_list_member_tags($list_id, $email_address, array $data) { $subscriber_hash = $this->get_subscriber_hash($email_address); $resource = sprintf('/lists/%s/members/%s/tags', $list_id, $subscriber_hash); return $this->client->post($resource, $data); } /** * Get information about all available segments for a specific list. * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/lists/segments/#read-get_lists_list_id_segments * @param string $list_id * @param array $args * @return object * @throws MC4WP_API_Exception */ public function get_list_segments($list_id, array $args = []) { $resource = sprintf('/lists/%s/segments', $list_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/#read-get_ecommerce_stores * * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_stores(array $args = []) { $resource = '/ecommerce/stores'; return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/#read-get_ecommerce_stores_store_id * * @param string $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store($store_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s', $store_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/#create-post_ecommerce_stores * * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function add_ecommerce_store(array $args) { $resource = '/ecommerce/stores'; return $this->client->post($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/#edit-patch_ecommerce_stores_store_id * * @param string $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function update_ecommerce_store($store_id, array $args) { $resource = sprintf('/ecommerce/stores/%s', $store_id); return $this->client->patch($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/#delete-delete_ecommerce_stores_store_id * * @param string $store_id * * @return boolean * @throws MC4WP_API_Exception */ public function delete_ecommerce_store($store_id) { $resource = sprintf('/ecommerce/stores/%s', $store_id); return ! ! $this->client->delete($resource); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/customers/#read-get_ecommerce_stores_store_id_customers * * @param string $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_customers($store_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/customers', $store_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/customers/#read-get_ecommerce_stores_store_id_customers_customer_id * * @param string $store_id * @param string $customer_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_customer($store_id, $customer_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/customers/%s', $store_id, $customer_id); return $this->client->get($resource, $args); } /** * Add OR update a store customer * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/customers/#edit-put_ecommerce_stores_store_id_customers_customer_id * * @param $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function add_ecommerce_store_customer($store_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/customers/%s', $store_id, $args['id']); return $this->client->put($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/customers/#edit-patch_ecommerce_stores_store_id_customers_customer_id * * @param string $store_id * @param string $customer_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function update_ecommerce_store_customer($store_id, $customer_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/customers/%s', $store_id, $customer_id); return $this->client->patch($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/customers/#delete-delete_ecommerce_stores_store_id_customers_customer_id * * @param string $store_id * @param string $customer_id * * @return bool * @throws MC4WP_API_Exception */ public function delete_ecommerce_store_customer($store_id, $customer_id) { $resource = sprintf('/ecommerce/stores/%s/customers/%s', $store_id, $customer_id); return ! ! $this->client->delete($resource); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/products/#read-get_ecommerce_stores_store_id_products * * @param string $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_products($store_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/products', $store_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/products/#read-get_ecommerce_stores_store_id_products_product_id * * @param string $store_id * @param string $product_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_product($store_id, $product_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/products/%s', $store_id, $product_id); return $this->client->get($resource, $args); } /** * Add a product to a store * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/products/#create-post_ecommerce_stores_store_id_products * * @param string $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function add_ecommerce_store_product($store_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/products', $store_id); return $this->client->post($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/products/#edit-patch_ecommerce_stores_store_id_products_product_id * * @param string $store_id * @param string $product_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function update_ecommerce_store_product($store_id, $product_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/products/%s', $store_id, $product_id); return $this->client->patch($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/products/#delete-delete_ecommerce_stores_store_id_products_product_id * * @param string $store_id * @param string $product_id * * @return boolean * @throws MC4WP_API_Exception */ public function delete_ecommerce_store_product($store_id, $product_id) { $resource = sprintf('/ecommerce/stores/%s/products/%s', $store_id, $product_id); return ! ! $this->client->delete($resource); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/products/variants/#read-get_ecommerce_stores_store_id_products_product_id_variants * * @param string $store_id * @param string $product_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_product_variants($store_id, $product_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/products/%s/variants', $store_id, $product_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/products/variants/#read-get_ecommerce_stores_store_id_products_product_id_variants_variant_id * * @param string $store_id * @param string $product_id * @param string $variant_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_product_variant($store_id, $product_id, $variant_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/products/%s/variants/%s', $store_id, $product_id, $variant_id); return $this->client->get($resource, $args); } /** * Add OR update a product variant. * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/products/variants/#edit-put_ecommerce_stores_store_id_products_product_id_variants_variant_id * * @param string $store_id * @param string $product_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function add_ecommerce_store_product_variant($store_id, $product_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/products/%s/variants/%s', $store_id, $product_id, $args['id']); return $this->client->put($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/products/variants/#edit-patch_ecommerce_stores_store_id_products_product_id_variants_variant_id * * @param string $store_id * @param string $product_id * @param string $variant_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function update_ecommerce_store_product_variant($store_id, $product_id, $variant_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/products/%s/variants/%s', $store_id, $product_id, $variant_id); return $this->client->patch($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/products/variants/#delete-delete_ecommerce_stores_store_id_products_product_id_variants_variant_id * * @param string $store_id * @param string $product_id * @param string $variant_id * * @return boolean * @throws MC4WP_API_Exception */ public function delete_ecommerce_store_product_variant($store_id, $product_id, $variant_id) { $resource = sprintf('/ecommerce/stores/%s/products/%s/variants/%s', $store_id, $product_id, $variant_id); return ! ! $this->client->delete($resource); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/orders/#read-get_ecommerce_stores_store_id_orders * * @param string $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_orders($store_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/orders', $store_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/orders/#read-get_ecommerce_stores_store_id_orders_order_id * * @param string $store_id * @param string $order_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_order($store_id, $order_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/orders/%s', $store_id, $order_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/orders/#create-post_ecommerce_stores_store_id_orders * * @param string $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function add_ecommerce_store_order($store_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/orders', $store_id); return $this->client->post($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/orders/#edit-patch_ecommerce_stores_store_id_orders_order_id * * @param string $store_id * @param string $order_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function update_ecommerce_store_order($store_id, $order_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/orders/%s', $store_id, $order_id); return $this->client->patch($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/orders/#delete-delete_ecommerce_stores_store_id_orders_order_id * * @param string $store_id * @param string $order_id * * @return bool * @throws MC4WP_API_Exception */ public function delete_ecommerce_store_order($store_id, $order_id) { return ! ! $this->client->delete(sprintf('/ecommerce/stores/%s/orders/%s', $store_id, $order_id)); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/orders/lines/#create-post_ecommerce_stores_store_id_orders_order_id_lines * * @param string $store_id * @param string $order_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function add_ecommerce_store_order_line($store_id, $order_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/orders/%s/lines', $store_id, $order_id); return $this->client->post($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/orders/lines/#read-get_ecommerce_stores_store_id_orders_order_id_lines * * @param string $store_id * @param string $order_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_order_lines($store_id, $order_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/orders/%s/lines', $store_id, $order_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/orders/lines/#read-get_ecommerce_stores_store_id_orders_order_id_lines_line_id * * @param string $store_id * @param string $order_id * @param string $line_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_order_line($store_id, $order_id, $line_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/orders/%s/lines/%s', $store_id, $order_id, $line_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/orders/lines/#edit-patch_ecommerce_stores_store_id_orders_order_id_lines_line_id * * @param string $store_id * @param string $order_id * @param string $line_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function update_ecommerce_store_order_line($store_id, $order_id, $line_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/orders/%s/lines/%s', $store_id, $order_id, $line_id); return $this->client->patch($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/orders/lines/#delete-delete_ecommerce_stores_store_id_orders_order_id_lines_line_id * * @param string $store_id * @param string $order_id * @param string $line_id * * @return bool * @throws MC4WP_API_Exception */ public function delete_ecommerce_store_order_line($store_id, $order_id, $line_id) { $resource = sprintf('/ecommerce/stores/%s/orders/%s/lines/%s', $store_id, $order_id, $line_id); return ! ! $this->client->delete($resource); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/carts/#read-get_ecommerce_stores_store_id_carts * * @param string $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_carts($store_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/carts', $store_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/carts/#read-get_ecommerce_stores_store_id_carts_cart_id * * @param string $store_id * @param string $cart_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_cart($store_id, $cart_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/carts/%s', $store_id, $cart_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/carts/#create-post_ecommerce_stores_store_id_carts * * @param string $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function add_ecommerce_store_cart($store_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/carts', $store_id); return $this->client->post($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/carts/#edit-patch_ecommerce_stores_store_id_carts_cart_id * * @param string $store_id * @param string $cart_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function update_ecommerce_store_cart($store_id, $cart_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/carts/%s', $store_id, $cart_id); return $this->client->patch($resource, $args); } /** * @link https://mailchimp.com/developer/reference/ecommerce-stores/ecommerce-carts/#delete-delete_ecommerce_stores_store_id_carts_cart_id * * @param string $store_id * @param string $cart_id * * @return bool */ public function delete_ecommerce_store_cart($store_id, $cart_id) { return ! ! $this->client->delete(sprintf('/ecommerce/stores/%s/carts/%s', $store_id, $cart_id)); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/carts/lines/#read-get_ecommerce_stores_store_id_carts_cart_id_lines * * @param string $store_id * @param string $cart_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_cart_lines($store_id, $cart_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/carts/%/lines', $store_id, $cart_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/carts/lines/#read-get_ecommerce_stores_store_id_carts_cart_id_lines_line_id * * @param string $store_id * @param string $cart_id * @param string $line_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_cart_line($store_id, $cart_id, $line_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/carts/%s/lines/%s', $store_id, $cart_id, $line_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/carts/lines/#create-post_ecommerce_stores_store_id_carts_cart_id_lines * * @param string $store_id * @param string $cart_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function add_ecommerce_store_cart_line($store_id, $cart_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/carts/%s/lines', $store_id, $cart_id); return $this->client->post($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/carts/lines/#edit-patch_ecommerce_stores_store_id_carts_cart_id_lines_line_id * * @param string $store_id * @param string $cart_id * @param string $line_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function update_ecommerce_store_cart_line($store_id, $cart_id, $line_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/carts/%s/lines/%s', $store_id, $cart_id, $line_id); return $this->client->patch($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/carts/lines/#delete-delete_ecommerce_stores_store_id_carts_cart_id_lines_line_id * * @param string $store_id * @param string $cart_id * @param string $line_id * * @return bool * @throws MC4WP_API_Exception */ public function delete_ecommerce_store_cart_line($store_id, $cart_id, $line_id) { $resource = sprintf('/ecommerce/stores/%s/carts/%s/lines/%s', $store_id, $cart_id, $line_id); return ! ! $this->client->delete($resource); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/promo-rules/#create-post_ecommerce_stores_store_id_promo_rules * * @param string $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function add_ecommerce_store_promo_rule($store_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/promo-rules', $store_id); return $this->client->post($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/promo-rules/#read-get_ecommerce_stores_store_id_promo_rules * * @param string $store_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_promo_rules($store_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/promo-rules', $store_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/promo-rules/#read-get_ecommerce_stores_store_id_promo_rules_promo_rule_id * * @param string $store_id * @param string $promo_rule_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_promo_rule($store_id, $promo_rule_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/promo-rules/%s', $store_id, $promo_rule_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/promo-rules/#edit-patch_ecommerce_stores_store_id_promo_rules_promo_rule_id * * @param string $store_id * @param string $promo_rule_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function update_ecommerce_store_promo_rule($store_id, $promo_rule_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/promo-rules/%s', $store_id, $promo_rule_id); return $this->client->patch($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/promo-rules/#delete-delete_ecommerce_stores_store_id_promo_rules_promo_rule_id * * @param string $store_id * @param string $promo_rule_id * * @return boolean * @throws MC4WP_API_Exception */ public function delete_ecommerce_store_promo_rule($store_id, $promo_rule_id) { $resource = sprintf('/ecommerce/stores/%s/promo-rules/%s', $store_id, $promo_rule_id); return ! ! $this->client->delete($resource); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/promo-rules/promo-codes/#create-post_ecommerce_stores_store_id_promo_rules_promo_rule_id_promo_codes * * @param string $store_id * @param string $promo_rule_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function add_ecommerce_store_promo_rule_promo_code($store_id, $promo_rule_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/promo-rules/%s/promo-codes', $store_id, $promo_rule_id); return $this->client->post($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/promo-rules/promo-codes/#read-get_ecommerce_stores_store_id_promo_rules_promo_rule_id_promo_codes * * @param string $store_id * @param string $promo_rule_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_promo_rule_promo_codes($store_id, $promo_rule_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/promo-rules/%s/promo-codes', $store_id, $promo_rule_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/promo-rules/promo-codes/#read-get_ecommerce_stores_store_id_promo_rules_promo_rule_id_promo_codes_promo_code_id * * @param string $store_id * @param string $promo_rule_id * @param string $promo_code_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function get_ecommerce_store_promo_rule_promo_code($store_id, $promo_rule_id, $promo_code_id, array $args = []) { $resource = sprintf('/ecommerce/stores/%s/promo-rules/%s/promo-codes/%s', $store_id, $promo_rule_id, $promo_code_id); return $this->client->get($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/promo-rules/promo-codes/#edit-patch_ecommerce_stores_store_id_promo_rules_promo_rule_id_promo_codes_promo_code_id * * @param string $store_id * @param string $promo_rule_id * @param string $promo_code_id * @param array $args * * @return object * @throws MC4WP_API_Exception */ public function update_ecommerce_store_promo_rule_promo_code($store_id, $promo_rule_id, $promo_code_id, array $args) { $resource = sprintf('/ecommerce/stores/%s/promo-rules/%s/promo-codes/%s', $store_id, $promo_rule_id, $promo_code_id); return $this->client->patch($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/ecommerce/stores/promo-rules/promo-codes/#delete-delete_ecommerce_stores_store_id_promo_rules_promo_rule_id_promo_codes_promo_code_id * * @param string $store_id * @param string $promo_rule_id * @param string $promo_code_id * * @return boolean * @throws MC4WP_API_Exception */ public function delete_ecommerce_store_promo_rule_promo_code($store_id, $promo_rule_id, $promo_code_id) { $resource = sprintf('/ecommerce/stores/%s/promo-rules/%s/promo-codes/%s', $store_id, $promo_rule_id, $promo_code_id); return ! ! $this->client->delete($resource); } /** * Get a list of an account's available templates * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/templates/#read-get_templates * @param array $args * @return object * @throws MC4WP_API_Exception */ public function get_templates(array $args = []) { $resource = '/templates'; return $this->client->get($resource, $args); } /** * Get information about a specific template. * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/templates/#read-get_templates_template_id * @param string $template_id * @param array $args * @return object * @throws MC4WP_API_Exception */ public function get_template($template_id, array $args = []) { $resource = sprintf('/templates/%s', $template_id); return $this->client->get($resource, $args); } /** * Create a new template. * * @link https://mailchimp.com/developer/reference/templates/#post_/templates * @param array $args * @return object * @throws MC4WP_API_Exception */ public function add_template(array $args) { $resource = '/templates'; return $this->client->post($resource, $args); } /** * @link https://developer.mailchimp.com/documentation/mailchimp/reference/templates/default-content/ * @param string $template_id * @param array $args * @return object * @throws MC4WP_API_Exception */ public function get_template_default_content($template_id, array $args = []) { $resource = sprintf('/templates/%s/default-content', $template_id); return $this->client->get($resource, $args); } /** * Create a new campaign * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/campaigns/#create-post_campaigns * @param array $args * @return object * @throws MC4WP_API_Exception */ public function add_campaign(array $args) { $resource = '/campaigns'; return $this->client->post($resource, $args); } /** * Get all campaigns in an account * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/campaigns/#read-get_campaigns * @param array $args * @return object * @throws MC4WP_API_Exception */ public function get_campaigns(array $args = []) { $resource = '/campaigns'; return $this->client->get($resource, $args); } /** * Get information about a specific campaign. * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/campaigns/#read-get_campaigns_campaign_id * @param string $campaign_id * @param array $args * @return object * @throws MC4WP_API_Exception */ public function get_campaign($campaign_id, array $args = []) { $resource = sprintf('/campaigns/%s', $campaign_id); return $this->client->get($resource, $args); } /** * Update some or all of the settings for a specific campaign. * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/campaigns/#edit-patch_campaigns_campaign_id * @param string $campaign_id * @param array $args * @return object * @throws MC4WP_API_Exception */ public function update_campaign($campaign_id, array $args) { $resource = sprintf('/campaigns/%s', $campaign_id); return $this->client->patch($resource, $args); } /** * Remove a campaign from the Mailchimp account * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/campaigns/#delete-delete_campaigns_campaign_id * @param string $campaign_id * @return bool * @throws MC4WP_API_Exception */ public function delete_campaign($campaign_id) { $resource = sprintf('/campaigns/%s', $campaign_id); return ! ! $this->client->delete($resource); } /** * Perform an action on a Mailchimp campaign * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/campaigns/#action-post_campaigns * * @param string $campaign_id * @param string $action * @param array $args * @return object * @throws MC4WP_API_Exception */ public function campaign_action($campaign_id, $action, array $args = []) { $resource = sprintf('/campaigns/%s/actions/%s', $campaign_id, $action); return $this->client->post($resource, $args); } /** * Get the HTML and plain-text content for a campaign * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/campaigns/content/#read-get_campaigns_campaign_id_content * @param string $campaign_id * @param array $args * @return object * @throws MC4WP_API_Exception */ public function get_campaign_content($campaign_id, array $args = []) { $resource = sprintf('/campaigns/%s/content', $campaign_id); return $this->client->get($resource, $args); } /** * Set the content for a campaign * * @link https://developer.mailchimp.com/documentation/mailchimp/reference/campaigns/content/#edit-put_campaigns_campaign_id_content * @param string $campaign_id * @param array $args * @return object * @throws MC4WP_API_Exception */ public function update_campaign_content($campaign_id, array $args) { $resource = sprintf('/campaigns/%s/content', $campaign_id); return $this->client->put($resource, $args); } /** * @return string */ public function get_last_response_body() { return $this->client->get_last_response_body(); } /** * @return array */ public function get_last_response_headers() { return $this->client->get_last_response_headers(); } } includes/views/other-settings.php 0000777 00000020344 15251522663 0013220 0 ustar 00 <?php defined('ABSPATH') or exit; /** @var array $opts */ /** @var MC4WP_Debug_Log $log */ /** @var MC4WP_Debug_Log_Reader $log_reader */ ?> <div id="mc4wp-admin" class="wrap mc4wp-settings"> <p class="mc4wp-breadcrumbs"> <span class="prefix"><?php echo esc_html__('You are here: ', 'mailchimp-for-wp'); ?></span> <a href="<?php echo admin_url('admin.php?page=mailchimp-for-wp'); ?>">Mailchimp for WordPress</a> › <span class="current-crumb"><strong><?php echo esc_html__('Other Settings', 'mailchimp-for-wp'); ?></strong></span> </p> <div class="mc4wp-row"> <?php /* main content */ ?> <div class="main-content mc4wp-col"> <h1 class="mc4wp-page-title"> <?php echo esc_html__('Other Settings', 'mailchimp-for-wp'); ?> </h1> <h2 style="display: none;"></h2> <?php settings_errors(); ?> <?php do_action('mc4wp_admin_before_other_settings', $opts); ?> <form action="<?php echo admin_url('options.php'); ?>" method="post"> <?php settings_fields('mc4wp_settings'); ?> <div class="mc4wp-margin-m" > <h3><?php echo esc_html__('Miscellaneous settings', 'mailchimp-for-wp'); ?></h3> <table class="form-table"> <tr> <th><label for="mc4wp-debug-log-level"><?php echo esc_html__('Logging', 'mailchimp-for-wp'); ?></label></th> <td> <select id="mc4wp-debug-log-level" name="mc4wp[debug_log_level]"> <option value="warning" <?php selected('warning', $opts['debug_log_level']); ?>><?php echo esc_html__('Errors & warnings only', 'mailchimp-for-wp'); ?></option> <option value="debug" <?php selected('debug', $opts['debug_log_level']); ?>><?php echo esc_html__('Everything', 'mailchimp-for-wp'); ?></option> </select> <p class="description"> <?php echo sprintf(wp_kses(__('Determines what events should be written to <a href="%s">the debug log</a> (see below).', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ] ]), 'https://www.mc4wp.com/kb/how-to-enable-log-debugging/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=settings-page'); ?> </p> </td> </tr> </table> <table class="form-table"> <tr> <th><label for="mc4wp-email-on-error"><?php echo esc_html__('Send email on critical error', 'mailchimp-for-wp'); ?></label></th> <td> <input type="email" id="mc4wp-email-on-error" name="mc4wp[email_on_error]" value="<?php echo esc_attr($opts['email_on_error']); ?>" class="regular-text" placeholder="your@email.com" /> <p class="description"> <?php echo esc_html__('Enter an email address to receive a notification when a critical error occurs. Max 1 email per 24 hours.', 'mailchimp-for-wp'); ?> </p> </td> </tr> </table> </div> <?php do_action('mc4wp_admin_other_settings', $opts); ?> <div style="margin-top: -20px;"><?php submit_button(); ?></div> </form> <!-- Debug Log --> <div class="mc4wp-margin-m"> <h3><?php echo esc_html__('Debug Log', 'mailchimp-for-wp'); ?> <input type="text" id="debug-log-filter" class="alignright regular-text" placeholder="<?php echo esc_attr__('Filter..', 'mailchimp-for-wp'); ?>" /></h3> <?php if (! $log->test()) { echo '<p>'; echo esc_html__('Log file is not writable.', 'mailchimp-for-wp') . ' '; echo sprintf(wp_kses(__('Please ensure %1$s has the proper <a href="%2$s">file permissions</a>.', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ] ]), '<code>' . $log->file . '</code>', 'https://codex.wordpress.org/Changing_File_Permissions'); echo '</p>'; // hack to hide filter input echo '<style>#debug-log-filter { display: none; }</style>'; } else { ?> <div id="debug-log" class="mc4wp-log widefat"> <?php $line = $log_reader->read_as_html(); if (! empty($line)) { while (is_string($line)) { if (! empty($line)) { echo '<div class="debug-log-line">' . $line . '</div>'; } $line = $log_reader->read_as_html(); } } else { echo '<div class="debug-log-empty">'; echo '-- ', esc_html__('Nothing here. Which means there are no errors!', 'mailchimp-for-wp'); echo '</div>'; } ?> </div> <form method="post"> <input type="hidden" name="_mc4wp_action" value="empty_debug_log"> <?php wp_nonce_field('_mc4wp_action', '_wpnonce'); ?> <p> <input type="submit" class="button" value="<?php echo esc_attr__('Empty Log', 'mailchimp-for-wp'); ?>"/> </p> </form> <?php } // end if is writable if ($log->level >= 300) { echo '<p>'; echo esc_html__('Right now, the plugin is configured to only log errors and warnings.', 'mailchimp-for-wp'); echo '</p>'; } ?> <script> (function() { // scroll to bottom of log let log = document.getElementById("debug-log"), logItems; log.scrollTop = log.scrollHeight; log.style.minHeight = ''; log.style.maxHeight = ''; log.style.height = log.clientHeight + "px"; // add filter document.getElementById('debug-log-filter').addEventListener('keydown', function(evt) { if(evt.keyCode === 13 ) { searchLog(evt.target.value.trim()); } }); // search log for query function searchLog(query) { if( ! logItems ) { logItems = [].map.call(log.children, function(node) { return node.cloneNode(true); }) } const ri = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), 'i'); const newLog = log.cloneNode(false); logItems.forEach(function(node) { if( ! node.textContent ) { return ; } if( ! query.length || ri.test(node.textContent) ) { newLog.appendChild(node); } }); log.parentNode.replaceChild(newLog, log); log = newLog; log.scrollTop = log.scrollHeight; } })(); </script> </div> <?php require __DIR__ . '/parts/admin-footer.php'; ?> </div> <div class="mc4wp-sidebar mc4wp-col"> <?php require __DIR__ . '/parts/admin-sidebar.php'; ?> </div> </div> </div> includes/views/parts/lists-overview.php 0000777 00000005440 15251522663 0014374 0 ustar 00 <h3><?php echo esc_html__('Your Mailchimp Account', 'mailchimp-for-wp'); ?></h3> <p><?php echo esc_html__('The table below shows your Mailchimp audiences and their details. If you just applied changes to your Mailchimp account, please use the following button to renew the cache.', 'mailchimp-for-wp'); ?></p> <div id="mc4wp-list-fetcher"> <form method="post" action=""> <input type="hidden" name="_mc4wp_action" value="empty_lists_cache" /> <?php echo wp_nonce_field('_mc4wp_action'); ?> <p> <input type="submit" value="<?php echo esc_attr__('Renew Mailchimp audiences', 'mailchimp-for-wp'); ?>" class="button"> </p> </form> </div> <div class="mc4wp-lists-overview"> <?php if (empty($lists)) { ?> <p><?php echo esc_html__('No audiences were found in your Mailchimp account', 'mailchimp-for-wp'); ?>.</p> <?php } else { echo '<p>', sprintf(esc_html__('A total of %d audiences were found in your Mailchimp account.', 'mailchimp-for-wp'), count($lists)), '</p>'; echo '<table class="widefat striped" id="mc4wp-mailchimp-lists-overview">'; $headings = [ esc_html__('Audience name', 'mailchimp-for-wp'), esc_html__('Audience ID', 'mailchimp-for-wp'), esc_html__('# of contacts', 'mailchimp-for-wp'), ]; echo '<thead>'; echo '<tr>'; foreach ($headings as $heading) { echo '<th>', $heading, '</th>'; } echo '</tr>'; echo '</thead>'; echo '<tbody>'; foreach ($lists as $list) { $attr_data_list_id = esc_attr($list->id); $list_name = esc_html($list->name); echo '<tr>'; echo '<td><a href="#" class="mc4wp-mailchimp-list" data-list-id="', $attr_data_list_id, '">', $list_name, '</a><span class="row-actions alignright"></span></td>'; echo '<td><code>', esc_html($list->id), '</code></td>'; echo '<td>', esc_html($list->stats->member_count), '</td>'; echo '</tr>'; echo '<tr class="list-details list-', $list->id, '-details" style="display: none;">'; echo '<td colspan="3" style="padding: 0 20px 40px;">'; echo '<p class="alignright" style="margin: 20px 0;"><a href="https://admin.mailchimp.com/audience/contacts/?id=', $list->web_id, '" target="_blank"><span class="dashicons dashicons-edit"></span> ', esc_html__('Edit this audience in Mailchimp', 'mailchimp-for-wp'), '</a></p>'; echo '<div><div>', esc_html__('Loading... Please wait.', 'mailchimp-for-wp'), '</div></div>'; echo '</td>'; echo '</tr>'; ?> <?php } // end foreach $lists echo '</tbody>'; echo '</table>'; } // end if empty ?> </div> includes/views/parts/admin-sidebar.php 0000777 00000005122 15251522663 0014066 0 ustar 00 <?php defined('ABSPATH') or exit; /** * @ignore */ function _mc4wp_admin_sidebar_support_notice() { ?> <div class="mc4wp-box mc4wp-margin-m"> <h4 class="mc4wp-title"><?php echo esc_html__('Looking for help?', 'mailchimp-for-wp'); ?></h4> <p><?php echo esc_html__('We have some resources available to help you in the right direction.', 'mailchimp-for-wp'); ?></p> <ul class="ul-square"> <li><a href="https://www.mc4wp.com/kb/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=sidebar"><?php echo esc_html__('Knowledge Base', 'mailchimp-for-wp'); ?></a></li> <li><a href="https://wordpress.org/plugins/mailchimp-for-wp/faq/"><?php echo esc_html__('Frequently Asked Questions', 'mailchimp-for-wp'); ?></a></li> </ul> <p><?php echo sprintf(wp_kses(__('If your answer can not be found in the resources listed above, please use the <a href="%s">support forums on WordPress.org</a>.', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ] ]), 'https://wordpress.org/support/plugin/mailchimp-for-wp'); ?></p> <p><?php echo sprintf(wp_kses(__('Found a bug? Please <a href="%s">open an issue on GitHub</a>.', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ] ]), 'https://github.com/ibericode/mailchimp-for-wordpress/issues'); ?></p> </div> <?php } /** * @ignore */ function _mc4wp_admin_sidebar_other_plugins() { echo '<div class="mc4wp-box mc4wp-margin-m">'; echo '<h4 class="mc4wp-title">', esc_html__('Other plugins by ibericode', 'mailchimp-for-wp'), '</h4>'; echo '<ul style="margin-bottom: 0;">'; // Koko Analytics echo '<li style="margin: 12px 0;">'; echo '<strong><a href="https://wordpress.org/plugins/koko-analytics/">Koko Analytics</a></strong><br />'; echo esc_html__('Plug and play, privacy-friendly and GDPR/CCPA compliant statistics for WordPress.', 'mailchimp-for-wp'); echo '</li>'; // Boxzilla echo '<li style="margin: 12px 0;">'; echo '<strong><a href="https://wordpress.org/plugins/boxzilla/">Boxzilla Pop-ups</a></strong><br />'; echo esc_html__('Pop-ups or boxes that slide-in with a newsletter sign-up form. A sure-fire way to grow your email lists.', 'mailchimp-for-wp'); echo '</li>'; echo '</ul>'; echo '</div>'; } add_action('mc4wp_admin_sidebar', '_mc4wp_admin_sidebar_other_plugins', 40); add_action('mc4wp_admin_sidebar', '_mc4wp_admin_sidebar_support_notice', 50); /** * Runs when the sidebar is outputted on Mailchimp for WordPress settings pages. * * Please note that not all pages have a sidebar. * * @since 3.0 */ do_action('mc4wp_admin_sidebar'); includes/views/parts/admin-footer.php 0000777 00000003217 15251522663 0013756 0 ustar 00 <?php defined('ABSPATH') or exit; function _mc4wp_admin_translation_notice() { // show for every language other than the default if (get_locale() === 'en_US') { return; } /* translators: %s links to the WordPress.org translation project */ echo '<p class="description">' . sprintf(wp_kses(__('Mailchimp for WordPress is in need of translations. Is the plugin not translated in your language or do you spot errors with the current translations? Helping out is easy! Please <a href="%s">help translate the plugin using your WordPress.org account</a>.', 'mailchimp-for-wp'), ['a' => ['href' => []]]), 'https://translate.wordpress.org/projects/wp-plugins/mailchimp-for-wp/stable/') . '</p>'; } function _mc4wp_admin_github_notice() { if (strpos($_SERVER['HTTP_HOST'], 'localhost') === false && ! WP_DEBUG) { return; } echo '<p class="description">Developer? Follow <a href="https://github.com/ibericode/mailchimp-for-wordpress">Mailchimp for WordPress on GitHub</a> or have a look at our repository of <a href="https://github.com/ibericode/mailchimp-for-wordpress/tree/master/sample-code-snippets">sample code snippets</a>.</p>'; } function _mc4wp_admin_disclaimer_notice() { echo '<p class="description">', esc_html__('This plugin is not developed by or affiliated with Mailchimp in any way.', 'mailchimp-for-wp'), '</p>'; } add_action('mc4wp_admin_footer', '_mc4wp_admin_translation_notice', 20); add_action('mc4wp_admin_footer', '_mc4wp_admin_github_notice', 50); add_action('mc4wp_admin_footer', '_mc4wp_admin_disclaimer_notice', 80); ?> <div class="mc4wp-margin-l"> <?php do_action('mc4wp_admin_footer'); ?> </div> includes/views/parts/lists-overview-details.php 0000777 00000005440 15251522663 0016017 0 ustar 00 <?php /** * @var object[] $merge_fields * @var object[] $interest_categories * @var object[] $marketing_permissions */ ?> <h3>Merge fields</h3> <table class="widefat striped"> <thead> <tr> <th>Name</th> <th>Tag</th> <th>Type</th> </tr> </thead> <tbody> <?php foreach ($merge_fields as $f) { ?> <tr> <td><?php echo esc_html($f->name); ?> <?php if ($f->required) { ?> <span class="mc4wp-red">*</span> <?php } ?></td> <td><code><?php echo esc_html($f->tag); ?></code></td> <td> <?php echo esc_html($f->type); ?> <?php if (isset($f->options->date_format)) { echo esc_html('(' . $f->options->date_format . ')'); } ?> <?php if (isset($f->options->choices)) { echo esc_html('(' . join(', ', $f->options->choices) . ')'); } ?> </td> </tr> <?php } ?> </tbody> </table> <?php if ($interest_categories) { ?> <h3>Interest Categories</h3> <table class="striped widefat"> <thead> <tr> <th>Name</th> <th>Type</th> <th>Interests</th> </tr> </thead> <tbody> <?php foreach ($interest_categories as $f) { ?> <tr> <td> <strong><?php echo esc_html($f->title); ?></strong> <br /> <br /> ID: <code><?php echo esc_html($f->id); ?></code> </td> <td><?php echo esc_html($f->type); ?></td> <td> <table> <thead> <tr><th>Name</th><th>ID</th></tr> </thead> <tbody> <?php foreach ($f->interests as $id => $name) { ?> <tr> <td><?php echo esc_html($name); ?></td> <td><code><?php echo esc_html($id); ?></code></td> </tr> <?php } ?> </tbody> </table> </td> </tr> <?php } ?> </tbody> </table> <?php } // end if interest categories ?> <?php if ($marketing_permissions) { ?> <h3>Marketing Permissions</h3> <table class="striped widefat"> <thead> <tr> <th>ID</th> <th>Name</th> </tr> </thead> <tbody> <?php foreach ($marketing_permissions as $mp) { ?> <tr> <td><code><?php echo esc_html($mp->marketing_permission_id); ?></code></td> <td><?php echo esc_html($mp->text); ?></td> </tr> <?php } ?> </tbody> </table> <?php } // end if marketing permissions ?> includes/views/extensions.php 0000777 00000006212 15251522663 0012436 0 ustar 00 <?php defined('ABSPATH') or exit; ?> <div id="mc4wp-admin" class="wrap mc4wp-settings"> <style> #mc4wp-admin h4{ margin-bottom: 2px; } #mc4wp-admin h4 + p { margin-top: 0; } </style> <h1 class="mc4wp-page-title">Mailchimp for WordPress: Add-on plugins</h1> <div class="mc4wp-margin-m" > <h2><span style="color: #c44;">Mailchimp for WordPress Premium</span>, take your email marketing to the next level!</h2> <p>You're currently on the free version of the <strong>MC4WP: Mailchimp for WordPress</strong> plugin.</p> <p>Did you know that there is a premium version too? It comes with the following additional features:</p> <ul class="ul-square"> <li><strong>Multiple and improved forms</strong> — allowing an unlimited amount of sign-up forms that submit without requiring a full page reload.</li> <li><strong>E-Commerce integration</strong> — tightly integrate your WooCommerce store with Mailchimp. <li><strong>User Sync</strong> — keep your WordPress user database in sync with a Mailchimp list.</li> <li><strong>Logging</strong> - every form submission is stored locally, allowing charted data and exporting to CSV or JSON</li> <li><strong>Form designer</strong> — make your forms look pretty without having to know or write a single line of CSS.</li> <li><strong>Append form to posts</strong> — an easy setting to automatically append a form to all posts (in a certain category).</li> <li><strong>Priority support</strong> — gain access to our 24/7 support team.</li> </ul> <p> <a href="https://www.mc4wp.com/pricing/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=extensions-page" class="button" style="background: #c44; border: #c44; color: white; padding: 6px 12px; height: auto; font-weight: bold;">Buy Mailchimp for WordPress Premium</a> <a href="https://www.mc4wp.com/premium-features/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=extensions-page"><span style="text-decoration: none; vertical-align: middle; margin-right: 6px;" class="dashicons dashicons-info"> </span>More information</a> </p> <p><em>Comes with <a href="https://www.mc4wp.com/refund-policy/">our 30-day no questions asked money back guarantee</a>.</em> </div> <hr /> <div class="mc4wp-margin-m"> <p>The following (free) add-on plugins are available for Mailchimp for WordPress.</p> <div> <h4><a href="https://wordpress.org/plugins/mailchimp-top-bar/">Mailchimp Top Bar</a></h4> <p>Adds a sign-up bar to the top or bottom of your site. A sure fire way to grow your lists.</p> </div> <div> <h4><a href="https://wordpress.org/plugins/mc4wp-wpml/">WPML Integration</a></h4> <p>Improved Mailchimp integration for multilingual sites using WPML.</p> </div> <div> <h4><a href="https://wordpress.org/plugins/boxzilla/">Boxzilla Pop-ups</a></h4> <p>Pop-ups for your sign-up forms.</p> </div> </div> </div> includes/views/general-settings.php 0000777 00000007134 15251522663 0013516 0 ustar 00 <?php defined('ABSPATH') or exit; ?> <div id="mc4wp-admin" class="wrap mc4wp-settings"> <p class="mc4wp-breadcrumbs"> <span class="prefix"><?php echo esc_html__('You are here: ', 'mailchimp-for-wp'); ?></span> <span class="current-crumb"><strong>Mailchimp for WordPress</strong></span> </p> <div class="mc4wp-row"> <div class="main-content mc4wp-col"> <h1 class="mc4wp-page-title"> Mailchimp for WordPress: <?php echo esc_html__('API Settings', 'mailchimp-for-wp'); ?> </h1> <h2 style="display: none;"></h2> <?php settings_errors(); $this->messages->show(); ?> <form action="<?php echo esc_attr(admin_url('options.php')); ?>" method="post"> <?php settings_fields('mc4wp_settings'); ?> <table class="form-table"> <tr valign="top"> <th scope="row"> <?php echo esc_html__('Status', 'mailchimp-for-wp'); ?> </th> <td> <?php if ($connected) { ?> <span class="mc4wp-status positive"><?php echo esc_html__('CONNECTED', 'mailchimp-for-wp'); ?></span> <?php } else { ?> <span class="mc4wp-status neutral"><?php echo esc_html__('NOT CONNECTED', 'mailchimp-for-wp'); ?></span> <?php } ?> </td> </tr> <tr valign="top"> <th scope="row"><label for="mailchimp_api_key"><?php echo esc_html__('API Key', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" placeholder="<?php echo esc_attr__('Your Mailchimp API key', 'mailchimp-for-wp'); ?>" id="mailchimp_api_key" name="mc4wp[api_key]" value="<?php echo esc_attr($obfuscated_api_key); ?>" <?php echo defined('MC4WP_API_KEY') ? 'readonly="readonly"' : ''; ?> /> <p class="description"> <?php echo esc_html__('The API key for connecting with your Mailchimp account.', 'mailchimp-for-wp'); ?> <a target="_blank" href="https://admin.mailchimp.com/account/api"><?php echo esc_html__('Get your API key here.', 'mailchimp-for-wp'); ?></a> </p> <?php if (defined('MC4WP_API_KEY')) { echo '<p class="description">', wp_kses(__('You defined your Mailchimp API key using the <code>MC4WP_API_KEY</code> constant.', 'mailchimp-for-wp'), [ 'code' => [] ]), '</p>'; } ?> </td> </tr> </table> <?php submit_button(); ?> </form> <?php do_action('mc4wp_admin_after_general_settings'); if (! empty($opts['api_key'])) { echo '<hr />'; include __DIR__ . '/parts/lists-overview.php'; } require __DIR__ . '/parts/admin-footer.php'; ?> </div> <div class="mc4wp-sidebar mc4wp-col"> <?php require __DIR__ . '/parts/admin-sidebar.php'; ?> </div> </div> </div> includes/class-debug-log-reader.php 0000777 00000006434 15251522663 0013320 0 ustar 00 <?php /** * Class MC4WP_Debug_Log_Reader */ class MC4WP_Debug_Log_Reader { /** * @var resource|null */ private $handle; /** * @var string */ private static $regex = '/^(\[[\d \-\:]+\]) (\w+\:) (.*)$/S'; /** * @var string */ private static $html_template = '<span class="time">$1</span> <span class="level">$2</span> <span class="message">$3</span>'; /** * @var string The log file location. */ private $file; /** * MC4WP_Debug_Log_Reader constructor. * * @param $file */ public function __construct($file) { $this->file = $file; } /** * @return string */ public function all() { return file_get_contents($this->file); } /** * Sets file pointer to $n of lines from the end of file. * * @param int $n */ private function seek_line_from_end($n) { $line_count = 0; // get line count while (! feof($this->handle)) { fgets($this->handle); ++$line_count; } // rewind to beginning rewind($this->handle); // calculate target $target = $line_count - $n; $target = $target > 1 ? $target : 1; // always skip first line because oh PHP header $current = 0; // keep reading until we're at target while ($current < $target) { fgets($this->handle); ++$current; } } /** * @return string|null */ public function read() { // open file if not yet opened if (! is_resource($this->handle)) { // doesn't exist? if (! file_exists($this->file)) { return null; } $this->handle = @fopen($this->file, 'r'); // unable to read? if (! is_resource($this->handle)) { return null; } // set pointer to 1000 files from EOF $this->seek_line_from_end(1000); } // stop reading once we're at the end if (feof($this->handle)) { fclose($this->handle); $this->handle = null; return null; } // read line, up to 8kb $text = fgets($this->handle); // strip tags & trim $text = strip_tags($text); $text = trim($text); return $text; } /** * @return string */ public function read_as_html() { $line = $this->read(); // null means end of file if (is_null($line)) { return null; } // empty string means empty line, but not yet eof if (empty($line)) { return ''; } $line = preg_replace(self::$regex, self::$html_template, $line); return $line; } /** * Reads X number of lines. * * If $start is negative, reads from end of log file. * * @param int $start * @param int $number * @return string */ public function lines($start, $number) { $handle = fopen($start, 'r'); $lines = ''; $current_line = 0; while ($current_line < $number) { $lines .= fgets($handle); } fclose($handle); return $lines; } } includes/forms/functions.php 0000777 00000003124 15251522663 0012237 0 ustar 00 <?php /** * Returns a Form instance * * @access public * * @param int|WP_Post $form_id. * * @return MC4WP_Form */ function mc4wp_get_form($form_id = 0) { return MC4WP_Form::get_instance($form_id); } /** * Get an array of Form instances * * @access public * * @param array $args Array of parameters * * @return MC4WP_Form[] */ function mc4wp_get_forms(array $args = []) { // parse function arguments $default_args = [ 'post_status' => 'publish', 'posts_per_page' => -1, 'ignore_sticky_posts' => true, 'no_found_rows' => true, ]; $args = array_merge($default_args, $args); // set post_type here so it can't be overwritten using function arguments $args['post_type'] = 'mc4wp-form'; $q = new WP_Query(); $posts = $q->query($args); $forms = []; foreach ($posts as $post) { try { $form = mc4wp_get_form($post); } catch (Exception $e) { continue; } $forms[] = $form; } return $forms; } /** * Echoes the given form * * @access public * * @param int $form_id * @param array $config * @param bool $echo * * @return string */ function mc4wp_show_form($form_id = 0, $config = [], $echo = true) { /** @var MC4WP_Form_Manager $forms */ $forms = mc4wp('forms'); return $forms->output_form($form_id, $config, $echo); } /** * Gets an instance of the submitted form, if any. * * @access public * * @return MC4WP_Form|null */ function mc4wp_get_submitted_form() { return mc4wp('forms')->get_submitted_form(); } includes/forms/class-asset-manager.php 0000777 00000017411 15251522663 0014065 0 ustar 00 <?php /** * This class takes care of all form assets related functionality * * @access private * @ignore */ class MC4WP_Form_Asset_Manager { /** * @var bool Flag to determine whether scripts should be enqueued. */ private $load_scripts = false; /** * @var bool Flag to determine whether email typo checker script should be enqueued. */ private $load_typo_checker = false; /** * Add hooks */ public function add_hooks() { add_action('init', [ $this, 'register_scripts' ]); add_action('wp_enqueue_scripts', [ $this, 'load_stylesheets' ]); add_action('wp_footer', [ $this, 'load_scripts' ]); add_action('mc4wp_output_form', [ $this, 'before_output_form' ]); add_action('script_loader_tag', [ $this, 'add_defer_attribute' ], 10, 2); } /** * Register scripts to be enqueued later. */ public function register_scripts() { wp_register_script('mc4wp-forms-api', mc4wp_plugin_url('assets/js/forms.js'), [], MC4WP_VERSION, true); wp_register_script('mc4wp-email-typo-checker', mc4wp_plugin_url('assets/js/email-typo-checker.js'), [], MC4WP_VERSION, ['strategy' => 'defer', 'in_footer' => true]); } /** * @param string $stylesheet * * @return bool */ public function is_registered_stylesheet($stylesheet) { $stylesheets = $this->get_registered_stylesheets(); return in_array($stylesheet, $stylesheets, true); } /** * @return array */ public function get_registered_stylesheets() { return [ 'basic', 'themes', ]; } /** * @param string $stylesheet * * @return string */ public function get_stylesheet_url($stylesheet) { return mc4wp_plugin_url('assets/css/form-' . $stylesheet . '.css'); } /** * Get array of stylesheet handles which should be enqueued. * * @return array */ public function get_active_stylesheets() { $stylesheets = (array) get_option('mc4wp_form_stylesheets', []); /** * Filters the stylesheets to be loaded * * Should be an array of stylesheet handles previously registered using `wp_register_style`. * Each value is prefixed with `mc4wp-form-` to get the handle. * * Return an empty array if you want to disable the loading of all stylesheets. * * @since 3.0 * @param array $stylesheets Array of valid stylesheet handles */ $stylesheets = (array) apply_filters('mc4wp_form_stylesheets', $stylesheets); return $stylesheets; } /** * Load the various stylesheets */ public function load_stylesheets() { $stylesheets = $this->get_active_stylesheets(); foreach ($stylesheets as $stylesheet) { if (! $this->is_registered_stylesheet($stylesheet)) { continue; } $handle = 'mc4wp-form-' . $stylesheet; $url = $this->get_stylesheet_url($stylesheet); wp_enqueue_style($handle, $url, [], MC4WP_VERSION); add_editor_style($url); } /** * @ignore */ do_action('mc4wp_load_form_stylesheets', $stylesheets); } /** * Get data object for client-side use for after a form is submitted over HTTP POST (not AJAX). * * @return array */ public function get_submitted_form_data() { $submitted_form = mc4wp_get_submitted_form(); if (! $submitted_form instanceof MC4WP_Form) { return null; } $data = [ 'id' => $submitted_form->ID, 'event' => $submitted_form->last_event, 'data' => $submitted_form->get_data(), 'element_id' => $submitted_form->config['element_id'], 'auto_scroll' => true, ]; if ($submitted_form->has_errors()) { $data['errors'] = $submitted_form->errors; } /** * Filters the `auto_scroll` setting for when a form is submitted. * Set to false to disable scrolling to form. * * @param boolean $auto_scroll * @since 3.0 */ $data['auto_scroll'] = apply_filters('mc4wp_form_auto_scroll', $data['auto_scroll']); return $data; } /** * Load JavaScript files */ public function before_output_form($form) { $load_scripts = apply_filters('mc4wp_load_form_scripts', true); if (! $load_scripts) { return; } $this->print_dummy_javascript(); $this->load_scripts = true; // check if this form has typo checker enabled if (! empty($form->settings['email_typo_check'])) { $this->load_typo_checker = true; } } /** * Prints dummy JavaScript which allows people to call `mc4wp.forms.on()` before the JS is loaded. */ public function print_dummy_javascript() { echo '<script>'; include __DIR__ . '/views/js/dummy-api.js'; echo '</script>'; } /** * Outputs the inline JavaScript that is used to enhance forms */ public function load_scripts() { $load_scripts = apply_filters('mc4wp_load_form_scripts', $this->load_scripts); if (! $load_scripts) { return; } // load general client-side form API wp_enqueue_script('mc4wp-forms-api'); // load email typo checker script only if at least one form has it enabled if ($this->load_typo_checker) { wp_enqueue_script('mc4wp-email-typo-checker'); wp_localize_script('mc4wp-email-typo-checker', 'mc4wp_email_typo_checker', [ 'suggestion_text' => __('Did you mean %s?', 'mailchimp-for-wp'), 'domains' => apply_filters('mc4wp_email_typo_checker_domains', [ 'gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com', 'icloud.com', 'aol.com', 'live.com', 'msn.com', 'me.com', 'mac.com', 'googlemail.com', 'ymail.com', 'protonmail.com', 'mail.com', 'gmx.com', 'zoho.com', ]), ]); } // maybe load JS file for when a form was submitted over HTTP POST $submitted_form_data = $this->get_submitted_form_data(); if ($submitted_form_data !== null) { wp_enqueue_script('mc4wp-forms-submitted', mc4wp_plugin_url('assets/js/forms-submitted.js'), [ 'mc4wp-forms-api' ], MC4WP_VERSION, true); wp_localize_script('mc4wp-forms-submitted', 'mc4wp_submitted_form', $submitted_form_data); } // print inline scripts echo '<script>'; echo '(function() {'; include __DIR__ . '/views/js/url-fields.js'; echo '})();'; echo '</script>'; /** @ignore */ do_action('mc4wp_load_form_scripts'); } /** * Adds `defer` attribute to all form-related `<script>` elements so they do not block page rendering. * * @param string $tag * @param string $handle * @return string */ public function add_defer_attribute($tag, $handle) { // only act on scripts registered with any of these handles if ($handle !== 'mc4wp-forms-api' && $handle !== 'mc4wp-forms-submitted') { return $tag; } // don't add twice if (strpos($tag, ' defer') !== false) { return $tag; } return str_replace(' src=', ' defer src=', $tag); } } includes/forms/class-admin.php 0000777 00000041356 15251522663 0012433 0 ustar 00 <?php /** * Class MC4WP_Forms_Admin * * @ignore * @access private */ class MC4WP_Forms_Admin { /** * @var MC4WP_Admin_Messages */ protected $messages; /** * @param MC4WP_Admin_Messages $messages */ public function __construct(MC4WP_Admin_Messages $messages) { $this->messages = $messages; } /** * Add hooks */ public function add_hooks() { add_action('register_shortcode_ui', [ $this, 'register_shortcake_ui' ]); add_action('mc4wp_save_form', [ $this, 'update_form_stylesheets' ]); add_action('mc4wp_admin_edit_form', [ $this, 'process_save_form' ]); add_action('mc4wp_admin_add_form', [ $this, 'process_add_form' ]); add_filter('mc4wp_admin_menu_items', [ $this, 'add_menu_item' ], 5); add_action('mc4wp_admin_show_forms_page-edit-form', [ $this, 'show_edit_page' ]); add_action('mc4wp_admin_show_forms_page-add-form', [ $this, 'show_add_page' ]); add_action('mc4wp_admin_enqueue_assets', [ $this, 'enqueue_assets' ], 10, 2); add_action('enqueue_block_editor_assets', [ $this, 'enqueue_gutenberg_assets' ]); } public function enqueue_gutenberg_assets() { wp_enqueue_script('mc4wp-form-block', mc4wp_plugin_url('assets/js/forms-block.js'), [ 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-components' ]); $forms = mc4wp_get_forms(); $data = []; foreach ($forms as $form) { $data[] = [ 'name' => $form->name, 'id' => $form->ID, ]; } wp_localize_script('mc4wp-form-block', 'mc4wp_forms', $data); } /** * @param string $suffix * @param string $page */ public function enqueue_assets($suffix, $page = '') { if ($page !== 'forms' || empty($_GET['view']) || $_GET['view'] !== 'edit-form') { return; } wp_register_script('mc4wp-forms-admin', mc4wp_plugin_url('assets/js/forms-admin.js'), [ 'mc4wp-admin' ], MC4WP_VERSION, true); wp_enqueue_script('mc4wp-forms-admin'); wp_localize_script( 'mc4wp-forms-admin', 'mc4wp_forms_i18n', [ 'addToForm' => __('Add to form', 'mailchimp-for-wp'), 'agreeToTerms' => __('I have read and agree to the terms & conditions', 'mailchimp-for-wp'), 'agreeToTermsShort' => __('Agree to terms', 'mailchimp-for-wp'), 'agreeToTermsLink' => __('Link to your terms & conditions page', 'mailchimp-for-wp'), 'city' => __('City', 'mailchimp-for-wp'), 'checkboxes' => __('Checkboxes', 'mailchimp-for-wp'), 'choices' => __('Choices', 'mailchimp-for-wp'), 'choiceType' => __('Choice type', 'mailchimp-for-wp'), 'chooseField' => __('Choose a field to add to the form', 'mailchimp-for-wp'), 'close' => __('Close', 'mailchimp-for-wp'), 'country' => __('Country', 'mailchimp-for-wp'), 'dropdown' => __('Dropdown', 'mailchimp-for-wp'), 'emailAddress' => __('Email address', 'mailchimp-for-wp'), 'fieldType' => __('Field type', 'mailchimp-for-wp'), 'fieldLabel' => __('Field label', 'mailchimp-for-wp'), 'formAction' => __('Form action', 'mailchimp-for-wp'), 'formActionDescription' => __('This field will allow your visitors to choose whether they would like to subscribe or unsubscribe', 'mailchimp-for-wp'), 'formFields' => __('Form fields', 'mailchimp-for-wp'), 'forceRequired' => __('This field is marked as required in Mailchimp.', 'mailchimp-for-wp'), 'initialValue' => __('Initial value', 'mailchimp-for-wp'), 'interestCategories' => __('Interest categories', 'mailchimp-for-wp'), 'isFieldRequired' => __('Is this field required?', 'mailchimp-for-wp'), 'listChoice' => __('Audience choice', 'mailchimp-for-wp'), 'listChoiceDescription' => __('This field will allow your visitors to choose an audience to subscribe to.', 'mailchimp-for-wp'), 'listFields' => __('Audience fields', 'mailchimp-for-wp'), 'min' => __('Min', 'mailchimp-for-wp'), 'max' => __('Max', 'mailchimp-for-wp'), 'noAvailableFields' => __('No available fields. Did you select a Mailchimp list in the form settings?', 'mailchimp-for-wp'), 'optional' => __('Optional', 'mailchimp-for-wp'), 'placeholder' => __('Placeholder', 'mailchimp-for-wp'), 'placeholderHelp' => __('Text to show when field has no value.', 'mailchimp-for-wp'), 'preselect' => __('Preselect', 'mailchimp-for-wp'), 'remove' => __('Remove', 'mailchimp-for-wp'), 'radioButtons' => __('Radio buttons', 'mailchimp-for-wp'), 'streetAddress' => __('Street Address', 'mailchimp-for-wp'), 'state' => __('State', 'mailchimp-for-wp'), 'subscribe' => __('Subscribe', 'mailchimp-for-wp'), 'submitButton' => __('Submit button', 'mailchimp-for-wp'), 'wrapInParagraphTags' => __('Wrap in paragraph tags?', 'mailchimp-for-wp'), 'value' => __('Value', 'mailchimp-for-wp'), 'valueHelp' => __('Text to prefill this field with.', 'mailchimp-for-wp'), 'zip' => __('ZIP', 'mailchimp-for-wp'), ] ); } /** * @param $items * * @return mixed */ public function add_menu_item($items) { $items['forms'] = [ 'title' => esc_html__('Forms', 'mailchimp-for-wp'), 'text' => esc_html__('Form', 'mailchimp-for-wp'), 'slug' => 'forms', 'callback' => [ $this, 'show_forms_page' ], 'load_callback' => [ $this, 'redirect_to_form_action' ], 'position' => 10, ]; return $items; } /** * Act on the "add form" form */ public function process_add_form() { $form_data = $_POST['mc4wp_form']; $form_content = include MC4WP_PLUGIN_DIR . '/config/default-form-content.php'; // Fix for MultiSite stripping KSES for roles other than administrator remove_all_filters('content_save_pre'); $form_id = wp_insert_post( [ 'post_type' => 'mc4wp-form', 'post_status' => 'publish', 'post_title' => $form_data['name'], 'post_content' => $form_content, ] ); // if settings were passed, save those too. if (isset($form_data['settings'])) { update_post_meta($form_id, '_mc4wp_settings', $form_data['settings']); } // set default form ID $this->set_default_form_id($form_id); $this->messages->flash(esc_html__('Form saved.', 'mailchimp-for-wp')); $edit_form_url = mc4wp_get_edit_form_url($form_id); wp_redirect($edit_form_url); exit; } /** * Saves a form to the database * @param int $form_id * @param array $data * @return int */ private function save_form($form_id, array $data) { $keys = [ 'settings' => [], 'messages' => [], 'name' => '', 'content' => '', ]; $data = array_merge($keys, $data); $data = $this->sanitize_form_data($data); $post_data = [ 'ID' => $form_id, 'post_type' => 'mc4wp-form', 'post_status' => ! empty($data['status']) ? $data['status'] : 'publish', 'post_title' => $data['name'], 'post_content' => $data['content'], ]; // Fix for MultiSite stripping KSES for roles other than administrator remove_all_filters('content_save_pre'); wp_insert_post($post_data); // merge new settings with current settings to allow passing partial data $current_settings = get_post_meta($form_id, '_mc4wp_settings', true); if (is_array($current_settings)) { $data['settings'] = array_merge($current_settings, $data['settings']); } update_post_meta($form_id, '_mc4wp_settings', $data['settings']); // save form messages in individual meta keys foreach ($data['messages'] as $key => $message) { update_post_meta($form_id, 'text_' . $key, $message); } /** * Runs right after a form is updated. * * @since 3.0 * * @param int $form_id */ do_action('mc4wp_save_form', $form_id); return $form_id; } /** * @param array $data * @return array */ public function sanitize_form_data(array $data) { $raw_data = $data; // strip <form> tags from content $data['content'] = preg_replace('/<\/?form(.|\s)*?>/i', '', $data['content']); // replace lowercased name="name" to prevent 404 $data['content'] = str_ireplace(' name=\"name\"', ' name=\"NAME\"', $data['content']); // sanitize text fields $data['settings']['redirect'] = sanitize_text_field($data['settings']['redirect']); // strip tags from messages foreach ($data['messages'] as $key => $message) { $data['messages'][ $key ] = strip_tags($message, '<strong><b><br><a><script><u><em><i><span><img>'); } // make sure lists is an array if (! isset($data['settings']['lists'])) { $data['settings']['lists'] = []; } $data['settings']['lists'] = array_filter((array) $data['settings']['lists']); // if current user can not post unfiltered HTML, run HTML through whitelist using wp_kses if (! current_user_can('unfiltered_html')) { $data['content'] = mc4wp_kses($data['content']); foreach ($data['messages'] as $key => $message) { $data['messages'][ $key ] = mc4wp_kses($data['messages'][ $key ]); } } /** * Filters the form data just before it is saved. * * @param array $data Sanitized array of form data. * @param array $raw_data Raw array of form data. * * @since 3.0.8 * @ignore */ $data = (array) apply_filters('mc4wp_form_sanitized_data', $data, $raw_data); return $data; } /** * Saves a form */ public function process_save_form() { // save global settings (if submitted) if (isset($_POST['mc4wp']) && is_array($_POST['mc4wp'])) { $options = get_option('mc4wp', []); $posted = $_POST['mc4wp']; foreach ($posted as $key => $value) { $options[ $key ] = trim($value); } update_option('mc4wp', $options); } // update form, settings and messages $form_id = (int) $_POST['mc4wp_form_id']; $form_data = $_POST['mc4wp_form']; $this->save_form($form_id, $form_data); $this->set_default_form_id($form_id); $this->messages->flash(esc_html__('Form saved.', 'mailchimp-for-wp')); } /** * @param int $form_id */ private function set_default_form_id($form_id) { $default_form_id = get_option('mc4wp_default_form_id', 0); if (empty($default_form_id)) { update_option('mc4wp_default_form_id', $form_id); } } /** * Goes through each form and aggregates array of stylesheet slugs to load. * * @hooked `mc4wp_save_form` */ public function update_form_stylesheets() { $stylesheets = []; $forms = mc4wp_get_forms(); foreach ($forms as $form) { $stylesheet = $form->get_stylesheet(); if (! empty($stylesheet) && ! in_array($stylesheet, $stylesheets, true)) { $stylesheets[] = $stylesheet; } } update_option('mc4wp_form_stylesheets', $stylesheets); } /** * Redirect to correct form action * * @ignore */ public function redirect_to_form_action() { if (! empty($_GET['view'])) { return; } try { // try default form first $default_form = mc4wp_get_form(); $redirect_url = mc4wp_get_edit_form_url($default_form->ID); } catch (Exception $e) { // no default form, query first available form and go there $forms = mc4wp_get_forms( [ 'posts_per_page' => 1, 'orderby' => 'ID', 'order' => 'ASC', ] ); if (count($forms) > 0) { // take first form and use it to go to the "edit form" screen $form = array_shift($forms); $redirect_url = mc4wp_get_edit_form_url($form->ID); } else { // we don't have a form yet, go to "add new" screen $redirect_url = mc4wp_get_add_form_url(); } } if (headers_sent()) { echo sprintf('<meta http-equiv="refresh" content="0;url=%s" />', $redirect_url); } else { wp_redirect($redirect_url); } exit; } /** * Show the Forms Settings page * * @internal */ public function show_forms_page() { $view = ! empty($_GET['view']) ? $_GET['view'] : ''; /** * @ignore */ do_action('mc4wp_admin_show_forms_page', $view); /** * @ignore */ do_action('mc4wp_admin_show_forms_page-' . $view); } /** * Show the "Edit Form" page * * @internal */ public function show_edit_page() { $form_id = ! empty($_GET['form_id']) ? (int) $_GET['form_id'] : 0; $mailchimp = new MC4WP_MailChimp(); $lists = $mailchimp->get_lists(); try { $form = mc4wp_get_form($form_id); } catch (Exception $e) { echo '<h2>', esc_html__('Form not found.', 'mailchimp-for-wp'), '</h2>'; echo '<p>', $e->getMessage(), '</p>'; echo '<p><a href="javascript:history.go(-1);"> ‹ ', esc_html__('Go back', 'mailchimp-for-wp'), '</a></p>'; return; } $opts = $form->settings; $active_tab = isset($_GET['tab']) ? trim($_GET['tab']) : 'fields'; $form_preview_url = add_query_arg( [ 'mc4wp_preview_form' => $form_id, ], site_url('/', 'admin') ); require __DIR__ . '/views/edit-form.php'; } /** * Shows the "Add Form" page * * @internal */ public function show_add_page() { $mailchimp = new MC4WP_MailChimp(); $lists = $mailchimp->get_lists(); $number_of_lists = count($lists); require __DIR__ . '/views/add-form.php'; } /** * Get URL for a tab on the current page. * * @since 3.0 * @internal * @param $tab * @return string */ public function tab_url($tab) { return add_query_arg([ 'tab' => $tab ], remove_query_arg('tab')); } /** * Registers UI for when shortcake is activated */ public function register_shortcake_ui() { $assets = new MC4WP_Form_Asset_Manager(); $assets->load_stylesheets(); $forms = mc4wp_get_forms(); $options = []; foreach ($forms as $form) { $options[ $form->ID ] = $form->name; } /** * Register UI for your shortcode * * @param string $shortcode_tag * @param array $ui_args */ shortcode_ui_register_for_shortcode( 'mc4wp_form', [ 'label' => esc_html__('Mailchimp Sign-Up Form', 'mailchimp-for-wp'), 'listItemImage' => 'dashicons-feedback', 'attrs' => [ [ 'label' => esc_html__('Select the form to show', 'mailchimp-for-wp'), 'attr' => 'id', 'type' => 'select', 'options' => $options, ], ], ] ); } } includes/forms/class-form.php 0000777 00000052643 15251522663 0012307 0 ustar 00 <?php /** * Class MC4WP_Form * * Represents a Form object. * * To get a form instance, use `mc4wp_get_form( $id );` where `$id` is the post ID. * * @access public * @since 3.0 */ class MC4WP_Form { /** * @var array Array of instantiated form objects. */ public static $instances = []; /** * @param int $post_id * @throws Exception */ public static function throw_not_found_exception($post_id) { $message = sprintf(__('There is no form with ID %d, perhaps it was deleted?', 'mailchimp-for-wp'), $post_id); throw new Exception($message); } /** * Get a shared form instance. * * @param WP_Post|int $post Post instance or post ID. * @return MC4WP_Form * @throws Exception */ public static function get_instance($post = 0) { if ($post instanceof WP_Post) { $post_id = $post->ID; } else { $post_id = (int) $post; if ($post_id === 0) { $post_id = (int) get_option('mc4wp_default_form_id', 0); } } if ($post_id === 0) { self::throw_not_found_exception($post_id); } if (isset(self::$instances[ $post_id ])) { return self::$instances[ $post_id ]; } // get post object if we don't have it by now if (! $post instanceof WP_Post) { $post = get_post($post_id); } // check post object if (! $post instanceof WP_Post || $post->post_type !== 'mc4wp-form') { self::throw_not_found_exception($post_id); } // get all post meta in single call for performance $post_meta = (array) get_post_meta($post_id); $form = new MC4WP_Form($post_id, $post, $post_meta); // store instance self::$instances[ $post_id ] = $form; return $form; } /** * @var int The form ID, matches the underlying post its ID */ public $ID = 0; /** * @var string The form name */ public $name = 'Default Form'; /** * @var string The form HTML content */ public $content = ''; /** * @var array Array of settings */ public $settings = []; /** * @var array Array of messages */ public $messages = []; /** * @var array Array of notices to be shown when this form is rendered */ public $notices = []; /** * @var array Array of error codes */ public $errors = []; /** * @var bool Was this form submitted? */ public $is_submitted = false; /** * @var array Array of the data that was submitted, in name => value pairs. * * Keys in this array are uppercased and keys starting with _ are stripped. */ private $data = []; /** * @var array Array of the raw form data that was submitted. */ public $raw_data = []; /** * @var array */ public $config = [ 'action' => 'subscribe', 'lists' => [], 'email_type' => '', 'element_id' => '', ]; /** * @var string */ public $last_event = ''; /** * @var string */ public $status; /** * @param int $id The post ID * @param WP_Post $post * @param array $post_meta */ public function __construct($id, WP_Post $post, array $post_meta = []) { $this->ID = (int) $id; $this->name = $post->post_title; $this->content = $post->post_content; $this->status = $post->post_status; $this->settings = $this->load_settings($post_meta); $this->messages = $this->load_messages($post_meta); // update config from settings $this->config['lists'] = $this->settings['lists']; } /** * @param string $name * * @return mixed */ public function __get($name) { $method_name = "get_$name"; if (method_exists($this, $method_name)) { return $this->$method_name(); } } /** * Gets the form response string * * This does not take the submitted form element into account. * * @see MC4WP_Form_Element::get_response_html() * * @return string */ public function get_response_html() { return $this->get_element()->get_response_html(true); } /** * @param string $element_id * @param array $config * @return MC4WP_Form_element */ public function get_element($element_id = 'mc4wp-form', array $config = []) { return new MC4WP_Form_Element($this, $element_id, $config); } /** * Get HTML string for this form. * * If you want to output a form, use `mc4wp_show_form` instead as it. * * @param string $element_id * @param array $config * * @return string */ public function get_html($element_id = 'mc4wp-form', array $config = []) { $element = $this->get_element($element_id, $config); $html = $element->generate_html(); return $html; } /** * @param array $post_meta * @return array */ protected function load_settings(array $post_meta = []) { $form = $this; $default_settings = include MC4WP_PLUGIN_DIR . '/config/default-form-settings.php'; // start with defaults $settings = $default_settings; // get custom settings from meta if (! empty($post_meta['_mc4wp_settings'])) { $meta = $post_meta['_mc4wp_settings'][0]; $meta = (array) maybe_unserialize($meta); // ensure lists is an array if (empty($meta['lists'])) { $meta['lists'] = []; } // merge with current settings (defaults) $settings = array_merge($settings, $meta); } /** * Filters the form settings * * @since 3.0 * * @param array $settings * @param MC4WP_Form $form */ $settings = (array) apply_filters('mc4wp_form_settings', $settings, $form); return $settings; } /** * @param array $post_meta * @return array */ protected function load_messages(array $post_meta = []) { $form = $this; // get default messages $default_messages = include MC4WP_PLUGIN_DIR . '/config/default-form-messages.php'; // start with default messages $messages = $default_messages; /** * Filters the default form messages * * @since 3.0 * * @param array $messages * @param MC4WP_Form $form */ $messages = (array) apply_filters('mc4wp_form_messages', $messages, $form); // for backwards compatiblity, grab text of each message (if is array) foreach ($messages as $key => $message) { if (is_array($message) && isset($message['text'])) { $messages[ $key ] = $message['text']; } } foreach ($messages as $key => $message_text) { // overwrite default text with text in form meta. if (isset($post_meta[ 'text_' . $key ][0])) { $message_text = $post_meta[ 'text_' . $key ][0]; } // run final value through gettext filter to allow translation of stored setting values $messages[ $key ] = __($message_text, 'mailchimp-for-wp'); } return $messages; } /** * Does this form has a field of the given type? * * @param string $type * * @return bool */ public function has_field_type($type) { return in_array(strtolower($type), $this->get_field_types(), true); } /** * Get an array of field types which are present in this form. * * @return array */ public function get_field_types() { preg_match_all('/type=\"(\w+)?\"/', strtolower($this->content), $result); $field_types = $result[1]; return $field_types; } /** * Add notice to this form when it is rendered * @param string $text * @param string $type */ public function add_notice($text, $type = 'notice') { $this->notices[] = new MC4WP_Form_Notice($text, $type); } /** * Output this form * * @return string */ public function __toString() { return mc4wp_show_form($this->ID, [], false); } /** * Get "redirect to url after success" setting for this form * * @return string */ public function get_redirect_url() { $form = $this; $url = trim($this->settings['redirect']); /** * Filters the redirect URL setting * * @since 3.0 * * @param string $url * @param MC4WP_Form $form */ $url = (string) apply_filters('mc4wp_form_redirect_url', $url, $form); return $url; } /** * Is this form valid? * * Will always return true if the form is not yet submitted. Otherwise, it will run validation and store any errors. * This method should be called before `get_errors()` * * @return bool */ public function validate() { if (! $this->is_submitted) { return true; } $form = $this; $errors = []; if (empty($this->config['lists'])) { $errors[] = 'no_lists_selected'; } // perform some basic anti-spam checks // User-Agent header should be set and not bot-like if (empty($_SERVER['HTTP_USER_AGENT']) || preg_match('/bot|crawl|spider|seo|lighthouse|facebookexternalhit|preview/', strtolower($_SERVER['HTTP_USER_AGENT']))) { $errors[] = 'spam.user_agent'; // _mc4wp_timestamp field should be between 30 days ago (to deal with aggressively cached pages) and 2 seconds ago } elseif (! isset($this->raw_data['_mc4wp_timestamp']) || $this->raw_data['_mc4wp_timestamp'] < (time() - DAY_IN_SECONDS * 90) || $this->raw_data['_mc4wp_timestamp'] > ( time() - 2 )) { $errors[] = 'spam.timestamp'; // _mc4wp_honeypot field should be submitted and empty } elseif (! isset($this->raw_data['_mc4wp_honeypot']) || '' !== $this->raw_data['_mc4wp_honeypot']) { $errors[] = 'spam.honeypot'; } if (empty($errors)) { // validate email field if (empty($this->data['EMAIL']) || ! is_email($this->data['EMAIL'])) { $errors[] = 'invalid_email'; } // validate other required fields foreach ($this->get_required_fields() as $field) { $value = mc4wp_array_get($this->data, $field); // check for empty string or array here instead of empty() since we want to allow for "0" values. if ($value === '' || $value === []) { $errors[] = 'required_field_missing'; break; } } } /** * Filters whether this form has errors. Runs only when a form is submitted. * Expects an array of message keys with an error type (string). * * Beware: all non-string values added to this array will be filtered out. * * @since 3.0 * * @param array $errors * @param MC4WP_Form $form */ $errors = (array) apply_filters('mc4wp_form_errors', $errors, $form); // filter out all non-string values $this->errors = array_filter($errors, 'is_string'); // return whether we have errors return ! $this->has_errors(); } /** * Handle an incoming request. Should be called before calling validate() method. * * @see MC4WP_Form::validate * @param array $data * @return void */ public function handle_request(array $data) { $this->is_submitted = true; $this->raw_data = $data; $this->data = $this->parse_request_data($data); $this->last_event = ''; // update form configuration from given data $config = []; $map = [ '_mc4wp_lists' => 'lists', '_mc4wp_action' => 'action', '_mc4wp_form_element_id' => 'element_id', '_mc4wp_email_type' => 'email_type', ]; // use isset here to allow empty lists (which should show a notice) foreach ($map as $param_key => $config_key) { if (isset($this->raw_data[ $param_key ])) { $value = $this->raw_data[ $param_key ]; if (is_array($value)) { $value = array_filter($value); } $config[ $config_key ] = $value; } } if (! empty($config)) { $this->set_config($config); } } /** * Parse a request for data which should be binded to `$data` property. * * This does the following on all post data. * * - Removes fields starting with an underscore. * - Remove fields which are set to be ignored. * - Uppercase all field names * * @param array $data * * @return array */ protected function parse_request_data(array $data) { $form = $this; $filtered = []; $ignored_field_names = []; /** * Filters field names which should be ignored when showing data. * * @since 3.0 * * @param array $ignored_field_names Array of ignored field names * @param MC4WP_Form $form The form instance. */ $ignored_field_names = apply_filters('mc4wp_form_ignored_field_names', $ignored_field_names, $form); foreach ($data as $key => $value) { // skip fields in ignored field names if ($key[0] === '_' || in_array($key, $ignored_field_names, true)) { continue; } // uppercase key $key = strtoupper($key); // filter empty array values if (is_array($value)) { $value = array_filter($value); } $filtered[ $key ] = $value; } return $filtered; } /** * Update configuration for this form * * @param array $config * @return array */ public function set_config(array $config) { $this->config = array_merge($this->config, $config); // make sure lists is an array if (! is_array($this->config['lists'])) { $this->config['lists'] = array_map('trim', explode(',', $this->config['lists'])); } // make sure action is valid if (! in_array($this->config['action'], [ 'subscribe', 'unsubscribe' ], true)) { $this->config['action'] = 'subscribe'; } // email_type should be a valid value if (! in_array($this->config['email_type'], [ 'html', 'text' ], true)) { $this->config['email_type'] = ''; } return $this->config; } /** * Get ID's of Mailchimp lists this form subscribes to * * @return array */ public function get_lists() { $lists = $this->config['lists']; $form = $this; /** * Filters Mailchimp lists new subscribers should be added to. * * @param array $lists */ $lists = (array) apply_filters('mc4wp_lists', $lists); /** * Filters Mailchimp lists new subscribers coming from this form should be added to. * * @param array $lists * @param MC4WP_Form $form */ $lists = (array) apply_filters('mc4wp_form_lists', $lists, $form); // filter out empty array elements $lists = array_filter($lists); return $lists; } /** * Does this form have errors? * * Should always evaluate to false when form has not been submitted. * * @see `mc4wp_form_errors` filter. * @return bool */ public function has_errors() { return count($this->errors) > 0; } /** * Add an error to this form * * @param string $error_code */ public function add_error($error_code) { // only add each error once if (! in_array($error_code, $this->errors, true)) { $this->errors[] = $error_code; } } /** * Get the form action * * Valid return values are "subscribe" and "unsubscribe" * * @return string */ public function get_action() { return $this->config['action']; } /** * @return array */ public function get_data() { $data = $this->data; $form = $this; /** * Filters the form data. * * @param array $data * @param MC4WP_Form $form */ $data = apply_filters('mc4wp_form_data', $data, $form); return $data; } /** * @return array */ public function get_raw_data() { return $this->raw_data; } /** * Get array of name attributes for the required fields in this form. * * @return array */ public function get_required_fields() { $form = $this; // explode required fields (generated in JS) to an array (uppercased) $required_fields_string = strtoupper($this->settings['required_fields']); // remove array-formatted fields // workaround for #261 (https://github.com/ibericode/mailchimp-for-wordpress/issues/261) $required_fields_string = preg_replace('/\[\w+\]/', '', $required_fields_string); // turn into an array $required_fields = explode(',', $required_fields_string); // EMAIL is not a required field as it has its own validation rules $required_fields = array_diff($required_fields, [ 'EMAIL' ]); // filter duplicate & empty values $required_fields = array_unique($required_fields); $required_fields = array_filter($required_fields); // fix uppercased subkeys, see https://github.com/ibericode/mailchimp-for-wordpress/issues/516 foreach ($required_fields as $key => $value) { $pos = strpos($value, '.'); if ($pos > 0) { $required_fields[ $key ] = substr($value, 0, $pos) . strtolower(substr($value, $pos)); } } /** * Filters the required fields for a form * * By default, this holds the following fields. * * - All fields which are required for the selected Mailchimp lists * - All fields in the form with a `required` attribute. * * @param array $required_fields * @param MC4WP_Form $form */ $required_fields = (array) apply_filters('mc4wp_form_required_fields', $required_fields, $form); return $required_fields; } /** * Get "email_type" setting for new Mailchimp subscribers added by this form. * * @return string */ public function get_email_type() { $email_type = $this->config['email_type']; if (empty($email_type)) { $email_type = mc4wp_get_email_type(); } return $email_type; } /** * Gets the filename of the stylesheet to load for this form. * * @return string */ public function get_stylesheet() { $stylesheet = $this->settings['css']; if (empty($stylesheet)) { return ''; } // form themes live in the same stylesheet if (strpos($stylesheet, 'theme-') !== false) { $stylesheet = 'themes'; } return $stylesheet; } /** * @param string $key * @return string */ public function get_message($key) { // default to generic error message $message = $this->messages['error']; // if error key contains a dot, use only part before the dot (example: spam.honeypot) if (($dot_pos = strpos($key, '.')) !== false) { $key = substr($key, 0, $dot_pos); } // if a more specific message exists for this error key, use that if (isset($this->messages[$key])) { $message = $this->messages[$key]; } if ($key === 'no_lists_selected' && current_user_can('manage_options')) { $message .= sprintf(' (<a href="%s">%s</a>)', mc4wp_get_edit_form_url($this->ID, 'settings'), 'edit form settings'); } return $message; } /** * @since 4.4 * @return array */ public function get_subscriber_tags() { $tags = []; // Add active tags $tags = array_merge($tags, $this->parse_tags_from_setting($this->settings['subscriber_tags'], 'active')); // Add inactive (remove) tags $tags = array_merge($tags, $this->parse_tags_from_setting($this->settings['remove_subscriber_tags'], 'inactive')); return $tags; } /** * Parse comma-separated tags from a setting into Mailchimp API format * * @since 4.10.10 * @param string $setting_value * @param string $status * @return array */ private function parse_tags_from_setting($setting_value, $status) { $tags = []; foreach (explode(',', $setting_value) as $v) { $v = trim($v); if ($v == '') { continue; } $tags[] = ['name' => $v, 'status' => $status]; } return $tags; } } includes/forms/class-form-message.php 0000777 00000001076 15251522663 0013723 0 ustar 00 <?php /** * Class MC4WP_Form_Notice * * @ignore * @access private */ class MC4WP_Form_Notice { /** * @var string */ public $type = 'error'; /** * @var string */ public $text; /** * @param string $text * @param string $type */ public function __construct($text, $type = 'error') { $this->text = $text; if (! empty($type)) { $this->type = $type; } } /** * @return string */ public function __toString() { return $this->text; } } includes/forms/class-form-listener.php 0000777 00000026324 15251522663 0014127 0 ustar 00 <?php /** * Class MC4WP_Form_Listener * * @since 3.0 * @access private */ class MC4WP_Form_Listener { /** * @var MC4WP_Form The submitted form instance */ public $submitted_form; public function add_hooks() { add_action('init', [ $this, 'listen' ]); } /** * Listen for submitted forms * @return bool */ public function listen() { if (empty($_POST['_mc4wp_form_id'])) { return false; } // get form instance try { $form_id = (int) $_POST['_mc4wp_form_id']; $form = mc4wp_get_form($form_id); } catch (Exception $e) { return false; } // sanitize request data $request_data = $_POST; $request_data = mc4wp_sanitize_deep($request_data); $request_data = stripslashes_deep($request_data); // bind request to form & validate $form->handle_request($request_data); $form->validate(); // store submitted form $this->submitted_form = $form; // did form have errors? if (! $form->has_errors()) { switch ($form->get_action()) { case 'subscribe': $this->process_subscribe_form($form); break; case 'unsubscribe': $this->process_unsubscribe_form($form); break; } } else { foreach ($form->errors as $error_code) { $form->add_notice($form->get_message($error_code), 'error'); } $this->get_log()->info(sprintf('Form %d > Submitted with errors: %s', $form->ID, join(', ', $form->errors))); } $this->respond($form); return true; } /** * Process a subscribe form. * * @param MC4WP_Form $form */ public function process_subscribe_form(MC4WP_Form $form) { $result = false; $mailchimp = new MC4WP_MailChimp(); $email_type = $form->get_email_type(); $data = $form->get_data(); $ip_address = mc4wp_get_request_ip_address(); /** @var MC4WP_MailChimp_Subscriber $subscriber */ $subscriber = null; // create a map of all lists with list-specific data $mapper = new MC4WP_List_Data_Mapper($data, $form->get_lists()); /** @var MC4WP_MailChimp_Subscriber[] $map */ $map = $mapper->map(); // loop through lists foreach ($map as $list_id => $subscriber) { $subscriber->status = $form->settings['double_optin'] ? 'pending' : 'subscribed'; $subscriber->email_type = $email_type; $subscriber->ip_signup = $ip_address; $subscriber->tags = $form->get_subscriber_tags(); /** * Filters subscriber data before it is sent to Mailchimp. Fires for both form & integration requests. * * @param MC4WP_MailChimp_Subscriber $subscriber * @param string $list_id ID of the Mailchimp list this subscriber will be added/updated in */ $subscriber = apply_filters('mc4wp_subscriber_data', $subscriber, $list_id); if (! $subscriber instanceof MC4WP_MailChimp_Subscriber) { continue; } /** * Filters subscriber data before it is sent to Mailchimp. Only fires for form requests. * * @param MC4WP_MailChimp_Subscriber $subscriber * @param string $list_id ID of the Mailchimp list this subscriber will be added/updated in */ $subscriber = apply_filters('mc4wp_form_subscriber_data', $subscriber, $list_id); if (! $subscriber instanceof MC4WP_MailChimp_Subscriber) { continue; } // send a subscribe request to Mailchimp for each list $result = $mailchimp->list_subscribe($list_id, $subscriber->email_address, $subscriber->to_array(), $form->settings['update_existing'], $form->settings['replace_interests']); } $log = $this->get_log(); // do stuff on failure if (! is_object($result) || empty($result->id)) { $error_code = $mailchimp->get_error_code(); $error_message = $mailchimp->get_error_message(); if ((int) $mailchimp->get_error_code() === 214) { $form->add_error('already_subscribed'); $form->add_notice($form->messages['already_subscribed'], 'notice'); $log->warning(sprintf('Form %d > %s is already subscribed to the selected list(s)', $form->ID, $data['EMAIL'])); } else { $form->add_error($error_code); $form->add_notice($form->messages['error'], 'error'); $log->error(sprintf('Form %d > Mailchimp API error: %s %s', $form->ID, $error_code, $error_message)); /** * Fire action hook so API errors can be hooked into. * * @param MC4WP_Form $form * @param string $error_message */ do_action('mc4wp_form_api_error', $form, $error_message); } // bail return; } // Success! Did we update or newly subscribe? if ($result->status === 'subscribed' && $result->was_already_on_list) { $form->last_event = 'updated_subscriber'; $form->add_notice($form->messages['updated'], 'success'); $log->info(sprintf('Form %d > Successfully updated %s', $form->ID, $data['EMAIL'])); /** * Fires right after a form was used to update an existing subscriber. * * @since 3.0 * * @param MC4WP_Form $form Instance of the submitted form * @param string $email * @param array $data */ do_action('mc4wp_form_updated_subscriber', $form, $subscriber->email_address, $data); } else { $form->last_event = 'subscribed'; $form->add_notice($form->messages['subscribed'], 'success'); $log->info(sprintf('Form %d > Successfully subscribed %s', $form->ID, $data['EMAIL'])); /** * Fires right after a form was used to add a new subscriber. * * @since 4.8.13 * * @param MC4WP_Form $form Instance of the submitted form * @param string $email * @param array $data */ do_action('mc4wp_form_added_subscriber', $form, $subscriber->email_address, $data); } /** * Fires right after a form was used to add a new subscriber (or update an existing one). * * @since 3.0 * * @param MC4WP_Form $form Instance of the submitted form * @param string $email * @param array $data * @param MC4WP_MailChimp_Subscriber[] $subscriber */ do_action('mc4wp_form_subscribed', $form, $subscriber->email_address, $data, $map); } /** * @param MC4WP_Form $form */ public function process_unsubscribe_form(MC4WP_Form $form) { $mailchimp = new MC4WP_MailChimp(); $log = $this->get_log(); $result = null; $data = $form->get_data(); // unsubscribe from each list foreach ($form->get_lists() as $list_id) { $result = $mailchimp->list_unsubscribe($list_id, $data['EMAIL']); } if (! $result) { $form->add_notice($form->messages['error'], 'error'); $log->error(sprintf('Form %d > Mailchimp API error: %s', $form->ID, $mailchimp->get_error_message())); // bail return; } // Success! Unsubscribed. $form->last_event = 'unsubscribed'; $form->add_notice($form->messages['unsubscribed'], 'notice'); $log->info(sprintf('Form %d > Successfully unsubscribed %s', $form->ID, $data['EMAIL'])); /** * Fires right after a form was used to unsubscribe. * * @since 3.0 * * @param MC4WP_Form $form Instance of the submitted form. * @param string $email */ do_action('mc4wp_form_unsubscribed', $form, $data['EMAIL']); } /** * @param MC4WP_Form $form */ public function respond(MC4WP_Form $form) { $success = ! $form->has_errors(); if ($success) { /** * Fires right after a form is submitted without any errors (success). * * @since 3.0 * * @param MC4WP_Form $form Instance of the submitted form */ do_action('mc4wp_form_success', $form); } else { /** * Fires right after a form is submitted with errors. * * @since 3.0 * * @param MC4WP_Form $form The submitted form instance. */ do_action('mc4wp_form_error', $form); // fire a dedicated event for each error foreach ($form->errors as $error) { /** * Fires right after a form was submitted with errors. * * The dynamic portion of the hook, `$error`, refers to the error that occurred. * * Default errors give us the following possible hooks: * * - mc4wp_form_error_error General errors * - mc4wp_form_error_spam * - mc4wp_form_error_invalid_email Invalid email address * - mc4wp_form_error_already_subscribed Email is already on selected list(s) * - mc4wp_form_error_required_field_missing One or more required fields are missing * - mc4wp_form_error_no_lists_selected No Mailchimp lists were selected * * @since 3.0 * * @param MC4WP_Form $form The form instance of the submitted form. */ do_action('mc4wp_form_error_' . $error, $form); } } /** * Fires right before responding to the form request. * * @since 3.0 * * @param MC4WP_Form $form Instance of the submitted form. */ do_action('mc4wp_form_respond', $form); // do stuff on success (if form was submitted over plain HTTP, not for AJAX or REST requests) if ($success && ! $this->request_wants_json()) { $redirect_url = $form->get_redirect_url(); if (! empty($redirect_url)) { wp_redirect($redirect_url); exit; } } } private function request_wants_json() { if (isset($_SERVER['HTTP_ACCEPT']) && false !== strpos($_SERVER['HTTP_ACCEPT'], 'application/json')) { return true; } return false; } /** * @return MC4WP_API_V3 */ protected function get_api() { return mc4wp('api'); } /** * @return MC4WP_Debug_Log */ protected function get_log() { return mc4wp('log'); } } includes/forms/class-form-tags.php 0000777 00000006551 15251522663 0013240 0 ustar 00 <?php /** * Class MC4WP_Form_Tags * * @access private * @ignore */ class MC4WP_Form_Tags extends MC4WP_Dynamic_Content_Tags { /** * @var MC4WP_Form */ protected $form; /** * @var MC4WP_Form_Element */ protected $form_element; public function add_hooks() { add_filter('mc4wp_form_response_html', [ $this, 'replace_in_form_response' ], 10, 2); add_filter('mc4wp_form_content', [ $this, 'replace_in_form_content' ], 10, 3); add_filter('mc4wp_form_redirect_url', [ $this, 'replace_in_form_redirect_url' ], 10, 2); } /** * Register template tags */ public function register() { parent::register(); $this->tags['response'] = [ 'description' => __('Replaced with the form response (error or success messages).', 'mailchimp-for-wp'), 'callback' => [ $this, 'get_form_response' ], 'raw_html' => true, ]; $this->tags['data'] = [ 'description' => sprintf(__('Data from the URL or a submitted form.', 'mailchimp-for-wp')), 'callback' => [ $this, 'get_data' ], 'example' => "data key='UTM_SOURCE' default='Default Source'", ]; $this->tags['subscriber_count'] = [ 'description' => __('Replaced with the number of subscribers on the selected list(s)', 'mailchimp-for-wp'), 'callback' => [ $this, 'get_subscriber_count' ], ]; } public function replace_in_form_content($string, MC4WP_Form $form, MC4WP_Form_Element $element) { $this->form = $form; $this->form_element = $element; $string = $this->replace_in_html($string); return $string; } public function replace_in_form_response($string, MC4WP_Form $form) { $this->form = $form; $string = $this->replace_in_html($string); return $string; } public function replace_in_form_redirect_url($string, MC4WP_Form $form) { $this->form = $form; $string = $this->replace_in_url($string); return $string; } /** * Returns the number of subscribers on the selected lists (for the form context) * * @return int */ public function get_subscriber_count() { $mailchimp = new MC4WP_MailChimp(); $count = $mailchimp->get_subscriber_count($this->form->get_lists()); return number_format($count); } /** * Returns the form response * * @return string */ public function get_form_response() { if ($this->form_element instanceof MC4WP_Form_Element) { return $this->form_element->get_response_html(); } return ''; } /** * Gets data value from GET or POST variables. * * @param array $args * @return string */ public function get_data(array $args = []) { if (empty($args['key'])) { return ''; } $default = isset($args['default']) ? $args['default'] : ''; $key = $args['key']; $data = array_merge($_GET, $_POST); $value = isset($data[ $key ]) ? $data[ $key ] : $default; // turn array into readable value if (is_array($value)) { $value = array_filter($value); $value = join(', ', $value); } return $value; } } includes/forms/class-output-manager.php 0000777 00000007134 15251522663 0014307 0 ustar 00 <?php /** * Class MC4WP_Form_Output_Manager * * @ignore * @access private */ class MC4WP_Form_Output_Manager { /** * @var int The # of forms outputted */ public $count = 0; /** * @const string */ private const SHORTCODE = 'mc4wp_form'; /** * Add hooks */ public function add_hooks() { // enable shortcodes in form content add_filter('mc4wp_form_content', 'do_shortcode'); add_action('init', [ $this, 'register_shortcode' ]); } /** * Registers the [mc4wp_form] shortcode */ public function register_shortcode() { add_shortcode(self::SHORTCODE, [ $this, 'shortcode' ]); } /** * @param array $attributes * @param string $content * @return string */ public function shortcode($attributes = [], $content = '') { $default_attributes = [ 'id' => '', 'lists' => '', 'email_type' => '', 'element_id' => '', 'element_class' => '', ]; $attributes = shortcode_atts( $default_attributes, $attributes, self::SHORTCODE ); $config = [ 'element_id' => $attributes['element_id'], 'lists' => $attributes['lists'], 'email_type' => $attributes['email_type'], 'element_class' => $attributes['element_class'], ]; return $this->output_form($attributes['id'], $config, false); } /** * @param int $id * @param array $config * @param bool $echo * * @return string */ public function output_form($id = 0, $config = [], $echo = true) { $html = $this->generate_html($id, $config); // echo content if necessary if ($echo) { echo $html; } return $html; } protected function generate_html($id = 0, $config = []) { try { $form = mc4wp_get_form($id); } catch (Exception $e) { if (current_user_can('manage_options')) { return sprintf('<strong style="color: indianred;">Mailchimp for WordPress error:</strong> %s', $e->getMessage()); } return ''; } $html = ''; if (!mc4wp_get_api_key()) { if (current_user_can('manage_options')) { $html .= '<p style="color: indianred;">' . __('You need to configure your Mailchimp API key for this form to work properly.', 'mailchimp-for-wp') . '</p>'; } else { // if no API key set and request is for an unauthorized user // show nothing return ''; } } ++$this->count; // set a default element_id if none is given if (empty($config['element_id'])) { $config['element_id'] = 'mc4wp-form-' . $this->count; } $form_html = $form->get_html($config['element_id'], $config); try { // start new output buffer ob_start(); /** * Runs just before a form element is outputted. * * @since 3.0 * * @param MC4WP_Form $form */ do_action('mc4wp_output_form', $form); // output the form (in output buffer) echo $form_html; // grab all contents in current output buffer & then clean + end it. $html .= ob_get_clean(); } catch (Error $e) { $html .= $form_html; } return $html; } } includes/forms/class-widget.php 0000777 00000007363 15251522663 0012626 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Adds MC4WP_Widget widget. * * @ignore */ class MC4WP_Form_Widget extends WP_Widget { /** * @var array */ private $default_instance_settings = [ 'title' => '', 'form_id' => '', ]; /** * Register widget with WordPress. */ public function __construct() { // translate default widget title $this->default_instance_settings['title'] = __('Newsletter', 'mailchimp-for-wp'); parent::__construct( 'mc4wp_form_widget', // Base ID __('Mailchimp Sign-Up Form', 'mailchimp-for-wp'), // Name [ 'description' => __('Displays your Mailchimp for WordPress sign-up form', 'mailchimp-for-wp'), ] ); } /** * Front-end display of widget. * * @see WP_Widget::widget() * * @param array $args Widget arguments. * @param array $instance_settings Saved values from database. */ public function widget($args, $instance_settings) { // ensure $instance_settings is an array if (! is_array($instance_settings)) { $instance_settings = []; } $instance_settings = array_merge($this->default_instance_settings, $instance_settings); $title = apply_filters('widget_title', $instance_settings['title'], $instance_settings, $this->id_base); echo $args['before_widget']; if (! empty($title)) { echo $args['before_title'] . $title . $args['after_title']; } mc4wp_show_form($instance_settings['form_id']); echo $args['after_widget']; } /** * Back-end widget form. * * @see WP_Widget::form() * * @param array $settings Previously saved values from database. * * @return string|void */ public function form($settings) { $settings = array_merge($this->default_instance_settings, (array) $settings); ?> <p> <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:', 'mailchimp-for-wp'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($settings['title']); ?>" /> </p> <?php /** * Runs right after the widget settings form is outputted * * @param array $settings * @param MC4WP_Form_Widget $this * @ignore */ do_action('mc4wp_form_widget_form', $settings, $this); ?> <p class="description"> <?php printf(__('You can edit your sign-up form in the <a href="%s">Mailchimp for WordPress form settings</a>.', 'mailchimp-for-wp'), admin_url('admin.php?page=mailchimp-for-wp-forms')); ?> </p> <?php } /** * Validates widget form values as they are saved. * * @see WP_Widget::update() * * @param array $new_settings Values just sent to be saved. * @param array $old_settings Previously saved values from database. * * @return array Updated safe values to be saved. */ public function update($new_settings, $old_settings) { if (! empty($new_settings['title'])) { $new_settings['title'] = sanitize_text_field($new_settings['title']); } /** * Filters the widget settings before they are saved. * * @param array $new_settings * @param array $old_settings * @param MC4WP_Form_Widget $widget * @ignore */ $new_settings = apply_filters('mc4wp_form_widget_update_settings', $new_settings, $old_settings, $this); return $new_settings; } } includes/forms/class-form-element.php 0000777 00000025773 15251522663 0013742 0 ustar 00 <?php /** * Class MC4WP_Form_Element * * @since 3.0 * @ignore * @access private */ class MC4WP_Form_Element { /** * @var string */ public $ID; /** * @var MC4WP_Form */ public $form; /** * @var array * * Can be used to set element-specific config settings. Accepts the following keys. * * - lists: Customized number of Mailchimp list ID's to subscribe to. * - email_type: The email type */ public $config = []; /** * @var bool */ public $is_submitted = false; /** * @param MC4WP_Form $form * @param string $id * @param array $config */ public function __construct(MC4WP_Form $form, $id, array $config = []) { $this->form = $form; $this->ID = $id; $this->config = $config; $this->is_submitted = $this->form->is_submitted && $this->form->config['element_id'] === $this->ID; } /** * @return string */ protected function get_visible_fields() { $content = $this->form->content; $form = $this->form; $element = $this; /** * Filters the HTML for the form fields. * * Use this filter to add custom HTML to a form programmatically * * @param string $content * @param MC4WP_Form $form * @param MC4WP_Form_Element $element * @since 2.0 */ $visible_fields = (string) apply_filters('mc4wp_form_content', $content, $form, $element); return $visible_fields; } /** * @return string */ protected function get_hidden_fields() { // hidden fields $hidden_fields = '<label style="display: none !important;">' . __('Leave this field empty if you\'re human:', 'mailchimp-for-wp') . ' ' . '<input type="text" name="_mc4wp_honeypot" value="" tabindex="-1" autocomplete="off" /></label>'; $hidden_fields .= '<input type="hidden" name="_mc4wp_timestamp" value="' . time() . '" />'; $hidden_fields .= '<input type="hidden" name="_mc4wp_form_id" value="' . esc_attr($this->form->ID) . '" />'; $hidden_fields .= '<input type="hidden" name="_mc4wp_form_element_id" value="' . esc_attr($this->ID) . '" />'; // was "lists" parameter passed in shortcode arguments? if (! empty($this->config['lists'])) { $lists_string = is_array($this->config['lists']) ? join(',', $this->config['lists']) : $this->config['lists']; $hidden_fields .= '<input type="hidden" name="_mc4wp_lists" value="' . esc_attr($lists_string) . '" />'; } // was "lists" parameter passed in shortcode arguments? if (! empty($this->config['email_type'])) { $hidden_fields .= '<input type="hidden" name="_mc4wp_email_type" value="' . esc_attr($this->config['email_type']) . '" />'; } return (string) $hidden_fields; } /** * Get HTML string for a notice, including wrapper element. * * @param MC4WP_Form_Notice $notice * * @return string */ protected function get_notice_html(MC4WP_Form_Notice $notice) { if ($notice->text === '') { return ''; } $html = sprintf('<div class="mc4wp-alert mc4wp-%s" role="alert"><p>%s</p></div>', esc_attr($notice->type), $notice->text); return $html; } /** * Gets the form response string * * @param boolean $force_show * @return string */ public function get_response_html($force_show = false) { $html = ''; $form = $this->form; if ($this->is_submitted || $force_show) { foreach ($this->form->notices as $notice) { $html .= $this->get_notice_html($notice); } } /** * Filter the form response HTML * * Use this to add your own HTML to the form response. The form instance is passed to the callback function. * * @since 3.0 * * @param string $html The complete HTML string of the response, excluding the wrapper element. * @param MC4WP_Form $form The form object */ $html = (string) apply_filters('mc4wp_form_response_html', $html, $form); // wrap entire response in div, regardless of a form was submitted $html = '<div class="mc4wp-response">' . $html . '</div>'; return $html; } /** * @return string */ protected function get_response_position() { $position = 'after'; $form = $this->form; // check if content contains {response} tag if (strpos($this->form->content, '{response}') !== false) { return ''; } /** * Filters the position for the form response. * * Valid values are "before" and "after". Will have no effect if `{response}` is used in the form content. * * @param string $position * @param MC4WP_Form $form * @since 2.0 */ $response_position = (string) apply_filters('mc4wp_form_response_position', $position, $form); return $response_position; } /** * Get HTML to be added _before_ the HTML of the form fields. * * @return string */ protected function get_html_before_fields() { $html = ''; $form = $this->form; /** * Filters the HTML before the form fields. * * @param string $html * @param MC4WP_Form $form * @ignore */ $html = (string) apply_filters('mc4wp_form_before_fields', $html, $form); if ($this->get_response_position() === 'before') { $html = $html . $this->get_response_html(); } return $html; } /** * Get HTML to be added _after_ the HTML of the form fields. * * @return string */ protected function get_html_after_fields() { $html = ''; $form = $this->form; /** * Filters the HTML after the form fields. * * @param string $html * @param MC4WP_Form $form * @ignore */ $html = (string) apply_filters('mc4wp_form_after_fields', $html, $form); if ($this->get_response_position() === 'after') { $html = $this->get_response_html() . $html; } return $html; } /** * Get all HTMl attributes for the form element * * @return string */ protected function get_form_element_attributes() { $form = $this; $form_action_attribute = null; $attributes = [ 'id' => $this->ID, 'class' => $this->get_css_classes(), ]; /** * Filters the `action` attribute of the `<form>` element. * * Defaults to `null`, which means no `action` attribute will be printed. * * @param string $form_action_attribute * @param MC4WP_Form $form */ $form_action_attribute = apply_filters('mc4wp_form_action', $form_action_attribute, $form); if (is_string($form_action_attribute)) { $attributes['action'] = $form_action_attribute; } /** * Filters all attributes to be added to the `<form>` element * * @param array $attributes Key-value pairs of attributes. * @param MC4WP_Form $form */ $attributes = (array) apply_filters('mc4wp_form_element_attributes', $attributes, $form); // hardcoded attributes, can not be changed. $attributes['method'] = 'post'; $attributes['data-id'] = $this->form->ID; $attributes['data-name'] = $this->form->name; // add typo checker data attribute if enabled if (! empty($this->form->settings['email_typo_check'])) { $attributes['data-typo-check'] = '1'; } // build string of key="value" from array $string = ''; foreach ($attributes as $name => $value) { $string .= sprintf('%s="%s" ', $name, esc_attr($value)); } return $string; } /** * @param array|null $config Use this to override the configuration for this form element * @return string */ public function generate_html(?array $config = null) { if ($config) { $this->config = $config; } // return empty string if form is in trash if ($this->form->status !== 'publish') { return ''; } // Start building content string $opening_html = '<!-- Mailchimp for WordPress v' . MC4WP_VERSION . ' - https://wordpress.org/plugins/mailchimp-for-wp/ -->'; $opening_html .= '<form ' . $this->get_form_element_attributes() . '>'; $before_fields = $this->get_html_before_fields(); $fields = ''; $after_fields = $this->get_html_after_fields(); $closing_html = '</form><!-- / Mailchimp for WordPress Plugin -->'; if ( ! $this->is_submitted || ! $this->form->settings['hide_after_success'] || $this->form->has_errors() ) { // add HTML for fields + wrapper element. $fields = '<div class="mc4wp-form-fields">' . $this->get_visible_fields() . '</div>' . $this->get_hidden_fields(); } // concatenate everything $output = $opening_html . $before_fields . $fields . $after_fields . $closing_html; return $output; } /** * Get a space separated list of CSS classes for this form * * @return string */ protected function get_css_classes() { $classes = []; $form = $this->form; $classes[] = 'mc4wp-form'; $classes[] = 'mc4wp-form-' . $form->ID; // Add form classes if this specific form element was submitted if ($this->is_submitted) { $classes[] = 'mc4wp-form-submitted'; if (! $form->has_errors()) { $classes[] = 'mc4wp-form-success'; } else { $classes[] = 'mc4wp-form-error'; } } // add class for CSS targeting in custom stylesheets if (! empty($form->settings['css'])) { if (strpos($form->settings['css'], 'theme-') === 0) { $classes[] = 'mc4wp-form-theme'; } $classes[] = 'mc4wp-form-' . $form->settings['css']; } // add classes from config array if (! empty($this->config['element_class'])) { $classes = array_merge($classes, explode(' ', $this->config['element_class'])); } /** * Filters `class` attributes for the `<form>` element. * * @param array $classes * @param MC4WP_Form $form */ $classes = apply_filters('mc4wp_form_css_classes', $classes, $form); return implode(' ', $classes); } } includes/forms/class-form-manager.php 0000777 00000011433 15251522663 0013707 0 ustar 00 <?php /** * This class takes care of all form related functionality * * Do not interact with this class directly, use `mc4wp_form` functions tagged with @access public instead. * * @class MC4WP_Form_Manager * @ignore * @access private */ class MC4WP_Form_Manager { /** * @var MC4WP_Form_Output_Manager */ protected $output_manager; /** * @var MC4WP_Form_Listener */ protected $listener; /** * @var MC4WP_Form_Tags */ protected $tags; /** * @var MC4WP_Form_Previewer */ protected $previewer; /** * @var MC4WP_Form_Asset_Manager */ protected $assets; /** * @var MC4WP_Form_AMP */ protected $amp_compatibility; /** * Constructor */ public function __construct() { $this->output_manager = new MC4WP_Form_Output_Manager(); $this->tags = new MC4WP_Form_Tags(); $this->listener = new MC4WP_Form_Listener(); $this->previewer = new MC4WP_Form_Previewer(); $this->assets = new MC4WP_Form_Asset_Manager(); $this->amp_compatibility = new MC4WP_Form_AMP(); } /** * Hook! */ public function add_hooks() { add_action('init', [ $this, 'initialize' ]); add_action('widgets_init', [ $this, 'register_widget' ]); add_action('rest_api_init', [ $this, 'register_endpoint' ]); $this->listener->add_hooks(); $this->output_manager->add_hooks(); $this->assets->add_hooks(); $this->tags->add_hooks(); $this->previewer->add_hooks(); $this->amp_compatibility->add_hooks(); } /** * Initialize */ public function initialize() { $this->register_post_type(); $this->register_block_type(); } private function register_block_type() { // Bail if register_block_type does not exist (available since WP 5.0) if (! function_exists('register_block_type')) { return; } register_block_type( 'mailchimp-for-wp/form', [ 'render_callback' => [ $this->output_manager, 'shortcode' ], ] ); } /** * Register post type "mc4wp-form" */ private function register_post_type() { // register post type register_post_type( 'mc4wp-form', [ 'labels' => [ 'name' => 'Mailchimp Sign-up Forms', 'singular_name' => 'Sign-up Form', ], 'public' => false, ] ); } /** * Register our Form widget */ public function register_widget() { register_widget('MC4WP_Form_Widget'); } /** * Register an API endpoint for handling a form. */ public function register_endpoint() { register_rest_route( 'mc4wp/v1', '/form', [ 'methods' => 'POST', 'permission_callback' => '__return_true', 'callback' => [ $this, 'handle_endpoint' ], ] ); } /** * Process requests to the form endpoint. * * A listener checks every request for a form submit, so we just need to fetch the listener and get its status. */ public function handle_endpoint() { $form = mc4wp_get_submitted_form(); if (! $form instanceof MC4WP_Form) { return new WP_Error( 'not_found', esc_html__('Resource does not exist.', 'mailchimp-for-wp'), [ 'status' => 404, ] ); } if ($form->has_errors()) { $message_key = $form->errors[0]; $message = $form->get_message($message_key); return new WP_Error( $message_key, $message, [ 'status' => 400, ] ); } return new WP_REST_Response(true, 200); } /** * @param $form_id * @param array $config * @param bool $echo * * @return string */ public function output_form($form_id, $config = [], $echo = true) { return $this->output_manager->output_form($form_id, $config, $echo); } /** * Gets the currently submitted form * * @return MC4WP_Form|null */ public function get_submitted_form() { if ($this->listener->submitted_form instanceof MC4WP_Form) { return $this->listener->submitted_form; } return null; } /** * Return all tags * * @return array */ public function get_tags() { return $this->tags->all(); } } includes/forms/class-form-previewer.php 0000777 00000001600 15251522663 0014300 0 ustar 00 <?php class MC4WP_Form_Previewer { public function add_hooks() { add_action('parse_request', [ $this, 'listen' ]); } public function listen() { if (empty($_GET['mc4wp_preview_form'])) { return; } if (! current_user_can('edit_posts')) { return; } show_admin_bar(false); add_filter('pre_handle_404', '__return_true'); remove_all_actions('template_redirect'); add_action('template_redirect', [ $this, 'load_preview' ]); } public function load_preview() { // clear output, some plugin or hooked code might have thrown errors by now. if (ob_get_level() > 0) { ob_end_clean(); } $form_id = (int) $_GET['mc4wp_preview_form']; status_header(200); require __DIR__ . '/views/preview.php'; exit; } } includes/forms/class-form-amp.php 0000777 00000004567 15251522663 0013064 0 ustar 00 <?php /** * Class MC4WP_Form_AMP */ class MC4WP_Form_AMP { /** * Hook! */ public function add_hooks() { add_filter('mc4wp_form_content', [ $this, 'add_response_templates' ], 10, 2); add_filter('mc4wp_form_element_attributes', [ $this, 'add_amp_request' ]); add_filter('mc4wp_load_form_scripts', [ $this, 'suppress_scripts' ]); } /** * Add AMP templates for submit/success/error. * * @param string $content The form content. * @param MC4WP_Form $form The form object. * @return string Modified $content. */ public function add_response_templates($content, $form) { if (! function_exists('amp_is_request') || ! amp_is_request()) { return $content; } ob_start(); ?> <div submitting> <template type="amp-mustache"> <?php echo esc_html__('Submitting...', 'mailchimp-for-wp'); ?> </template> </div> <div submit-success> <template type="amp-mustache"> <?php echo wp_kses( $form->get_message('subscribed'), [ 'a' => [], 'strong' => [], 'em' => [], ] ); ?> </template> </div> <div submit-error> <template type="amp-mustache"> {{message}} </template> </div> <?php $content .= ob_get_clean(); return $content; } /** * Add 'action-xhr' to AMP forms. * * @param array $attributes Key-Value pairs of attributes output on form. * @return array Modified $attributes. */ public function add_amp_request($attributes) { if (function_exists('amp_is_request') && amp_is_request()) { $attributes['action-xhr'] = get_rest_url(null, 'mc4wp/v1/form'); } return $attributes; } /** * Suppress form scripts on AMP pages. * * @param bool $load_scripts Whether scripts should be loaded. * @return bool Modified $load_scripts. */ public function suppress_scripts($load_scripts) { if (function_exists('amp_is_request') && amp_is_request()) { return false; } return $load_scripts; } } includes/forms/admin-functions.php 0000777 00000001157 15251522663 0013331 0 ustar 00 <?php /** * Gets the absolute url to edit a form * * @param int $form_id ID of the form * @param string $tab Tab identifier to open * * @return string */ function mc4wp_get_edit_form_url($form_id, $tab = '') { $url = admin_url(sprintf('admin.php?page=mailchimp-for-wp-forms&view=edit-form&form_id=%d', $form_id)); if (! empty($tab)) { $url .= sprintf('&tab=%s', $tab); } return $url; } /** * Get absolute URL to create a new form * * @return string */ function mc4wp_get_add_form_url() { $url = admin_url('admin.php?page=mailchimp-for-wp-forms&view=add-form'); return $url; } includes/forms/views/edit-form.php 0000777 00000011014 15251522663 0013247 0 ustar 00 <?php defined('ABSPATH') or exit; $tabs = [ 'fields' => esc_html__('Fields', 'mailchimp-for-wp'), 'messages' => esc_html__('Messages', 'mailchimp-for-wp'), 'settings' => esc_html__('Settings', 'mailchimp-for-wp'), 'appearance' => esc_html__('Appearance', 'mailchimp-for-wp'), ]; /** * Filters the setting tabs on the "edit form" screen. * * @param array $tabs */ $tabs = apply_filters('mc4wp_admin_edit_form_tabs', $tabs); ?> <div id="mc4wp-admin" class="wrap mc4wp-settings"> <p class="mc4wp-breadcrumbs"> <span class="prefix"><?php echo esc_html__('You are here: ', 'mailchimp-for-wp'); ?></span> <a href="<?php echo esc_url(admin_url('admin.php?page=mailchimp-for-wp')); ?>">Mailchimp for WordPress</a> › <a href="<?php echo esc_url(admin_url('admin.php?page=mailchimp-for-wp-forms')); ?>"><?php echo esc_html__('Forms', 'mailchimp-for-wp'); ?></a> › <span class="current-crumb"><strong><?php echo esc_html__('Form', 'mailchimp-for-wp'); ?> <?php echo esc_html($form_id); ?> | <?php echo esc_html($form->name); ?></strong></span> </p> <div> <h1 class="mc4wp-page-title"> <?php echo esc_html__('Edit Form', 'mailchimp-for-wp'); ?> <?php do_action('mc4wp_admin_edit_form_after_title'); ?> </h1> <?php // fake h2 for admin notices ?> <h2 style="display: none;"></h2> <?php // wrap entire page in <form> element ?> <form method="post"> <?php // default submit button to prevent opening preview ?> <input type="submit" style="display: none;" /> <input type="hidden" name="_mc4wp_action" value="edit_form"/> <?php wp_nonce_field('_mc4wp_action', '_wpnonce'); ?> <input type="hidden" name="mc4wp_form_id" value="<?php echo esc_attr($form->ID); ?>"/> <div id="titlediv" class="mc4wp-margin-s"> <div id="titlewrap"> <label class="screen-reader-text" for="title"><?php echo esc_html__('Enter form title here', 'mailchimp-for-wp'); ?></label> <input type="text" name="mc4wp_form[name]" size="30" value="<?php echo esc_attr($form->name); ?>" id="title" spellcheck="true" autocomplete="off" placeholder="<?php echo esc_html__('Enter the title of your sign-up form', 'mailchimp-for-wp'); ?>" style="line-height: initial;"> </div> <div> <?php echo sprintf(esc_html__('Use the shortcode %s to display this form inside a post, page or text widget.', 'mailchimp-for-wp'), '<input type="text" onfocus="this.select();" readonly="readonly" value="' . esc_attr(sprintf('[mc4wp_form id=%d]', $form->ID)) . '" size="' . ( strlen($form->ID) + 15 ) . '">'); ?> </div> </div> <div> <h2 class="nav-tab-wrapper" id="mc4wp-tabs-nav"> <?php foreach ($tabs as $tab => $name) { $class = ( $active_tab === $tab ) ? 'nav-tab-active' : ''; $href = esc_attr($this->tab_url($tab)); echo "<a class=\"nav-tab nav-tab-{$tab} {$class}\" data-tab=\"{$tab}\" href=\"{$href}\">{$name}</a>"; } ?> </h2> <div id="mc4wp-tabs"> <?php foreach ($tabs as $tab => $name) { $class = ( $active_tab === $tab ) ? 'mc4wp-tab-active' : ''; echo "<div class=\"mc4wp-tab {$class}\" id=\"mc4wp-tab-{$tab}\">"; /** * Runs when outputting a tab section on the "edit form" screen * * @param string $tab */ do_action('mc4wp_admin_edit_form_output_' . $tab . '_tab', $opts, $form); $tab_file = __DIR__ . '/tabs/form-' . $tab . '.php'; if (file_exists($tab_file)) { include $tab_file; } // end of .tab echo '</div>'; } // foreach tabs ?> </div> </div> </form> <?php include MC4WP_PLUGIN_DIR . '/includes/views/parts/admin-footer.php'; ?> </div> </div> includes/forms/views/preview.php 0000777 00000002520 15251522663 0013044 0 ustar 00 <?php defined('ABSPATH') or exit; // fake post to prevent notices in wp_enqueue_scripts call $GLOBALS['post'] = new \WP_Post((object) [ 'filter' => 'raw' ]); $GLOBALS['wp_query'] = new \WP_Query(); // render simple page with form in it. ?><!DOCTYPE html> <html> <head> <title>Mailchimp for WordPress Form Preview</title> <meta charset="utf-8"> <meta name="robots" content="noindex"> <link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>"> <?php wp_head(); ?> <style> html, body{ background: white; width: 100%; text-align: left; } <?php // hide all other elements except the form preview ?> html::before, html::after, body::before, body::after, body > *:not(#form-preview) { display:none !important; } #form-preview { display: block !important; width: 100%; height: 100%; padding: 20px; border: 0; margin: 0; box-sizing: border-box; } </style> </head> <body class="page-template-default page"> <div id="form-preview" class="page type-page status-publish hentry post post-content"> <?php mc4wp_show_form($form_id); ?> </div> <?php wp_footer(); ?> </body> </html> includes/forms/views/js/dummy-api.js 0000777 00000000327 15251522663 0013531 0 ustar 00 (function() { window.mc4wp = window.mc4wp || { listeners: [], forms: { on: function(evt, cb) { window.mc4wp.listeners.push( { event : evt, callback: cb } ); } } } })(); includes/forms/views/js/url-fields.js 0000777 00000000534 15251522663 0013675 0 ustar 00 function maybePrefixUrlField () { const value = this.value.trim() if (value !== '' && value.indexOf('http') !== 0) { this.value = 'http://' + value } } const urlFields = document.querySelectorAll('.mc4wp-form input[type="url"]') for (let j = 0; j < urlFields.length; j++) { urlFields[j].addEventListener('blur', maybePrefixUrlField) } includes/forms/views/parts/add-fields-help.php 0000777 00000005054 15251522663 0015443 0 ustar 00 <?php defined('ABSPATH') or exit; ?> <div class="mc4wp-admin"> <h2><?php echo esc_html__('Add more fields', 'mailchimp-for-wp'); ?></h2> <div> <p> <?php echo esc_html__('To add more fields to your form, you will need to create those fields in Mailchimp first.', 'mailchimp-for-wp'); ?> </p> <p><strong><?php echo esc_html__("Here's how:", 'mailchimp-for-wp'); ?></strong></p> <ol> <li> <p> <?php echo esc_html__('Log in to your Mailchimp account.', 'mailchimp-for-wp'); ?> </p> </li> <li> <p> <?php echo esc_html__('Add list fields to any of your selected lists.', 'mailchimp-for-wp'); ?> <?php echo esc_html__('Clicking the following links will take you to the right screen.', 'mailchimp-for-wp'); ?> </p> <ul class="children lists--only-selected"> <?php foreach ($lists as $list) { ?> <li data-list-id="<?php echo $list->id; ?>" style="display: <?php echo in_array($list->id, $opts['lists']) ? '' : 'none'; ?>"> <a href="https://admin.mailchimp.com/lists/settings/merge-tags?id=<?php echo $list->web_id; ?>"> <span class="screen-reader-text"><?php echo esc_html__('Edit list fields for', 'mailchimp-for-wp'); ?> </span> <?php echo $list->name; ?> </a> </li> <?php } ?> </ul> </li> <li> <p> <?php echo esc_html__('Click the following button to have Mailchimp for WordPress pick up on your changes.', 'mailchimp-for-wp'); ?> </p> <p> <a class="button button-primary" href=" <?php echo esc_attr( add_query_arg( [ '_mc4wp_action' => 'empty_lists_cache', '_wpnonce' => wp_create_nonce('_mc4wp_action'), ] ) ); ?> "> <?php echo esc_html__('Renew Mailchimp audiences', 'mailchimp-for-wp'); ?> </a> </p> </li> </ol> </div> </div> includes/forms/views/parts/dynamic-content-tags.php 0000777 00000002146 15251522663 0016550 0 ustar 00 <?php defined('ABSPATH') or exit; $tags = mc4wp('forms')->get_tags(); ?> <h2><?php echo esc_html__('Add dynamic form variable', 'mailchimp-for-wp'); ?></h2> <p> <?php echo sprintf(wp_kses(__('The following list of variables can be used to <a href="%s">add some dynamic content to your form or success and error messages</a>.', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ] ]), 'https://www.mc4wp.com/kb/using-variables-in-your-form-or-messages/') . ' ' . __('This allows you to personalise your form or response messages.', 'mailchimp-for-wp'); ?> </p> <table class="widefat striped"> <?php foreach ($tags as $tag => $config) { $tag = ! empty($config['example']) ? $config['example'] : $tag; ?> <tr> <td> <input type="text" class="widefat" value="<?php echo esc_attr(sprintf('{%s}', $tag)); ?>" readonly="readonly" onfocus="this.select();" /> <p class="description" style="margin-bottom:0;"><?php echo strip_tags($config['description'], '<strong><b><em><i><a><code>'); ?></p> </td> </tr> <?php } ?> </table> includes/forms/views/tabs/form-fields.php 0000777 00000005375 15251522663 0014536 0 ustar 00 <?php add_thickbox(); ?> <div class="alignright"> <a href="#TB_inline?width=0&height=550&inlineId=mc4wp-form-variables" class="thickbox button-secondary"> <span class="dashicons dashicons-info"></span> <?php echo esc_html__('Form variables', 'mailchimp-for-wp'); ?> </a> <a href="#TB_inline?width=600&height=400&inlineId=mc4wp-add-field-help" class="thickbox button-secondary"> <span class="dashicons dashicons-editor-help"></span> <?php echo esc_html__('Add more fields', 'mailchimp-for-wp'); ?> </a> </div> <h2><?php echo esc_html__('Form Fields', 'mailchimp-for-wp'); ?></h2> <!-- Placeholder for the field wizard --> <div id="mc4wp-field-wizard"></div> <div class="mc4wp-form-markup-wrap"> <div class="mc4wp-form-editor-wrap"> <h4 style="margin: 0"><?php echo esc_html__('Form code', 'mailchimp-for-wp'); ?> <span style="visibility: hidden;" class="dashicons dashicons-editor-help"></span></h4> <!-- Textarea for the actual form content HTML --> <textarea class="widefat" cols="160" rows="20" id="mc4wp-form-content" name="mc4wp_form[content]" placeholder="<?php echo esc_attr__('Enter the HTML code for your form fields..', 'mailchimp-for-wp'); ?>" autocomplete="false" autocorrect="false" autocapitalize="false" spellcheck="false"><?php echo htmlspecialchars($form->content, ENT_QUOTES, get_option('blog_charset')); ?></textarea> </div> <div class="mc4wp-form-preview-wrap"> <h4 style="margin: 0;"> <?php echo esc_html__('Form preview', 'mailchimp-for-wp'); ?> <span class="dashicons dashicons-editor-help" title="<?php echo esc_attr__('The form may look slightly different than this when shown in a post, page or widget area.', 'mailchimp-for-wp'); ?>"></span> </h4> <iframe id="mc4wp-form-preview" src="<?php echo esc_attr($form_preview_url); ?>"></iframe> </div> </div> <!-- This field is updated by JavaScript as the form content changes --> <input type="hidden" id="required-fields" name="mc4wp_form[settings][required_fields]" value="<?php echo esc_attr($form->settings['required_fields']); ?>" /> <?php submit_button(); ?> <p class="mc4wp-form-usage"><?php printf(esc_html__('Use the shortcode %s to display this form inside a post, page or text widget.', 'mailchimp-for-wp'), '<input type="text" onfocus="this.select();" readonly="readonly" value="' . esc_attr(sprintf('[mc4wp_form id=%d]', $form->ID)) . '" size="' . ( strlen($form->ID) + 15 ) . '">'); ?></p> <?php // Content for Thickboxes ?> <div id="mc4wp-form-variables" style="display: none;"> <?php require __DIR__ . '/../parts/dynamic-content-tags.php'; ?> </div> <div id="mc4wp-add-field-help" style="display: none;"> <?php require __DIR__ . '/../parts/add-fields-help.php'; ?> </div> includes/forms/views/tabs/form-settings.php 0000777 00000023431 15251522663 0015121 0 ustar 00 <h2><?php echo esc_html__('Form Settings', 'mailchimp-for-wp'); ?></h2> <div class="mc4wp-margin-m"></div> <h3><?php echo esc_html__('Mailchimp specific settings', 'mailchimp-for-wp'); ?></h3> <table class="form-table" style="table-layout: fixed;"> <?php do_action('mc4wp_admin_form_before_mailchimp_settings_rows', $opts, $form); ?> <tr valign="top"> <th scope="row" style="width: 250px;"><?php echo esc_html__('Audiences this form subscribes to', 'mailchimp-for-wp'); ?></th> <?php // loop through lists if (empty($lists)) { ?> <td colspan="2"><?php echo sprintf(wp_kses(__('No audiences found, <a href="%s">are you connected to Mailchimp</a>?', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ] ]), admin_url('admin.php?page=mailchimp-for-wp')); ?></td> <?php } else { ?> <td > <ul id="mc4wp-lists" style="margin-bottom: 20px; max-height: 300px; overflow-y: auto;"> <?php foreach ($lists as $list) { ?> <li> <label> <input class="mc4wp-list-input" type="checkbox" name="mc4wp_form[settings][lists][]" value="<?php echo esc_attr($list->id); ?>" <?php checked(in_array($list->id, $opts['lists']), true); ?>> <?php echo esc_html($list->name); ?> </label> </li> <?php } ?> </ul> <p class="description"><?php echo esc_html__('Select the Mailchimp audience to which people who submit this form should be subscribed.', 'mailchimp-for-wp'); ?></p> </td> <?php } ?> </tr> <tr valign="top"> <th scope="row"><?php echo esc_html__('Use double opt-in?', 'mailchimp-for-wp'); ?></th> <td class="nowrap"> <label> <input type="radio" name="mc4wp_form[settings][double_optin]" value="1" <?php checked($opts['double_optin'], 1); ?> />‏ <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?> </label> <label> <input type="radio" name="mc4wp_form[settings][double_optin]" value="0" <?php checked($opts['double_optin'], 0); ?> onclick="return confirm('<?php echo esc_attr__('Are you sure you want to disable double opt-in?', 'mailchimp-for-wp'); ?>');" />‏ <?php echo esc_html__('No', 'mailchimp-for-wp'); ?> </label> <p class="description"><?php echo esc_html__('We strongly suggest keeping double opt-in enabled. Disabling double opt-in may affect your GDPR compliance.', 'mailchimp-for-wp'); ?></p> </td> </tr> <tr valign="top"> <th scope="row"><?php echo esc_html__('Update existing subscribers?', 'mailchimp-for-wp'); ?></th> <td class="nowrap"> <label> <input type="radio" name="mc4wp_form[settings][update_existing]" value="1" <?php checked($opts['update_existing'], 1); ?> />‏ <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?> </label> <label> <input type="radio" name="mc4wp_form[settings][update_existing]" value="0" <?php checked($opts['update_existing'], 0); ?> />‏ <?php echo esc_html__('No', 'mailchimp-for-wp'); ?> </label> <p class="description"><?php echo esc_html__('Select "yes" if you want to update existing subscribers with the data that is sent.', 'mailchimp-for-wp'); ?></p> </td> </tr> <?php $config = [ 'element' => 'mc4wp_form[settings][update_existing]', 'value' => 1, ]; ?> <tr valign="top" data-showif="<?php echo esc_attr(json_encode($config)); ?>"> <th scope="row"><?php echo esc_html__('Replace interest groups?', 'mailchimp-for-wp'); ?></th> <td class="nowrap"> <label> <input type="radio" name="mc4wp_form[settings][replace_interests]" value="1" <?php checked($opts['replace_interests'], 1); ?> />‏ <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?> </label> <label> <input type="radio" name="mc4wp_form[settings][replace_interests]" value="0" <?php checked($opts['replace_interests'], 0); ?> />‏ <?php echo esc_html__('No', 'mailchimp-for-wp'); ?> </label> <p class="description"> <?php echo esc_html__('Select "no" if you want to add the selected interests to any previously selected interests when updating a subscriber.', 'mailchimp-for-wp'); ?> <?php echo sprintf(' <a href="%s" target="_blank">' . esc_html__('What does this do?', 'mailchimp-for-wp') . '</a>', 'https://www.mc4wp.com/kb/what-does-replace-groupings-mean/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=settings-page'); ?> </p> </td> </tr> <tr valign="top"> <th scope="row"><label for="mc4wp_form_add_tags"><?php echo esc_html__('Add tags', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" name="mc4wp_form[settings][subscriber_tags]" id="mc4wp_form_add_tags" placeholder="<?php echo esc_attr__('Example: My tag, another tag', 'mailchimp-for-wp'); ?>" value="<?php echo esc_attr($opts['subscriber_tags']); ?>" /> <p class="description"> <?php echo esc_html__('The listed tags will be applied to all subscribers added or updated by this form.', 'mailchimp-for-wp'); ?> <?php echo esc_html__('Separate multiple values with a comma.', 'mailchimp-for-wp'); ?> </p> </td> </tr> <tr valign="top"> <th scope="row"><label for="mc4wp_form_remove_tags"><?php echo esc_html__('Remove tags', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" name="mc4wp_form[settings][remove_subscriber_tags]" id="mc4wp_form_remove_tags" placeholder="<?php echo esc_attr__('Example: My tag, another tag', 'mailchimp-for-wp'); ?>" value="<?php echo esc_attr($opts['remove_subscriber_tags']); ?>" /> <p class="description"> <?php echo esc_html__('The listed tags will be removed from all subscribers updated by this form.', 'mailchimp-for-wp'); ?> <?php echo esc_html__('Separate multiple values with a comma.', 'mailchimp-for-wp'); ?> </p> </td> </tr> <?php do_action('mc4wp_admin_form_after_mailchimp_settings_rows', $opts, $form); ?> </table> <div class="mc4wp-margin-m"></div> <h3><?php echo esc_html__('Form behaviour', 'mailchimp-for-wp'); ?></h3> <table class="form-table" style="table-layout: fixed;"> <?php do_action('mc4wp_admin_form_before_behaviour_settings_rows', $opts, $form); ?> <tr valign="top"> <th scope="row"><?php echo esc_html__('Hide form after a successful sign-up?', 'mailchimp-for-wp'); ?></th> <td class="nowrap"> <label> <input type="radio" name="mc4wp_form[settings][hide_after_success]" value="1" <?php checked($opts['hide_after_success'], 1); ?> />‏ <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?> </label> <label> <input type="radio" name="mc4wp_form[settings][hide_after_success]" value="0" <?php checked($opts['hide_after_success'], 0); ?> />‏ <?php echo esc_html__('No', 'mailchimp-for-wp'); ?> </label> <p class="description"> <?php echo esc_html__('Select "yes" to hide the form fields after a successful sign-up.', 'mailchimp-for-wp'); ?> </p> </td> </tr> <tr valign="top"> <th scope="row"><?php echo esc_html__('Enable email domain typo checker?', 'mailchimp-for-wp'); ?></th> <td class="nowrap"> <label> <input type="radio" name="mc4wp_form[settings][email_typo_check]" value="1" <?php checked($opts['email_typo_check'], 1); ?> />‏ <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?> </label> <label> <input type="radio" name="mc4wp_form[settings][email_typo_check]" value="0" <?php checked($opts['email_typo_check'], 0); ?> />‏ <?php echo esc_html__('No', 'mailchimp-for-wp'); ?> </label> <p class="description"> <?php echo esc_html__('When enabled, the form will suggest corrections for common email domain typos (e.g., "gmial.com" → "gmail.com").', 'mailchimp-for-wp'); ?> </p> </td> </tr> <tr valign="top"> <th scope="row"><label for="mc4wp_form_redirect"><?php echo esc_html__('Redirect to URL after successful sign-ups', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" name="mc4wp_form[settings][redirect]" id="mc4wp_form_redirect" placeholder="<?php echo sprintf(esc_attr__('Example: %s', 'mailchimp-for-wp'), esc_attr(site_url('/thank-you/'))); ?>" value="<?php echo esc_attr($opts['redirect']); ?>" /> <p class="description"> <?php echo wp_kses(__('Leave empty or enter <code>0</code> for no redirect. Otherwise, use complete (absolute) URLs, including <code>http://</code>.', 'mailchimp-for-wp'), [ 'code' => [] ]); ?> </p> <p class="description"> <?php echo esc_html__('Your "subscribed" message will not show when redirecting to another page, so make sure to let your visitors know they were successfully subscribed.', 'mailchimp-for-wp'); ?> </p> </td> </tr> <?php do_action('mc4wp_admin_form_after_behaviour_settings_rows', $opts, $form); ?> </table> <?php submit_button(); ?> includes/forms/views/tabs/form-messages.php 0000777 00000014730 15251522663 0015072 0 ustar 00 <?php defined('ABSPATH') or exit; /** @var MC4WP_Form $form */ ?> <h2><?php echo esc_html__('Form Messages', 'mailchimp-for-wp'); ?></h2> <table class="form-table mc4wp-form-messages"> <?php do_action('mc4wp_admin_form_before_messages_settings_rows', $opts, $form); ?> <tr valign="top"> <th scope="row"><label for="mc4wp_form_subscribed"><?php echo esc_html__('Successfully subscribed', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" id="mc4wp_form_subscribed" name="mc4wp_form[messages][subscribed]" value="<?php echo esc_attr($form->messages['subscribed']); ?>" /> <p class="description"><?php echo esc_html__('The text that shows when an email address is successfully subscribed to the selected Mailchimp audiences.', 'mailchimp-for-wp'); ?></p> </td> </tr> <tr valign="top"> <th scope="row"><label for="mc4wp_form_invalid_email"><?php echo esc_html__('Invalid email address', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" id="mc4wp_form_invalid_email" name="mc4wp_form[messages][invalid_email]" value="<?php echo esc_attr($form->messages['invalid_email']); ?>" required /> <p class="description"><?php echo esc_html__('The text that shows when an invalid email address is given.', 'mailchimp-for-wp'); ?></p> </td> </tr> <tr valign="top"> <th scope="row"><label for="mc4wp_form_required_field_missing"><?php echo esc_html__('Required field missing', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" id="mc4wp_form_required_field_missing" name="mc4wp_form[messages][required_field_missing]" value="<?php echo esc_attr($form->messages['required_field_missing']); ?>" required /> <p class="description"><?php echo esc_html__('The text that shows when a required field for the selected Mailchimp audiences is missing.', 'mailchimp-for-wp'); ?></p> </td> </tr> <tr valign="top"> <th scope="row"><label for="mc4wp_form_already_subscribed"><?php echo esc_html__('Already subscribed', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" id="mc4wp_form_already_subscribed" name="mc4wp_form[messages][already_subscribed]" value="<?php echo esc_attr($form->messages['already_subscribed']); ?>" required /> <p class="description"><?php echo esc_html__('The text that shows when the given email is already subscribed to the selected Mailchimp audiences.', 'mailchimp-for-wp'); ?></p> </td> </tr> <tr valign="top"> <th scope="row"><label for="mc4wp_form_error"><?php echo esc_html__('General error', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" id="mc4wp_form_error" name="mc4wp_form[messages][error]" value="<?php echo esc_attr($form->messages['error']); ?>" required /> <p class="description"><?php echo esc_html__('The text that shows when a general error occured.', 'mailchimp-for-wp'); ?></p> </td> </tr> <tr valign="top"> <th scope="row"><label for="mc4wp_form_unsubscribed"><?php echo esc_html__('Unsubscribed', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" id="mc4wp_form_unsubscribed" name="mc4wp_form[messages][unsubscribed]" value="<?php echo esc_attr($form->messages['unsubscribed']); ?>" required /> <p class="description"><?php echo esc_html__('When using the unsubscribe method, this is the text that shows when the given email address is successfully unsubscribed from the selected Mailchimp audiences).', 'mailchimp-for-wp'); ?></p> </td> </tr> <tr valign="top"> <th scope="row"><label for="mc4wp_form_not_subscribed"><?php echo esc_html__('Not subscribed', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" id="mc4wp_form_not_subscribed" name="mc4wp_form[messages][not_subscribed]" value="<?php echo esc_attr($form->messages['not_subscribed']); ?>" required /> <p class="description"><?php echo esc_html__('When using the unsubscribe method, this is the text that shows when the given email address is not on the selected Mailchimp audiences.', 'mailchimp-for-wp'); ?></p> </td> </tr> <tr valign="top"> <th scope="row"><label for="mc4wp_form_no_lists_selected"><?php echo esc_html__('No Mailchimp audiences selected', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" id="mc4wp_form_no_lists_selected" name="mc4wp_form[messages][no_lists_selected]" value="<?php echo esc_attr($form->messages['no_lists_selected']); ?>" required /> <p class="description"><?php echo esc_html__('When offering an audience choice, this is the text that shows when no Mailchimp audiences were selected.', 'mailchimp-for-wp'); ?></p> </td> </tr> <?php $config = [ 'element' => 'mc4wp_form[settings][update_existing]', 'value' => 1, ]; ?> <tr valign="top" data-showif="<?php echo esc_attr(json_encode($config)); ?>"> <th scope="row"><label for="mc4wp_form_updated"><?php echo esc_html__('Updated', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" id="mc4wp_form_updated" name="mc4wp_form[messages][updated]" value="<?php echo esc_attr($form->messages['updated']); ?>" /> <p class="description"><?php echo esc_html__('The text that shows when an existing subscriber is updated.', 'mailchimp-for-wp'); ?></p> </td> </tr> <tr valign="top"> <th scope="row"><label for="mc4wp_form_message_spam"><?php echo esc_html__('Spam', 'mailchimp-for-wp'); ?></label></th> <td> <input type="text" class="widefat" id="mc4wp_form_message_spam" name="mc4wp_form[messages][spam]" value="<?php echo esc_attr($form->messages['spam']); ?>" /> <p class="description"><?php echo esc_html__('The text that shows when a submission is marked as spam.', 'mailchimp-for-wp'); ?></p> </td> </tr> <?php do_action('mc4wp_admin_form_after_messages_settings_rows', [], $form); ?> <tr valign="top"> <th></th> <td> <p class="description"><?php echo sprintf(esc_html__('HTML tags like %s are allowed in the message fields.', 'mailchimp-for-wp'), '<code>' . esc_html('<strong><em><a>') . '</code>'); ?></p> </td> </tr> </table> <?php submit_button(); ?> includes/forms/views/tabs/form-appearance.php 0000777 00000004523 15251522663 0015361 0 ustar 00 <?php $theme = wp_get_theme(); $css_options = [ '0' => sprintf(esc_html__('Inherit from %s theme', 'mailchimp-for-wp'), $theme->Name), 'basic' => esc_html__('Basic', 'mailchimp-for-wp'), esc_html__('Form Themes', 'mailchimp-for-wp') => [ 'theme-light' => esc_html__('Light Theme', 'mailchimp-for-wp'), 'theme-dark' => esc_html__('Dark Theme', 'mailchimp-for-wp'), 'theme-red' => esc_html__('Red Theme', 'mailchimp-for-wp'), 'theme-green' => esc_html__('Green Theme', 'mailchimp-for-wp'), 'theme-blue' => esc_html__('Blue Theme', 'mailchimp-for-wp'), ], ]; /** * Filters the <option>'s in the "CSS Stylesheet" <select> box. */ $css_options = apply_filters('mc4wp_admin_form_css_options', $css_options); ?> <h2><?php echo esc_html__('Form Appearance', 'mailchimp-for-wp'); ?></h2> <table class="form-table"> <tr valign="top"> <th scope="row"><label for="mc4wp_load_stylesheet_select"><?php echo esc_html__('Form Style', 'mailchimp-for-wp'); ?></label></th> <td class="nowrap valigntop"> <select name="mc4wp_form[settings][css]" id="mc4wp_load_stylesheet_select"> <?php foreach ($css_options as $key => $option) { if (is_array($option)) { $label = $key; $options = $option; printf('<optgroup label="%s">', $label); foreach ($options as $key => $option) { printf('<option value="%s" %s>%s</option>', $key, selected($opts['css'], $key, false), $option); } print( '</optgroup>' ); } else { printf('<option value="%s" %s>%s</option>', $key, selected($opts['css'], $key, false), $option); } } ?> </select> <p class="description"> <?php echo esc_html__('If you want to load some default CSS styles, select "basic formatting styles" or choose one of the color themes', 'mailchimp-for-wp'); ?> </p> </td> </tr> <?php do_action('mc4wp_admin_form_after_appearance_settings_rows', $opts, $form); ?> </table> <?php submit_button(); ?> includes/forms/views/add-form.php 0000777 00000006322 15251522663 0013060 0 ustar 00 <?php defined('ABSPATH') or exit; ?> <div id="mc4wp-admin" class="wrap mc4wp-settings"> <div class="mc4wp-row"> <div class="main-content mc4wp-col"> <h1 class="mc4wp-page-title"> <?php echo esc_html__('Add new form', 'mailchimp-for-wp'); ?> </h1> <h2 style="display: none;"></h2><?php // fake h2 for admin notices ?> <div style="max-width: 480px;"> <form method="post"> <input type="hidden" name="_mc4wp_action" value="add_form" /> <?php wp_nonce_field('_mc4wp_action', '_wpnonce'); ?> <div class="mc4wp-margin-s"> <h3> <label> <?php echo esc_html__('What is the name of this form?', 'mailchimp-for-wp'); ?> </label> </h3> <input type="text" name="mc4wp_form[name]" class="widefat" value="" spellcheck="true" autocomplete="off" placeholder="<?php echo esc_attr__('Enter your form title..', 'mailchimp-for-wp'); ?>"> </div> <div class="mc4wp-margin-s"> <h3> <label> <?php echo esc_html__('To which Mailchimp audience should this form subscribe?', 'mailchimp-for-wp'); ?> </label> </h3> <?php if (! empty($lists)) { ?> <ul id="mc4wp-lists"> <?php foreach ($lists as $list) { ?> <li> <label> <input type="checkbox" name="mc4wp_form[settings][lists][<?php echo esc_attr($list->id); ?>]" value="<?php echo esc_attr($list->id); ?>" <?php checked($number_of_lists, 1); ?> > <?php echo esc_html($list->name); ?> </label> </li> <?php } ?> </ul> <?php } else { ?> <p class="mc4wp-notice"> <?php echo sprintf(wp_kses(__('No Mailchimp audiences found. Did you <a href="%s">connect with Mailchimp</a>?', 'mailchimp-for-wp'), [ 'a' => [ 'href' => [] ] ]), admin_url('admin.php?page=mailchimp-for-wp')); ?> </p> <?php } ?> </div> <?php submit_button(esc_html__('Add new form', 'mailchimp-for-wp')); ?> </form> </div> <?php require MC4WP_PLUGIN_DIR . '/includes/views/parts/admin-footer.php'; ?> </div> <div class="mc4wp-sidebar mc4wp-col"> <?php require MC4WP_PLUGIN_DIR . '/includes/views/parts/admin-sidebar.php'; ?> </div> </div> </div> README.md 0000777 00000004477 15251522663 0006055 0 ustar 00 MC4WP: Mailchimp for WordPress ====================== [](https://www.gnu.org/licenses/gpl-3.0)   [](https://wordpress.org/support/plugin/mailchimp-for-wp/reviews/) Here, you can browse the source code of the [MC4WP: Mailchimp for WordPress Plugin](https://wordpress.org/plugins/mailchimp-for-wp/), find and discuss open issues or contribute code to the plugin. Requirements -------------- - PHP version 7.4 or higher - WordPress version 4.6 or higher Installation ------------ If you just want to install this plugin on your WordPress site, please download and install the latest version from WordPress.org: [Mailchimp for WordPress plugin on WordPress.org](https://wordpress.org/plugins/mailchimp-for-wp/). To install the development version, take the following steps: 1. Clone the GitHub repository: ``` git clone https://github.com/ibericode/mailchimp-for-wordpress.git mailchimp-for-wp ``` 1. Install Composer dependencies: ```sh composer install ``` 1. Install NPM dependencies: ``` npm install ``` 1. Generate plugin asset files: ``` npm run build ``` 1. Activate the plugin in your WordPress admin panel. Bugs ---- If you think you've found a bug, [please open an issue here](https://github.com/ibericode/mailchimp-for-wordpress/issues?state=open)! Translations ------------- You can help [help translate Mailchimp for WordPress](https://translate.wordpress.org/projects/wp-plugins/mailchimp-for-wp/stable/) on WordPress.org. Support ------- This is a developer's portal for the Mailchimp for WordPress plugin and should not be used for support. Please visit the [Mailchimp for WordPress support forum on WordPress.org](https://wordpress.org/support/plugin/mailchimp-for-wp). If you need priority support, [upgrade to Mailchimp for WordPress Premium](https://www.mc4wp.com/). Developers ---------- Looking for code snippets? Have a look at the [sample code snippets directory](https://github.com/ibericode/mailchimp-for-wordpress/tree/main/sample-code-snippets) for a collection of modification examples. LICENSE 0000777 00000104005 15251522663 0005567 0 ustar 00 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: <program> Copyright (C) <year> <name of author> This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <https://www.gnu.org/licenses/>. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <https://www.gnu.org/licenses/why-not-lgpl.html>. assets/js/admin.js 0000777 00000011236 15251522663 0010131 0 ustar 00 (()=>{var e={1485(){function e(e,t,n,i){if("radio"===n.type&&!n.checked)return;const l="checkbox"===n.type?n.checked:n.value,o=String(l)===String(i);t?(e.style.display=o?"":"none",e.style.visibility=o?"":"hidden"):(e.style.opacity=o?"":"0.4",e.style.pointerEvents=o?"":"none"),[].forEach.call(e.querySelectorAll("input,select,textarea:not([readonly])"),function(e){e.readOnly=!o})}[].forEach.call(document.querySelectorAll("[data-showif]"),function(t){const n=JSON.parse(t.getAttribute("data-showif")),i=document.querySelectorAll('[name="'+n.element+'"]'),l=void 0===n.hide||n.hide;for(let o=0;o<i.length;o++)i[o].addEventListener("change",e.bind(null,t,l,i[o],n.value)),e(t,l,i[o],n.value)})},4688(e){const t=document.getElementById("mc4wp-admin"),n=t.querySelectorAll(".mc4wp-tab"),i=t.querySelectorAll(".nav-tab"),l=t.querySelector('input[name="_wp_http_referer"]'),o=[].map.call(n,e=>{const n=e.id.split("-").pop();return{id:n,title:e.querySelector("h2:first-of-type").textContent,element:e,nav:t.querySelectorAll(".nav-tab-"+n),open:d.bind(null,n)}});function a(e){for(let t=0;t<o.length;t++)if(o[t].id===e)return o[t];throw new Error("get() called with invalid tab id: "+e)}function c(e){e.className=e.className.replace("nav-tab-active","")}function s(e){e.className+=" nav-tab-active",e.blur()}function r(e){e.className=e.className.replace("mc4wp-tab-active",""),e.style.display=" none"}function d(e,t){if(!(e="string"==typeof e?a(e):e))return!1;[].forEach.call(n,r),[].forEach.call(i,c),[].forEach.call(e.nav,s),e.element.style.display="block",e.element.className+=" mc4wp-tab-active";const o=new URLSearchParams(window.location.search);o.set("tab",e.id);const d=window.location.pathname+"?"+o.toString();return history.pushState&&t&&history.pushState(e.id,"",d),p(e),l.value=d,"function"==typeof window.tb_remove&&window.tb_remove(),window.mc4wp&&window.mc4wp.forms&&window.mc4wp.forms.editor&&window.mc4wp.forms.editor.refresh(),!0}function p(e){const t=document.title.split("-");document.title=document.title.replace(t[0],e.title+" ")}document.addEventListener("click",function(e){e.target.hasAttribute("data-tab")&&function(e){d(e.target.getAttribute("data-tab"),!0)&&e.preventDefault()}(e)}),window.addEventListener("popstate",function(e){e.state&&d(e.state,!1)}),function(){const e=o.filter(e=>null!==e.element.offsetParent).shift();if(!e)return;const t=a(e.id);t&&(history.replaceState&&null===history.state&&history.replaceState(t.id,""),p(t))}(),e.exports={open:d,get:a}},5359(){const e=document.getElementById("mailchimp_api_key");e&&e.addEventListener("change",function(){const t=document.createElement("p");t.className="mc4wp-red",t.innerText=window.mc4wp_vars.i18n.invalid_api_key,e.nextElementSibling.innerText===t.innerText&&e.nextElementSibling.parentElement.removeChild(e.nextElementSibling),e.value.match(/^[0-9a-zA-Z*]{32}-[a-z]{2}[0-9]{1,2}$/)||e.parentElement.insertBefore(t,e.nextElementSibling)})},5602(){const e=window.mc4wp_vars.ajaxurl,t=document.getElementById("mc4wp-mailchimp-lists-overview");t&&t.addEventListener("click",t=>{t.target.matches(".mc4wp-mailchimp-list")&&function(t){t.preventDefault();const n=t.target,i=n.parentElement.parentElement.nextElementSibling,l=n.getAttribute("data-list-id"),o=i.querySelector("div");if("none"===i.style.display){const t=new XMLHttpRequest;t.open("GET",e+"?action=mc4wp_get_list_details&format=html&ids="+l,!0),t.onload=function(){this.status>=400||(o.innerHTML=this.responseText)},t.send(null),i.style.display=""}else i.style.display="none"}(t)})},7785(e,t,n){const i=document.getElementById("mc4wp-admin").querySelectorAll(".mc4wp-list-input"),l=window.mc4wp_vars.mailchimp.lists;let o=[];const a=new(n(9885));function c(){o=[];for(let e=0;e<i.length;e++){const t=i[e];("boolean"!=typeof t.checked||t.checked)&&"object"==typeof l[t.value]&&o.push(l[t.value])}return function(){const e=document.querySelectorAll(".lists--only-selected > *");for(let t=0;t<e.length;t++){const n=e[t].getAttribute("data-list-id"),i=o.filter(e=>e.id===n).length>0;e[t].style.display=i?"":"none"}}(),a.emit("selectedLists.change",[o]),o}const s=document.getElementById("mc4wp-lists");s&&s.addEventListener("change",c),c(),e.exports={getSelectedLists:function(){return o},on:a.on.bind(a)}},9885(e){function t(){this.listeners={}}t.prototype.emit=function(e,t){this.listeners[e]=this.listeners[e]??[],this.listeners[e].forEach(e=>e.apply(null,t))},t.prototype.on=function(e,t){this.listeners[e]=this.listeners[e]??[],this.listeners[e].push(t)},e.exports=t}},t={};function n(i){var l=t[i];if(void 0!==l)return l.exports;var o=t[i]={exports:{}};return e[i](o,o.exports,n),o.exports}const i=n(4688),l=n(7785);n(5359),n(5602),n(1485),window.mc4wp=window.mc4wp||{},window.mc4wp.settings=l,window.mc4wp.tabs=i})(); assets/js/forms-block.js 0000777 00000005123 15251522663 0011255 0 ustar 00 (()=>{const e=window.wp.i18n.__,{registerBlockType:t}=window.wp.blocks,{SelectControl:i}=window.wp.components,o=window.mc4wp_forms;t("mailchimp-for-wp/form",{apiVersion:3,title:e("Mailchimp for WordPress Form"),description:e("Block showing a Mailchimp for WordPress sign-up form"),category:"widgets",attributes:{id:{type:"int"}},icon:React.createElement("svg",{width:"16",height:"16",viewBox:"0 0 16 16",version:"1.1"},React.createElement("path",{opacity:"1",fill:"#a0a5aa",fillOpacity:"1",stroke:"none",d:"M 8.0097656 0.052734375 A 8 8 0 0 0 0.009765625 8.0527344 A 8 8 0 0 0 8.0097656 16.052734 A 8 8 0 0 0 16.009766 8.0527344 A 8 8 0 0 0 8.0097656 0.052734375 z M 9.2597656 4.171875 C 9.3205456 4.171875 9.9296146 5.0233822 10.611328 6.0664062 C 11.293041 7.1094313 12.296018 8.5331666 12.841797 9.2285156 L 13.833984 10.492188 L 13.316406 11.041016 C 13.031321 11.342334 12.708299 11.587891 12.599609 11.587891 C 12.253798 11.587891 11.266634 10.490156 10.349609 9.0859375 C 9.8610009 8.3377415 9.4126385 7.7229 9.3515625 7.71875 C 9.2904825 7.71455 9.2402344 8.3477011 9.2402344 9.1269531 L 9.2402344 10.544922 L 8.5839844 10.982422 C 8.2233854 11.223015 7.8735746 11.418294 7.8066406 11.417969 C 7.7397106 11.417644 7.4861075 10.997223 7.2421875 10.482422 C 6.9982675 9.9676199 6.6560079 9.3946444 6.4824219 9.2089844 L 6.1679688 8.8710938 L 6.0664062 9.34375 C 5.7203313 10.974656 5.6693219 11.090791 5.0917969 11.505859 C 4.5805569 11.873288 4.2347982 12.017623 4.1914062 11.882812 C 4.1839062 11.859632 4.1482681 11.574497 4.1113281 11.25 C 3.9708341 10.015897 3.5347399 8.7602861 2.8105469 7.5019531 C 2.5672129 7.0791451 2.5711235 7.0651693 2.9765625 6.8320312 C 3.2046215 6.7008903 3.5466561 6.4845105 3.7363281 6.3515625 C 4.0587811 6.1255455 4.1076376 6.1466348 4.4941406 6.6679688 C 4.8138896 7.0992628 4.9275606 7.166285 4.9941406 6.96875 C 5.0960956 6.666263 6.181165 5.8574219 6.484375 5.8574219 C 6.600668 5.8574219 6.8857635 6.1981904 7.1171875 6.6152344 C 7.3486105 7.0322784 7.5790294 7.3728809 7.6308594 7.3730469 C 7.7759584 7.3735219 7.9383234 5.8938023 7.8339844 5.5195312 C 7.7605544 5.2561423 7.8865035 5.0831575 8.4453125 4.6796875 C 8.8327545 4.3999485 9.1989846 4.171875 9.2597656 4.171875 z "})),supports:{html:!1},edit:function(t){const r=o.map(e=>({label:e.name,value:e.id}));return void 0===t.attributes.id&&o.length>0&&t.setAttributes({id:o[0].id}),React.createElement("div",{style:{backgroundColor:"#f8f9f9",padding:"14px"}},React.createElement(i,{label:e("Mailchimp for WordPress Sign-up Form"),value:t.attributes.id,options:r,onChange:e=>{t.setAttributes({id:e})}}))},save:function(e){return null}})})(); assets/js/forms-admin.js 0000777 00001044046 15251522663 0011263 0 ustar 00 (()=>{var e={115(e,t,n){!function(e){"use strict";function t(e){e.state.tagHit&&e.state.tagHit.clear(),e.state.tagOther&&e.state.tagOther.clear(),e.state.tagHit=e.state.tagOther=null}function n(n){n.state.failedTagMatch=!1,n.operation(function(){if(t(n),!n.somethingSelected()){var r=n.getCursor(),i=n.getViewport();i.from=Math.min(i.from,r.line),i.to=Math.max(r.line+1,i.to);var o=e.findMatchingTag(n,r,i);if(o){if(n.state.matchBothTags){var a="open"==o.at?o.open:o.close;a&&(n.state.tagHit=n.markText(a.from,a.to,{className:"CodeMirror-matchingtag"}))}var l="close"==o.at?o.open:o.close;l?n.state.tagOther=n.markText(l.from,l.to,{className:"CodeMirror-matchingtag"}):n.state.failedTagMatch=!0}}})}function r(e){e.state.failedTagMatch&&n(e)}e.defineOption("matchTags",!1,function(i,o,a){a&&a!=e.Init&&(i.off("cursorActivity",n),i.off("viewportChange",r),t(i)),o&&(i.state.matchBothTags="object"==typeof o&&o.bothTags,i.on("cursorActivity",n),i.on("viewportChange",r),n(i))}),e.commands.toMatchingTag=function(t){var n=e.findMatchingTag(t,t.getCursor());if(n){var r="close"==n.at?n.open:n.close;r&&t.extendSelection(r.to,r.from)}}}(n(5237),n(6753))},361(e,t,n){const r=window.mc4wp_forms_i18n,i=n(4862),o={showType:function(e){let t=e.type;return t=t.charAt(0).toUpperCase()+t.slice(1),i("div",[i("label",r.fieldType),i("span",t)])},label:function(e){return i("div",[i("label",r.fieldLabel),i("input.widefat",{type:"text",value:e.label,onchange:t=>{e.label=t.target.value},placeholder:e.title})])},value:function(e){const t="hidden"===e.type;return i("div",[i("label",[t?r.value:r.initialValue," ",t?"":i("small",{style:"float: right; font-weight: normal;"},r.optional)]),i("input.widefat",{type:"text",value:e.value,onchange:t=>{e.value=t.target.value}}),t?"":i("p.description",r.valueHelp)])},numberMinMax:function(e){return i("div.mc4wp-row",[i("div.mc4wp-col.mc4wp-col-3",[i("label",r.min),i("input",{type:"number",onchange:t=>{e.min=t.target.value}})]),i("div.mc4wp-col.mc4wp-col-3",[i("label",r.max),i("input",{type:"number",onchange:t=>{e.max=t.target.value}})])])},isRequired:function(e){const t={type:"checkbox",checked:e.required,onchange:t=>{e.required=t.target.checked}};let n;return e.forceRequired&&(t.required=!0,t.disabled=!0,n=i("p.description",r.forceRequired)),i("div",[i("label.cb-wrap",[i("input",t),r.isFieldRequired]),n])},placeholder:function(e){return i("div",[i("label",[r.placeholder," ",i("small",{style:"float: right; font-weight: normal;"},r.optional)]),i("input.widefat",{type:"text",value:e.placeholder,onchange:t=>{e.placeholder=t.target.value},placeholder:""}),i("p.description",r.placeholderHelp)])},useParagraphs:function(e){return i("div",[i("label.cb-wrap",[i("input",{type:"checkbox",checked:e.wrap,onchange:t=>{e.wrap=t.target.checked}}),r.wrapInParagraphTags])])},choiceType:function(e){const t=[i("option",{value:"select",selected:"select"===e.type&&"selected"},r.dropdown),i("option",{value:"radio",selected:"radio"===e.type&&"selected"},r.radioButtons)];return e.acceptsMultipleValues&&t.push(i("option",{value:"checkbox",selected:"checkbox"===e.type&&"selected"},r.checkboxes)),i("div",[i("label",r.choiceType),i("select",{value:e.type,onchange:t=>{e.type=t.target.value}},t)])},choices:function(e){const t=[];return t.push(i("div",[i("label",r.choices),i("div.limit-height",[i("table",e.choices.map(function(t,n){return i("tr",{"data-id":n},[i("td.cb",i("input",{name:"selected",type:"checkbox"===e.type?"checkbox":"radio",onchange:t=>{e.choices=e.choices.map(n=>(n.value===t.target.value?n.selected=!n.selected:"checkbox"!==e.type&&(n.selected=!1),n))},checked:t.selected,value:t.value,title:r.preselect})),i("td.stretch",i("input.widefat",{type:"text",value:t.label,placeholder:t.title,onchange:e=>{t.label=e.target.value}})),i("td",i("span",{title:r.remove,class:"dashicons dashicons-no-alt hover-activated",onclick:function(e){this.choices.splice(e,1)}.bind(e,n)},""))])}))])])),t},linkToTerms:function(e){return i("div",[i("label",r.agreeToTermsLink),i("input.widefat",{type:"text",value:e.link,onchange:t=>{e.link=t.target.value},placeholder:"https://..."})])},description:function(e){return""===e.description?[]:i("p",i.trust(e.description))}};e.exports=o},576(e,t,n){!function(e){"use strict";var t={autoSelfClosers:{area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0,menuitem:!0},implicitlyClosed:{dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},contextGrabbers:{dd:{dd:!0,dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}},doNotIndent:{pre:!0},allowUnquoted:!0,allowMissing:!0,caseFold:!0},n={autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:!1,allowMissing:!1,allowMissingTagName:!1,caseFold:!1};e.defineMode("xml",function(r,i){var o,a,l=r.indentUnit,s={},c=i.htmlMode?t:n;for(var u in c)s[u]=c[u];for(var u in i)s[u]=i[u];function d(e,t){function n(n){return t.tokenize=n,n(e,t)}var r=e.next();return"<"==r?e.eat("!")?e.eat("[")?e.match("CDATA[")?n(h("atom","]]>")):null:e.match("--")?n(h("comment","--\x3e")):e.match("DOCTYPE",!0,!0)?(e.eatWhile(/[\w\._\-]/),n(p(1))):null:e.eat("?")?(e.eatWhile(/[\w\._\-]/),t.tokenize=h("meta","?>"),"meta"):(o=e.eat("/")?"closeTag":"openTag",t.tokenize=f,"tag bracket"):"&"==r?(e.eat("#")?e.eat("x")?e.eatWhile(/[a-fA-F\d]/)&&e.eat(";"):e.eatWhile(/[\d]/)&&e.eat(";"):e.eatWhile(/[\w\.\-:]/)&&e.eat(";"))?"atom":"error":(e.eatWhile(/[^&<]/),null)}function f(e,t){var n,r,i=e.next();if(">"==i||"/"==i&&e.eat(">"))return t.tokenize=d,o=">"==i?"endTag":"selfcloseTag","tag bracket";if("="==i)return o="equals",null;if("<"==i){t.tokenize=d,t.state=b,t.tagName=t.tagStart=null;var a=t.tokenize(e,t);return a?a+" tag error":"tag error"}return/[\'\"]/.test(i)?(t.tokenize=(n=i,r=function(e,t){for(;!e.eol();)if(e.next()==n){t.tokenize=f;break}return"string"},r.isInAttribute=!0,r),t.stringStartCol=e.column(),t.tokenize(e,t)):(e.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/),"word")}function h(e,t){return function(n,r){for(;!n.eol();){if(n.match(t)){r.tokenize=d;break}n.next()}return e}}function p(e){return function(t,n){for(var r;null!=(r=t.next());){if("<"==r)return n.tokenize=p(e+1),n.tokenize(t,n);if(">"==r){if(1==e){n.tokenize=d;break}return n.tokenize=p(e-1),n.tokenize(t,n)}}return"meta"}}function m(e){return e&&e.toLowerCase()}function g(e,t,n){this.prev=e.context,this.tagName=t||"",this.indent=e.indented,this.startOfLine=n,(s.doNotIndent.hasOwnProperty(t)||e.context&&e.context.noIndent)&&(this.noIndent=!0)}function v(e){e.context&&(e.context=e.context.prev)}function y(e,t){for(var n;;){if(!e.context)return;if(n=e.context.tagName,!s.contextGrabbers.hasOwnProperty(m(n))||!s.contextGrabbers[m(n)].hasOwnProperty(m(t)))return;v(e)}}function b(e,t,n){return"openTag"==e?(n.tagStart=t.column(),w):"closeTag"==e?x:b}function w(e,t,n){return"word"==e?(n.tagName=t.current(),a="tag",S):s.allowMissingTagName&&"endTag"==e?(a="tag bracket",S(e,0,n)):(a="error",w)}function x(e,t,n){if("word"==e){var r=t.current();return n.context&&n.context.tagName!=r&&s.implicitlyClosed.hasOwnProperty(m(n.context.tagName))&&v(n),n.context&&n.context.tagName==r||!1===s.matchClosing?(a="tag",k):(a="tag error",C)}return s.allowMissingTagName&&"endTag"==e?(a="tag bracket",k(e,0,n)):(a="error",C)}function k(e,t,n){return"endTag"!=e?(a="error",k):(v(n),b)}function C(e,t,n){return a="error",k(e,0,n)}function S(e,t,n){if("word"==e)return a="attribute",T;if("endTag"==e||"selfcloseTag"==e){var r=n.tagName,i=n.tagStart;return n.tagName=n.tagStart=null,"selfcloseTag"==e||s.autoSelfClosers.hasOwnProperty(m(r))?y(n,r):(y(n,r),n.context=new g(n,r,i==n.indented)),b}return a="error",S}function T(e,t,n){return"equals"==e?L:(s.allowMissing||(a="error"),S(e,0,n))}function L(e,t,n){return"string"==e?M:"word"==e&&s.allowUnquoted?(a="string",S):(a="error",S(e,0,n))}function M(e,t,n){return"string"==e?M:S(e,0,n)}return d.isInText=!0,{startState:function(e){var t={tokenize:d,state:b,indented:e||0,tagName:null,tagStart:null,context:null};return null!=e&&(t.baseIndent=e),t},token:function(e,t){if(!t.tagName&&e.sol()&&(t.indented=e.indentation()),e.eatSpace())return null;o=null;var n=t.tokenize(e,t);return(n||o)&&"comment"!=n&&(a=null,t.state=t.state(o||n,e,t),a&&(n="error"==a?n+" error":a)),n},indent:function(t,n,r){var i=t.context;if(t.tokenize.isInAttribute)return t.tagStart==t.indented?t.stringStartCol+1:t.indented+l;if(i&&i.noIndent)return e.Pass;if(t.tokenize!=f&&t.tokenize!=d)return r?r.match(/^(\s*)/)[0].length:0;if(t.tagName)return!1!==s.multilineTagIndentPastTag?t.tagStart+t.tagName.length+2:t.tagStart+l*(s.multilineTagIndentFactor||1);if(s.alignCDATA&&/<!\[CDATA\[/.test(n))return 0;var o=n&&/^<(\/)?([\w_:\.-]*)/.exec(n);if(o&&o[1])for(;i;){if(i.tagName==o[2]){i=i.prev;break}if(!s.implicitlyClosed.hasOwnProperty(m(i.tagName)))break;i=i.prev}else if(o)for(;i;){var a=s.contextGrabbers[m(i.tagName)];if(!a||!a.hasOwnProperty(m(o[2])))break;i=i.prev}for(;i&&i.prev&&!i.startOfLine;)i=i.prev;return i?i.indent+l:t.baseIndent||0},electricInput:/<\/[\s\w:]+>$/,blockCommentStart:"\x3c!--",blockCommentEnd:"--\x3e",configuration:s.htmlMode?"html":"xml",helperType:s.htmlMode?"html":"xml",skipAttribute:function(e){e.state==L&&(e.state=S)},xmlCurrentTag:function(e){return e.tagName?{name:e.tagName,close:"closeTag"==e.type}:null},xmlCurrentContext:function(e){for(var t=[],n=e.context;n;n=n.prev)t.push(n.tagName);return t.reverse()}}}),e.defineMIME("text/xml","xml"),e.defineMIME("application/xml","xml"),e.mimeModes.hasOwnProperty("text/html")||e.defineMIME("text/html",{name:"xml",htmlMode:!0})}(n(5237))},795(e){"use strict";e.exports={}.hasOwnProperty},1088(e,t,n){"use strict";e.exports=n(8147)()},1500(e,t,n){"use strict";var r=n(7224);e.exports=function(e){var t=r(e),n=Object.keys(t.params),i=[],o=new RegExp("^"+t.path.replace(/:([^\/.-]+)(\.{3}|\.(?!\.)|-)?|[\\^$*+.()|\[\]{}]/g,function(e,t,n){return null==t?"\\"+e:(i.push({k:t,r:"..."===n}),"..."===n?"(.*)":"."===n?"([^/]+)\\.":"([^/]+)"+(n||""))})+"\\/?$");return function(e){for(var r=0;r<n.length;r++)if(t.params[n[r]]!==e.params[n[r]])return!1;if(!i.length)return o.test(e.path);var a=o.exec(e.path);if(null==a)return!1;for(r=0;r<i.length;r++)e.params[i[r].k]=i[r].r?a[r+1]:decodeURIComponent(a[r+1]);return!0}}},1640(e){"use strict";e.exports={}},2232(e,t,n){const r=new(n(9885)),i={};function o(e){return{name:e.name,title:e.title||e.name,type:e.type,mailchimpType:e.mailchimpType||null,label:e.label||e.title||"",showLabel:"boolean"!=typeof e.showLabel||e.showLabel,value:e.value||"",placeholder:e.placeholder||"",required:"boolean"==typeof e.required&&e.required,forceRequired:"boolean"==typeof e.forceRequired&&e.forceRequired,wrap:"boolean"!=typeof e.wrap||e.wrap,min:e.min,max:e.max,help:e.help||"",choices:e.choices||[],inFormContent:null,acceptsMultipleValues:e.acceptsMultipleValues,link:e.link||"",description:e.description||""}}function a(e){return{title:e.title||e.label,selected:e.selected||!1,value:e.value||e.label,label:e.label}}e.exports={get:function(e){return i[e]},getAll:function(){return Object.values(i)},deregister:function(e){delete i[e.name]},register:function(e,t){const n=i[t.name];if(n)return!n.forceRequired&&t.forceRequired&&(n.forceRequired=!0),n;t.choices&&(t.choices=function(e){return Object.keys(e).map(t=>new a({label:e[t],value:Array.isArray(e)?null:t}))}(t.choices),t.value&&(t.choices=t.choices.map(function(e){return e.value===t.value&&(e.selected=!0),e})));const l=new o(t);return l.category=e,i[t.name]=l,r.emit("change",[]),l},on:r.on.bind(r)}},2325(e,t,n){const r=n(5237);n(2520),n(115);const i={},o=document.createElement("form");let a,l=!1;const s=document.getElementById("mc4wp-form-content"),c=document.getElementById("mc4wp-form-preview");let u;const d=/\{[^{}]+\}/g;function f(){const e=c.contentDocument||c.contentWindow.document;u=e.querySelector(".mc4wp-form-fields"),u&&h()}function h(){if(!u)return f();let e=i.getValue();e=e.replace(d,"").replace(d,""),u.innerHTML=e,u.dispatchEvent(new Event("mc4wp-refresh"))}function p(){return l&&(o.innerHTML=i.getValue().toLowerCase(),l=!1),o}i.getValue=function(){return a?a.getValue():s.value},i.query=function(e){return p().querySelectorAll(e.toLowerCase())},i.containsField=function(e){return null!==p().elements.namedItem(e.toLowerCase())},i.insert=function(e){a?(a.replaceSelection(e),a.focus()):s.value+=e},i.on=function(e,t){return a?(e="input"===e?"changes":e,a.on(e,t)):s.addEventListener(e,t)},i.refresh=function(){a&&a.refresh()},s&&(o.innerHTML=s.value.toLowerCase(),a=r.fromTextArea(s,{selectionPointer:!0,mode:"htmlmixed",htmlMode:!0,autoCloseTags:!0,autoRefresh:!0,styleActiveLine:!0,matchBrackets:!0,matchTags:{bothTags:!0}}),a.on("change",function(){const e=new Event("change",{bubbles:!0});s.dispatchEvent(e)}),s.addEventListener("change",function(){l=!0,h()}),window.addEventListener("load",function(){r.signal(a,"change")})),c&&(c.addEventListener("load",f),f()),e.exports=i},2419(e,t,n){"use strict";var r=n(4726);r.trust=n(9665),r.fragment=n(8995),e.exports=r},2520(e,t,n){!function(e){"use strict";var t={script:[["lang",/(javascript|babel)/i,"javascript"],["type",/^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i,"javascript"],["type",/./,"text/plain"],[null,null,"javascript"]],style:[["lang",/^css$/i,"css"],["type",/^(text\/)?(x-)?(stylesheet|css)$/i,"css"],["type",/./,"text/plain"],[null,null,"css"]]};var n={};function r(e,t){var r=e.match(function(e){return n[e]||(n[e]=new RegExp("\\s+"+e+"\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*"))}(t));return r?/^\s*(.*?)\s*$/.exec(r[2])[1]:""}function i(e,t){return new RegExp((t?"^":"")+"</\\s*"+e+"\\s*>","i")}function o(e,t){for(var n in e)for(var r=t[n]||(t[n]=[]),i=e[n],o=i.length-1;o>=0;o--)r.unshift(i[o])}e.defineMode("htmlmixed",function(n,a){var l=e.getMode(n,{name:"xml",htmlMode:!0,multilineTagIndentFactor:a.multilineTagIndentFactor,multilineTagIndentPastTag:a.multilineTagIndentPastTag,allowMissingTagName:a.allowMissingTagName}),s={},c=a&&a.tags,u=a&&a.scriptTypes;if(o(t,s),c&&o(c,s),u)for(var d=u.length-1;d>=0;d--)s.script.unshift(["type",u[d].matches,u[d].mode]);function f(t,o){var a,c=l.token(t,o.htmlState),u=/\btag\b/.test(c);if(u&&!/[<>\s\/]/.test(t.current())&&(a=o.htmlState.tagName&&o.htmlState.tagName.toLowerCase())&&s.hasOwnProperty(a))o.inTag=a+" ";else if(o.inTag&&u&&/>$/.test(t.current())){var d=/^([\S]+) (.*)/.exec(o.inTag);o.inTag=null;var h=">"==t.current()&&function(e,t){for(var n=0;n<e.length;n++){var i=e[n];if(!i[0]||i[1].test(r(t,i[0])))return i[2]}}(s[d[1]],d[2]),p=e.getMode(n,h),m=i(d[1],!0),g=i(d[1],!1);o.token=function(e,t){return e.match(m,!1)?(t.token=f,t.localState=t.localMode=null,null):function(e,t,n){var r=e.current(),i=r.search(t);return i>-1?e.backUp(r.length-i):r.match(/<\/?$/)&&(e.backUp(r.length),e.match(t,!1)||e.match(r)),n}(e,g,t.localMode.token(e,t.localState))},o.localMode=p,o.localState=e.startState(p,l.indent(o.htmlState,"",""))}else o.inTag&&(o.inTag+=t.current(),t.eol()&&(o.inTag+=" "));return c}return{startState:function(){return{token:f,inTag:null,localMode:null,localState:null,htmlState:e.startState(l)}},copyState:function(t){var n;return t.localState&&(n=e.copyState(t.localMode,t.localState)),{token:t.token,inTag:t.inTag,localMode:t.localMode,localState:n,htmlState:e.copyState(l,t.htmlState)}},token:function(e,t){return t.token(e,t)},indent:function(t,n,r){return!t.localMode||/^\s*<\//.test(n)?l.indent(t.htmlState,n,r):t.localMode.indent?t.localMode.indent(t.localState,n,r):e.Pass},innerMode:function(e){return{state:e.localState||e.htmlState,mode:e.localMode||l}}}},"xml","javascript","css"),e.defineMIME("text/html","htmlmixed")}(n(5237),n(576),n(6792),n(8656))},2965(e){"use strict";e.exports=new WeakMap},2975(e,t,n){"use strict";var r=n(5199);e.exports=n(4389)("undefined"!=typeof window?window:null,r.redraw)},3322(e,t,n){const r=n(4862),i=window.mc4wp_forms_i18n;function o(){}function a(e){const t=e.children[0],n=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,r=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight,i=(n-t.clientWidth-40)/2,o=(r-t.clientHeight-40)/2;t.style.left=(i>0?i:0)+"px",t.style.top=(o>0?o:0)+"px"}function l(e,t){switch(t.keyCode){case 27:e();break;case 13:t.preventDefault()}}o.prototype.oncreate=function(e){this.onDocumentKeydown=l.bind(null,e.attrs.onClose),this.onWindowResize=a.bind(null,e.dom),document.addEventListener("keydown",this.onDocumentKeydown),window.addEventListener("resize",this.onWindowResize),this.onWindowResize()},o.prototype.onremove=function(){document.removeEventListener("keydown",this.onDocumentKeydown),window.removeEventListener("resize",this.onWindowResize)},o.prototype.view=function(e){return[r("div.mc4wp-overlay-wrap",r("div.mc4wp-overlay",[r("span",{class:"close dashicons dashicons-no",title:i.close,onclick:e.attrs.onClose}),e.children])),r("div.mc4wp-overlay-background",{title:i.close,onclick:e.attrs.onClose})]},e.exports=o},3804(e,t,n){"use strict";var r=n(7165),i=n(4726),o=n(8157),a=n(8555),l=n(7224),s=n(1500),c=n(8333);e.exports=function(e,t){var n,u,d,f,h,p,m,g,v=Promise.resolve(),y=!1,b=!1,w=!1,x={onremove:function(){b=w=!1,e.removeEventListener("popstate",S,!1)},view:function(){var e=r(h,p.key,p);return f?f.render(e):[e]}},k=T.SKIP={};function C(){y=!1;var r=e.location.hash;"#"!==T.prefix[0]&&(r=e.location.search+r,"?"!==T.prefix[0]&&"/"!==(r=e.location.pathname+r)[0]&&(r="/"+r));var i=o(r).slice(T.prefix.length),a=l(i);function s(e){console.error(e),T.set(d,null,{replace:!0})}Object.assign(a.params,e.history.state),function e(r){for(;r<u.length;r++)if(u[r].check(a)){var o=u[r].component,l=u[r].route,c=o,y=g=function(l){if(y===g){if(l===k)return e(r+1);h=null==l||"function"!=typeof l.view&&"function"!=typeof l?"div":l,p=a.params,m=i,g=null,f=o.render?o:null,w?t.redraw():(w=!0,t.mount(n,x))}};return void(o.view||"function"==typeof o?(o={},y(c)):o.onmatch?v.then(function(){return o.onmatch(a.params,i,l)}).then(y,i===d?null:s):y())}if(i===d)throw new Error("Could not resolve default route "+d+".");T.set(d,null,{replace:!0})}(0)}function S(){y||(y=!0,setTimeout(C))}function T(t,r,i){if(!t)throw new TypeError("DOM element being rendered to does not exist.");if(u=Object.keys(i).map(function(e){if("/"!==e[0])throw new SyntaxError("Routes must start with a '/'.");if(/:([^\/\.-]+)(\.{3})?:/.test(e))throw new SyntaxError("Route parameter names must be separated with either '/', '.', or '-'.");return{route:e,component:i[e],check:s(e)}}),d=r,null!=r){var o=l(r);if(!u.some(function(e){return e.check(o)}))throw new ReferenceError("Default route doesn't match any known routes.")}n=t,e.addEventListener("popstate",S,!1),b=!0,C()}return T.set=function(t,n,r){if(null!=g&&((r=r||{}).replace=!0),g=null,t=a(t,n),b){S();var i=r?r.state:null,o=r?r.title:null;r&&r.replace?e.history.replaceState(i,o,T.prefix+t):e.history.pushState(i,o,T.prefix+t)}else e.location.href=T.prefix+t},T.get=function(){return m},T.prefix="#!",T.Link={view:function(e){var t,n,r,o=i(e.attrs.selector||"a",c(e.attrs,["options","params","selector","onclick"]),e.children);return(o.attrs.disabled=Boolean(o.attrs.disabled))?(o.attrs.href=null,o.attrs["aria-disabled"]="true"):(t=e.attrs.options,n=e.attrs.onclick,r=a(o.attrs.href,e.attrs.params),o.attrs.href=T.prefix+r,o.attrs.onclick=function(e){var i;"function"==typeof n?i=n.call(e.currentTarget,e):null==n||"object"!=typeof n||"function"==typeof n.handleEvent&&n.handleEvent(e),!1===i||e.defaultPrevented||0!==e.button&&0!==e.which&&1!==e.which||e.currentTarget.target&&"_self"!==e.currentTarget.target||e.ctrlKey||e.metaKey||e.shiftKey||e.altKey||(e.preventDefault(),e.redraw=!1,T.set(r,null,t))}),o}},T.param=function(e){return p&&null!=e?p[e]:p},T}},4224(e){"use strict";e.exports=function(e){if("[object Object]"!==Object.prototype.toString.call(e))return"";var t=[];for(var n in e)r(n,e[n]);return t.join("&");function r(e,n){if(Array.isArray(n))for(var i=0;i<n.length;i++)r(e+"["+i+"]",n[i]);else if("[object Object]"===Object.prototype.toString.call(n))for(var i in n)r(e+"["+i+"]",n[i]);else t.push(encodeURIComponent(e)+(null!=n&&""!==n?"="+encodeURIComponent(n):""))}}},4389(e,t,n){"use strict";var r=n(8555),i=n(795);e.exports=function(e,t){function n(e){return new Promise(e)}function o(e,t){for(var n in e.headers)if(i.call(e.headers,n)&&n.toLowerCase()===t)return!0;return!1}return n.prototype=Promise.prototype,n.__proto__=Promise,{request:function(a,l){"string"!=typeof a?(l=a,a=a.url):null==l&&(l={});var s=function(t,n){return new Promise(function(a,l){t=r(t,n.params);var s,c=null!=n.method?n.method.toUpperCase():"GET",u=n.body,d=(null==n.serialize||n.serialize===JSON.serialize)&&!(u instanceof e.FormData||u instanceof e.URLSearchParams),f=n.responseType||("function"==typeof n.extract?"":"json"),h=new e.XMLHttpRequest,p=!1,m=!1,g=h,v=h.abort;for(var y in h.abort=function(){p=!0,v.call(this)},h.open(c,t,!1!==n.async,"string"==typeof n.user?n.user:void 0,"string"==typeof n.password?n.password:void 0),d&&null!=u&&!o(n,"content-type")&&h.setRequestHeader("Content-Type","application/json; charset=utf-8"),"function"==typeof n.deserialize||o(n,"accept")||h.setRequestHeader("Accept","application/json, text/*"),n.withCredentials&&(h.withCredentials=n.withCredentials),n.timeout&&(h.timeout=n.timeout),h.responseType=f,n.headers)i.call(n.headers,y)&&h.setRequestHeader(y,n.headers[y]);h.onreadystatechange=function(e){if(!p&&4===e.target.readyState)try{var r,i=e.target.status>=200&&e.target.status<300||304===e.target.status||/^file:\/\//i.test(t),o=e.target.response;if("json"===f){if(!e.target.responseType&&"function"!=typeof n.extract)try{o=JSON.parse(e.target.responseText)}catch(e){o=null}}else f&&"text"!==f||null==o&&(o=e.target.responseText);if("function"==typeof n.extract?(o=n.extract(e.target,n),i=!0):"function"==typeof n.deserialize&&(o=n.deserialize(o)),i){if("function"==typeof n.type)if(Array.isArray(o))for(var s=0;s<o.length;s++)o[s]=new n.type(o[s]);else o=new n.type(o);a(o)}else{var c=function(){try{r=e.target.responseText}catch(e){r=o}var t=new Error(r);t.code=e.target.status,t.response=o,l(t)};0===h.status?setTimeout(function(){m||c()}):c()}}catch(e){l(e)}},h.ontimeout=function(e){m=!0;var t=new Error("Request timed out");t.code=e.target.status,l(t)},"function"==typeof n.config&&(h=n.config(h,n,t)||h)!==g&&(s=h.abort,h.abort=function(){p=!0,s.call(this)}),null==u?h.send():"function"==typeof n.serialize?h.send(n.serialize(u)):u instanceof e.FormData||u instanceof e.URLSearchParams?h.send(u):h.send(JSON.stringify(u))})}(a,l);if(!0===l.background)return s;var c=0;function u(){0===--c&&"function"==typeof t&&t()}return function e(t){var r=t.then;return t.constructor=n,t.then=function(){c++;var n=r.apply(t,arguments);return n.then(u,function(e){if(u(),0===c)throw e}),e(n)},t}(s)}}}},4550(e,t,n){const r=n(4862),i=n(2325),o=n(2232),a=window.mc4wp_forms_i18n,l=n(6685),s=n(3322),c=n(7779);let u;function d(e){u=null!==e?o.get(e):null,u&&"hidden"===u.type&&u.choices.length>0&&(u.value=u.choices.map(function(e){return e.label}).join("|")),r.redraw()}function f(){const e=l(u);i.insert(e),d(null)}i.on("blur",()=>r.redraw());const h=document.getElementById("mc4wp-field-wizard");h&&r.mount(h,{view:function(){const e=o.getAll(),t=r("div#mc4wp-available-fields.mc4wp-margin-s",[r("h4",{style:{marginTop:0}},a.chooseField),[a.listFields,a.interestCategories,a.formFields].map(function(t){const n=e.filter(function(e){return e.category===t});return 0===n.length?"":r("div.mc4wp-margin-s",[r("h4",t),n.map(function(e){let t="button";e.forceRequired&&(t+=" is-required");const n=e.inFormContent;return null!==n&&(t+=" "+(n?"in-form":"not-in-form")),r("button",{className:t,type:"button",onclick:e=>d(e.target.value),value:e.name},e.title)})])})]);let n=null;return u&&(n=r(s,{onClose:()=>d(null)},r("div#mc4wp-add-form-field",[r("h3",[u.title,u.forceRequired?r("span.mc4wp-red","*"):"",u.name.length?r("code",u.name):""]),u.help.length?r("p",r.trust(u.help)):"",c.render(u),r("p",[r("button",{class:"button-primary",type:"button",onkeydown:function(e){13===e.keyCode&&f()},onclick:f},a.addToForm)])]))),[t,n]}})},4726(e,t,n){"use strict";var r=n(7165),i=n(5178),o=n(795),a=n(1640),l=n(8885),s=/(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g,c=Object.create(null);function u(e){return"value"===e||"checked"===e||"selectedIndex"===e||"selected"===e}e.exports=function(e,t,...n){if(null==e||"string"!=typeof e&&"function"!=typeof e&&"function"!=typeof e.view)throw Error("The selector must be either a string or a component.");var d=i(t,n);return"string"==typeof e&&(d.children=r.normalizeChildren(d.children),"["!==e)?function(e,t){t.tag=e.tag;var n=t.attrs;if(null==n)return t.attrs=e.attrs,t.is=e.is,t;if(o.call(n,"class")&&(null!=n.class&&(n.className=n.class),n.class=null),e.attrs!==a){var r=n.className;n=Object.assign({},e.attrs,n),null!=e.attrs.className&&(n.className=null!=r?String(e.attrs.className)+" "+String(r):e.attrs.className)}return"input"===e.tag&&o.call(n,"type")&&(n=Object.assign({type:n.type},n)),t.is=n.is,t.attrs=n,t}(c[e]||function(e){for(var t,n="div",r=[],i={},d=!0;t=s.exec(e);){var f=t[1],h=t[2];if(""===f&&""!==h)n=h;else if("#"===f)i.id=h;else if("."===f)r.push(h);else if("["===t[3][0]){var p=t[6];p&&(p=p.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===t[4]?r.push(p):(i[t[4]]=""===p?p:p||!0,u(t[4])&&(d=!1))}}return r.length>0&&(i.className=r.join(" ")),function(e){for(var t in e)if(o.call(e,t))return!1;return!0}(i)?i=a:l.set(i,d),c[e]={tag:n,attrs:i,is:i.is}}(e),d):(null==d.attrs&&(d.attrs={}),d.tag=e,d)}},4862(e,t,n){"use strict";var r=n(2419),i=n(5199),o=n(2975),a=n(6843),l=function(){return r.apply(this,arguments)};l.m=r,l.trust=r.trust,l.fragment=r.fragment,l.Fragment="[",l.mount=i.mount,l.route=a,l.render=n(1088),l.redraw=i.redraw,l.request=o.request,l.parseQueryString=n(7755),l.buildQueryString=n(4224),l.parsePathname=n(7224),l.buildPathname=n(8555),l.vnode=n(7165),l.censor=n(8333),l.domFor=n(9788),e.exports=l},5051(e,t,n){const r=n(4862),i=n(2232),o=window.mc4wp.settings,a=window.mc4wp_vars.ajaxurl,l=window.mc4wp_forms_i18n,s=window.mc4wp_vars.mailchimp,c=window.mc4wp_vars.countries,u=[];function d(e,t,n){const r=i.register(e,t);n||u.push(r)}function f(e){const t={phone:"tel",dropdown:"select",checkboxes:"checkbox",birthday:"text"};return void 0!==t[e]?t[e]:e}function h(e){const t=l.listFields,n=f(e.type),r={name:e.tag,title:e.name,required:e.required,forceRequired:e.required,type:n,choices:e.options.choices,acceptsMultipleValues:!1};return"address"!==r.type?d(t,r,!1):(d(t,{name:r.name+"[addr1]",type:"text",mailchimpType:"address",title:l.streetAddress},!1),d(t,{name:r.name+"[city]",type:"text",mailchimpType:"address",title:l.city},!1),d(t,{name:r.name+"[state]",type:"text",mailchimpType:"address",title:l.state},!1),d(t,{name:r.name+"[zip]",type:"text",mailchimpType:"address",title:l.zip},!1),d(t,{name:r.name+"[country]",type:"select",mailchimpType:"address",title:l.country,choices:c},!1)),!0}function p(e){const t=f(e.type),n={title:e.title,name:"INTERESTS["+e.id+"]",type:t,choices:e.interests,acceptsMultipleValues:"checkbox"===t};d(l.interestCategories,n,!1)}function m(e){e.merge_fields=e.merge_fields.sort(function(e,t){return"EMAIL"===e.tag||e.public&&!t.public?-1:!e.public&&t.public?1:0}),e.merge_fields.forEach(h),e.interest_categories.forEach(p),r.redraw()}function g(e){const t=a+"?action=mc4wp_get_list_details&ids="+e.map(e=>e.id).join(",");r.request({url:t,method:"GET"}).then(e=>{u.forEach(i.deregister),r.redraw(),e.forEach(m)})}o.on("selectedLists.change",g),g(o.getSelectedLists()),function(e){let t;d(l.listFields,{name:"EMAIL",title:l.emailAddress,required:!0,forceRequired:!0,type:"email"},!0),d(l.formFields,{name:"",value:l.subscribe,type:"submit",title:l.submitButton},!0),d(l.formFields,{name:"procaptcha",type:"procaptcha",label:"Procaptcha",title:"Procaptcha",wrap:!1,showLabel:!1,description:'Privacy-friendly and GDPR-compliant anti-bot protection. Go to <a href="admin.php?page=mailchimp-for-wp-integrations&integration=prosopo-procaptcha">MC4WP > Integrations > Procaptcha</a> to configure it.'},!0),t={};for(const n in e)t[e[n].id]=e[n].name;d(l.formFields,{name:"_mc4wp_lists",type:"checkbox",title:l.listChoice,choices:t,help:l.listChoiceDescription,acceptsMultipleValues:!0},!0),t={subscribe:"Subscribe",unsubscribe:"Unsubscribe"},d(l.formFields,{name:"_mc4wp_action",type:"radio",title:l.formAction,choices:t,value:"subscribe",help:l.formActionDescription},!0),d(l.formFields,{name:"AGREE_TO_TERMS",value:1,type:"terms-checkbox",label:l.agreeToTerms,title:l.agreeToTermsShort,showLabel:!1,required:!0},!0)}(s.lists)},5178(e,t,n){"use strict";var r=n(7165);e.exports=function(e,t){return null==e||"object"==typeof e&&null==e.tag&&!Array.isArray(e)?1===t.length&&Array.isArray(t[0])&&(t=t[0]):(t=0===t.length&&Array.isArray(e)?e:[e,...t],e=void 0),r("",e&&e.key,e,t)}},5199(e,t,n){"use strict";var r=n(1088);e.exports=n(9674)(r,"undefined"!=typeof requestAnimationFrame?requestAnimationFrame:null,"undefined"!=typeof console?console:null)},5237(e){e.exports=function(){"use strict";var e=navigator.userAgent,t=navigator.platform,n=/gecko\/\d/i.test(e),r=/MSIE \d/.test(e),i=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(e),o=/Edge\/(\d+)/.exec(e),a=r||i||o,l=a&&(r?document.documentMode||6:+(o||i)[1]),s=!o&&/WebKit\//.test(e),c=s&&/Qt\/\d+\.\d+/.test(e),u=!o&&/Chrome\/(\d+)/.exec(e),d=u&&+u[1],f=/Opera\//.test(e),h=/Apple Computer/.test(navigator.vendor),p=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(e),m=/PhantomJS/.test(e),g=h&&(/Mobile\/\w+/.test(e)||navigator.maxTouchPoints>2),v=/Android/.test(e),y=g||v||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(e),b=g||/Mac/.test(t),w=/\bCrOS\b/.test(e),x=/win/i.test(t),k=f&&e.match(/Version\/(\d*\.\d*)/);k&&(k=Number(k[1])),k&&k>=15&&(f=!1,s=!0);var C=b&&(c||f&&(null==k||k<12.11)),S=n||a&&l>=9;function T(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}var L,M=function(e,t){var n=e.className,r=T(t).exec(n);if(r){var i=n.slice(r.index+r[0].length);e.className=n.slice(0,r.index)+(i?r[1]+i:"")}};function A(e){for(var t=e.childNodes.length;t>0;--t)e.removeChild(e.firstChild);return e}function N(e,t){return A(e).appendChild(t)}function O(e,t,n,r){var i=document.createElement(e);if(n&&(i.className=n),r&&(i.style.cssText=r),"string"==typeof t)i.appendChild(document.createTextNode(t));else if(t)for(var o=0;o<t.length;++o)i.appendChild(t[o]);return i}function _(e,t,n,r){var i=O(e,t,n,r);return i.setAttribute("role","presentation"),i}function E(e,t){if(3==t.nodeType&&(t=t.parentNode),e.contains)return e.contains(t);do{if(11==t.nodeType&&(t=t.host),t==e)return!0}while(t=t.parentNode)}function z(e){var t,n=e.ownerDocument||e;try{t=e.activeElement}catch(e){t=n.body||null}for(;t&&t.shadowRoot&&t.shadowRoot.activeElement;)t=t.shadowRoot.activeElement;return t}function D(e,t){var n=e.className;T(t).test(n)||(e.className+=(n?" ":"")+t)}function P(e,t){for(var n=e.split(" "),r=0;r<n.length;r++)n[r]&&!T(n[r]).test(t)&&(t+=" "+n[r]);return t}L=document.createRange?function(e,t,n,r){var i=document.createRange();return i.setEnd(r||e,n),i.setStart(e,t),i}:function(e,t,n){var r=document.body.createTextRange();try{r.moveToElementText(e.parentNode)}catch(e){return r}return r.collapse(!0),r.moveEnd("character",n),r.moveStart("character",t),r};var W=function(e){e.select()};function F(e){return e.display.wrapper.ownerDocument}function I(e){return H(e.display.wrapper)}function H(e){return e.getRootNode?e.getRootNode():e.ownerDocument}function R(e){return F(e).defaultView}function j(e){var t=Array.prototype.slice.call(arguments,1);return function(){return e.apply(null,t)}}function B(e,t,n){for(var r in t||(t={}),e)!e.hasOwnProperty(r)||!1===n&&t.hasOwnProperty(r)||(t[r]=e[r]);return t}function q(e,t,n,r,i){null==t&&-1==(t=e.search(/[^\s\u00a0]/))&&(t=e.length);for(var o=r||0,a=i||0;;){var l=e.indexOf("\t",o);if(l<0||l>=t)return a+(t-o);a+=l-o,a+=n-a%n,o=l+1}}g?W=function(e){e.selectionStart=0,e.selectionEnd=e.value.length}:a&&(W=function(e){try{e.select()}catch(e){}});var U=function(){this.id=null,this.f=null,this.time=0,this.handler=j(this.onTimeout,this)};function K(e,t){for(var n=0;n<e.length;++n)if(e[n]==t)return n;return-1}U.prototype.onTimeout=function(e){e.id=0,e.time<=+new Date?e.f():setTimeout(e.handler,e.time-+new Date)},U.prototype.set=function(e,t){this.f=t;var n=+new Date+e;(!this.id||n<this.time)&&(clearTimeout(this.id),this.id=setTimeout(this.handler,e),this.time=n)};var V={toString:function(){return"CodeMirror.Pass"}},G={scroll:!1},$={origin:"*mouse"},Y={origin:"+move"};function X(e,t,n){for(var r=0,i=0;;){var o=e.indexOf("\t",r);-1==o&&(o=e.length);var a=o-r;if(o==e.length||i+a>=t)return r+Math.min(a,t-i);if(i+=o-r,r=o+1,(i+=n-i%n)>=t)return r}}var Z=[""];function J(e){for(;Z.length<=e;)Z.push(Q(Z)+" ");return Z[e]}function Q(e){return e[e.length-1]}function ee(e,t){for(var n=[],r=0;r<e.length;r++)n[r]=t(e[r],r);return n}function te(){}function ne(e,t){var n;return Object.create?n=Object.create(e):(te.prototype=e,n=new te),t&&B(t,n),n}var re=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;function ie(e){return/\w/.test(e)||e>""&&(e.toUpperCase()!=e.toLowerCase()||re.test(e))}function oe(e,t){return t?!!(t.source.indexOf("\\w")>-1&&ie(e))||t.test(e):ie(e)}function ae(e){for(var t in e)if(e.hasOwnProperty(t)&&e[t])return!1;return!0}var le=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function se(e){return e.charCodeAt(0)>=768&&le.test(e)}function ce(e,t,n){for(;(n<0?t>0:t<e.length)&&se(e.charAt(t));)t+=n;return t}function ue(e,t,n){for(var r=t>n?-1:1;;){if(t==n)return t;var i=(t+n)/2,o=r<0?Math.ceil(i):Math.floor(i);if(o==t)return e(o)?t:n;e(o)?n=o:t=o+r}}var de=null;function fe(e,t,n){var r;de=null;for(var i=0;i<e.length;++i){var o=e[i];if(o.from<t&&o.to>t)return i;o.to==t&&(o.from!=o.to&&"before"==n?r=i:de=i),o.from==t&&(o.from!=o.to&&"before"!=n?r=i:de=i)}return null!=r?r:de}var he=function(){function e(e){return e<=247?"bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN".charAt(e):1424<=e&&e<=1524?"R":1536<=e&&e<=1785?"nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111".charAt(e-1536):1774<=e&&e<=2220?"r":8192<=e&&e<=8203?"w":8204==e?"b":"L"}var t=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,n=/[stwN]/,r=/[LRr]/,i=/[Lb1n]/,o=/[1n]/;function a(e,t,n){this.level=e,this.from=t,this.to=n}return function(l,s){var c="ltr"==s?"L":"R";if(0==l.length||"ltr"==s&&!t.test(l))return!1;for(var u=l.length,d=[],f=0;f<u;++f)d.push(e(l.charCodeAt(f)));for(var h=0,p=c;h<u;++h){var m=d[h];"m"==m?d[h]=p:p=m}for(var g=0,v=c;g<u;++g){var y=d[g];"1"==y&&"r"==v?d[g]="n":r.test(y)&&(v=y,"r"==y&&(d[g]="R"))}for(var b=1,w=d[0];b<u-1;++b){var x=d[b];"+"==x&&"1"==w&&"1"==d[b+1]?d[b]="1":","!=x||w!=d[b+1]||"1"!=w&&"n"!=w||(d[b]=w),w=x}for(var k=0;k<u;++k){var C=d[k];if(","==C)d[k]="N";else if("%"==C){var S=void 0;for(S=k+1;S<u&&"%"==d[S];++S);for(var T=k&&"!"==d[k-1]||S<u&&"1"==d[S]?"1":"N",L=k;L<S;++L)d[L]=T;k=S-1}}for(var M=0,A=c;M<u;++M){var N=d[M];"L"==A&&"1"==N?d[M]="L":r.test(N)&&(A=N)}for(var O=0;O<u;++O)if(n.test(d[O])){var _=void 0;for(_=O+1;_<u&&n.test(d[_]);++_);for(var E="L"==(O?d[O-1]:c),z=E==("L"==(_<u?d[_]:c))?E?"L":"R":c,D=O;D<_;++D)d[D]=z;O=_-1}for(var P,W=[],F=0;F<u;)if(i.test(d[F])){var I=F;for(++F;F<u&&i.test(d[F]);++F);W.push(new a(0,I,F))}else{var H=F,R=W.length,j="rtl"==s?1:0;for(++F;F<u&&"L"!=d[F];++F);for(var B=H;B<F;)if(o.test(d[B])){H<B&&(W.splice(R,0,new a(1,H,B)),R+=j);var q=B;for(++B;B<F&&o.test(d[B]);++B);W.splice(R,0,new a(2,q,B)),R+=j,H=B}else++B;H<F&&W.splice(R,0,new a(1,H,F))}return"ltr"==s&&(1==W[0].level&&(P=l.match(/^\s+/))&&(W[0].from=P[0].length,W.unshift(new a(0,0,P[0].length))),1==Q(W).level&&(P=l.match(/\s+$/))&&(Q(W).to-=P[0].length,W.push(new a(0,u-P[0].length,u)))),"rtl"==s?W.reverse():W}}();function pe(e,t){var n=e.order;return null==n&&(n=e.order=he(e.text,t)),n}var me=[],ge=function(e,t,n){if(e.addEventListener)e.addEventListener(t,n,!1);else if(e.attachEvent)e.attachEvent("on"+t,n);else{var r=e._handlers||(e._handlers={});r[t]=(r[t]||me).concat(n)}};function ve(e,t){return e._handlers&&e._handlers[t]||me}function ye(e,t,n){if(e.removeEventListener)e.removeEventListener(t,n,!1);else if(e.detachEvent)e.detachEvent("on"+t,n);else{var r=e._handlers,i=r&&r[t];if(i){var o=K(i,n);o>-1&&(r[t]=i.slice(0,o).concat(i.slice(o+1)))}}}function be(e,t){var n=ve(e,t);if(n.length)for(var r=Array.prototype.slice.call(arguments,2),i=0;i<n.length;++i)n[i].apply(null,r)}function we(e,t,n){return"string"==typeof t&&(t={type:t,preventDefault:function(){this.defaultPrevented=!0}}),be(e,n||t.type,e,t),Le(t)||t.codemirrorIgnore}function xe(e){var t=e._handlers&&e._handlers.cursorActivity;if(t)for(var n=e.curOp.cursorActivityHandlers||(e.curOp.cursorActivityHandlers=[]),r=0;r<t.length;++r)-1==K(n,t[r])&&n.push(t[r])}function ke(e,t){return ve(e,t).length>0}function Ce(e){e.prototype.on=function(e,t){ge(this,e,t)},e.prototype.off=function(e,t){ye(this,e,t)}}function Se(e){e.preventDefault?e.preventDefault():e.returnValue=!1}function Te(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function Le(e){return null!=e.defaultPrevented?e.defaultPrevented:0==e.returnValue}function Me(e){Se(e),Te(e)}function Ae(e){return e.target||e.srcElement}function Ne(e){var t=e.which;return null==t&&(1&e.button?t=1:2&e.button?t=3:4&e.button&&(t=2)),b&&e.ctrlKey&&1==t&&(t=3),t}var Oe,_e,Ee=function(){if(a&&l<9)return!1;var e=O("div");return"draggable"in e||"dragDrop"in e}();function ze(e){if(null==Oe){var t=O("span","");N(e,O("span",[t,document.createTextNode("x")])),0!=e.firstChild.offsetHeight&&(Oe=t.offsetWidth<=1&&t.offsetHeight>2&&!(a&&l<8))}var n=Oe?O("span",""):O("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");return n.setAttribute("cm-text",""),n}function De(e){if(null!=_e)return _e;var t=N(e,document.createTextNode("AخA")),n=L(t,0,1).getBoundingClientRect(),r=L(t,1,2).getBoundingClientRect();return A(e),!(!n||n.left==n.right)&&(_e=r.right-n.right<3)}var Pe,We=3!="\n\nb".split(/\n/).length?function(e){for(var t=0,n=[],r=e.length;t<=r;){var i=e.indexOf("\n",t);-1==i&&(i=e.length);var o=e.slice(t,"\r"==e.charAt(i-1)?i-1:i),a=o.indexOf("\r");-1!=a?(n.push(o.slice(0,a)),t+=a+1):(n.push(o),t=i+1)}return n}:function(e){return e.split(/\r\n?|\n/)},Fe=window.getSelection?function(e){try{return e.selectionStart!=e.selectionEnd}catch(e){return!1}}:function(e){var t;try{t=e.ownerDocument.selection.createRange()}catch(e){}return!(!t||t.parentElement()!=e)&&0!=t.compareEndPoints("StartToEnd",t)},Ie="oncopy"in(Pe=O("div"))||(Pe.setAttribute("oncopy","return;"),"function"==typeof Pe.oncopy),He=null;var Re={},je={};function Be(e,t){arguments.length>2&&(t.dependencies=Array.prototype.slice.call(arguments,2)),Re[e]=t}function qe(e){if("string"==typeof e&&je.hasOwnProperty(e))e=je[e];else if(e&&"string"==typeof e.name&&je.hasOwnProperty(e.name)){var t=je[e.name];"string"==typeof t&&(t={name:t}),(e=ne(t,e)).name=t.name}else{if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+xml$/.test(e))return qe("application/xml");if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+json$/.test(e))return qe("application/json")}return"string"==typeof e?{name:e}:e||{name:"null"}}function Ue(e,t){t=qe(t);var n=Re[t.name];if(!n)return Ue(e,"text/plain");var r=n(e,t);if(Ke.hasOwnProperty(t.name)){var i=Ke[t.name];for(var o in i)i.hasOwnProperty(o)&&(r.hasOwnProperty(o)&&(r["_"+o]=r[o]),r[o]=i[o])}if(r.name=t.name,t.helperType&&(r.helperType=t.helperType),t.modeProps)for(var a in t.modeProps)r[a]=t.modeProps[a];return r}var Ke={};function Ve(e,t){B(t,Ke.hasOwnProperty(e)?Ke[e]:Ke[e]={})}function Ge(e,t){if(!0===t)return t;if(e.copyState)return e.copyState(t);var n={};for(var r in t){var i=t[r];i instanceof Array&&(i=i.concat([])),n[r]=i}return n}function $e(e,t){for(var n;e.innerMode&&(n=e.innerMode(t))&&n.mode!=e;)t=n.state,e=n.mode;return n||{mode:e,state:t}}function Ye(e,t,n){return!e.startState||e.startState(t,n)}var Xe=function(e,t,n){this.pos=this.start=0,this.string=e,this.tabSize=t||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0,this.lineOracle=n};function Ze(e,t){if((t-=e.first)<0||t>=e.size)throw new Error("There is no line "+(t+e.first)+" in the document.");for(var n=e;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(t<o){n=i;break}t-=o}return n.lines[t]}function Je(e,t,n){var r=[],i=t.line;return e.iter(t.line,n.line+1,function(e){var o=e.text;i==n.line&&(o=o.slice(0,n.ch)),i==t.line&&(o=o.slice(t.ch)),r.push(o),++i}),r}function Qe(e,t,n){var r=[];return e.iter(t,n,function(e){r.push(e.text)}),r}function et(e,t){var n=t-e.height;if(n)for(var r=e;r;r=r.parent)r.height+=n}function tt(e){if(null==e.parent)return null;for(var t=e.parent,n=K(t.lines,e),r=t.parent;r;t=r,r=r.parent)for(var i=0;r.children[i]!=t;++i)n+=r.children[i].chunkSize();return n+t.first}function nt(e,t){var n=e.first;e:do{for(var r=0;r<e.children.length;++r){var i=e.children[r],o=i.height;if(t<o){e=i;continue e}t-=o,n+=i.chunkSize()}return n}while(!e.lines);for(var a=0;a<e.lines.length;++a){var l=e.lines[a].height;if(t<l)break;t-=l}return n+a}function rt(e,t){return t>=e.first&&t<e.first+e.size}function it(e,t){return String(e.lineNumberFormatter(t+e.firstLineNumber))}function ot(e,t,n){if(void 0===n&&(n=null),!(this instanceof ot))return new ot(e,t,n);this.line=e,this.ch=t,this.sticky=n}function at(e,t){return e.line-t.line||e.ch-t.ch}function lt(e,t){return e.sticky==t.sticky&&0==at(e,t)}function st(e){return ot(e.line,e.ch)}function ct(e,t){return at(e,t)<0?t:e}function ut(e,t){return at(e,t)<0?e:t}function dt(e,t){return Math.max(e.first,Math.min(t,e.first+e.size-1))}function ft(e,t){if(t.line<e.first)return ot(e.first,0);var n=e.first+e.size-1;return t.line>n?ot(n,Ze(e,n).text.length):function(e,t){var n=e.ch;return null==n||n>t?ot(e.line,t):n<0?ot(e.line,0):e}(t,Ze(e,t.line).text.length)}function ht(e,t){for(var n=[],r=0;r<t.length;r++)n[r]=ft(e,t[r]);return n}Xe.prototype.eol=function(){return this.pos>=this.string.length},Xe.prototype.sol=function(){return this.pos==this.lineStart},Xe.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},Xe.prototype.next=function(){if(this.pos<this.string.length)return this.string.charAt(this.pos++)},Xe.prototype.eat=function(e){var t=this.string.charAt(this.pos);if("string"==typeof e?t==e:t&&(e.test?e.test(t):e(t)))return++this.pos,t},Xe.prototype.eatWhile=function(e){for(var t=this.pos;this.eat(e););return this.pos>t},Xe.prototype.eatSpace=function(){for(var e=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>e},Xe.prototype.skipToEnd=function(){this.pos=this.string.length},Xe.prototype.skipTo=function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},Xe.prototype.backUp=function(e){this.pos-=e},Xe.prototype.column=function(){return this.lastColumnPos<this.start&&(this.lastColumnValue=q(this.string,this.start,this.tabSize,this.lastColumnPos,this.lastColumnValue),this.lastColumnPos=this.start),this.lastColumnValue-(this.lineStart?q(this.string,this.lineStart,this.tabSize):0)},Xe.prototype.indentation=function(){return q(this.string,null,this.tabSize)-(this.lineStart?q(this.string,this.lineStart,this.tabSize):0)},Xe.prototype.match=function(e,t,n){if("string"!=typeof e){var r=this.string.slice(this.pos).match(e);return r&&r.index>0?null:(r&&!1!==t&&(this.pos+=r[0].length),r)}var i=function(e){return n?e.toLowerCase():e};if(i(this.string.substr(this.pos,e.length))==i(e))return!1!==t&&(this.pos+=e.length),!0},Xe.prototype.current=function(){return this.string.slice(this.start,this.pos)},Xe.prototype.hideFirstChars=function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}},Xe.prototype.lookAhead=function(e){var t=this.lineOracle;return t&&t.lookAhead(e)},Xe.prototype.baseToken=function(){var e=this.lineOracle;return e&&e.baseToken(this.pos)};var pt=function(e,t){this.state=e,this.lookAhead=t},mt=function(e,t,n,r){this.state=t,this.doc=e,this.line=n,this.maxLookAhead=r||0,this.baseTokens=null,this.baseTokenPos=1};function gt(e,t,n,r){var i=[e.state.modeGen],o={};Tt(e,t.text,e.doc.mode,n,function(e,t){return i.push(e,t)},o,r);for(var a=n.state,l=function(r){n.baseTokens=i;var l=e.state.overlays[r],s=1,c=0;n.state=!0,Tt(e,t.text,l.mode,n,function(e,t){for(var n=s;c<e;){var r=i[s];r>e&&i.splice(s,1,e,i[s+1],r),s+=2,c=Math.min(e,r)}if(t)if(l.opaque)i.splice(n,s-n,e,"overlay "+t),s=n+2;else for(;n<s;n+=2){var o=i[n+1];i[n+1]=(o?o+" ":"")+"overlay "+t}},o),n.state=a,n.baseTokens=null,n.baseTokenPos=1},s=0;s<e.state.overlays.length;++s)l(s);return{styles:i,classes:o.bgClass||o.textClass?o:null}}function vt(e,t,n){if(!t.styles||t.styles[0]!=e.state.modeGen){var r=yt(e,tt(t)),i=t.text.length>e.options.maxHighlightLength&&Ge(e.doc.mode,r.state),o=gt(e,t,r);i&&(r.state=i),t.stateAfter=r.save(!i),t.styles=o.styles,o.classes?t.styleClasses=o.classes:t.styleClasses&&(t.styleClasses=null),n===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))}return t.styles}function yt(e,t,n){var r=e.doc,i=e.display;if(!r.mode.startState)return new mt(r,!0,t);var o=function(e,t,n){for(var r,i,o=e.doc,a=n?-1:t-(e.doc.mode.innerMode?1e3:100),l=t;l>a;--l){if(l<=o.first)return o.first;var s=Ze(o,l-1),c=s.stateAfter;if(c&&(!n||l+(c instanceof pt?c.lookAhead:0)<=o.modeFrontier))return l;var u=q(s.text,null,e.options.tabSize);(null==i||r>u)&&(i=l-1,r=u)}return i}(e,t,n),a=o>r.first&&Ze(r,o-1).stateAfter,l=a?mt.fromSaved(r,a,o):new mt(r,Ye(r.mode),o);return r.iter(o,t,function(n){bt(e,n.text,l);var r=l.line;n.stateAfter=r==t-1||r%5==0||r>=i.viewFrom&&r<i.viewTo?l.save():null,l.nextLine()}),n&&(r.modeFrontier=l.line),l}function bt(e,t,n,r){var i=e.doc.mode,o=new Xe(t,e.options.tabSize,n);for(o.start=o.pos=r||0,""==t&&wt(i,n.state);!o.eol();)xt(i,o,n.state),o.start=o.pos}function wt(e,t){if(e.blankLine)return e.blankLine(t);if(e.innerMode){var n=$e(e,t);return n.mode.blankLine?n.mode.blankLine(n.state):void 0}}function xt(e,t,n,r){for(var i=0;i<10;i++){r&&(r[0]=$e(e,n).mode);var o=e.token(t,n);if(t.pos>t.start)return o}throw new Error("Mode "+e.name+" failed to advance stream.")}mt.prototype.lookAhead=function(e){var t=this.doc.getLine(this.line+e);return null!=t&&e>this.maxLookAhead&&(this.maxLookAhead=e),t},mt.prototype.baseToken=function(e){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=e;)this.baseTokenPos+=2;var t=this.baseTokens[this.baseTokenPos+1];return{type:t&&t.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-e}},mt.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},mt.fromSaved=function(e,t,n){return t instanceof pt?new mt(e,Ge(e.mode,t.state),n,t.lookAhead):new mt(e,Ge(e.mode,t),n)},mt.prototype.save=function(e){var t=!1!==e?Ge(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new pt(t,this.maxLookAhead):t};var kt=function(e,t,n){this.start=e.start,this.end=e.pos,this.string=e.current(),this.type=t||null,this.state=n};function Ct(e,t,n,r){var i,o,a=e.doc,l=a.mode,s=Ze(a,(t=ft(a,t)).line),c=yt(e,t.line,n),u=new Xe(s.text,e.options.tabSize,c);for(r&&(o=[]);(r||u.pos<t.ch)&&!u.eol();)u.start=u.pos,i=xt(l,u,c.state),r&&o.push(new kt(u,i,Ge(a.mode,c.state)));return r?o:new kt(u,i,c.state)}function St(e,t){if(e)for(;;){var n=e.match(/(?:^|\s+)line-(background-)?(\S+)/);if(!n)break;e=e.slice(0,n.index)+e.slice(n.index+n[0].length);var r=n[1]?"bgClass":"textClass";null==t[r]?t[r]=n[2]:new RegExp("(?:^|\\s)"+n[2]+"(?:$|\\s)").test(t[r])||(t[r]+=" "+n[2])}return e}function Tt(e,t,n,r,i,o,a){var l=n.flattenSpans;null==l&&(l=e.options.flattenSpans);var s,c=0,u=null,d=new Xe(t,e.options.tabSize,r),f=e.options.addModeClass&&[null];for(""==t&&St(wt(n,r.state),o);!d.eol();){if(d.pos>e.options.maxHighlightLength?(l=!1,a&&bt(e,t,r,d.pos),d.pos=t.length,s=null):s=St(xt(n,d,r.state,f),o),f){var h=f[0].name;h&&(s="m-"+(s?h+" "+s:h))}if(!l||u!=s){for(;c<d.start;)i(c=Math.min(d.start,c+5e3),u);u=s}d.start=d.pos}for(;c<d.pos;){var p=Math.min(d.pos,c+5e3);i(p,u),c=p}}var Lt=!1,Mt=!1;function At(e,t,n){this.marker=e,this.from=t,this.to=n}function Nt(e,t){if(e)for(var n=0;n<e.length;++n){var r=e[n];if(r.marker==t)return r}}function Ot(e,t){for(var n,r=0;r<e.length;++r)e[r]!=t&&(n||(n=[])).push(e[r]);return n}function _t(e,t){if(t.full)return null;var n=rt(e,t.from.line)&&Ze(e,t.from.line).markedSpans,r=rt(e,t.to.line)&&Ze(e,t.to.line).markedSpans;if(!n&&!r)return null;var i=t.from.ch,o=t.to.ch,a=0==at(t.from,t.to),l=function(e,t,n){var r;if(e)for(var i=0;i<e.length;++i){var o=e[i],a=o.marker;if(null==o.from||(a.inclusiveLeft?o.from<=t:o.from<t)||o.from==t&&"bookmark"==a.type&&(!n||!o.marker.insertLeft)){var l=null==o.to||(a.inclusiveRight?o.to>=t:o.to>t);(r||(r=[])).push(new At(a,o.from,l?null:o.to))}}return r}(n,i,a),s=function(e,t,n){var r;if(e)for(var i=0;i<e.length;++i){var o=e[i],a=o.marker;if(null==o.to||(a.inclusiveRight?o.to>=t:o.to>t)||o.from==t&&"bookmark"==a.type&&(!n||o.marker.insertLeft)){var l=null==o.from||(a.inclusiveLeft?o.from<=t:o.from<t);(r||(r=[])).push(new At(a,l?null:o.from-t,null==o.to?null:o.to-t))}}return r}(r,o,a),c=1==t.text.length,u=Q(t.text).length+(c?i:0);if(l)for(var d=0;d<l.length;++d){var f=l[d];if(null==f.to){var h=Nt(s,f.marker);h?c&&(f.to=null==h.to?null:h.to+u):f.to=i}}if(s)for(var p=0;p<s.length;++p){var m=s[p];null!=m.to&&(m.to+=u),null==m.from?Nt(l,m.marker)||(m.from=u,c&&(l||(l=[])).push(m)):(m.from+=u,c&&(l||(l=[])).push(m))}l&&(l=Et(l)),s&&s!=l&&(s=Et(s));var g=[l];if(!c){var v,y=t.text.length-2;if(y>0&&l)for(var b=0;b<l.length;++b)null==l[b].to&&(v||(v=[])).push(new At(l[b].marker,null,null));for(var w=0;w<y;++w)g.push(v);g.push(s)}return g}function Et(e){for(var t=0;t<e.length;++t){var n=e[t];null!=n.from&&n.from==n.to&&!1!==n.marker.clearWhenEmpty&&e.splice(t--,1)}return e.length?e:null}function zt(e){var t=e.markedSpans;if(t){for(var n=0;n<t.length;++n)t[n].marker.detachLine(e);e.markedSpans=null}}function Dt(e,t){if(t){for(var n=0;n<t.length;++n)t[n].marker.attachLine(e);e.markedSpans=t}}function Pt(e){return e.inclusiveLeft?-1:0}function Wt(e){return e.inclusiveRight?1:0}function Ft(e,t){var n=e.lines.length-t.lines.length;if(0!=n)return n;var r=e.find(),i=t.find(),o=at(r.from,i.from)||Pt(e)-Pt(t);return o?-o:at(r.to,i.to)||Wt(e)-Wt(t)||t.id-e.id}function It(e,t){var n,r=Mt&&e.markedSpans;if(r)for(var i=void 0,o=0;o<r.length;++o)(i=r[o]).marker.collapsed&&null==(t?i.from:i.to)&&(!n||Ft(n,i.marker)<0)&&(n=i.marker);return n}function Ht(e){return It(e,!0)}function Rt(e){return It(e,!1)}function jt(e,t){var n,r=Mt&&e.markedSpans;if(r)for(var i=0;i<r.length;++i){var o=r[i];o.marker.collapsed&&(null==o.from||o.from<t)&&(null==o.to||o.to>t)&&(!n||Ft(n,o.marker)<0)&&(n=o.marker)}return n}function Bt(e,t,n,r,i){var o=Ze(e,t),a=Mt&&o.markedSpans;if(a)for(var l=0;l<a.length;++l){var s=a[l];if(s.marker.collapsed){var c=s.marker.find(0),u=at(c.from,n)||Pt(s.marker)-Pt(i),d=at(c.to,r)||Wt(s.marker)-Wt(i);if(!(u>=0&&d<=0||u<=0&&d>=0)&&(u<=0&&(s.marker.inclusiveRight&&i.inclusiveLeft?at(c.to,n)>=0:at(c.to,n)>0)||u>=0&&(s.marker.inclusiveRight&&i.inclusiveLeft?at(c.from,r)<=0:at(c.from,r)<0)))return!0}}}function qt(e){for(var t;t=Ht(e);)e=t.find(-1,!0).line;return e}function Ut(e,t){var n=Ze(e,t),r=qt(n);return n==r?t:tt(r)}function Kt(e,t){if(t>e.lastLine())return t;var n,r=Ze(e,t);if(!Vt(e,r))return t;for(;n=Rt(r);)r=n.find(1,!0).line;return tt(r)+1}function Vt(e,t){var n=Mt&&t.markedSpans;if(n)for(var r=void 0,i=0;i<n.length;++i)if((r=n[i]).marker.collapsed){if(null==r.from)return!0;if(!r.marker.widgetNode&&0==r.from&&r.marker.inclusiveLeft&&Gt(e,t,r))return!0}}function Gt(e,t,n){if(null==n.to){var r=n.marker.find(1,!0);return Gt(e,r.line,Nt(r.line.markedSpans,n.marker))}if(n.marker.inclusiveRight&&n.to==t.text.length)return!0;for(var i=void 0,o=0;o<t.markedSpans.length;++o)if((i=t.markedSpans[o]).marker.collapsed&&!i.marker.widgetNode&&i.from==n.to&&(null==i.to||i.to!=n.from)&&(i.marker.inclusiveLeft||n.marker.inclusiveRight)&&Gt(e,t,i))return!0}function $t(e){for(var t=0,n=(e=qt(e)).parent,r=0;r<n.lines.length;++r){var i=n.lines[r];if(i==e)break;t+=i.height}for(var o=n.parent;o;o=(n=o).parent)for(var a=0;a<o.children.length;++a){var l=o.children[a];if(l==n)break;t+=l.height}return t}function Yt(e){if(0==e.height)return 0;for(var t,n=e.text.length,r=e;t=Ht(r);){var i=t.find(0,!0);r=i.from.line,n+=i.from.ch-i.to.ch}for(r=e;t=Rt(r);){var o=t.find(0,!0);n-=r.text.length-o.from.ch,n+=(r=o.to.line).text.length-o.to.ch}return n}function Xt(e){var t=e.display,n=e.doc;t.maxLine=Ze(n,n.first),t.maxLineLength=Yt(t.maxLine),t.maxLineChanged=!0,n.iter(function(e){var n=Yt(e);n>t.maxLineLength&&(t.maxLineLength=n,t.maxLine=e)})}var Zt=function(e,t,n){this.text=e,Dt(this,t),this.height=n?n(this):1};function Jt(e){e.parent=null,zt(e)}Zt.prototype.lineNo=function(){return tt(this)},Ce(Zt);var Qt={},en={};function tn(e,t){if(!e||/^\s*$/.test(e))return null;var n=t.addModeClass?en:Qt;return n[e]||(n[e]=e.replace(/\S+/g,"cm-$&"))}function nn(e,t){var n=_("span",null,null,s?"padding-right: .1px":null),r={pre:_("pre",[n],"CodeMirror-line"),content:n,col:0,pos:0,cm:e,trailingSpace:!1,splitSpaces:e.getOption("lineWrapping")};t.measure={};for(var i=0;i<=(t.rest?t.rest.length:0);i++){var o=i?t.rest[i-1]:t.line,a=void 0;r.pos=0,r.addToken=on,De(e.display.measure)&&(a=pe(o,e.doc.direction))&&(r.addToken=an(r.addToken,a)),r.map=[],sn(o,r,vt(e,o,t!=e.display.externalMeasured&&tt(o))),o.styleClasses&&(o.styleClasses.bgClass&&(r.bgClass=P(o.styleClasses.bgClass,r.bgClass||"")),o.styleClasses.textClass&&(r.textClass=P(o.styleClasses.textClass,r.textClass||""))),0==r.map.length&&r.map.push(0,0,r.content.appendChild(ze(e.display.measure))),0==i?(t.measure.map=r.map,t.measure.cache={}):((t.measure.maps||(t.measure.maps=[])).push(r.map),(t.measure.caches||(t.measure.caches=[])).push({}))}if(s){var l=r.content.lastChild;(/\bcm-tab\b/.test(l.className)||l.querySelector&&l.querySelector(".cm-tab"))&&(r.content.className="cm-tab-wrap-hack")}return be(e,"renderLine",e,t.line,r.pre),r.pre.className&&(r.textClass=P(r.pre.className,r.textClass||"")),r}function rn(e){var t=O("span","•","cm-invalidchar");return t.title="\\u"+e.charCodeAt(0).toString(16),t.setAttribute("aria-label",t.title),t}function on(e,t,n,r,i,o,s){if(t){var c,u=e.splitSpaces?function(e,t){if(e.length>1&&!/ /.test(e))return e;for(var n=t,r="",i=0;i<e.length;i++){var o=e.charAt(i);" "!=o||!n||i!=e.length-1&&32!=e.charCodeAt(i+1)||(o=" "),r+=o,n=" "==o}return r}(t,e.trailingSpace):t,d=e.cm.state.specialChars,f=!1;if(d.test(t)){c=document.createDocumentFragment();for(var h=0;;){d.lastIndex=h;var p=d.exec(t),m=p?p.index-h:t.length-h;if(m){var g=document.createTextNode(u.slice(h,h+m));a&&l<9?c.appendChild(O("span",[g])):c.appendChild(g),e.map.push(e.pos,e.pos+m,g),e.col+=m,e.pos+=m}if(!p)break;h+=m+1;var v=void 0;if("\t"==p[0]){var y=e.cm.options.tabSize,b=y-e.col%y;(v=c.appendChild(O("span",J(b),"cm-tab"))).setAttribute("role","presentation"),v.setAttribute("cm-text","\t"),e.col+=b}else"\r"==p[0]||"\n"==p[0]?((v=c.appendChild(O("span","\r"==p[0]?"␍":"","cm-invalidchar"))).setAttribute("cm-text",p[0]),e.col+=1):((v=e.cm.options.specialCharPlaceholder(p[0])).setAttribute("cm-text",p[0]),a&&l<9?c.appendChild(O("span",[v])):c.appendChild(v),e.col+=1);e.map.push(e.pos,e.pos+1,v),e.pos++}}else e.col+=t.length,c=document.createTextNode(u),e.map.push(e.pos,e.pos+t.length,c),a&&l<9&&(f=!0),e.pos+=t.length;if(e.trailingSpace=32==u.charCodeAt(t.length-1),n||r||i||f||o||s){var w=n||"";r&&(w+=r),i&&(w+=i);var x=O("span",[c],w,o);if(s)for(var k in s)s.hasOwnProperty(k)&&"style"!=k&&"class"!=k&&x.setAttribute(k,s[k]);return e.content.appendChild(x)}e.content.appendChild(c)}}function an(e,t){return function(n,r,i,o,a,l,s){i=i?i+" cm-force-border":"cm-force-border";for(var c=n.pos,u=c+r.length;;){for(var d=void 0,f=0;f<t.length&&!((d=t[f]).to>c&&d.from<=c);f++);if(d.to>=u)return e(n,r,i,o,a,l,s);e(n,r.slice(0,d.to-c),i,o,null,l,s),o=null,r=r.slice(d.to-c),c=d.to}}}function ln(e,t,n,r){var i=!r&&n.widgetNode;i&&e.map.push(e.pos,e.pos+t,i),!r&&e.cm.display.input.needsContentAttribute&&(i||(i=e.content.appendChild(document.createElement("span"))),i.setAttribute("cm-marker",n.id)),i&&(e.cm.display.input.setUneditable(i),e.content.appendChild(i)),e.pos+=t,e.trailingSpace=!1}function sn(e,t,n){var r=e.markedSpans,i=e.text,o=0;if(r)for(var a,l,s,c,u,d,f,h=i.length,p=0,m=1,g="",v=0;;){if(v==p){s=c=u=l="",f=null,d=null,v=1/0;for(var y=[],b=void 0,w=0;w<r.length;++w){var x=r[w],k=x.marker;if("bookmark"==k.type&&x.from==p&&k.widgetNode)y.push(k);else if(x.from<=p&&(null==x.to||x.to>p||k.collapsed&&x.to==p&&x.from==p)){if(null!=x.to&&x.to!=p&&v>x.to&&(v=x.to,c=""),k.className&&(s+=" "+k.className),k.css&&(l=(l?l+";":"")+k.css),k.startStyle&&x.from==p&&(u+=" "+k.startStyle),k.endStyle&&x.to==v&&(b||(b=[])).push(k.endStyle,x.to),k.title&&((f||(f={})).title=k.title),k.attributes)for(var C in k.attributes)(f||(f={}))[C]=k.attributes[C];k.collapsed&&(!d||Ft(d.marker,k)<0)&&(d=x)}else x.from>p&&v>x.from&&(v=x.from)}if(b)for(var S=0;S<b.length;S+=2)b[S+1]==v&&(c+=" "+b[S]);if(!d||d.from==p)for(var T=0;T<y.length;++T)ln(t,0,y[T]);if(d&&(d.from||0)==p){if(ln(t,(null==d.to?h+1:d.to)-p,d.marker,null==d.from),null==d.to)return;d.to==p&&(d=!1)}}if(p>=h)break;for(var L=Math.min(h,v);;){if(g){var M=p+g.length;if(!d){var A=M>L?g.slice(0,L-p):g;t.addToken(t,A,a?a+s:s,u,p+A.length==v?c:"",l,f)}if(M>=L){g=g.slice(L-p),p=L;break}p=M,u=""}g=i.slice(o,o=n[m++]),a=tn(n[m++],t.cm.options)}}else for(var N=1;N<n.length;N+=2)t.addToken(t,i.slice(o,o=n[N]),tn(n[N+1],t.cm.options))}function cn(e,t,n){this.line=t,this.rest=function(e){for(var t,n;t=Rt(e);)e=t.find(1,!0).line,(n||(n=[])).push(e);return n}(t),this.size=this.rest?tt(Q(this.rest))-n+1:1,this.node=this.text=null,this.hidden=Vt(e,t)}function un(e,t,n){for(var r,i=[],o=t;o<n;o=r){var a=new cn(e.doc,Ze(e.doc,o),o);r=o+a.size,i.push(a)}return i}var dn=null;var fn=null;function hn(e,t){var n=ve(e,t);if(n.length){var r,i=Array.prototype.slice.call(arguments,2);dn?r=dn.delayedCallbacks:fn?r=fn:(r=fn=[],setTimeout(pn,0));for(var o=function(e){r.push(function(){return n[e].apply(null,i)})},a=0;a<n.length;++a)o(a)}}function pn(){var e=fn;fn=null;for(var t=0;t<e.length;++t)e[t]()}function mn(e,t,n,r){for(var i=0;i<t.changes.length;i++){var o=t.changes[i];"text"==o?yn(e,t):"gutter"==o?wn(e,t,n,r):"class"==o?bn(e,t):"widget"==o&&xn(e,t,r)}t.changes=null}function gn(e){return e.node==e.text&&(e.node=O("div",null,null,"position: relative"),e.text.parentNode&&e.text.parentNode.replaceChild(e.node,e.text),e.node.appendChild(e.text),a&&l<8&&(e.node.style.zIndex=2)),e.node}function vn(e,t){var n=e.display.externalMeasured;return n&&n.line==t.line?(e.display.externalMeasured=null,t.measure=n.measure,n.built):nn(e,t)}function yn(e,t){var n=t.text.className,r=vn(e,t);t.text==t.node&&(t.node=r.pre),t.text.parentNode.replaceChild(r.pre,t.text),t.text=r.pre,r.bgClass!=t.bgClass||r.textClass!=t.textClass?(t.bgClass=r.bgClass,t.textClass=r.textClass,bn(e,t)):n&&(t.text.className=n)}function bn(e,t){(function(e,t){var n=t.bgClass?t.bgClass+" "+(t.line.bgClass||""):t.line.bgClass;if(n&&(n+=" CodeMirror-linebackground"),t.background)n?t.background.className=n:(t.background.parentNode.removeChild(t.background),t.background=null);else if(n){var r=gn(t);t.background=r.insertBefore(O("div",null,n),r.firstChild),e.display.input.setUneditable(t.background)}})(e,t),t.line.wrapClass?gn(t).className=t.line.wrapClass:t.node!=t.text&&(t.node.className="");var n=t.textClass?t.textClass+" "+(t.line.textClass||""):t.line.textClass;t.text.className=n||""}function wn(e,t,n,r){if(t.gutter&&(t.node.removeChild(t.gutter),t.gutter=null),t.gutterBackground&&(t.node.removeChild(t.gutterBackground),t.gutterBackground=null),t.line.gutterClass){var i=gn(t);t.gutterBackground=O("div",null,"CodeMirror-gutter-background "+t.line.gutterClass,"left: "+(e.options.fixedGutter?r.fixedPos:-r.gutterTotalWidth)+"px; width: "+r.gutterTotalWidth+"px"),e.display.input.setUneditable(t.gutterBackground),i.insertBefore(t.gutterBackground,t.text)}var o=t.line.gutterMarkers;if(e.options.lineNumbers||o){var a=gn(t),l=t.gutter=O("div",null,"CodeMirror-gutter-wrapper","left: "+(e.options.fixedGutter?r.fixedPos:-r.gutterTotalWidth)+"px");if(l.setAttribute("aria-hidden","true"),e.display.input.setUneditable(l),a.insertBefore(l,t.text),t.line.gutterClass&&(l.className+=" "+t.line.gutterClass),!e.options.lineNumbers||o&&o["CodeMirror-linenumbers"]||(t.lineNumber=l.appendChild(O("div",it(e.options,n),"CodeMirror-linenumber CodeMirror-gutter-elt","left: "+r.gutterLeft["CodeMirror-linenumbers"]+"px; width: "+e.display.lineNumInnerWidth+"px"))),o)for(var s=0;s<e.display.gutterSpecs.length;++s){var c=e.display.gutterSpecs[s].className,u=o.hasOwnProperty(c)&&o[c];u&&l.appendChild(O("div",[u],"CodeMirror-gutter-elt","left: "+r.gutterLeft[c]+"px; width: "+r.gutterWidth[c]+"px"))}}}function xn(e,t,n){t.alignable&&(t.alignable=null);for(var r=T("CodeMirror-linewidget"),i=t.node.firstChild,o=void 0;i;i=o)o=i.nextSibling,r.test(i.className)&&t.node.removeChild(i);Cn(e,t,n)}function kn(e,t,n,r){var i=vn(e,t);return t.text=t.node=i.pre,i.bgClass&&(t.bgClass=i.bgClass),i.textClass&&(t.textClass=i.textClass),bn(e,t),wn(e,t,n,r),Cn(e,t,r),t.node}function Cn(e,t,n){if(Sn(e,t.line,t,n,!0),t.rest)for(var r=0;r<t.rest.length;r++)Sn(e,t.rest[r],t,n,!1)}function Sn(e,t,n,r,i){if(t.widgets)for(var o=gn(n),a=0,l=t.widgets;a<l.length;++a){var s=l[a],c=O("div",[s.node],"CodeMirror-linewidget"+(s.className?" "+s.className:""));s.handleMouseEvents||c.setAttribute("cm-ignore-events","true"),Tn(s,c,n,r),e.display.input.setUneditable(c),i&&s.above?o.insertBefore(c,n.gutter||n.text):o.appendChild(c),hn(s,"redraw")}}function Tn(e,t,n,r){if(e.noHScroll){(n.alignable||(n.alignable=[])).push(t);var i=r.wrapperWidth;t.style.left=r.fixedPos+"px",e.coverGutter||(i-=r.gutterTotalWidth,t.style.paddingLeft=r.gutterTotalWidth+"px"),t.style.width=i+"px"}e.coverGutter&&(t.style.zIndex=5,t.style.position="relative",e.noHScroll||(t.style.marginLeft=-r.gutterTotalWidth+"px"))}function Ln(e){if(null!=e.height)return e.height;var t=e.doc.cm;if(!t)return 0;if(!E(document.body,e.node)){var n="position: relative;";e.coverGutter&&(n+="margin-left: -"+t.display.gutters.offsetWidth+"px;"),e.noHScroll&&(n+="width: "+t.display.wrapper.clientWidth+"px;"),N(t.display.measure,O("div",[e.node],null,n))}return e.height=e.node.parentNode.offsetHeight}function Mn(e,t){for(var n=Ae(t);n!=e.wrapper;n=n.parentNode)if(!n||1==n.nodeType&&"true"==n.getAttribute("cm-ignore-events")||n.parentNode==e.sizer&&n!=e.mover)return!0}function An(e){return e.lineSpace.offsetTop}function Nn(e){return e.mover.offsetHeight-e.lineSpace.offsetHeight}function On(e){if(e.cachedPaddingH)return e.cachedPaddingH;var t=N(e.measure,O("pre","x","CodeMirror-line-like")),n=window.getComputedStyle?window.getComputedStyle(t):t.currentStyle,r={left:parseInt(n.paddingLeft),right:parseInt(n.paddingRight)};return isNaN(r.left)||isNaN(r.right)||(e.cachedPaddingH=r),r}function _n(e){return 50-e.display.nativeBarWidth}function En(e){return e.display.scroller.clientWidth-_n(e)-e.display.barWidth}function zn(e){return e.display.scroller.clientHeight-_n(e)-e.display.barHeight}function Dn(e,t,n){if(e.line==t)return{map:e.measure.map,cache:e.measure.cache};if(e.rest){for(var r=0;r<e.rest.length;r++)if(e.rest[r]==t)return{map:e.measure.maps[r],cache:e.measure.caches[r]};for(var i=0;i<e.rest.length;i++)if(tt(e.rest[i])>n)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}}function Pn(e,t,n,r){return In(e,Fn(e,t),n,r)}function Wn(e,t){if(t>=e.display.viewFrom&&t<e.display.viewTo)return e.display.view[mr(e,t)];var n=e.display.externalMeasured;return n&&t>=n.lineN&&t<n.lineN+n.size?n:void 0}function Fn(e,t){var n=tt(t),r=Wn(e,n);r&&!r.text?r=null:r&&r.changes&&(mn(e,r,n,ur(e)),e.curOp.forceUpdate=!0),r||(r=function(e,t){var n=tt(t=qt(t)),r=e.display.externalMeasured=new cn(e.doc,t,n);r.lineN=n;var i=r.built=nn(e,r);return r.text=i.pre,N(e.display.lineMeasure,i.pre),r}(e,t));var i=Dn(r,t,n);return{line:t,view:r,rect:null,map:i.map,cache:i.cache,before:i.before,hasHeights:!1}}function In(e,t,n,r,i){t.before&&(n=-1);var o,s=n+(r||"");return t.cache.hasOwnProperty(s)?o=t.cache[s]:(t.rect||(t.rect=t.view.text.getBoundingClientRect()),t.hasHeights||(function(e,t,n){var r=e.options.lineWrapping,i=r&&En(e);if(!t.measure.heights||r&&t.measure.width!=i){var o=t.measure.heights=[];if(r){t.measure.width=i;for(var a=t.text.firstChild.getClientRects(),l=0;l<a.length-1;l++){var s=a[l],c=a[l+1];Math.abs(s.bottom-c.bottom)>2&&o.push((s.bottom+c.top)/2-n.top)}}o.push(n.bottom-n.top)}}(e,t.view,t.rect),t.hasHeights=!0),(o=function(e,t,n,r){var i,o=jn(t.map,n,r),s=o.node,c=o.start,u=o.end,d=o.collapse;if(3==s.nodeType){for(var f=0;f<4;f++){for(;c&&se(t.line.text.charAt(o.coverStart+c));)--c;for(;o.coverStart+u<o.coverEnd&&se(t.line.text.charAt(o.coverStart+u));)++u;if((i=a&&l<9&&0==c&&u==o.coverEnd-o.coverStart?s.parentNode.getBoundingClientRect():Bn(L(s,c,u).getClientRects(),r)).left||i.right||0==c)break;u=c,c-=1,d="right"}a&&l<11&&(i=function(e,t){if(!window.screen||null==screen.logicalXDPI||screen.logicalXDPI==screen.deviceXDPI||!function(e){if(null!=He)return He;var t=N(e,O("span","x")),n=t.getBoundingClientRect(),r=L(t,0,1).getBoundingClientRect();return He=Math.abs(n.left-r.left)>1}(e))return t;var n=screen.logicalXDPI/screen.deviceXDPI,r=screen.logicalYDPI/screen.deviceYDPI;return{left:t.left*n,right:t.right*n,top:t.top*r,bottom:t.bottom*r}}(e.display.measure,i))}else{var h;c>0&&(d=r="right"),i=e.options.lineWrapping&&(h=s.getClientRects()).length>1?h["right"==r?h.length-1:0]:s.getBoundingClientRect()}if(a&&l<9&&!c&&(!i||!i.left&&!i.right)){var p=s.parentNode.getClientRects()[0];i=p?{left:p.left,right:p.left+cr(e.display),top:p.top,bottom:p.bottom}:Rn}for(var m=i.top-t.rect.top,g=i.bottom-t.rect.top,v=(m+g)/2,y=t.view.measure.heights,b=0;b<y.length-1&&!(v<y[b]);b++);var w=b?y[b-1]:0,x=y[b],k={left:("right"==d?i.right:i.left)-t.rect.left,right:("left"==d?i.left:i.right)-t.rect.left,top:w,bottom:x};return i.left||i.right||(k.bogus=!0),e.options.singleCursorHeightPerLine||(k.rtop=m,k.rbottom=g),k}(e,t,n,r)).bogus||(t.cache[s]=o)),{left:o.left,right:o.right,top:i?o.rtop:o.top,bottom:i?o.rbottom:o.bottom}}var Hn,Rn={left:0,right:0,top:0,bottom:0};function jn(e,t,n){for(var r,i,o,a,l,s,c=0;c<e.length;c+=3)if(l=e[c],s=e[c+1],t<l?(i=0,o=1,a="left"):t<s?o=1+(i=t-l):(c==e.length-3||t==s&&e[c+3]>t)&&(i=(o=s-l)-1,t>=s&&(a="right")),null!=i){if(r=e[c+2],l==s&&n==(r.insertLeft?"left":"right")&&(a=n),"left"==n&&0==i)for(;c&&e[c-2]==e[c-3]&&e[c-1].insertLeft;)r=e[2+(c-=3)],a="left";if("right"==n&&i==s-l)for(;c<e.length-3&&e[c+3]==e[c+4]&&!e[c+5].insertLeft;)r=e[(c+=3)+2],a="right";break}return{node:r,start:i,end:o,collapse:a,coverStart:l,coverEnd:s}}function Bn(e,t){var n=Rn;if("left"==t)for(var r=0;r<e.length&&(n=e[r]).left==n.right;r++);else for(var i=e.length-1;i>=0&&(n=e[i]).left==n.right;i--);return n}function qn(e){if(e.measure&&(e.measure.cache={},e.measure.heights=null,e.rest))for(var t=0;t<e.rest.length;t++)e.measure.caches[t]={}}function Un(e){e.display.externalMeasure=null,A(e.display.lineMeasure);for(var t=0;t<e.display.view.length;t++)qn(e.display.view[t])}function Kn(e){Un(e),e.display.cachedCharWidth=e.display.cachedTextHeight=e.display.cachedPaddingH=null,e.options.lineWrapping||(e.display.maxLineChanged=!0),e.display.lineNumChars=null}function Vn(e){return u&&v?-(e.body.getBoundingClientRect().left-parseInt(getComputedStyle(e.body).marginLeft)):e.defaultView.pageXOffset||(e.documentElement||e.body).scrollLeft}function Gn(e){return u&&v?-(e.body.getBoundingClientRect().top-parseInt(getComputedStyle(e.body).marginTop)):e.defaultView.pageYOffset||(e.documentElement||e.body).scrollTop}function $n(e){var t=qt(e).widgets,n=0;if(t)for(var r=0;r<t.length;++r)t[r].above&&(n+=Ln(t[r]));return n}function Yn(e,t,n,r,i){if(!i){var o=$n(t);n.top+=o,n.bottom+=o}if("line"==r)return n;r||(r="local");var a=$t(t);if("local"==r?a+=An(e.display):a-=e.display.viewOffset,"page"==r||"window"==r){var l=e.display.lineSpace.getBoundingClientRect();a+=l.top+("window"==r?0:Gn(F(e)));var s=l.left+("window"==r?0:Vn(F(e)));n.left+=s,n.right+=s}return n.top+=a,n.bottom+=a,n}function Xn(e,t,n){if("div"==n)return t;var r=t.left,i=t.top;if("page"==n)r-=Vn(F(e)),i-=Gn(F(e));else if("local"==n||!n){var o=e.display.sizer.getBoundingClientRect();r+=o.left,i+=o.top}var a=e.display.lineSpace.getBoundingClientRect();return{left:r-a.left,top:i-a.top}}function Zn(e,t,n,r,i){return r||(r=Ze(e.doc,t.line)),Yn(e,r,Pn(e,r,t.ch,i),n)}function Jn(e,t,n,r,i,o){function a(t,a){var l=In(e,i,t,a?"right":"left",o);return a?l.left=l.right:l.right=l.left,Yn(e,r,l,n)}r=r||Ze(e.doc,t.line),i||(i=Fn(e,r));var l=pe(r,e.doc.direction),s=t.ch,c=t.sticky;if(s>=r.text.length?(s=r.text.length,c="before"):s<=0&&(s=0,c="after"),!l)return a("before"==c?s-1:s,"before"==c);function u(e,t,n){return a(n?e-1:e,1==l[t].level!=n)}var d=fe(l,s,c),f=de,h=u(s,d,"before"==c);return null!=f&&(h.other=u(s,f,"before"!=c)),h}function Qn(e,t){var n=0;t=ft(e.doc,t),e.options.lineWrapping||(n=cr(e.display)*t.ch);var r=Ze(e.doc,t.line),i=$t(r)+An(e.display);return{left:n,right:n,top:i,bottom:i+r.height}}function er(e,t,n,r,i){var o=ot(e,t,n);return o.xRel=i,r&&(o.outside=r),o}function tr(e,t,n){var r=e.doc;if((n+=e.display.viewOffset)<0)return er(r.first,0,null,-1,-1);var i=nt(r,n),o=r.first+r.size-1;if(i>o)return er(r.first+r.size-1,Ze(r,o).text.length,null,1,1);t<0&&(t=0);for(var a=Ze(r,i);;){var l=or(e,a,i,t,n),s=jt(a,l.ch+(l.xRel>0||l.outside>0?1:0));if(!s)return l;var c=s.find(1);if(c.line==i)return c;a=Ze(r,i=c.line)}}function nr(e,t,n,r){r-=$n(t);var i=t.text.length,o=ue(function(t){return In(e,n,t-1).bottom<=r},i,0);return{begin:o,end:i=ue(function(t){return In(e,n,t).top>r},o,i)}}function rr(e,t,n,r){return n||(n=Fn(e,t)),nr(e,t,n,Yn(e,t,In(e,n,r),"line").top)}function ir(e,t,n,r){return!(e.bottom<=n)&&(e.top>n||(r?e.left:e.right)>t)}function or(e,t,n,r,i){i-=$t(t);var o=Fn(e,t),a=$n(t),l=0,s=t.text.length,c=!0,u=pe(t,e.doc.direction);if(u){var d=(e.options.lineWrapping?lr:ar)(e,t,n,o,u,r,i);l=(c=1!=d.level)?d.from:d.to-1,s=c?d.to:d.from-1}var f,h,p=null,m=null,g=ue(function(t){var n=In(e,o,t);return n.top+=a,n.bottom+=a,!!ir(n,r,i,!1)&&(n.top<=i&&n.left<=r&&(p=t,m=n),!0)},l,s),v=!1;if(m){var y=r-m.left<m.right-r,b=y==c;g=p+(b?0:1),h=b?"after":"before",f=y?m.left:m.right}else{c||g!=s&&g!=l||g++,h=0==g?"after":g==t.text.length?"before":In(e,o,g-(c?1:0)).bottom+a<=i==c?"after":"before";var w=Jn(e,ot(n,g,h),"line",t,o);f=w.left,v=i<w.top?-1:i>=w.bottom?1:0}return er(n,g=ce(t.text,g,1),h,v,r-f)}function ar(e,t,n,r,i,o,a){var l=ue(function(l){var s=i[l],c=1!=s.level;return ir(Jn(e,ot(n,c?s.to:s.from,c?"before":"after"),"line",t,r),o,a,!0)},0,i.length-1),s=i[l];if(l>0){var c=1!=s.level,u=Jn(e,ot(n,c?s.from:s.to,c?"after":"before"),"line",t,r);ir(u,o,a,!0)&&u.top>a&&(s=i[l-1])}return s}function lr(e,t,n,r,i,o,a){var l=nr(e,t,r,a),s=l.begin,c=l.end;/\s/.test(t.text.charAt(c-1))&&c--;for(var u=null,d=null,f=0;f<i.length;f++){var h=i[f];if(!(h.from>=c||h.to<=s)){var p=In(e,r,1!=h.level?Math.min(c,h.to)-1:Math.max(s,h.from)).right,m=p<o?o-p+1e9:p-o;(!u||d>m)&&(u=h,d=m)}}return u||(u=i[i.length-1]),u.from<s&&(u={from:s,to:u.to,level:u.level}),u.to>c&&(u={from:u.from,to:c,level:u.level}),u}function sr(e){if(null!=e.cachedTextHeight)return e.cachedTextHeight;if(null==Hn){Hn=O("pre",null,"CodeMirror-line-like");for(var t=0;t<49;++t)Hn.appendChild(document.createTextNode("x")),Hn.appendChild(O("br"));Hn.appendChild(document.createTextNode("x"))}N(e.measure,Hn);var n=Hn.offsetHeight/50;return n>3&&(e.cachedTextHeight=n),A(e.measure),n||1}function cr(e){if(null!=e.cachedCharWidth)return e.cachedCharWidth;var t=O("span","xxxxxxxxxx"),n=O("pre",[t],"CodeMirror-line-like");N(e.measure,n);var r=t.getBoundingClientRect(),i=(r.right-r.left)/10;return i>2&&(e.cachedCharWidth=i),i||10}function ur(e){for(var t=e.display,n={},r={},i=t.gutters.clientLeft,o=t.gutters.firstChild,a=0;o;o=o.nextSibling,++a){var l=e.display.gutterSpecs[a].className;n[l]=o.offsetLeft+o.clientLeft+i,r[l]=o.clientWidth}return{fixedPos:dr(t),gutterTotalWidth:t.gutters.offsetWidth,gutterLeft:n,gutterWidth:r,wrapperWidth:t.wrapper.clientWidth}}function dr(e){return e.scroller.getBoundingClientRect().left-e.sizer.getBoundingClientRect().left}function fr(e){var t=sr(e.display),n=e.options.lineWrapping,r=n&&Math.max(5,e.display.scroller.clientWidth/cr(e.display)-3);return function(i){if(Vt(e.doc,i))return 0;var o=0;if(i.widgets)for(var a=0;a<i.widgets.length;a++)i.widgets[a].height&&(o+=i.widgets[a].height);return n?o+(Math.ceil(i.text.length/r)||1)*t:o+t}}function hr(e){var t=e.doc,n=fr(e);t.iter(function(e){var t=n(e);t!=e.height&&et(e,t)})}function pr(e,t,n,r){var i=e.display;if(!n&&"true"==Ae(t).getAttribute("cm-not-content"))return null;var o,a,l=i.lineSpace.getBoundingClientRect();try{o=t.clientX-l.left,a=t.clientY-l.top}catch(e){return null}var s,c=tr(e,o,a);if(r&&c.xRel>0&&(s=Ze(e.doc,c.line).text).length==c.ch){var u=q(s,s.length,e.options.tabSize)-s.length;c=ot(c.line,Math.max(0,Math.round((o-On(e.display).left)/cr(e.display))-u))}return c}function mr(e,t){if(t>=e.display.viewTo)return null;if((t-=e.display.viewFrom)<0)return null;for(var n=e.display.view,r=0;r<n.length;r++)if((t-=n[r].size)<0)return r}function gr(e,t,n,r){null==t&&(t=e.doc.first),null==n&&(n=e.doc.first+e.doc.size),r||(r=0);var i=e.display;if(r&&n<i.viewTo&&(null==i.updateLineNumbers||i.updateLineNumbers>t)&&(i.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=i.viewTo)Mt&&Ut(e.doc,t)<i.viewTo&&yr(e);else if(n<=i.viewFrom)Mt&&Kt(e.doc,n+r)>i.viewFrom?yr(e):(i.viewFrom+=r,i.viewTo+=r);else if(t<=i.viewFrom&&n>=i.viewTo)yr(e);else if(t<=i.viewFrom){var o=br(e,n,n+r,1);o?(i.view=i.view.slice(o.index),i.viewFrom=o.lineN,i.viewTo+=r):yr(e)}else if(n>=i.viewTo){var a=br(e,t,t,-1);a?(i.view=i.view.slice(0,a.index),i.viewTo=a.lineN):yr(e)}else{var l=br(e,t,t,-1),s=br(e,n,n+r,1);l&&s?(i.view=i.view.slice(0,l.index).concat(un(e,l.lineN,s.lineN)).concat(i.view.slice(s.index)),i.viewTo+=r):yr(e)}var c=i.externalMeasured;c&&(n<c.lineN?c.lineN+=r:t<c.lineN+c.size&&(i.externalMeasured=null))}function vr(e,t,n){e.curOp.viewChanged=!0;var r=e.display,i=e.display.externalMeasured;if(i&&t>=i.lineN&&t<i.lineN+i.size&&(r.externalMeasured=null),!(t<r.viewFrom||t>=r.viewTo)){var o=r.view[mr(e,t)];if(null!=o.node){var a=o.changes||(o.changes=[]);-1==K(a,n)&&a.push(n)}}}function yr(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function br(e,t,n,r){var i,o=mr(e,t),a=e.display.view;if(!Mt||n==e.doc.first+e.doc.size)return{index:o,lineN:n};for(var l=e.display.viewFrom,s=0;s<o;s++)l+=a[s].size;if(l!=t){if(r>0){if(o==a.length-1)return null;i=l+a[o].size-t,o++}else i=l-t;t+=i,n+=i}for(;Ut(e.doc,n)!=n;){if(o==(r<0?0:a.length-1))return null;n+=r*a[o-(r<0?1:0)].size,o+=r}return{index:o,lineN:n}}function wr(e){for(var t=e.display.view,n=0,r=0;r<t.length;r++){var i=t[r];i.hidden||i.node&&!i.changes||++n}return n}function xr(e){e.display.input.showSelection(e.display.input.prepareSelection())}function kr(e,t){void 0===t&&(t=!0);var n=e.doc,r={},i=r.cursors=document.createDocumentFragment(),o=r.selection=document.createDocumentFragment(),a=e.options.$customCursor;a&&(t=!0);for(var l=0;l<n.sel.ranges.length;l++)if(t||l!=n.sel.primIndex){var s=n.sel.ranges[l];if(!(s.from().line>=e.display.viewTo||s.to().line<e.display.viewFrom)){var c=s.empty();if(a){var u=a(e,s);u&&Cr(e,u,i)}else(c||e.options.showCursorWhenSelecting)&&Cr(e,s.head,i);c||Tr(e,s,o)}}return r}function Cr(e,t,n){var r=Jn(e,t,"div",null,null,!e.options.singleCursorHeightPerLine),i=n.appendChild(O("div"," ","CodeMirror-cursor"));if(i.style.left=r.left+"px",i.style.top=r.top+"px",i.style.height=Math.max(0,r.bottom-r.top)*e.options.cursorHeight+"px",/\bcm-fat-cursor\b/.test(e.getWrapperElement().className)){var o=Zn(e,t,"div",null,null),a=o.right-o.left;i.style.width=(a>0?a:e.defaultCharWidth())+"px"}if(r.other){var l=n.appendChild(O("div"," ","CodeMirror-cursor CodeMirror-secondarycursor"));l.style.display="",l.style.left=r.other.left+"px",l.style.top=r.other.top+"px",l.style.height=.85*(r.other.bottom-r.other.top)+"px"}}function Sr(e,t){return e.top-t.top||e.left-t.left}function Tr(e,t,n){var r=e.display,i=e.doc,o=document.createDocumentFragment(),a=On(e.display),l=a.left,s=Math.max(r.sizerWidth,En(e)-r.sizer.offsetLeft)-a.right,c="ltr"==i.direction;function u(e,t,n,r){t<0&&(t=0),t=Math.round(t),r=Math.round(r),o.appendChild(O("div",null,"CodeMirror-selected","position: absolute; left: "+e+"px;\n top: "+t+"px; width: "+(null==n?s-e:n)+"px;\n height: "+(r-t)+"px"))}function d(t,n,r){var o,a,d=Ze(i,t),f=d.text.length;function h(n,r){return Zn(e,ot(t,n),"div",d,r)}function p(t,n,r){var i=rr(e,d,null,t),o="ltr"==n==("after"==r)?"left":"right";return h("after"==r?i.begin:i.end-(/\s/.test(d.text.charAt(i.end-1))?2:1),o)[o]}var m=pe(d,i.direction);return function(e,t,n,r){if(!e)return r(t,n,"ltr",0);for(var i=!1,o=0;o<e.length;++o){var a=e[o];(a.from<n&&a.to>t||t==n&&a.to==t)&&(r(Math.max(a.from,t),Math.min(a.to,n),1==a.level?"rtl":"ltr",o),i=!0)}i||r(t,n,"ltr")}(m,n||0,null==r?f:r,function(e,t,i,d){var g="ltr"==i,v=h(e,g?"left":"right"),y=h(t-1,g?"right":"left"),b=null==n&&0==e,w=null==r&&t==f,x=0==d,k=!m||d==m.length-1;if(y.top-v.top<=3){var C=(c?w:b)&&k,S=(c?b:w)&&x?l:(g?v:y).left,T=C?s:(g?y:v).right;u(S,v.top,T-S,v.bottom)}else{var L,M,A,N;g?(L=c&&b&&x?l:v.left,M=c?s:p(e,i,"before"),A=c?l:p(t,i,"after"),N=c&&w&&k?s:y.right):(L=c?p(e,i,"before"):l,M=!c&&b&&x?s:v.right,A=!c&&w&&k?l:y.left,N=c?p(t,i,"after"):s),u(L,v.top,M-L,v.bottom),v.bottom<y.top&&u(l,v.bottom,null,y.top),u(A,y.top,N-A,y.bottom)}(!o||Sr(v,o)<0)&&(o=v),Sr(y,o)<0&&(o=y),(!a||Sr(v,a)<0)&&(a=v),Sr(y,a)<0&&(a=y)}),{start:o,end:a}}var f=t.from(),h=t.to();if(f.line==h.line)d(f.line,f.ch,h.ch);else{var p=Ze(i,f.line),m=Ze(i,h.line),g=qt(p)==qt(m),v=d(f.line,f.ch,g?p.text.length+1:null).end,y=d(h.line,g?0:null,h.ch).start;g&&(v.top<y.top-2?(u(v.right,v.top,null,v.bottom),u(l,y.top,y.left,y.bottom)):u(v.right,v.top,y.left-v.right,v.bottom)),v.bottom<y.top&&u(l,v.bottom,null,y.top)}n.appendChild(o)}function Lr(e){if(e.state.focused){var t=e.display;clearInterval(t.blinker);var n=!0;t.cursorDiv.style.visibility="",e.options.cursorBlinkRate>0?t.blinker=setInterval(function(){e.hasFocus()||Or(e),t.cursorDiv.style.visibility=(n=!n)?"":"hidden"},e.options.cursorBlinkRate):e.options.cursorBlinkRate<0&&(t.cursorDiv.style.visibility="hidden")}}function Mr(e){e.hasFocus()||(e.display.input.focus(),e.state.focused||Nr(e))}function Ar(e){e.state.delayingBlurEvent=!0,setTimeout(function(){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1,e.state.focused&&Or(e))},100)}function Nr(e,t){e.state.delayingBlurEvent&&!e.state.draggingText&&(e.state.delayingBlurEvent=!1),"nocursor"!=e.options.readOnly&&(e.state.focused||(be(e,"focus",e,t),e.state.focused=!0,D(e.display.wrapper,"CodeMirror-focused"),e.curOp||e.display.selForContextMenu==e.doc.sel||(e.display.input.reset(),s&&setTimeout(function(){return e.display.input.reset(!0)},20)),e.display.input.receivedFocus()),Lr(e))}function Or(e,t){e.state.delayingBlurEvent||(e.state.focused&&(be(e,"blur",e,t),e.state.focused=!1,M(e.display.wrapper,"CodeMirror-focused")),clearInterval(e.display.blinker),setTimeout(function(){e.state.focused||(e.display.shift=!1)},150))}function _r(e){for(var t=e.display,n=t.lineDiv.offsetTop,r=Math.max(0,t.scroller.getBoundingClientRect().top),i=t.lineDiv.getBoundingClientRect().top,o=0,s=0;s<t.view.length;s++){var c=t.view[s],u=e.options.lineWrapping,d=void 0,f=0;if(!c.hidden){if(i+=c.line.height,a&&l<8){var h=c.node.offsetTop+c.node.offsetHeight;d=h-n,n=h}else{var p=c.node.getBoundingClientRect();d=p.bottom-p.top,!u&&c.text.firstChild&&(f=c.text.firstChild.getBoundingClientRect().right-p.left-1)}var m=c.line.height-d;if((m>.005||m<-.005)&&(i<r&&(o-=m),et(c.line,d),Er(c.line),c.rest))for(var g=0;g<c.rest.length;g++)Er(c.rest[g]);if(f>e.display.sizerWidth){var v=Math.ceil(f/cr(e.display));v>e.display.maxLineLength&&(e.display.maxLineLength=v,e.display.maxLine=c.line,e.display.maxLineChanged=!0)}}}Math.abs(o)>2&&(t.scroller.scrollTop+=o)}function Er(e){if(e.widgets)for(var t=0;t<e.widgets.length;++t){var n=e.widgets[t],r=n.node.parentNode;r&&(n.height=r.offsetHeight)}}function zr(e,t,n){var r=n&&null!=n.top?Math.max(0,n.top):e.scroller.scrollTop;r=Math.floor(r-An(e));var i=n&&null!=n.bottom?n.bottom:r+e.wrapper.clientHeight,o=nt(t,r),a=nt(t,i);if(n&&n.ensure){var l=n.ensure.from.line,s=n.ensure.to.line;l<o?(o=l,a=nt(t,$t(Ze(t,l))+e.wrapper.clientHeight)):Math.min(s,t.lastLine())>=a&&(o=nt(t,$t(Ze(t,s))-e.wrapper.clientHeight),a=s)}return{from:o,to:Math.max(a,o+1)}}function Dr(e,t){var n=e.display,r=sr(e.display);t.top<0&&(t.top=0);var i=e.curOp&&null!=e.curOp.scrollTop?e.curOp.scrollTop:n.scroller.scrollTop,o=zn(e),a={};t.bottom-t.top>o&&(t.bottom=t.top+o);var l=e.doc.height+Nn(n),s=t.top<r,c=t.bottom>l-r;if(t.top<i)a.scrollTop=s?0:t.top;else if(t.bottom>i+o){var u=Math.min(t.top,(c?l:t.bottom)-o);u!=i&&(a.scrollTop=u)}var d=e.options.fixedGutter?0:n.gutters.offsetWidth,f=e.curOp&&null!=e.curOp.scrollLeft?e.curOp.scrollLeft:n.scroller.scrollLeft-d,h=En(e)-n.gutters.offsetWidth,p=t.right-t.left>h;return p&&(t.right=t.left+h),t.left<10?a.scrollLeft=0:t.left<f?a.scrollLeft=Math.max(0,t.left+d-(p?0:10)):t.right>h+f-3&&(a.scrollLeft=t.right+(p?0:10)-h),a}function Pr(e,t){null!=t&&(Ir(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc.scrollTop:e.curOp.scrollTop)+t)}function Wr(e){Ir(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function Fr(e,t,n){null==t&&null==n||Ir(e),null!=t&&(e.curOp.scrollLeft=t),null!=n&&(e.curOp.scrollTop=n)}function Ir(e){var t=e.curOp.scrollToPos;t&&(e.curOp.scrollToPos=null,Hr(e,Qn(e,t.from),Qn(e,t.to),t.margin))}function Hr(e,t,n,r){var i=Dr(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});Fr(e,i.scrollLeft,i.scrollTop)}function Rr(e,t){Math.abs(e.doc.scrollTop-t)<2||(n||hi(e,{top:t}),jr(e,t,!0),n&&hi(e),si(e,100))}function jr(e,t,n){t=Math.max(0,Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t)),(e.display.scroller.scrollTop!=t||n)&&(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function Br(e,t,n,r){t=Math.max(0,Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth)),(n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r||(e.doc.scrollLeft=t,gi(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function qr(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+Nn(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+_n(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}var Ur=function(e,t,n){this.cm=n;var r=this.vert=O("div",[O("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),i=this.horiz=O("div",[O("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");r.tabIndex=i.tabIndex=-1,e(r),e(i),ge(r,"scroll",function(){r.clientHeight&&t(r.scrollTop,"vertical")}),ge(i,"scroll",function(){i.clientWidth&&t(i.scrollLeft,"horizontal")}),this.checkedZeroWidth=!1,a&&l<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")};Ur.prototype.update=function(e){var t=e.scrollWidth>e.clientWidth+1,n=e.scrollHeight>e.clientHeight+1,r=e.nativeBarWidth;if(n){this.vert.style.display="block",this.vert.style.bottom=t?r+"px":"0";var i=e.viewHeight-(t?r:0);this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+i)+"px"}else this.vert.scrollTop=0,this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=n?r+"px":"0",this.horiz.style.left=e.barLeft+"px";var o=e.viewWidth-e.barLeft-(n?r:0);this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+o)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&e.clientHeight>0&&(0==r&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:n?r:0,bottom:t?r:0}},Ur.prototype.setScrollLeft=function(e){this.horiz.scrollLeft!=e&&(this.horiz.scrollLeft=e),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},Ur.prototype.setScrollTop=function(e){this.vert.scrollTop!=e&&(this.vert.scrollTop=e),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},Ur.prototype.zeroWidthHack=function(){var e=b&&!p?"12px":"18px";this.horiz.style.height=this.vert.style.width=e,this.horiz.style.visibility=this.vert.style.visibility="hidden",this.disableHoriz=new U,this.disableVert=new U},Ur.prototype.enableZeroWidthBar=function(e,t,n){e.style.visibility="",t.set(1e3,function r(){var i=e.getBoundingClientRect();("vert"==n?document.elementFromPoint(i.right-1,(i.top+i.bottom)/2):document.elementFromPoint((i.right+i.left)/2,i.bottom-1))!=e?e.style.visibility="hidden":t.set(1e3,r)})},Ur.prototype.clear=function(){var e=this.horiz.parentNode;e.removeChild(this.horiz),e.removeChild(this.vert)};var Kr=function(){};function Vr(e,t){t||(t=qr(e));var n=e.display.barWidth,r=e.display.barHeight;Gr(e,t);for(var i=0;i<4&&n!=e.display.barWidth||r!=e.display.barHeight;i++)n!=e.display.barWidth&&e.options.lineWrapping&&_r(e),Gr(e,qr(e)),n=e.display.barWidth,r=e.display.barHeight}function Gr(e,t){var n=e.display,r=n.scrollbars.update(t);n.sizer.style.paddingRight=(n.barWidth=r.right)+"px",n.sizer.style.paddingBottom=(n.barHeight=r.bottom)+"px",n.heightForcer.style.borderBottom=r.bottom+"px solid transparent",r.right&&r.bottom?(n.scrollbarFiller.style.display="block",n.scrollbarFiller.style.height=r.bottom+"px",n.scrollbarFiller.style.width=r.right+"px"):n.scrollbarFiller.style.display="",r.bottom&&e.options.coverGutterNextToScrollbar&&e.options.fixedGutter?(n.gutterFiller.style.display="block",n.gutterFiller.style.height=r.bottom+"px",n.gutterFiller.style.width=t.gutterWidth+"px"):n.gutterFiller.style.display=""}Kr.prototype.update=function(){return{bottom:0,right:0}},Kr.prototype.setScrollLeft=function(){},Kr.prototype.setScrollTop=function(){},Kr.prototype.clear=function(){};var $r={native:Ur,null:Kr};function Yr(e){e.display.scrollbars&&(e.display.scrollbars.clear(),e.display.scrollbars.addClass&&M(e.display.wrapper,e.display.scrollbars.addClass)),e.display.scrollbars=new $r[e.options.scrollbarStyle](function(t){e.display.wrapper.insertBefore(t,e.display.scrollbarFiller),ge(t,"mousedown",function(){e.state.focused&&setTimeout(function(){return e.display.input.focus()},0)}),t.setAttribute("cm-not-content","true")},function(t,n){"horizontal"==n?Br(e,t):Rr(e,t)},e),e.display.scrollbars.addClass&&D(e.display.wrapper,e.display.scrollbars.addClass)}var Xr=0;function Zr(e){var t;e.curOp={cm:e,viewChanged:!1,startHeight:e.doc.height,forceUpdate:!1,updateInput:0,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++Xr,markArrays:null},t=e.curOp,dn?dn.ops.push(t):t.ownsGroup=dn={ops:[t],delayedCallbacks:[]}}function Jr(e){var t=e.curOp;t&&function(e,t){var n=e.ownsGroup;if(n)try{!function(e){var t=e.delayedCallbacks,n=0;do{for(;n<t.length;n++)t[n].call(null);for(var r=0;r<e.ops.length;r++){var i=e.ops[r];if(i.cursorActivityHandlers)for(;i.cursorActivityCalled<i.cursorActivityHandlers.length;)i.cursorActivityHandlers[i.cursorActivityCalled++].call(null,i.cm)}}while(n<t.length)}(n)}finally{dn=null,t(n)}}(t,function(e){for(var t=0;t<e.ops.length;t++)e.ops[t].cm.curOp=null;!function(e){for(var t=e.ops,n=0;n<t.length;n++)Qr(t[n]);for(var r=0;r<t.length;r++)ei(t[r]);for(var i=0;i<t.length;i++)ti(t[i]);for(var o=0;o<t.length;o++)ni(t[o]);for(var a=0;a<t.length;a++)ri(t[a])}(e)})}function Qr(e){var t=e.cm,n=t.display;(function(e){var t=e.display;!t.scrollbarsClipped&&t.scroller.offsetWidth&&(t.nativeBarWidth=t.scroller.offsetWidth-t.scroller.clientWidth,t.heightForcer.style.height=_n(e)+"px",t.sizer.style.marginBottom=-t.nativeBarWidth+"px",t.sizer.style.borderRightWidth=_n(e)+"px",t.scrollbarsClipped=!0)})(t),e.updateMaxLine&&Xt(t),e.mustUpdate=e.viewChanged||e.forceUpdate||null!=e.scrollTop||e.scrollToPos&&(e.scrollToPos.from.line<n.viewFrom||e.scrollToPos.to.line>=n.viewTo)||n.maxLineChanged&&t.options.lineWrapping,e.update=e.mustUpdate&&new ui(t,e.mustUpdate&&{top:e.scrollTop,ensure:e.scrollToPos},e.forceUpdate)}function ei(e){e.updatedDisplay=e.mustUpdate&&di(e.cm,e.update)}function ti(e){var t=e.cm,n=t.display;e.updatedDisplay&&_r(t),e.barMeasure=qr(t),n.maxLineChanged&&!t.options.lineWrapping&&(e.adjustWidthTo=Pn(t,n.maxLine,n.maxLine.text.length).left+3,t.display.sizerWidth=e.adjustWidthTo,e.barMeasure.scrollWidth=Math.max(n.scroller.clientWidth,n.sizer.offsetLeft+e.adjustWidthTo+_n(t)+t.display.barWidth),e.maxScrollLeft=Math.max(0,n.sizer.offsetLeft+e.adjustWidthTo-En(t))),(e.updatedDisplay||e.selectionChanged)&&(e.preparedSelection=n.input.prepareSelection())}function ni(e){var t=e.cm;null!=e.adjustWidthTo&&(t.display.sizer.style.minWidth=e.adjustWidthTo+"px",e.maxScrollLeft<t.doc.scrollLeft&&Br(t,Math.min(t.display.scroller.scrollLeft,e.maxScrollLeft),!0),t.display.maxLineChanged=!1);var n=e.focus&&e.focus==z(I(t));e.preparedSelection&&t.display.input.showSelection(e.preparedSelection,n),(e.updatedDisplay||e.startHeight!=t.doc.height)&&Vr(t,e.barMeasure),e.updatedDisplay&&mi(t,e.barMeasure),e.selectionChanged&&Lr(t),t.state.focused&&e.updateInput&&t.display.input.reset(e.typing),n&&Mr(e.cm)}function ri(e){var t=e.cm,n=t.display,r=t.doc;e.updatedDisplay&&fi(t,e.update),null==n.wheelStartX||null==e.scrollTop&&null==e.scrollLeft&&!e.scrollToPos||(n.wheelStartX=n.wheelStartY=null),null!=e.scrollTop&&jr(t,e.scrollTop,e.forceScroll),null!=e.scrollLeft&&Br(t,e.scrollLeft,!0,!0),e.scrollToPos&&function(e,t){if(!we(e,"scrollCursorIntoView")){var n=e.display,r=n.sizer.getBoundingClientRect(),i=null,o=n.wrapper.ownerDocument;if(t.top+r.top<0?i=!0:t.bottom+r.top>(o.defaultView.innerHeight||o.documentElement.clientHeight)&&(i=!1),null!=i&&!m){var a=O("div","",null,"position: absolute;\n top: "+(t.top-n.viewOffset-An(e.display))+"px;\n height: "+(t.bottom-t.top+_n(e)+n.barHeight)+"px;\n left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;");e.display.lineSpace.appendChild(a),a.scrollIntoView(i),e.display.lineSpace.removeChild(a)}}}(t,function(e,t,n,r){var i;null==r&&(r=0),e.options.lineWrapping||t!=n||(n="before"==t.sticky?ot(t.line,t.ch+1,"before"):t,t=t.ch?ot(t.line,"before"==t.sticky?t.ch-1:t.ch,"after"):t);for(var o=0;o<5;o++){var a=!1,l=Jn(e,t),s=n&&n!=t?Jn(e,n):l,c=Dr(e,i={left:Math.min(l.left,s.left),top:Math.min(l.top,s.top)-r,right:Math.max(l.left,s.left),bottom:Math.max(l.bottom,s.bottom)+r}),u=e.doc.scrollTop,d=e.doc.scrollLeft;if(null!=c.scrollTop&&(Rr(e,c.scrollTop),Math.abs(e.doc.scrollTop-u)>1&&(a=!0)),null!=c.scrollLeft&&(Br(e,c.scrollLeft),Math.abs(e.doc.scrollLeft-d)>1&&(a=!0)),!a)break}return i}(t,ft(r,e.scrollToPos.from),ft(r,e.scrollToPos.to),e.scrollToPos.margin));var i=e.maybeHiddenMarkers,o=e.maybeUnhiddenMarkers;if(i)for(var a=0;a<i.length;++a)i[a].lines.length||be(i[a],"hide");if(o)for(var l=0;l<o.length;++l)o[l].lines.length&&be(o[l],"unhide");n.wrapper.offsetHeight&&(r.scrollTop=t.display.scroller.scrollTop),e.changeObjs&&be(t,"changes",t,e.changeObjs),e.update&&e.update.finish()}function ii(e,t){if(e.curOp)return t();Zr(e);try{return t()}finally{Jr(e)}}function oi(e,t){return function(){if(e.curOp)return t.apply(e,arguments);Zr(e);try{return t.apply(e,arguments)}finally{Jr(e)}}}function ai(e){return function(){if(this.curOp)return e.apply(this,arguments);Zr(this);try{return e.apply(this,arguments)}finally{Jr(this)}}}function li(e){return function(){var t=this.cm;if(!t||t.curOp)return e.apply(this,arguments);Zr(t);try{return e.apply(this,arguments)}finally{Jr(t)}}}function si(e,t){e.doc.highlightFrontier<e.display.viewTo&&e.state.highlight.set(t,j(ci,e))}function ci(e){var t=e.doc;if(!(t.highlightFrontier>=e.display.viewTo)){var n=+new Date+e.options.workTime,r=yt(e,t.highlightFrontier),i=[];t.iter(r.line,Math.min(t.first+t.size,e.display.viewTo+500),function(o){if(r.line>=e.display.viewFrom){var a=o.styles,l=o.text.length>e.options.maxHighlightLength?Ge(t.mode,r.state):null,s=gt(e,o,r,!0);l&&(r.state=l),o.styles=s.styles;var c=o.styleClasses,u=s.classes;u?o.styleClasses=u:c&&(o.styleClasses=null);for(var d=!a||a.length!=o.styles.length||c!=u&&(!c||!u||c.bgClass!=u.bgClass||c.textClass!=u.textClass),f=0;!d&&f<a.length;++f)d=a[f]!=o.styles[f];d&&i.push(r.line),o.stateAfter=r.save(),r.nextLine()}else o.text.length<=e.options.maxHighlightLength&&bt(e,o.text,r),o.stateAfter=r.line%5==0?r.save():null,r.nextLine();if(+new Date>n)return si(e,e.options.workDelay),!0}),t.highlightFrontier=r.line,t.modeFrontier=Math.max(t.modeFrontier,r.line),i.length&&ii(e,function(){for(var t=0;t<i.length;t++)vr(e,i[t],"text")})}}var ui=function(e,t,n){var r=e.display;this.viewport=t,this.visible=zr(r,e.doc,t),this.editorIsHidden=!r.wrapper.offsetWidth,this.wrapperHeight=r.wrapper.clientHeight,this.wrapperWidth=r.wrapper.clientWidth,this.oldDisplayWidth=En(e),this.force=n,this.dims=ur(e),this.events=[]};function di(e,t){var n=e.display,r=e.doc;if(t.editorIsHidden)return yr(e),!1;if(!t.force&&t.visible.from>=n.viewFrom&&t.visible.to<=n.viewTo&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo)&&n.renderedView==n.view&&0==wr(e))return!1;vi(e)&&(yr(e),t.dims=ur(e));var i=r.first+r.size,o=Math.max(t.visible.from-e.options.viewportMargin,r.first),a=Math.min(i,t.visible.to+e.options.viewportMargin);n.viewFrom<o&&o-n.viewFrom<20&&(o=Math.max(r.first,n.viewFrom)),n.viewTo>a&&n.viewTo-a<20&&(a=Math.min(i,n.viewTo)),Mt&&(o=Ut(e.doc,o),a=Kt(e.doc,a));var l=o!=n.viewFrom||a!=n.viewTo||n.lastWrapHeight!=t.wrapperHeight||n.lastWrapWidth!=t.wrapperWidth;(function(e,t,n){var r=e.display;0==r.view.length||t>=r.viewTo||n<=r.viewFrom?(r.view=un(e,t,n),r.viewFrom=t):(r.viewFrom>t?r.view=un(e,t,r.viewFrom).concat(r.view):r.viewFrom<t&&(r.view=r.view.slice(mr(e,t))),r.viewFrom=t,r.viewTo<n?r.view=r.view.concat(un(e,r.viewTo,n)):r.viewTo>n&&(r.view=r.view.slice(0,mr(e,n)))),r.viewTo=n})(e,o,a),n.viewOffset=$t(Ze(e.doc,n.viewFrom)),e.display.mover.style.top=n.viewOffset+"px";var c=wr(e);if(!l&&0==c&&!t.force&&n.renderedView==n.view&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo))return!1;var u=function(e){if(e.hasFocus())return null;var t=z(I(e));if(!t||!E(e.display.lineDiv,t))return null;var n={activeElt:t};if(window.getSelection){var r=R(e).getSelection();r.anchorNode&&r.extend&&E(e.display.lineDiv,r.anchorNode)&&(n.anchorNode=r.anchorNode,n.anchorOffset=r.anchorOffset,n.focusNode=r.focusNode,n.focusOffset=r.focusOffset)}return n}(e);return c>4&&(n.lineDiv.style.display="none"),function(e,t,n){var r=e.display,i=e.options.lineNumbers,o=r.lineDiv,a=o.firstChild;function l(t){var n=t.nextSibling;return s&&b&&e.display.currentWheelTarget==t?t.style.display="none":t.parentNode.removeChild(t),n}for(var c=r.view,u=r.viewFrom,d=0;d<c.length;d++){var f=c[d];if(f.hidden);else if(f.node&&f.node.parentNode==o){for(;a!=f.node;)a=l(a);var h=i&&null!=t&&t<=u&&f.lineNumber;f.changes&&(K(f.changes,"gutter")>-1&&(h=!1),mn(e,f,u,n)),h&&(A(f.lineNumber),f.lineNumber.appendChild(document.createTextNode(it(e.options,u)))),a=f.node.nextSibling}else{var p=kn(e,f,u,n);o.insertBefore(p,a)}u+=f.size}for(;a;)a=l(a)}(e,n.updateLineNumbers,t.dims),c>4&&(n.lineDiv.style.display=""),n.renderedView=n.view,function(e){if(e&&e.activeElt&&e.activeElt!=z(H(e.activeElt))&&(e.activeElt.focus(),!/^(INPUT|TEXTAREA)$/.test(e.activeElt.nodeName)&&e.anchorNode&&E(document.body,e.anchorNode)&&E(document.body,e.focusNode))){var t=e.activeElt.ownerDocument,n=t.defaultView.getSelection(),r=t.createRange();r.setEnd(e.anchorNode,e.anchorOffset),r.collapse(!1),n.removeAllRanges(),n.addRange(r),n.extend(e.focusNode,e.focusOffset)}}(u),A(n.cursorDiv),A(n.selectionDiv),n.gutters.style.height=n.sizer.style.minHeight=0,l&&(n.lastWrapHeight=t.wrapperHeight,n.lastWrapWidth=t.wrapperWidth,si(e,400)),n.updateLineNumbers=null,!0}function fi(e,t){for(var n=t.viewport,r=!0;;r=!1){if(r&&e.options.lineWrapping&&t.oldDisplayWidth!=En(e))r&&(t.visible=zr(e.display,e.doc,n));else if(n&&null!=n.top&&(n={top:Math.min(e.doc.height+Nn(e.display)-zn(e),n.top)}),t.visible=zr(e.display,e.doc,n),t.visible.from>=e.display.viewFrom&&t.visible.to<=e.display.viewTo)break;if(!di(e,t))break;_r(e);var i=qr(e);xr(e),Vr(e,i),mi(e,i),t.force=!1}t.signal(e,"update",e),e.display.viewFrom==e.display.reportedViewFrom&&e.display.viewTo==e.display.reportedViewTo||(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function hi(e,t){var n=new ui(e,t);if(di(e,n)){_r(e),fi(e,n);var r=qr(e);xr(e),Vr(e,r),mi(e,r),n.finish()}}function pi(e){var t=e.gutters.offsetWidth;e.sizer.style.marginLeft=t+"px",hn(e,"gutterChanged",e)}function mi(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+_n(e)+"px"}function gi(e){var t=e.display,n=t.view;if(t.alignWidgets||t.gutters.firstChild&&e.options.fixedGutter){for(var r=dr(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,o=r+"px",a=0;a<n.length;a++)if(!n[a].hidden){e.options.fixedGutter&&(n[a].gutter&&(n[a].gutter.style.left=o),n[a].gutterBackground&&(n[a].gutterBackground.style.left=o));var l=n[a].alignable;if(l)for(var s=0;s<l.length;s++)l[s].style.left=o}e.options.fixedGutter&&(t.gutters.style.left=r+i+"px")}}function vi(e){if(!e.options.lineNumbers)return!1;var t=e.doc,n=it(e.options,t.first+t.size-1),r=e.display;if(n.length!=r.lineNumChars){var i=r.measure.appendChild(O("div",[O("div",n)],"CodeMirror-linenumber CodeMirror-gutter-elt")),o=i.firstChild.offsetWidth,a=i.offsetWidth-o;return r.lineGutter.style.width="",r.lineNumInnerWidth=Math.max(o,r.lineGutter.offsetWidth-a)+1,r.lineNumWidth=r.lineNumInnerWidth+a,r.lineNumChars=r.lineNumInnerWidth?n.length:-1,r.lineGutter.style.width=r.lineNumWidth+"px",pi(e.display),!0}return!1}function yi(e,t){for(var n=[],r=!1,i=0;i<e.length;i++){var o=e[i],a=null;if("string"!=typeof o&&(a=o.style,o=o.className),"CodeMirror-linenumbers"==o){if(!t)continue;r=!0}n.push({className:o,style:a})}return t&&!r&&n.push({className:"CodeMirror-linenumbers",style:null}),n}function bi(e){var t=e.gutters,n=e.gutterSpecs;A(t),e.lineGutter=null;for(var r=0;r<n.length;++r){var i=n[r],o=i.className,a=i.style,l=t.appendChild(O("div",null,"CodeMirror-gutter "+o));a&&(l.style.cssText=a),"CodeMirror-linenumbers"==o&&(e.lineGutter=l,l.style.width=(e.lineNumWidth||1)+"px")}t.style.display=n.length?"":"none",pi(e)}function wi(e){bi(e.display),gr(e),gi(e)}function xi(e,t,r,i){var o=this;this.input=r,o.scrollbarFiller=O("div",null,"CodeMirror-scrollbar-filler"),o.scrollbarFiller.setAttribute("cm-not-content","true"),o.gutterFiller=O("div",null,"CodeMirror-gutter-filler"),o.gutterFiller.setAttribute("cm-not-content","true"),o.lineDiv=_("div",null,"CodeMirror-code"),o.selectionDiv=O("div",null,null,"position: relative; z-index: 1"),o.cursorDiv=O("div",null,"CodeMirror-cursors"),o.measure=O("div",null,"CodeMirror-measure"),o.lineMeasure=O("div",null,"CodeMirror-measure"),o.lineSpace=_("div",[o.measure,o.lineMeasure,o.selectionDiv,o.cursorDiv,o.lineDiv],null,"position: relative; outline: none");var c=_("div",[o.lineSpace],"CodeMirror-lines");o.mover=O("div",[c],null,"position: relative"),o.sizer=O("div",[o.mover],"CodeMirror-sizer"),o.sizerWidth=null,o.heightForcer=O("div",null,null,"position: absolute; height: 50px; width: 1px;"),o.gutters=O("div",null,"CodeMirror-gutters"),o.lineGutter=null,o.scroller=O("div",[o.sizer,o.heightForcer,o.gutters],"CodeMirror-scroll"),o.scroller.setAttribute("tabIndex","-1"),o.wrapper=O("div",[o.scrollbarFiller,o.gutterFiller,o.scroller],"CodeMirror"),u&&105===d&&(o.wrapper.style.clipPath="inset(0px)"),o.wrapper.setAttribute("translate","no"),a&&l<8&&(o.gutters.style.zIndex=-1,o.scroller.style.paddingRight=0),s||n&&y||(o.scroller.draggable=!0),e&&(e.appendChild?e.appendChild(o.wrapper):e(o.wrapper)),o.viewFrom=o.viewTo=t.first,o.reportedViewFrom=o.reportedViewTo=t.first,o.view=[],o.renderedView=null,o.externalMeasured=null,o.viewOffset=0,o.lastWrapHeight=o.lastWrapWidth=0,o.updateLineNumbers=null,o.nativeBarWidth=o.barHeight=o.barWidth=0,o.scrollbarsClipped=!1,o.lineNumWidth=o.lineNumInnerWidth=o.lineNumChars=null,o.alignWidgets=!1,o.cachedCharWidth=o.cachedTextHeight=o.cachedPaddingH=null,o.maxLine=null,o.maxLineLength=0,o.maxLineChanged=!1,o.wheelDX=o.wheelDY=o.wheelStartX=o.wheelStartY=null,o.shift=!1,o.selForContextMenu=null,o.activeTouch=null,o.gutterSpecs=yi(i.gutters,i.lineNumbers),bi(o),r.init(o)}ui.prototype.signal=function(e,t){ke(e,t)&&this.events.push(arguments)},ui.prototype.finish=function(){for(var e=0;e<this.events.length;e++)be.apply(null,this.events[e])};var ki=0,Ci=null;function Si(e){var t=e.wheelDeltaX,n=e.wheelDeltaY;return null==t&&e.detail&&e.axis==e.HORIZONTAL_AXIS&&(t=e.detail),null==n&&e.detail&&e.axis==e.VERTICAL_AXIS?n=e.detail:null==n&&(n=e.wheelDelta),{x:t,y:n}}function Ti(e){var t=Si(e);return t.x*=Ci,t.y*=Ci,t}function Li(e,t){u&&102==d&&(null==e.display.chromeScrollHack?e.display.sizer.style.pointerEvents="none":clearTimeout(e.display.chromeScrollHack),e.display.chromeScrollHack=setTimeout(function(){e.display.chromeScrollHack=null,e.display.sizer.style.pointerEvents=""},100));var r=Si(t),i=r.x,o=r.y,a=Ci;0===t.deltaMode&&(i=t.deltaX,o=t.deltaY,a=1);var l=e.display,c=l.scroller,h=c.scrollWidth>c.clientWidth,p=c.scrollHeight>c.clientHeight;if(i&&h||o&&p){if(o&&b&&s)e:for(var m=t.target,g=l.view;m!=c;m=m.parentNode)for(var v=0;v<g.length;v++)if(g[v].node==m){e.display.currentWheelTarget=m;break e}if(i&&!n&&!f&&null!=a)return o&&p&&Rr(e,Math.max(0,c.scrollTop+o*a)),Br(e,Math.max(0,c.scrollLeft+i*a)),(!o||o&&p)&&Se(t),void(l.wheelStartX=null);if(o&&null!=a){var y=o*a,w=e.doc.scrollTop,x=w+l.wrapper.clientHeight;y<0?w=Math.max(0,w+y-50):x=Math.min(e.doc.height,x+y+50),hi(e,{top:w,bottom:x})}ki<20&&0!==t.deltaMode&&(null==l.wheelStartX?(l.wheelStartX=c.scrollLeft,l.wheelStartY=c.scrollTop,l.wheelDX=i,l.wheelDY=o,setTimeout(function(){if(null!=l.wheelStartX){var e=c.scrollLeft-l.wheelStartX,t=c.scrollTop-l.wheelStartY,n=t&&l.wheelDY&&t/l.wheelDY||e&&l.wheelDX&&e/l.wheelDX;l.wheelStartX=l.wheelStartY=null,n&&(Ci=(Ci*ki+n)/(ki+1),++ki)}},200)):(l.wheelDX+=i,l.wheelDY+=o))}}a?Ci=-.53:n?Ci=15:u?Ci=-.7:h&&(Ci=-1/3);var Mi=function(e,t){this.ranges=e,this.primIndex=t};Mi.prototype.primary=function(){return this.ranges[this.primIndex]},Mi.prototype.equals=function(e){if(e==this)return!0;if(e.primIndex!=this.primIndex||e.ranges.length!=this.ranges.length)return!1;for(var t=0;t<this.ranges.length;t++){var n=this.ranges[t],r=e.ranges[t];if(!lt(n.anchor,r.anchor)||!lt(n.head,r.head))return!1}return!0},Mi.prototype.deepCopy=function(){for(var e=[],t=0;t<this.ranges.length;t++)e[t]=new Ai(st(this.ranges[t].anchor),st(this.ranges[t].head));return new Mi(e,this.primIndex)},Mi.prototype.somethingSelected=function(){for(var e=0;e<this.ranges.length;e++)if(!this.ranges[e].empty())return!0;return!1},Mi.prototype.contains=function(e,t){t||(t=e);for(var n=0;n<this.ranges.length;n++){var r=this.ranges[n];if(at(t,r.from())>=0&&at(e,r.to())<=0)return n}return-1};var Ai=function(e,t){this.anchor=e,this.head=t};function Ni(e,t,n){var r=e&&e.options.selectionsMayTouch,i=t[n];t.sort(function(e,t){return at(e.from(),t.from())}),n=K(t,i);for(var o=1;o<t.length;o++){var a=t[o],l=t[o-1],s=at(l.to(),a.from());if(r&&!a.empty()?s>0:s>=0){var c=ut(l.from(),a.from()),u=ct(l.to(),a.to()),d=l.empty()?a.from()==a.head:l.from()==l.head;o<=n&&--n,t.splice(--o,2,new Ai(d?u:c,d?c:u))}}return new Mi(t,n)}function Oi(e,t){return new Mi([new Ai(e,t||e)],0)}function _i(e){return e.text?ot(e.from.line+e.text.length-1,Q(e.text).length+(1==e.text.length?e.from.ch:0)):e.to}function Ei(e,t){if(at(e,t.from)<0)return e;if(at(e,t.to)<=0)return _i(t);var n=e.line+t.text.length-(t.to.line-t.from.line)-1,r=e.ch;return e.line==t.to.line&&(r+=_i(t).ch-t.to.ch),ot(n,r)}function zi(e,t){for(var n=[],r=0;r<e.sel.ranges.length;r++){var i=e.sel.ranges[r];n.push(new Ai(Ei(i.anchor,t),Ei(i.head,t)))}return Ni(e.cm,n,e.sel.primIndex)}function Di(e,t,n){return e.line==t.line?ot(n.line,e.ch-t.ch+n.ch):ot(n.line+(e.line-t.line),e.ch)}function Pi(e){e.doc.mode=Ue(e.options,e.doc.modeOption),Wi(e)}function Wi(e){e.doc.iter(function(e){e.stateAfter&&(e.stateAfter=null),e.styles&&(e.styles=null)}),e.doc.modeFrontier=e.doc.highlightFrontier=e.doc.first,si(e,100),e.state.modeGen++,e.curOp&&gr(e)}function Fi(e,t){return 0==t.from.ch&&0==t.to.ch&&""==Q(t.text)&&(!e.cm||e.cm.options.wholeLineUpdateBefore)}function Ii(e,t,n,r){function i(e){return n?n[e]:null}function o(e,n,i){(function(e,t,n,r){e.text=t,e.stateAfter&&(e.stateAfter=null),e.styles&&(e.styles=null),null!=e.order&&(e.order=null),zt(e),Dt(e,n);var i=r?r(e):1;i!=e.height&&et(e,i)})(e,n,i,r),hn(e,"change",e,t)}function a(e,t){for(var n=[],o=e;o<t;++o)n.push(new Zt(c[o],i(o),r));return n}var l=t.from,s=t.to,c=t.text,u=Ze(e,l.line),d=Ze(e,s.line),f=Q(c),h=i(c.length-1),p=s.line-l.line;if(t.full)e.insert(0,a(0,c.length)),e.remove(c.length,e.size-c.length);else if(Fi(e,t)){var m=a(0,c.length-1);o(d,d.text,h),p&&e.remove(l.line,p),m.length&&e.insert(l.line,m)}else if(u==d)if(1==c.length)o(u,u.text.slice(0,l.ch)+f+u.text.slice(s.ch),h);else{var g=a(1,c.length-1);g.push(new Zt(f+u.text.slice(s.ch),h,r)),o(u,u.text.slice(0,l.ch)+c[0],i(0)),e.insert(l.line+1,g)}else if(1==c.length)o(u,u.text.slice(0,l.ch)+c[0]+d.text.slice(s.ch),i(0)),e.remove(l.line+1,p);else{o(u,u.text.slice(0,l.ch)+c[0],i(0)),o(d,f+d.text.slice(s.ch),h);var v=a(1,c.length-1);p>1&&e.remove(l.line+1,p-1),e.insert(l.line+1,v)}hn(e,"change",e,t)}function Hi(e,t,n){!function e(r,i,o){if(r.linked)for(var a=0;a<r.linked.length;++a){var l=r.linked[a];if(l.doc!=i){var s=o&&l.sharedHist;n&&!s||(t(l.doc,s),e(l.doc,r,s))}}}(e,null,!0)}function Ri(e,t){if(t.cm)throw new Error("This document is already in use.");e.doc=t,t.cm=e,hr(e),Pi(e),ji(e),e.options.direction=t.direction,e.options.lineWrapping||Xt(e),e.options.mode=t.modeOption,gr(e)}function ji(e){("rtl"==e.doc.direction?D:M)(e.display.lineDiv,"CodeMirror-rtl")}function Bi(e){this.done=[],this.undone=[],this.undoDepth=e?e.undoDepth:1/0,this.lastModTime=this.lastSelTime=0,this.lastOp=this.lastSelOp=null,this.lastOrigin=this.lastSelOrigin=null,this.generation=this.maxGeneration=e?e.maxGeneration:1}function qi(e,t){var n={from:st(t.from),to:_i(t),text:Je(e,t.from,t.to)};return $i(e,n,t.from.line,t.to.line+1),Hi(e,function(e){return $i(e,n,t.from.line,t.to.line+1)},!0),n}function Ui(e){for(;e.length&&Q(e).ranges;)e.pop()}function Ki(e,t,n,r){var i=e.history;i.undone.length=0;var o,a,l=+new Date;if((i.lastOp==r||i.lastOrigin==t.origin&&t.origin&&("+"==t.origin.charAt(0)&&i.lastModTime>l-(e.cm?e.cm.options.historyEventDelay:500)||"*"==t.origin.charAt(0)))&&(o=function(e,t){return t?(Ui(e.done),Q(e.done)):e.done.length&&!Q(e.done).ranges?Q(e.done):e.done.length>1&&!e.done[e.done.length-2].ranges?(e.done.pop(),Q(e.done)):void 0}(i,i.lastOp==r)))a=Q(o.changes),0==at(t.from,t.to)&&0==at(t.from,a.to)?a.to=_i(t):o.changes.push(qi(e,t));else{var s=Q(i.done);for(s&&s.ranges||Gi(e.sel,i.done),o={changes:[qi(e,t)],generation:i.generation},i.done.push(o);i.done.length>i.undoDepth;)i.done.shift(),i.done[0].ranges||i.done.shift()}i.done.push(n),i.generation=++i.maxGeneration,i.lastModTime=i.lastSelTime=l,i.lastOp=i.lastSelOp=r,i.lastOrigin=i.lastSelOrigin=t.origin,a||be(e,"historyAdded")}function Vi(e,t,n,r){var i=e.history,o=r&&r.origin;n==i.lastSelOp||o&&i.lastSelOrigin==o&&(i.lastModTime==i.lastSelTime&&i.lastOrigin==o||function(e,t,n,r){var i=t.charAt(0);return"*"==i||"+"==i&&n.ranges.length==r.ranges.length&&n.somethingSelected()==r.somethingSelected()&&new Date-e.history.lastSelTime<=(e.cm?e.cm.options.historyEventDelay:500)}(e,o,Q(i.done),t))?i.done[i.done.length-1]=t:Gi(t,i.done),i.lastSelTime=+new Date,i.lastSelOrigin=o,i.lastSelOp=n,r&&!1!==r.clearRedo&&Ui(i.undone)}function Gi(e,t){var n=Q(t);n&&n.ranges&&n.equals(e)||t.push(e)}function $i(e,t,n,r){var i=t["spans_"+e.id],o=0;e.iter(Math.max(e.first,n),Math.min(e.first+e.size,r),function(n){n.markedSpans&&((i||(i=t["spans_"+e.id]={}))[o]=n.markedSpans),++o})}function Yi(e){if(!e)return null;for(var t,n=0;n<e.length;++n)e[n].marker.explicitlyCleared?t||(t=e.slice(0,n)):t&&t.push(e[n]);return t?t.length?t:null:e}function Xi(e,t){var n=function(e,t){var n=t["spans_"+e.id];if(!n)return null;for(var r=[],i=0;i<t.text.length;++i)r.push(Yi(n[i]));return r}(e,t),r=_t(e,t);if(!n)return r;if(!r)return n;for(var i=0;i<n.length;++i){var o=n[i],a=r[i];if(o&&a)e:for(var l=0;l<a.length;++l){for(var s=a[l],c=0;c<o.length;++c)if(o[c].marker==s.marker)continue e;o.push(s)}else a&&(n[i]=a)}return n}function Zi(e,t,n){for(var r=[],i=0;i<e.length;++i){var o=e[i];if(o.ranges)r.push(n?Mi.prototype.deepCopy.call(o):o);else{var a=o.changes,l=[];r.push({changes:l});for(var s=0;s<a.length;++s){var c=a[s],u=void 0;if(l.push({from:c.from,to:c.to,text:c.text}),t)for(var d in c)(u=d.match(/^spans_(\d+)$/))&&K(t,Number(u[1]))>-1&&(Q(l)[d]=c[d],delete c[d])}}}return r}function Ji(e,t,n,r){if(r){var i=e.anchor;if(n){var o=at(t,i)<0;o!=at(n,i)<0?(i=t,t=n):o!=at(t,n)<0&&(t=n)}return new Ai(i,t)}return new Ai(n||t,t)}function Qi(e,t,n,r,i){null==i&&(i=e.cm&&(e.cm.display.shift||e.extend)),io(e,new Mi([Ji(e.sel.primary(),t,n,i)],0),r)}function eo(e,t,n){for(var r=[],i=e.cm&&(e.cm.display.shift||e.extend),o=0;o<e.sel.ranges.length;o++)r[o]=Ji(e.sel.ranges[o],t[o],null,i);io(e,Ni(e.cm,r,e.sel.primIndex),n)}function to(e,t,n,r){var i=e.sel.ranges.slice(0);i[t]=n,io(e,Ni(e.cm,i,e.sel.primIndex),r)}function no(e,t,n,r){io(e,Oi(t,n),r)}function ro(e,t,n){var r=e.history.done,i=Q(r);i&&i.ranges?(r[r.length-1]=t,oo(e,t,n)):io(e,t,n)}function io(e,t,n){oo(e,t,n),Vi(e,e.sel,e.cm?e.cm.curOp.id:NaN,n)}function oo(e,t,n){(ke(e,"beforeSelectionChange")||e.cm&&ke(e.cm,"beforeSelectionChange"))&&(t=function(e,t,n){var r={ranges:t.ranges,update:function(t){this.ranges=[];for(var n=0;n<t.length;n++)this.ranges[n]=new Ai(ft(e,t[n].anchor),ft(e,t[n].head))},origin:n&&n.origin};return be(e,"beforeSelectionChange",e,r),e.cm&&be(e.cm,"beforeSelectionChange",e.cm,r),r.ranges!=t.ranges?Ni(e.cm,r.ranges,r.ranges.length-1):t}(e,t,n));var r=n&&n.bias||(at(t.primary().head,e.sel.primary().head)<0?-1:1);ao(e,so(e,t,r,!0)),n&&!1===n.scroll||!e.cm||"nocursor"==e.cm.getOption("readOnly")||Wr(e.cm)}function ao(e,t){t.equals(e.sel)||(e.sel=t,e.cm&&(e.cm.curOp.updateInput=1,e.cm.curOp.selectionChanged=!0,xe(e.cm)),hn(e,"cursorActivity",e))}function lo(e){ao(e,so(e,e.sel,null,!1))}function so(e,t,n,r){for(var i,o=0;o<t.ranges.length;o++){var a=t.ranges[o],l=t.ranges.length==e.sel.ranges.length&&e.sel.ranges[o],s=uo(e,a.anchor,l&&l.anchor,n,r),c=a.head==a.anchor?s:uo(e,a.head,l&&l.head,n,r);(i||s!=a.anchor||c!=a.head)&&(i||(i=t.ranges.slice(0,o)),i[o]=new Ai(s,c))}return i?Ni(e.cm,i,t.primIndex):t}function co(e,t,n,r,i){var o=Ze(e,t.line);if(o.markedSpans)for(var a=0;a<o.markedSpans.length;++a){var l=o.markedSpans[a],s=l.marker,c="selectLeft"in s?!s.selectLeft:s.inclusiveLeft,u="selectRight"in s?!s.selectRight:s.inclusiveRight;if((null==l.from||(c?l.from<=t.ch:l.from<t.ch))&&(null==l.to||(u?l.to>=t.ch:l.to>t.ch))){if(i&&(be(s,"beforeCursorEnter"),s.explicitlyCleared)){if(o.markedSpans){--a;continue}break}if(!s.atomic)continue;if(n){var d=s.find(r<0?1:-1),f=void 0;if((r<0?u:c)&&(d=fo(e,d,-r,d&&d.line==t.line?o:null)),d&&d.line==t.line&&(f=at(d,n))&&(r<0?f<0:f>0))return co(e,d,t,r,i)}var h=s.find(r<0?-1:1);return(r<0?c:u)&&(h=fo(e,h,r,h.line==t.line?o:null)),h?co(e,h,t,r,i):null}}return t}function uo(e,t,n,r,i){var o=r||1;return co(e,t,n,o,i)||!i&&co(e,t,n,o,!0)||co(e,t,n,-o,i)||!i&&co(e,t,n,-o,!0)||(e.cantEdit=!0,ot(e.first,0))}function fo(e,t,n,r){return n<0&&0==t.ch?t.line>e.first?ft(e,ot(t.line-1)):null:n>0&&t.ch==(r||Ze(e,t.line)).text.length?t.line<e.first+e.size-1?ot(t.line+1,0):null:new ot(t.line,t.ch+n)}function ho(e){e.setSelection(ot(e.firstLine(),0),ot(e.lastLine()),G)}function po(e,t,n){var r={canceled:!1,from:t.from,to:t.to,text:t.text,origin:t.origin,cancel:function(){return r.canceled=!0}};return n&&(r.update=function(t,n,i,o){t&&(r.from=ft(e,t)),n&&(r.to=ft(e,n)),i&&(r.text=i),void 0!==o&&(r.origin=o)}),be(e,"beforeChange",e,r),e.cm&&be(e.cm,"beforeChange",e.cm,r),r.canceled?(e.cm&&(e.cm.curOp.updateInput=2),null):{from:r.from,to:r.to,text:r.text,origin:r.origin}}function mo(e,t,n){if(e.cm){if(!e.cm.curOp)return oi(e.cm,mo)(e,t,n);if(e.cm.state.suppressEdits)return}if(!(ke(e,"beforeChange")||e.cm&&ke(e.cm,"beforeChange"))||(t=po(e,t,!0))){var r=Lt&&!n&&function(e,t,n){var r=null;if(e.iter(t.line,n.line+1,function(e){if(e.markedSpans)for(var t=0;t<e.markedSpans.length;++t){var n=e.markedSpans[t].marker;!n.readOnly||r&&-1!=K(r,n)||(r||(r=[])).push(n)}}),!r)return null;for(var i=[{from:t,to:n}],o=0;o<r.length;++o)for(var a=r[o],l=a.find(0),s=0;s<i.length;++s){var c=i[s];if(!(at(c.to,l.from)<0||at(c.from,l.to)>0)){var u=[s,1],d=at(c.from,l.from),f=at(c.to,l.to);(d<0||!a.inclusiveLeft&&!d)&&u.push({from:c.from,to:l.from}),(f>0||!a.inclusiveRight&&!f)&&u.push({from:l.to,to:c.to}),i.splice.apply(i,u),s+=u.length-3}}return i}(e,t.from,t.to);if(r)for(var i=r.length-1;i>=0;--i)go(e,{from:r[i].from,to:r[i].to,text:i?[""]:t.text,origin:t.origin});else go(e,t)}}function go(e,t){if(1!=t.text.length||""!=t.text[0]||0!=at(t.from,t.to)){var n=zi(e,t);Ki(e,t,n,e.cm?e.cm.curOp.id:NaN),bo(e,t,n,_t(e,t));var r=[];Hi(e,function(e,n){n||-1!=K(r,e.history)||(Co(e.history,t),r.push(e.history)),bo(e,t,null,_t(e,t))})}}function vo(e,t,n){var r=e.cm&&e.cm.state.suppressEdits;if(!r||n){for(var i,o=e.history,a=e.sel,l="undo"==t?o.done:o.undone,s="undo"==t?o.undone:o.done,c=0;c<l.length&&(i=l[c],n?!i.ranges||i.equals(e.sel):i.ranges);c++);if(c!=l.length){for(o.lastOrigin=o.lastSelOrigin=null;;){if(!(i=l.pop()).ranges){if(r)return void l.push(i);break}if(Gi(i,s),n&&!i.equals(e.sel))return void io(e,i,{clearRedo:!1});a=i}var u=[];Gi(a,s),s.push({changes:u,generation:o.generation}),o.generation=i.generation||++o.maxGeneration;for(var d=ke(e,"beforeChange")||e.cm&&ke(e.cm,"beforeChange"),f=function(n){var r=i.changes[n];if(r.origin=t,d&&!po(e,r,!1))return l.length=0,{};u.push(qi(e,r));var o=n?zi(e,r):Q(l);bo(e,r,o,Xi(e,r)),!n&&e.cm&&e.cm.scrollIntoView({from:r.from,to:_i(r)});var a=[];Hi(e,function(e,t){t||-1!=K(a,e.history)||(Co(e.history,r),a.push(e.history)),bo(e,r,null,Xi(e,r))})},h=i.changes.length-1;h>=0;--h){var p=f(h);if(p)return p.v}}}}function yo(e,t){if(0!=t&&(e.first+=t,e.sel=new Mi(ee(e.sel.ranges,function(e){return new Ai(ot(e.anchor.line+t,e.anchor.ch),ot(e.head.line+t,e.head.ch))}),e.sel.primIndex),e.cm)){gr(e.cm,e.first,e.first-t,t);for(var n=e.cm.display,r=n.viewFrom;r<n.viewTo;r++)vr(e.cm,r,"gutter")}}function bo(e,t,n,r){if(e.cm&&!e.cm.curOp)return oi(e.cm,bo)(e,t,n,r);if(t.to.line<e.first)yo(e,t.text.length-1-(t.to.line-t.from.line));else if(!(t.from.line>e.lastLine())){if(t.from.line<e.first){var i=t.text.length-1-(e.first-t.from.line);yo(e,i),t={from:ot(e.first,0),to:ot(t.to.line+i,t.to.ch),text:[Q(t.text)],origin:t.origin}}var o=e.lastLine();t.to.line>o&&(t={from:t.from,to:ot(o,Ze(e,o).text.length),text:[t.text[0]],origin:t.origin}),t.removed=Je(e,t.from,t.to),n||(n=zi(e,t)),e.cm?function(e,t,n){var r=e.doc,i=e.display,o=t.from,a=t.to,l=!1,s=o.line;e.options.lineWrapping||(s=tt(qt(Ze(r,o.line))),r.iter(s,a.line+1,function(e){if(e==i.maxLine)return l=!0,!0})),r.sel.contains(t.from,t.to)>-1&&xe(e),Ii(r,t,n,fr(e)),e.options.lineWrapping||(r.iter(s,o.line+t.text.length,function(e){var t=Yt(e);t>i.maxLineLength&&(i.maxLine=e,i.maxLineLength=t,i.maxLineChanged=!0,l=!1)}),l&&(e.curOp.updateMaxLine=!0)),function(e,t){if(e.modeFrontier=Math.min(e.modeFrontier,t),!(e.highlightFrontier<t-10)){for(var n=e.first,r=t-1;r>n;r--){var i=Ze(e,r).stateAfter;if(i&&(!(i instanceof pt)||r+i.lookAhead<t)){n=r+1;break}}e.highlightFrontier=Math.min(e.highlightFrontier,n)}}(r,o.line),si(e,400);var c=t.text.length-(a.line-o.line)-1;t.full?gr(e):o.line!=a.line||1!=t.text.length||Fi(e.doc,t)?gr(e,o.line,a.line+1,c):vr(e,o.line,"text");var u=ke(e,"changes"),d=ke(e,"change");if(d||u){var f={from:o,to:a,text:t.text,removed:t.removed,origin:t.origin};d&&hn(e,"change",e,f),u&&(e.curOp.changeObjs||(e.curOp.changeObjs=[])).push(f)}e.display.selForContextMenu=null}(e.cm,t,r):Ii(e,t,r),oo(e,n,G),e.cantEdit&&uo(e,ot(e.firstLine(),0))&&(e.cantEdit=!1)}}function wo(e,t,n,r,i){var o;r||(r=n),at(r,n)<0&&(n=(o=[r,n])[0],r=o[1]),"string"==typeof t&&(t=e.splitLines(t)),mo(e,{from:n,to:r,text:t,origin:i})}function xo(e,t,n,r){n<e.line?e.line+=r:t<e.line&&(e.line=t,e.ch=0)}function ko(e,t,n,r){for(var i=0;i<e.length;++i){var o=e[i],a=!0;if(o.ranges){o.copied||((o=e[i]=o.deepCopy()).copied=!0);for(var l=0;l<o.ranges.length;l++)xo(o.ranges[l].anchor,t,n,r),xo(o.ranges[l].head,t,n,r)}else{for(var s=0;s<o.changes.length;++s){var c=o.changes[s];if(n<c.from.line)c.from=ot(c.from.line+r,c.from.ch),c.to=ot(c.to.line+r,c.to.ch);else if(t<=c.to.line){a=!1;break}}a||(e.splice(0,i+1),i=0)}}}function Co(e,t){var n=t.from.line,r=t.to.line,i=t.text.length-(r-n)-1;ko(e.done,n,r,i),ko(e.undone,n,r,i)}function So(e,t,n,r){var i=t,o=t;return"number"==typeof t?o=Ze(e,dt(e,t)):i=tt(t),null==i?null:(r(o,i)&&e.cm&&vr(e.cm,i,n),o)}function To(e){this.lines=e,this.parent=null;for(var t=0,n=0;n<e.length;++n)e[n].parent=this,t+=e[n].height;this.height=t}function Lo(e){this.children=e;for(var t=0,n=0,r=0;r<e.length;++r){var i=e[r];t+=i.chunkSize(),n+=i.height,i.parent=this}this.size=t,this.height=n,this.parent=null}Ai.prototype.from=function(){return ut(this.anchor,this.head)},Ai.prototype.to=function(){return ct(this.anchor,this.head)},Ai.prototype.empty=function(){return this.head.line==this.anchor.line&&this.head.ch==this.anchor.ch},To.prototype={chunkSize:function(){return this.lines.length},removeInner:function(e,t){for(var n=e,r=e+t;n<r;++n){var i=this.lines[n];this.height-=i.height,Jt(i),hn(i,"delete")}this.lines.splice(e,t)},collapse:function(e){e.push.apply(e,this.lines)},insertInner:function(e,t,n){this.height+=n,this.lines=this.lines.slice(0,e).concat(t).concat(this.lines.slice(e));for(var r=0;r<t.length;++r)t[r].parent=this},iterN:function(e,t,n){for(var r=e+t;e<r;++e)if(n(this.lines[e]))return!0}},Lo.prototype={chunkSize:function(){return this.size},removeInner:function(e,t){this.size-=t;for(var n=0;n<this.children.length;++n){var r=this.children[n],i=r.chunkSize();if(e<i){var o=Math.min(t,i-e),a=r.height;if(r.removeInner(e,o),this.height-=a-r.height,i==o&&(this.children.splice(n--,1),r.parent=null),0==(t-=o))break;e=0}else e-=i}if(this.size-t<25&&(this.children.length>1||!(this.children[0]instanceof To))){var l=[];this.collapse(l),this.children=[new To(l)],this.children[0].parent=this}},collapse:function(e){for(var t=0;t<this.children.length;++t)this.children[t].collapse(e)},insertInner:function(e,t,n){this.size+=t.length,this.height+=n;for(var r=0;r<this.children.length;++r){var i=this.children[r],o=i.chunkSize();if(e<=o){if(i.insertInner(e,t,n),i.lines&&i.lines.length>50){for(var a=i.lines.length%25+25,l=a;l<i.lines.length;){var s=new To(i.lines.slice(l,l+=25));i.height-=s.height,this.children.splice(++r,0,s),s.parent=this}i.lines=i.lines.slice(0,a),this.maybeSpill()}break}e-=o}},maybeSpill:function(){if(!(this.children.length<=10)){var e=this;do{var t=new Lo(e.children.splice(e.children.length-5,5));if(e.parent){e.size-=t.size,e.height-=t.height;var n=K(e.parent.children,e);e.parent.children.splice(n+1,0,t)}else{var r=new Lo(e.children);r.parent=e,e.children=[r,t],e=r}t.parent=e.parent}while(e.children.length>10);e.parent.maybeSpill()}},iterN:function(e,t,n){for(var r=0;r<this.children.length;++r){var i=this.children[r],o=i.chunkSize();if(e<o){var a=Math.min(t,o-e);if(i.iterN(e,a,n))return!0;if(0==(t-=a))break;e=0}else e-=o}}};var Mo=function(e,t,n){if(n)for(var r in n)n.hasOwnProperty(r)&&(this[r]=n[r]);this.doc=e,this.node=t};function Ao(e,t,n){$t(t)<(e.curOp&&e.curOp.scrollTop||e.doc.scrollTop)&&Pr(e,n)}Mo.prototype.clear=function(){var e=this.doc.cm,t=this.line.widgets,n=this.line,r=tt(n);if(null!=r&&t){for(var i=0;i<t.length;++i)t[i]==this&&t.splice(i--,1);t.length||(n.widgets=null);var o=Ln(this);et(n,Math.max(0,n.height-o)),e&&(ii(e,function(){Ao(e,n,-o),vr(e,r,"widget")}),hn(e,"lineWidgetCleared",e,this,r))}},Mo.prototype.changed=function(){var e=this,t=this.height,n=this.doc.cm,r=this.line;this.height=null;var i=Ln(this)-t;i&&(Vt(this.doc,r)||et(r,r.height+i),n&&ii(n,function(){n.curOp.forceUpdate=!0,Ao(n,r,i),hn(n,"lineWidgetChanged",n,e,tt(r))}))},Ce(Mo);var No=0,Oo=function(e,t){this.lines=[],this.type=t,this.doc=e,this.id=++No};function _o(e,t,n,r,i){if(r&&r.shared)return function(e,t,n,r,i){(r=B(r)).shared=!1;var o=[_o(e,t,n,r,i)],a=o[0],l=r.widgetNode;return Hi(e,function(e){l&&(r.widgetNode=l.cloneNode(!0)),o.push(_o(e,ft(e,t),ft(e,n),r,i));for(var s=0;s<e.linked.length;++s)if(e.linked[s].isParent)return;a=Q(o)}),new Eo(o,a)}(e,t,n,r,i);if(e.cm&&!e.cm.curOp)return oi(e.cm,_o)(e,t,n,r,i);var o=new Oo(e,i),a=at(t,n);if(r&&B(r,o,!1),a>0||0==a&&!1!==o.clearWhenEmpty)return o;if(o.replacedWith&&(o.collapsed=!0,o.widgetNode=_("span",[o.replacedWith],"CodeMirror-widget"),r.handleMouseEvents||o.widgetNode.setAttribute("cm-ignore-events","true"),r.insertLeft&&(o.widgetNode.insertLeft=!0)),o.collapsed){if(Bt(e,t.line,t,n,o)||t.line!=n.line&&Bt(e,n.line,t,n,o))throw new Error("Inserting collapsed marker partially overlapping an existing one");Mt=!0}o.addToHistory&&Ki(e,{from:t,to:n,origin:"markText"},e.sel,NaN);var l,s=t.line,c=e.cm;if(e.iter(s,n.line+1,function(r){c&&o.collapsed&&!c.options.lineWrapping&&qt(r)==c.display.maxLine&&(l=!0),o.collapsed&&s!=t.line&&et(r,0),function(e,t,n){var r=n&&window.WeakSet&&(n.markedSpans||(n.markedSpans=new WeakSet));r&&e.markedSpans&&r.has(e.markedSpans)?e.markedSpans.push(t):(e.markedSpans=e.markedSpans?e.markedSpans.concat([t]):[t],r&&r.add(e.markedSpans)),t.marker.attachLine(e)}(r,new At(o,s==t.line?t.ch:null,s==n.line?n.ch:null),e.cm&&e.cm.curOp),++s}),o.collapsed&&e.iter(t.line,n.line+1,function(t){Vt(e,t)&&et(t,0)}),o.clearOnEnter&&ge(o,"beforeCursorEnter",function(){return o.clear()}),o.readOnly&&(Lt=!0,(e.history.done.length||e.history.undone.length)&&e.clearHistory()),o.collapsed&&(o.id=++No,o.atomic=!0),c){if(l&&(c.curOp.updateMaxLine=!0),o.collapsed)gr(c,t.line,n.line+1);else if(o.className||o.startStyle||o.endStyle||o.css||o.attributes||o.title)for(var u=t.line;u<=n.line;u++)vr(c,u,"text");o.atomic&&lo(c.doc),hn(c,"markerAdded",c,o)}return o}Oo.prototype.clear=function(){if(!this.explicitlyCleared){var e=this.doc.cm,t=e&&!e.curOp;if(t&&Zr(e),ke(this,"clear")){var n=this.find();n&&hn(this,"clear",n.from,n.to)}for(var r=null,i=null,o=0;o<this.lines.length;++o){var a=this.lines[o],l=Nt(a.markedSpans,this);e&&!this.collapsed?vr(e,tt(a),"text"):e&&(null!=l.to&&(i=tt(a)),null!=l.from&&(r=tt(a))),a.markedSpans=Ot(a.markedSpans,l),null==l.from&&this.collapsed&&!Vt(this.doc,a)&&e&&et(a,sr(e.display))}if(e&&this.collapsed&&!e.options.lineWrapping)for(var s=0;s<this.lines.length;++s){var c=qt(this.lines[s]),u=Yt(c);u>e.display.maxLineLength&&(e.display.maxLine=c,e.display.maxLineLength=u,e.display.maxLineChanged=!0)}null!=r&&e&&this.collapsed&&gr(e,r,i+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,e&&lo(e.doc)),e&&hn(e,"markerCleared",e,this,r,i),t&&Jr(e),this.parent&&this.parent.clear()}},Oo.prototype.find=function(e,t){var n,r;null==e&&"bookmark"==this.type&&(e=1);for(var i=0;i<this.lines.length;++i){var o=this.lines[i],a=Nt(o.markedSpans,this);if(null!=a.from&&(n=ot(t?o:tt(o),a.from),-1==e))return n;if(null!=a.to&&(r=ot(t?o:tt(o),a.to),1==e))return r}return n&&{from:n,to:r}},Oo.prototype.changed=function(){var e=this,t=this.find(-1,!0),n=this,r=this.doc.cm;t&&r&&ii(r,function(){var i=t.line,o=tt(t.line),a=Wn(r,o);if(a&&(qn(a),r.curOp.selectionChanged=r.curOp.forceUpdate=!0),r.curOp.updateMaxLine=!0,!Vt(n.doc,i)&&null!=n.height){var l=n.height;n.height=null;var s=Ln(n)-l;s&&et(i,i.height+s)}hn(r,"markerChanged",r,e)})},Oo.prototype.attachLine=function(e){if(!this.lines.length&&this.doc.cm){var t=this.doc.cm.curOp;t.maybeHiddenMarkers&&-1!=K(t.maybeHiddenMarkers,this)||(t.maybeUnhiddenMarkers||(t.maybeUnhiddenMarkers=[])).push(this)}this.lines.push(e)},Oo.prototype.detachLine=function(e){if(this.lines.splice(K(this.lines,e),1),!this.lines.length&&this.doc.cm){var t=this.doc.cm.curOp;(t.maybeHiddenMarkers||(t.maybeHiddenMarkers=[])).push(this)}},Ce(Oo);var Eo=function(e,t){this.markers=e,this.primary=t;for(var n=0;n<e.length;++n)e[n].parent=this};function zo(e){return e.findMarks(ot(e.first,0),e.clipPos(ot(e.lastLine())),function(e){return e.parent})}function Do(e){for(var t=function(t){var n=e[t],r=[n.primary.doc];Hi(n.primary.doc,function(e){return r.push(e)});for(var i=0;i<n.markers.length;i++){var o=n.markers[i];-1==K(r,o.doc)&&(o.parent=null,n.markers.splice(i--,1))}},n=0;n<e.length;n++)t(n)}Eo.prototype.clear=function(){if(!this.explicitlyCleared){this.explicitlyCleared=!0;for(var e=0;e<this.markers.length;++e)this.markers[e].clear();hn(this,"clear")}},Eo.prototype.find=function(e,t){return this.primary.find(e,t)},Ce(Eo);var Po=0,Wo=function(e,t,n,r,i){if(!(this instanceof Wo))return new Wo(e,t,n,r,i);null==n&&(n=0),Lo.call(this,[new To([new Zt("",null)])]),this.first=n,this.scrollTop=this.scrollLeft=0,this.cantEdit=!1,this.cleanGeneration=1,this.modeFrontier=this.highlightFrontier=n;var o=ot(n,0);this.sel=Oi(o),this.history=new Bi(null),this.id=++Po,this.modeOption=t,this.lineSep=r,this.direction="rtl"==i?"rtl":"ltr",this.extend=!1,"string"==typeof e&&(e=this.splitLines(e)),Ii(this,{from:o,to:o,text:e}),io(this,Oi(o),G)};Wo.prototype=ne(Lo.prototype,{constructor:Wo,iter:function(e,t,n){n?this.iterN(e-this.first,t-e,n):this.iterN(this.first,this.first+this.size,e)},insert:function(e,t){for(var n=0,r=0;r<t.length;++r)n+=t[r].height;this.insertInner(e-this.first,t,n)},remove:function(e,t){this.removeInner(e-this.first,t)},getValue:function(e){var t=Qe(this,this.first,this.first+this.size);return!1===e?t:t.join(e||this.lineSeparator())},setValue:li(function(e){var t=ot(this.first,0),n=this.first+this.size-1;mo(this,{from:t,to:ot(n,Ze(this,n).text.length),text:this.splitLines(e),origin:"setValue",full:!0},!0),this.cm&&Fr(this.cm,0,0),io(this,Oi(t),G)}),replaceRange:function(e,t,n,r){wo(this,e,t=ft(this,t),n=n?ft(this,n):t,r)},getRange:function(e,t,n){var r=Je(this,ft(this,e),ft(this,t));return!1===n?r:""===n?r.join(""):r.join(n||this.lineSeparator())},getLine:function(e){var t=this.getLineHandle(e);return t&&t.text},getLineHandle:function(e){if(rt(this,e))return Ze(this,e)},getLineNumber:function(e){return tt(e)},getLineHandleVisualStart:function(e){return"number"==typeof e&&(e=Ze(this,e)),qt(e)},lineCount:function(){return this.size},firstLine:function(){return this.first},lastLine:function(){return this.first+this.size-1},clipPos:function(e){return ft(this,e)},getCursor:function(e){var t=this.sel.primary();return null==e||"head"==e?t.head:"anchor"==e?t.anchor:"end"==e||"to"==e||!1===e?t.to():t.from()},listSelections:function(){return this.sel.ranges},somethingSelected:function(){return this.sel.somethingSelected()},setCursor:li(function(e,t,n){no(this,ft(this,"number"==typeof e?ot(e,t||0):e),null,n)}),setSelection:li(function(e,t,n){no(this,ft(this,e),ft(this,t||e),n)}),extendSelection:li(function(e,t,n){Qi(this,ft(this,e),t&&ft(this,t),n)}),extendSelections:li(function(e,t){eo(this,ht(this,e),t)}),extendSelectionsBy:li(function(e,t){eo(this,ht(this,ee(this.sel.ranges,e)),t)}),setSelections:li(function(e,t,n){if(e.length){for(var r=[],i=0;i<e.length;i++)r[i]=new Ai(ft(this,e[i].anchor),ft(this,e[i].head||e[i].anchor));null==t&&(t=Math.min(e.length-1,this.sel.primIndex)),io(this,Ni(this.cm,r,t),n)}}),addSelection:li(function(e,t,n){var r=this.sel.ranges.slice(0);r.push(new Ai(ft(this,e),ft(this,t||e))),io(this,Ni(this.cm,r,r.length-1),n)}),getSelection:function(e){for(var t,n=this.sel.ranges,r=0;r<n.length;r++){var i=Je(this,n[r].from(),n[r].to());t=t?t.concat(i):i}return!1===e?t:t.join(e||this.lineSeparator())},getSelections:function(e){for(var t=[],n=this.sel.ranges,r=0;r<n.length;r++){var i=Je(this,n[r].from(),n[r].to());!1!==e&&(i=i.join(e||this.lineSeparator())),t[r]=i}return t},replaceSelection:function(e,t,n){for(var r=[],i=0;i<this.sel.ranges.length;i++)r[i]=e;this.replaceSelections(r,t,n||"+input")},replaceSelections:li(function(e,t,n){for(var r=[],i=this.sel,o=0;o<i.ranges.length;o++){var a=i.ranges[o];r[o]={from:a.from(),to:a.to(),text:this.splitLines(e[o]),origin:n}}for(var l=t&&"end"!=t&&function(e,t,n){for(var r=[],i=ot(e.first,0),o=i,a=0;a<t.length;a++){var l=t[a],s=Di(l.from,i,o),c=Di(_i(l),i,o);if(i=l.to,o=c,"around"==n){var u=e.sel.ranges[a],d=at(u.head,u.anchor)<0;r[a]=new Ai(d?c:s,d?s:c)}else r[a]=new Ai(s,s)}return new Mi(r,e.sel.primIndex)}(this,r,t),s=r.length-1;s>=0;s--)mo(this,r[s]);l?ro(this,l):this.cm&&Wr(this.cm)}),undo:li(function(){vo(this,"undo")}),redo:li(function(){vo(this,"redo")}),undoSelection:li(function(){vo(this,"undo",!0)}),redoSelection:li(function(){vo(this,"redo",!0)}),setExtending:function(e){this.extend=e},getExtending:function(){return this.extend},historySize:function(){for(var e=this.history,t=0,n=0,r=0;r<e.done.length;r++)e.done[r].ranges||++t;for(var i=0;i<e.undone.length;i++)e.undone[i].ranges||++n;return{undo:t,redo:n}},clearHistory:function(){var e=this;this.history=new Bi(this.history),Hi(this,function(t){return t.history=e.history},!0)},markClean:function(){this.cleanGeneration=this.changeGeneration(!0)},changeGeneration:function(e){return e&&(this.history.lastOp=this.history.lastSelOp=this.history.lastOrigin=null),this.history.generation},isClean:function(e){return this.history.generation==(e||this.cleanGeneration)},getHistory:function(){return{done:Zi(this.history.done),undone:Zi(this.history.undone)}},setHistory:function(e){var t=this.history=new Bi(this.history);t.done=Zi(e.done.slice(0),null,!0),t.undone=Zi(e.undone.slice(0),null,!0)},setGutterMarker:li(function(e,t,n){return So(this,e,"gutter",function(e){var r=e.gutterMarkers||(e.gutterMarkers={});return r[t]=n,!n&&ae(r)&&(e.gutterMarkers=null),!0})}),clearGutter:li(function(e){var t=this;this.iter(function(n){n.gutterMarkers&&n.gutterMarkers[e]&&So(t,n,"gutter",function(){return n.gutterMarkers[e]=null,ae(n.gutterMarkers)&&(n.gutterMarkers=null),!0})})}),lineInfo:function(e){var t;if("number"==typeof e){if(!rt(this,e))return null;if(t=e,!(e=Ze(this,e)))return null}else if(null==(t=tt(e)))return null;return{line:t,handle:e,text:e.text,gutterMarkers:e.gutterMarkers,textClass:e.textClass,bgClass:e.bgClass,wrapClass:e.wrapClass,widgets:e.widgets}},addLineClass:li(function(e,t,n){return So(this,e,"gutter"==t?"gutter":"class",function(e){var r="text"==t?"textClass":"background"==t?"bgClass":"gutter"==t?"gutterClass":"wrapClass";if(e[r]){if(T(n).test(e[r]))return!1;e[r]+=" "+n}else e[r]=n;return!0})}),removeLineClass:li(function(e,t,n){return So(this,e,"gutter"==t?"gutter":"class",function(e){var r="text"==t?"textClass":"background"==t?"bgClass":"gutter"==t?"gutterClass":"wrapClass",i=e[r];if(!i)return!1;if(null==n)e[r]=null;else{var o=i.match(T(n));if(!o)return!1;var a=o.index+o[0].length;e[r]=i.slice(0,o.index)+(o.index&&a!=i.length?" ":"")+i.slice(a)||null}return!0})}),addLineWidget:li(function(e,t,n){return function(e,t,n,r){var i=new Mo(e,n,r),o=e.cm;return o&&i.noHScroll&&(o.display.alignWidgets=!0),So(e,t,"widget",function(t){var n=t.widgets||(t.widgets=[]);if(null==i.insertAt?n.push(i):n.splice(Math.min(n.length,Math.max(0,i.insertAt)),0,i),i.line=t,o&&!Vt(e,t)){var r=$t(t)<e.scrollTop;et(t,t.height+Ln(i)),r&&Pr(o,i.height),o.curOp.forceUpdate=!0}return!0}),o&&hn(o,"lineWidgetAdded",o,i,"number"==typeof t?t:tt(t)),i}(this,e,t,n)}),removeLineWidget:function(e){e.clear()},markText:function(e,t,n){return _o(this,ft(this,e),ft(this,t),n,n&&n.type||"range")},setBookmark:function(e,t){var n={replacedWith:t&&(null==t.nodeType?t.widget:t),insertLeft:t&&t.insertLeft,clearWhenEmpty:!1,shared:t&&t.shared,handleMouseEvents:t&&t.handleMouseEvents};return _o(this,e=ft(this,e),e,n,"bookmark")},findMarksAt:function(e){var t=[],n=Ze(this,(e=ft(this,e)).line).markedSpans;if(n)for(var r=0;r<n.length;++r){var i=n[r];(null==i.from||i.from<=e.ch)&&(null==i.to||i.to>=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(e,t,n){e=ft(this,e),t=ft(this,t);var r=[],i=e.line;return this.iter(e.line,t.line+1,function(o){var a=o.markedSpans;if(a)for(var l=0;l<a.length;l++){var s=a[l];null!=s.to&&i==e.line&&e.ch>=s.to||null==s.from&&i!=e.line||null!=s.from&&i==t.line&&s.from>=t.ch||n&&!n(s.marker)||r.push(s.marker.parent||s.marker)}++i}),r},getAllMarks:function(){var e=[];return this.iter(function(t){var n=t.markedSpans;if(n)for(var r=0;r<n.length;++r)null!=n[r].from&&e.push(n[r].marker)}),e},posFromIndex:function(e){var t,n=this.first,r=this.lineSeparator().length;return this.iter(function(i){var o=i.text.length+r;if(o>e)return t=e,!0;e-=o,++n}),ft(this,ot(n,t))},indexFromPos:function(e){var t=(e=ft(this,e)).ch;if(e.line<this.first||e.ch<0)return 0;var n=this.lineSeparator().length;return this.iter(this.first,e.line,function(e){t+=e.text.length+n}),t},copy:function(e){var t=new Wo(Qe(this,this.first,this.first+this.size),this.modeOption,this.first,this.lineSep,this.direction);return t.scrollTop=this.scrollTop,t.scrollLeft=this.scrollLeft,t.sel=this.sel,t.extend=!1,e&&(t.history.undoDepth=this.history.undoDepth,t.setHistory(this.getHistory())),t},linkedDoc:function(e){e||(e={});var t=this.first,n=this.first+this.size;null!=e.from&&e.from>t&&(t=e.from),null!=e.to&&e.to<n&&(n=e.to);var r=new Wo(Qe(this,t,n),e.mode||this.modeOption,t,this.lineSep,this.direction);return e.sharedHist&&(r.history=this.history),(this.linked||(this.linked=[])).push({doc:r,sharedHist:e.sharedHist}),r.linked=[{doc:this,isParent:!0,sharedHist:e.sharedHist}],function(e,t){for(var n=0;n<t.length;n++){var r=t[n],i=r.find(),o=e.clipPos(i.from),a=e.clipPos(i.to);if(at(o,a)){var l=_o(e,o,a,r.primary,r.primary.type);r.markers.push(l),l.parent=r}}}(r,zo(this)),r},unlinkDoc:function(e){if(e instanceof Ea&&(e=e.doc),this.linked)for(var t=0;t<this.linked.length;++t)if(this.linked[t].doc==e){this.linked.splice(t,1),e.unlinkDoc(this),Do(zo(this));break}if(e.history==this.history){var n=[e.id];Hi(e,function(e){return n.push(e.id)},!0),e.history=new Bi(null),e.history.done=Zi(this.history.done,n),e.history.undone=Zi(this.history.undone,n)}},iterLinkedDocs:function(e){Hi(this,e)},getMode:function(){return this.mode},getEditor:function(){return this.cm},splitLines:function(e){return this.lineSep?e.split(this.lineSep):We(e)},lineSeparator:function(){return this.lineSep||"\n"},setDirection:li(function(e){var t;"rtl"!=e&&(e="ltr"),e!=this.direction&&(this.direction=e,this.iter(function(e){return e.order=null}),this.cm&&ii(t=this.cm,function(){ji(t),gr(t)}))})}),Wo.prototype.eachLine=Wo.prototype.iter;var Fo=0;function Io(e){var t=this;if(Ho(t),!we(t,e)&&!Mn(t.display,e)){Se(e),a&&(Fo=+new Date);var n=pr(t,e,!0),r=e.dataTransfer.files;if(n&&!t.isReadOnly())if(r&&r.length&&window.FileReader&&window.File)for(var i=r.length,o=Array(i),l=0,s=function(){++l==i&&oi(t,function(){var e={from:n=ft(t.doc,n),to:n,text:t.doc.splitLines(o.filter(function(e){return null!=e}).join(t.doc.lineSeparator())),origin:"paste"};mo(t.doc,e),ro(t.doc,Oi(ft(t.doc,n),ft(t.doc,_i(e))))})()},c=function(e,n){if(t.options.allowDropFileTypes&&-1==K(t.options.allowDropFileTypes,e.type))s();else{var r=new FileReader;r.onerror=function(){return s()},r.onload=function(){var e=r.result;/[\x00-\x08\x0e-\x1f]{2}/.test(e)||(o[n]=e),s()},r.readAsText(e)}},u=0;u<r.length;u++)c(r[u],u);else{if(t.state.draggingText&&t.doc.sel.contains(n)>-1)return t.state.draggingText(e),void setTimeout(function(){return t.display.input.focus()},20);try{var d=e.dataTransfer.getData("Text");if(d){var f;if(t.state.draggingText&&!t.state.draggingText.copy&&(f=t.listSelections()),oo(t.doc,Oi(n,n)),f)for(var h=0;h<f.length;++h)wo(t.doc,"",f[h].anchor,f[h].head,"drag");t.replaceSelection(d,"around","paste"),t.display.input.focus()}}catch(e){}}}}function Ho(e){e.display.dragCursor&&(e.display.lineSpace.removeChild(e.display.dragCursor),e.display.dragCursor=null)}function Ro(e){if(document.getElementsByClassName){for(var t=document.getElementsByClassName("CodeMirror"),n=[],r=0;r<t.length;r++){var i=t[r].CodeMirror;i&&n.push(i)}n.length&&n[0].operation(function(){for(var t=0;t<n.length;t++)e(n[t])})}}var jo=!1;function Bo(){var e;jo||(ge(window,"resize",function(){null==e&&(e=setTimeout(function(){e=null,Ro(qo)},100))}),ge(window,"blur",function(){return Ro(Or)}),jo=!0)}function qo(e){var t=e.display;t.cachedCharWidth=t.cachedTextHeight=t.cachedPaddingH=null,t.scrollbarsClipped=!1,e.setSize()}for(var Uo={3:"Pause",8:"Backspace",9:"Tab",13:"Enter",16:"Shift",17:"Ctrl",18:"Alt",19:"Pause",20:"CapsLock",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"PrintScrn",45:"Insert",46:"Delete",59:";",61:"=",91:"Mod",92:"Mod",93:"Mod",106:"*",107:"=",109:"-",110:".",111:"/",145:"ScrollLock",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",224:"Mod",63232:"Up",63233:"Down",63234:"Left",63235:"Right",63272:"Delete",63273:"Home",63275:"End",63276:"PageUp",63277:"PageDown",63302:"Insert"},Ko=0;Ko<10;Ko++)Uo[Ko+48]=Uo[Ko+96]=String(Ko);for(var Vo=65;Vo<=90;Vo++)Uo[Vo]=String.fromCharCode(Vo);for(var Go=1;Go<=12;Go++)Uo[Go+111]=Uo[Go+63235]="F"+Go;var $o={};function Yo(e){var t,n,r,i,o=e.split(/-(?!$)/);e=o[o.length-1];for(var a=0;a<o.length-1;a++){var l=o[a];if(/^(cmd|meta|m)$/i.test(l))i=!0;else if(/^a(lt)?$/i.test(l))t=!0;else if(/^(c|ctrl|control)$/i.test(l))n=!0;else{if(!/^s(hift)?$/i.test(l))throw new Error("Unrecognized modifier name: "+l);r=!0}}return t&&(e="Alt-"+e),n&&(e="Ctrl-"+e),i&&(e="Cmd-"+e),r&&(e="Shift-"+e),e}function Xo(e){var t={};for(var n in e)if(e.hasOwnProperty(n)){var r=e[n];if(/^(name|fallthrough|(de|at)tach)$/.test(n))continue;if("..."==r){delete e[n];continue}for(var i=ee(n.split(" "),Yo),o=0;o<i.length;o++){var a=void 0,l=void 0;o==i.length-1?(l=i.join(" "),a=r):(l=i.slice(0,o+1).join(" "),a="...");var s=t[l];if(s){if(s!=a)throw new Error("Inconsistent bindings for "+l)}else t[l]=a}delete e[n]}for(var c in t)e[c]=t[c];return e}function Zo(e,t,n,r){var i=(t=ta(t)).call?t.call(e,r):t[e];if(!1===i)return"nothing";if("..."===i)return"multi";if(null!=i&&n(i))return"handled";if(t.fallthrough){if("[object Array]"!=Object.prototype.toString.call(t.fallthrough))return Zo(e,t.fallthrough,n,r);for(var o=0;o<t.fallthrough.length;o++){var a=Zo(e,t.fallthrough[o],n,r);if(a)return a}}}function Jo(e){var t="string"==typeof e?e:Uo[e.keyCode];return"Ctrl"==t||"Alt"==t||"Shift"==t||"Mod"==t}function Qo(e,t,n){var r=e;return t.altKey&&"Alt"!=r&&(e="Alt-"+e),(C?t.metaKey:t.ctrlKey)&&"Ctrl"!=r&&(e="Ctrl-"+e),(C?t.ctrlKey:t.metaKey)&&"Mod"!=r&&(e="Cmd-"+e),!n&&t.shiftKey&&"Shift"!=r&&(e="Shift-"+e),e}function ea(e,t){if(f&&34==e.keyCode&&e.char)return!1;var n=Uo[e.keyCode];return null!=n&&!e.altGraphKey&&(3==e.keyCode&&e.code&&(n=e.code),Qo(n,e,t))}function ta(e){return"string"==typeof e?$o[e]:e}function na(e,t){for(var n=e.doc.sel.ranges,r=[],i=0;i<n.length;i++){for(var o=t(n[i]);r.length&&at(o.from,Q(r).to)<=0;){var a=r.pop();if(at(a.from,o.from)<0){o.from=a.from;break}}r.push(o)}ii(e,function(){for(var t=r.length-1;t>=0;t--)wo(e.doc,"",r[t].from,r[t].to,"+delete");Wr(e)})}function ra(e,t,n){var r=ce(e.text,t+n,n);return r<0||r>e.text.length?null:r}function ia(e,t,n){var r=ra(e,t.ch,n);return null==r?null:new ot(t.line,r,n<0?"after":"before")}function oa(e,t,n,r,i){if(e){"rtl"==t.doc.direction&&(i=-i);var o=pe(n,t.doc.direction);if(o){var a,l=i<0?Q(o):o[0],s=i<0==(1==l.level)?"after":"before";if(l.level>0||"rtl"==t.doc.direction){var c=Fn(t,n);a=i<0?n.text.length-1:0;var u=In(t,c,a).top;a=ue(function(e){return In(t,c,e).top==u},i<0==(1==l.level)?l.from:l.to-1,a),"before"==s&&(a=ra(n,a,1))}else a=i<0?l.to:l.from;return new ot(r,a,s)}}return new ot(r,i<0?n.text.length:0,i<0?"before":"after")}$o.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"},$o.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"},$o.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars","Ctrl-O":"openLine"},$o.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight","Cmd-U":"undoSelection","Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]},$o.default=b?$o.macDefault:$o.pcDefault;var aa={selectAll:ho,singleSelection:function(e){return e.setSelection(e.getCursor("anchor"),e.getCursor("head"),G)},killLine:function(e){return na(e,function(t){if(t.empty()){var n=Ze(e.doc,t.head.line).text.length;return t.head.ch==n&&t.head.line<e.lastLine()?{from:t.head,to:ot(t.head.line+1,0)}:{from:t.head,to:ot(t.head.line,n)}}return{from:t.from(),to:t.to()}})},deleteLine:function(e){return na(e,function(t){return{from:ot(t.from().line,0),to:ft(e.doc,ot(t.to().line+1,0))}})},delLineLeft:function(e){return na(e,function(e){return{from:ot(e.from().line,0),to:e.from()}})},delWrappedLineLeft:function(e){return na(e,function(t){var n=e.charCoords(t.head,"div").top+5;return{from:e.coordsChar({left:0,top:n},"div"),to:t.from()}})},delWrappedLineRight:function(e){return na(e,function(t){var n=e.charCoords(t.head,"div").top+5,r=e.coordsChar({left:e.display.lineDiv.offsetWidth+100,top:n},"div");return{from:t.from(),to:r}})},undo:function(e){return e.undo()},redo:function(e){return e.redo()},undoSelection:function(e){return e.undoSelection()},redoSelection:function(e){return e.redoSelection()},goDocStart:function(e){return e.extendSelection(ot(e.firstLine(),0))},goDocEnd:function(e){return e.extendSelection(ot(e.lastLine()))},goLineStart:function(e){return e.extendSelectionsBy(function(t){return la(e,t.head.line)},{origin:"+move",bias:1})},goLineStartSmart:function(e){return e.extendSelectionsBy(function(t){return sa(e,t.head)},{origin:"+move",bias:1})},goLineEnd:function(e){return e.extendSelectionsBy(function(t){return function(e,t){var n=Ze(e.doc,t),r=function(e){for(var t;t=Rt(e);)e=t.find(1,!0).line;return e}(n);return r!=n&&(t=tt(r)),oa(!0,e,n,t,-1)}(e,t.head.line)},{origin:"+move",bias:-1})},goLineRight:function(e){return e.extendSelectionsBy(function(t){var n=e.cursorCoords(t.head,"div").top+5;return e.coordsChar({left:e.display.lineDiv.offsetWidth+100,top:n},"div")},Y)},goLineLeft:function(e){return e.extendSelectionsBy(function(t){var n=e.cursorCoords(t.head,"div").top+5;return e.coordsChar({left:0,top:n},"div")},Y)},goLineLeftSmart:function(e){return e.extendSelectionsBy(function(t){var n=e.cursorCoords(t.head,"div").top+5,r=e.coordsChar({left:0,top:n},"div");return r.ch<e.getLine(r.line).search(/\S/)?sa(e,t.head):r},Y)},goLineUp:function(e){return e.moveV(-1,"line")},goLineDown:function(e){return e.moveV(1,"line")},goPageUp:function(e){return e.moveV(-1,"page")},goPageDown:function(e){return e.moveV(1,"page")},goCharLeft:function(e){return e.moveH(-1,"char")},goCharRight:function(e){return e.moveH(1,"char")},goColumnLeft:function(e){return e.moveH(-1,"column")},goColumnRight:function(e){return e.moveH(1,"column")},goWordLeft:function(e){return e.moveH(-1,"word")},goGroupRight:function(e){return e.moveH(1,"group")},goGroupLeft:function(e){return e.moveH(-1,"group")},goWordRight:function(e){return e.moveH(1,"word")},delCharBefore:function(e){return e.deleteH(-1,"codepoint")},delCharAfter:function(e){return e.deleteH(1,"char")},delWordBefore:function(e){return e.deleteH(-1,"word")},delWordAfter:function(e){return e.deleteH(1,"word")},delGroupBefore:function(e){return e.deleteH(-1,"group")},delGroupAfter:function(e){return e.deleteH(1,"group")},indentAuto:function(e){return e.indentSelection("smart")},indentMore:function(e){return e.indentSelection("add")},indentLess:function(e){return e.indentSelection("subtract")},insertTab:function(e){return e.replaceSelection("\t")},insertSoftTab:function(e){for(var t=[],n=e.listSelections(),r=e.options.tabSize,i=0;i<n.length;i++){var o=n[i].from(),a=q(e.getLine(o.line),o.ch,r);t.push(J(r-a%r))}e.replaceSelections(t)},defaultTab:function(e){e.somethingSelected()?e.indentSelection("add"):e.execCommand("insertTab")},transposeChars:function(e){return ii(e,function(){for(var t=e.listSelections(),n=[],r=0;r<t.length;r++)if(t[r].empty()){var i=t[r].head,o=Ze(e.doc,i.line).text;if(o)if(i.ch==o.length&&(i=new ot(i.line,i.ch-1)),i.ch>0)i=new ot(i.line,i.ch+1),e.replaceRange(o.charAt(i.ch-1)+o.charAt(i.ch-2),ot(i.line,i.ch-2),i,"+transpose");else if(i.line>e.doc.first){var a=Ze(e.doc,i.line-1).text;a&&(i=new ot(i.line,1),e.replaceRange(o.charAt(0)+e.doc.lineSeparator()+a.charAt(a.length-1),ot(i.line-1,a.length-1),i,"+transpose"))}n.push(new Ai(i,i))}e.setSelections(n)})},newlineAndIndent:function(e){return ii(e,function(){for(var t=e.listSelections(),n=t.length-1;n>=0;n--)e.replaceRange(e.doc.lineSeparator(),t[n].anchor,t[n].head,"+input");t=e.listSelections();for(var r=0;r<t.length;r++)e.indentLine(t[r].from().line,null,!0);Wr(e)})},openLine:function(e){return e.replaceSelection("\n","start")},toggleOverwrite:function(e){return e.toggleOverwrite()}};function la(e,t){var n=Ze(e.doc,t),r=qt(n);return r!=n&&(t=tt(r)),oa(!0,e,r,t,1)}function sa(e,t){var n=la(e,t.line),r=Ze(e.doc,n.line),i=pe(r,e.doc.direction);if(!i||0==i[0].level){var o=Math.max(n.ch,r.text.search(/\S/)),a=t.line==n.line&&t.ch<=o&&t.ch;return ot(n.line,a?0:o,n.sticky)}return n}function ca(e,t,n){if("string"==typeof t&&!(t=aa[t]))return!1;e.display.input.ensurePolled();var r=e.display.shift,i=!1;try{e.isReadOnly()&&(e.state.suppressEdits=!0),n&&(e.display.shift=!1),i=t(e)!=V}finally{e.display.shift=r,e.state.suppressEdits=!1}return i}var ua=new U;function da(e,t,n,r){var i=e.state.keySeq;if(i){if(Jo(t))return"handled";if(/\'$/.test(t)?e.state.keySeq=null:ua.set(50,function(){e.state.keySeq==i&&(e.state.keySeq=null,e.display.input.reset())}),fa(e,i+" "+t,n,r))return!0}return fa(e,t,n,r)}function fa(e,t,n,r){var i=function(e,t,n){for(var r=0;r<e.state.keyMaps.length;r++){var i=Zo(t,e.state.keyMaps[r],n,e);if(i)return i}return e.options.extraKeys&&Zo(t,e.options.extraKeys,n,e)||Zo(t,e.options.keyMap,n,e)}(e,t,r);return"multi"==i&&(e.state.keySeq=t),"handled"==i&&hn(e,"keyHandled",e,t,n),"handled"!=i&&"multi"!=i||(Se(n),Lr(e)),!!i}function ha(e,t){var n=ea(t,!0);return!!n&&(t.shiftKey&&!e.state.keySeq?da(e,"Shift-"+n,t,function(t){return ca(e,t,!0)})||da(e,n,t,function(t){if("string"==typeof t?/^go[A-Z]/.test(t):t.motion)return ca(e,t)}):da(e,n,t,function(t){return ca(e,t)}))}var pa=null;function ma(e){var t=this;if(!(e.target&&e.target!=t.display.input.getField()||(t.curOp.focus=z(I(t)),we(t,e)))){a&&l<11&&27==e.keyCode&&(e.returnValue=!1);var r=e.keyCode;t.display.shift=16==r||e.shiftKey;var i=ha(t,e);f&&(pa=i?r:null,i||88!=r||Ie||!(b?e.metaKey:e.ctrlKey)||t.replaceSelection("",null,"cut")),n&&!b&&!i&&46==r&&e.shiftKey&&!e.ctrlKey&&document.execCommand&&document.execCommand("cut"),18!=r||/\bCodeMirror-crosshair\b/.test(t.display.lineDiv.className)||function(e){var t=e.display.lineDiv;function n(e){18!=e.keyCode&&e.altKey||(M(t,"CodeMirror-crosshair"),ye(document,"keyup",n),ye(document,"mouseover",n))}D(t,"CodeMirror-crosshair"),ge(document,"keyup",n),ge(document,"mouseover",n)}(t)}}function ga(e){16==e.keyCode&&(this.doc.sel.shift=!1),we(this,e)}function va(e){var t=this;if(!(e.target&&e.target!=t.display.input.getField()||Mn(t.display,e)||we(t,e)||e.ctrlKey&&!e.altKey||b&&e.metaKey)){var n=e.keyCode,r=e.charCode;if(f&&n==pa)return pa=null,void Se(e);if(!f||e.which&&!(e.which<10)||!ha(t,e)){var i=String.fromCharCode(null==r?n:r);"\b"!=i&&(function(e,t,n){return da(e,"'"+n+"'",t,function(t){return ca(e,t,!0)})}(t,e,i)||t.display.input.onKeyPress(e))}}}var ya,ba,wa=function(e,t,n){this.time=e,this.pos=t,this.button=n};function xa(e){var t=this,n=t.display;if(!(we(t,e)||n.activeTouch&&n.input.supportsTouch()))if(n.input.ensurePolled(),n.shift=e.shiftKey,Mn(n,e))s||(n.scroller.draggable=!1,setTimeout(function(){return n.scroller.draggable=!0},100));else if(!Sa(t,e)){var r=pr(t,e),i=Ne(e),o=r?function(e,t){var n=+new Date;return ba&&ba.compare(n,e,t)?(ya=ba=null,"triple"):ya&&ya.compare(n,e,t)?(ba=new wa(n,e,t),ya=null,"double"):(ya=new wa(n,e,t),ba=null,"single")}(r,i):"single";R(t).focus(),1==i&&t.state.selectingText&&t.state.selectingText(e),r&&function(e,t,n,r,i){var o="Click";return"double"==r?o="Double"+o:"triple"==r&&(o="Triple"+o),da(e,Qo(o=(1==t?"Left":2==t?"Middle":"Right")+o,i),i,function(t){if("string"==typeof t&&(t=aa[t]),!t)return!1;var r=!1;try{e.isReadOnly()&&(e.state.suppressEdits=!0),r=t(e,n)!=V}finally{e.state.suppressEdits=!1}return r})}(t,i,r,o,e)||(1==i?r?function(e,t,n,r){a?setTimeout(j(Mr,e),0):e.curOp.focus=z(I(e));var i,o=function(e,t,n){var r=e.getOption("configureMouse"),i=r?r(e,t,n):{};if(null==i.unit){var o=w?n.shiftKey&&n.metaKey:n.altKey;i.unit=o?"rectangle":"single"==t?"char":"double"==t?"word":"line"}return(null==i.extend||e.doc.extend)&&(i.extend=e.doc.extend||n.shiftKey),null==i.addNew&&(i.addNew=b?n.metaKey:n.ctrlKey),null==i.moveOnDrag&&(i.moveOnDrag=!(b?n.altKey:n.ctrlKey)),i}(e,n,r),c=e.doc.sel;e.options.dragDrop&&Ee&&!e.isReadOnly()&&"single"==n&&(i=c.contains(t))>-1&&(at((i=c.ranges[i]).from(),t)<0||t.xRel>0)&&(at(i.to(),t)>0||t.xRel<0)?function(e,t,n,r){var i=e.display,o=!1,c=oi(e,function(t){s&&(i.scroller.draggable=!1),e.state.draggingText=!1,e.state.delayingBlurEvent&&(e.hasFocus()?e.state.delayingBlurEvent=!1:Ar(e)),ye(i.wrapper.ownerDocument,"mouseup",c),ye(i.wrapper.ownerDocument,"mousemove",u),ye(i.scroller,"dragstart",d),ye(i.scroller,"drop",c),o||(Se(t),r.addNew||Qi(e.doc,n,null,null,r.extend),s&&!h||a&&9==l?setTimeout(function(){i.wrapper.ownerDocument.body.focus({preventScroll:!0}),i.input.focus()},20):i.input.focus())}),u=function(e){o=o||Math.abs(t.clientX-e.clientX)+Math.abs(t.clientY-e.clientY)>=10},d=function(){return o=!0};s&&(i.scroller.draggable=!0),e.state.draggingText=c,c.copy=!r.moveOnDrag,ge(i.wrapper.ownerDocument,"mouseup",c),ge(i.wrapper.ownerDocument,"mousemove",u),ge(i.scroller,"dragstart",d),ge(i.scroller,"drop",c),e.state.delayingBlurEvent=!0,setTimeout(function(){return i.input.focus()},20),i.scroller.dragDrop&&i.scroller.dragDrop()}(e,r,t,o):function(e,t,n,r){a&&Ar(e);var i=e.display,o=e.doc;Se(t);var l,s,c=o.sel,u=c.ranges;if(r.addNew&&!r.extend?(s=o.sel.contains(n),l=s>-1?u[s]:new Ai(n,n)):(l=o.sel.primary(),s=o.sel.primIndex),"rectangle"==r.unit)r.addNew||(l=new Ai(n,n)),n=pr(e,t,!0,!0),s=-1;else{var d=ka(e,n,r.unit);l=r.extend?Ji(l,d.anchor,d.head,r.extend):d}r.addNew?-1==s?(s=u.length,io(o,Ni(e,u.concat([l]),s),{scroll:!1,origin:"*mouse"})):u.length>1&&u[s].empty()&&"char"==r.unit&&!r.extend?(io(o,Ni(e,u.slice(0,s).concat(u.slice(s+1)),0),{scroll:!1,origin:"*mouse"}),c=o.sel):to(o,s,l,$):(s=0,io(o,new Mi([l],0),$),c=o.sel);var f=n;function h(t){if(0!=at(f,t))if(f=t,"rectangle"==r.unit){for(var i=[],a=e.options.tabSize,u=q(Ze(o,n.line).text,n.ch,a),d=q(Ze(o,t.line).text,t.ch,a),h=Math.min(u,d),p=Math.max(u,d),m=Math.min(n.line,t.line),g=Math.min(e.lastLine(),Math.max(n.line,t.line));m<=g;m++){var v=Ze(o,m).text,y=X(v,h,a);h==p?i.push(new Ai(ot(m,y),ot(m,y))):v.length>y&&i.push(new Ai(ot(m,y),ot(m,X(v,p,a))))}i.length||i.push(new Ai(n,n)),io(o,Ni(e,c.ranges.slice(0,s).concat(i),s),{origin:"*mouse",scroll:!1}),e.scrollIntoView(t)}else{var b,w=l,x=ka(e,t,r.unit),k=w.anchor;at(x.anchor,k)>0?(b=x.head,k=ut(w.from(),x.anchor)):(b=x.anchor,k=ct(w.to(),x.head));var C=c.ranges.slice(0);C[s]=function(e,t){var n=t.anchor,r=t.head,i=Ze(e.doc,n.line);if(0==at(n,r)&&n.sticky==r.sticky)return t;var o=pe(i);if(!o)return t;var a=fe(o,n.ch,n.sticky),l=o[a];if(l.from!=n.ch&&l.to!=n.ch)return t;var s,c=a+(l.from==n.ch==(1!=l.level)?0:1);if(0==c||c==o.length)return t;if(r.line!=n.line)s=(r.line-n.line)*("ltr"==e.doc.direction?1:-1)>0;else{var u=fe(o,r.ch,r.sticky),d=u-a||(r.ch-n.ch)*(1==l.level?-1:1);s=u==c-1||u==c?d<0:d>0}var f=o[c+(s?-1:0)],h=s==(1==f.level),p=h?f.from:f.to,m=h?"after":"before";return n.ch==p&&n.sticky==m?t:new Ai(new ot(n.line,p,m),r)}(e,new Ai(ft(o,k),b)),io(o,Ni(e,C,s),$)}}var p=i.wrapper.getBoundingClientRect(),m=0;function g(t){var n=++m,a=pr(e,t,!0,"rectangle"==r.unit);if(a)if(0!=at(a,f)){e.curOp.focus=z(I(e)),h(a);var l=zr(i,o);(a.line>=l.to||a.line<l.from)&&setTimeout(oi(e,function(){m==n&&g(t)}),150)}else{var s=t.clientY<p.top?-20:t.clientY>p.bottom?20:0;s&&setTimeout(oi(e,function(){m==n&&(i.scroller.scrollTop+=s,g(t))}),50)}}function v(t){e.state.selectingText=!1,m=1/0,t&&(Se(t),i.input.focus()),ye(i.wrapper.ownerDocument,"mousemove",y),ye(i.wrapper.ownerDocument,"mouseup",b),o.history.lastSelOrigin=null}var y=oi(e,function(e){0!==e.buttons&&Ne(e)?g(e):v(e)}),b=oi(e,v);e.state.selectingText=b,ge(i.wrapper.ownerDocument,"mousemove",y),ge(i.wrapper.ownerDocument,"mouseup",b)}(e,r,t,o)}(t,r,o,e):Ae(e)==n.scroller&&Se(e):2==i?(r&&Qi(t.doc,r),setTimeout(function(){return n.input.focus()},20)):3==i&&(S?t.display.input.onContextMenu(e):Ar(t)))}}function ka(e,t,n){if("char"==n)return new Ai(t,t);if("word"==n)return e.findWordAt(t);if("line"==n)return new Ai(ot(t.line,0),ft(e.doc,ot(t.line+1,0)));var r=n(e,t);return new Ai(r.from,r.to)}function Ca(e,t,n,r){var i,o;if(t.touches)i=t.touches[0].clientX,o=t.touches[0].clientY;else try{i=t.clientX,o=t.clientY}catch(e){return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;r&&Se(t);var a=e.display,l=a.lineDiv.getBoundingClientRect();if(o>l.bottom||!ke(e,n))return Le(t);o-=l.top-a.viewOffset;for(var s=0;s<e.display.gutterSpecs.length;++s){var c=a.gutters.childNodes[s];if(c&&c.getBoundingClientRect().right>=i)return be(e,n,e,nt(e.doc,o),e.display.gutterSpecs[s].className,t),Le(t)}}function Sa(e,t){return Ca(e,t,"gutterClick",!0)}function Ta(e,t){Mn(e.display,t)||function(e,t){return!!ke(e,"gutterContextMenu")&&Ca(e,t,"gutterContextMenu",!1)}(e,t)||we(e,t,"contextmenu")||S||e.display.input.onContextMenu(t)}function La(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),Kn(e)}wa.prototype.compare=function(e,t,n){return this.time+400>e&&0==at(t,this.pos)&&n==this.button};var Ma={toString:function(){return"CodeMirror.Init"}},Aa={},Na={};function Oa(e,t,n){if(!t!=!(n&&n!=Ma)){var r=e.display.dragFunctions,i=t?ge:ye;i(e.display.scroller,"dragstart",r.start),i(e.display.scroller,"dragenter",r.enter),i(e.display.scroller,"dragover",r.over),i(e.display.scroller,"dragleave",r.leave),i(e.display.scroller,"drop",r.drop)}}function _a(e){e.options.lineWrapping?(D(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(M(e.display.wrapper,"CodeMirror-wrap"),Xt(e)),hr(e),gr(e),Kn(e),setTimeout(function(){return Vr(e)},100)}function Ea(e,t){var n=this;if(!(this instanceof Ea))return new Ea(e,t);this.options=t=t?B(t):{},B(Aa,t,!1);var r=t.value;"string"==typeof r?r=new Wo(r,t.mode,null,t.lineSeparator,t.direction):t.mode&&(r.modeOption=t.mode),this.doc=r;var i=new Ea.inputStyles[t.inputStyle](this),o=this.display=new xi(e,r,i,t);for(var c in o.wrapper.CodeMirror=this,La(this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),Yr(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:-1,cutIncoming:-1,selectingText:!1,draggingText:!1,highlight:new U,keySeq:null,specialChars:null},t.autofocus&&!y&&o.input.focus(),a&&l<11&&setTimeout(function(){return n.display.input.reset(!0)},20),function(e){var t=e.display;ge(t.scroller,"mousedown",oi(e,xa)),ge(t.scroller,"dblclick",a&&l<11?oi(e,function(t){if(!we(e,t)){var n=pr(e,t);if(n&&!Sa(e,t)&&!Mn(e.display,t)){Se(t);var r=e.findWordAt(n);Qi(e.doc,r.anchor,r.head)}}}):function(t){return we(e,t)||Se(t)}),ge(t.scroller,"contextmenu",function(t){return Ta(e,t)}),ge(t.input.getField(),"contextmenu",function(n){t.scroller.contains(n.target)||Ta(e,n)});var n,r={end:0};function i(){t.activeTouch&&(n=setTimeout(function(){return t.activeTouch=null},1e3),(r=t.activeTouch).end=+new Date)}function o(e){if(1!=e.touches.length)return!1;var t=e.touches[0];return t.radiusX<=1&&t.radiusY<=1}function s(e,t){if(null==t.left)return!0;var n=t.left-e.left,r=t.top-e.top;return n*n+r*r>400}ge(t.scroller,"touchstart",function(i){if(!we(e,i)&&!o(i)&&!Sa(e,i)){t.input.ensurePolled(),clearTimeout(n);var a=+new Date;t.activeTouch={start:a,moved:!1,prev:a-r.end<=300?r:null},1==i.touches.length&&(t.activeTouch.left=i.touches[0].pageX,t.activeTouch.top=i.touches[0].pageY)}}),ge(t.scroller,"touchmove",function(){t.activeTouch&&(t.activeTouch.moved=!0)}),ge(t.scroller,"touchend",function(n){var r=t.activeTouch;if(r&&!Mn(t,n)&&null!=r.left&&!r.moved&&new Date-r.start<300){var o,a=e.coordsChar(t.activeTouch,"page");o=!r.prev||s(r,r.prev)?new Ai(a,a):!r.prev.prev||s(r,r.prev.prev)?e.findWordAt(a):new Ai(ot(a.line,0),ft(e.doc,ot(a.line+1,0))),e.setSelection(o.anchor,o.head),e.focus(),Se(n)}i()}),ge(t.scroller,"touchcancel",i),ge(t.scroller,"scroll",function(){t.scroller.clientHeight&&(Rr(e,t.scroller.scrollTop),Br(e,t.scroller.scrollLeft,!0),be(e,"scroll",e))}),ge(t.scroller,"mousewheel",function(t){return Li(e,t)}),ge(t.scroller,"DOMMouseScroll",function(t){return Li(e,t)}),ge(t.wrapper,"scroll",function(){return t.wrapper.scrollTop=t.wrapper.scrollLeft=0}),t.dragFunctions={enter:function(t){we(e,t)||Me(t)},over:function(t){we(e,t)||(function(e,t){var n=pr(e,t);if(n){var r=document.createDocumentFragment();Cr(e,n,r),e.display.dragCursor||(e.display.dragCursor=O("div",null,"CodeMirror-cursors CodeMirror-dragcursors"),e.display.lineSpace.insertBefore(e.display.dragCursor,e.display.cursorDiv)),N(e.display.dragCursor,r)}}(e,t),Me(t))},start:function(t){return function(e,t){if(a&&(!e.state.draggingText||+new Date-Fo<100))Me(t);else if(!we(e,t)&&!Mn(e.display,t)&&(t.dataTransfer.setData("Text",e.getSelection()),t.dataTransfer.effectAllowed="copyMove",t.dataTransfer.setDragImage&&!h)){var n=O("img",null,null,"position: fixed; left: 0; top: 0;");n.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",f&&(n.width=n.height=1,e.display.wrapper.appendChild(n),n._top=n.offsetTop),t.dataTransfer.setDragImage(n,0,0),f&&n.parentNode.removeChild(n)}}(e,t)},drop:oi(e,Io),leave:function(t){we(e,t)||Ho(e)}};var c=t.input.getField();ge(c,"keyup",function(t){return ga.call(e,t)}),ge(c,"keydown",oi(e,ma)),ge(c,"keypress",oi(e,va)),ge(c,"focus",function(t){return Nr(e,t)}),ge(c,"blur",function(t){return Or(e,t)})}(this),Bo(),Zr(this),this.curOp.forceUpdate=!0,Ri(this,r),t.autofocus&&!y||this.hasFocus()?setTimeout(function(){n.hasFocus()&&!n.state.focused&&Nr(n)},20):Or(this),Na)Na.hasOwnProperty(c)&&Na[c](this,t[c],Ma);vi(this),t.finishInit&&t.finishInit(this);for(var u=0;u<za.length;++u)za[u](this);Jr(this),s&&t.lineWrapping&&"optimizelegibility"==getComputedStyle(o.lineDiv).textRendering&&(o.lineDiv.style.textRendering="auto")}Ea.defaults=Aa,Ea.optionHandlers=Na;var za=[];function Da(e,t,n,r){var i,o=e.doc;null==n&&(n="add"),"smart"==n&&(o.mode.indent?i=yt(e,t).state:n="prev");var a=e.options.tabSize,l=Ze(o,t),s=q(l.text,null,a);l.stateAfter&&(l.stateAfter=null);var c,u=l.text.match(/^\s*/)[0];if(r||/\S/.test(l.text)){if("smart"==n&&((c=o.mode.indent(i,l.text.slice(u.length),l.text))==V||c>150)){if(!r)return;n="prev"}}else c=0,n="not";"prev"==n?c=t>o.first?q(Ze(o,t-1).text,null,a):0:"add"==n?c=s+e.options.indentUnit:"subtract"==n?c=s-e.options.indentUnit:"number"==typeof n&&(c=s+n),c=Math.max(0,c);var d="",f=0;if(e.options.indentWithTabs)for(var h=Math.floor(c/a);h;--h)f+=a,d+="\t";if(f<c&&(d+=J(c-f)),d!=u)return wo(o,d,ot(t,0),ot(t,u.length),"+input"),l.stateAfter=null,!0;for(var p=0;p<o.sel.ranges.length;p++){var m=o.sel.ranges[p];if(m.head.line==t&&m.head.ch<u.length){var g=ot(t,u.length);to(o,p,new Ai(g,g));break}}}Ea.defineInitHook=function(e){return za.push(e)};var Pa=null;function Wa(e){Pa=e}function Fa(e,t,n,r,i){var o=e.doc;e.display.shift=!1,r||(r=o.sel);var a=+new Date-200,l="paste"==i||e.state.pasteIncoming>a,s=We(t),c=null;if(l&&r.ranges.length>1)if(Pa&&Pa.text.join("\n")==t){if(r.ranges.length%Pa.text.length==0){c=[];for(var u=0;u<Pa.text.length;u++)c.push(o.splitLines(Pa.text[u]))}}else s.length==r.ranges.length&&e.options.pasteLinesPerSelection&&(c=ee(s,function(e){return[e]}));for(var d=e.curOp.updateInput,f=r.ranges.length-1;f>=0;f--){var h=r.ranges[f],p=h.from(),m=h.to();h.empty()&&(n&&n>0?p=ot(p.line,p.ch-n):e.state.overwrite&&!l?m=ot(m.line,Math.min(Ze(o,m.line).text.length,m.ch+Q(s).length)):l&&Pa&&Pa.lineWise&&Pa.text.join("\n")==s.join("\n")&&(p=m=ot(p.line,0)));var g={from:p,to:m,text:c?c[f%c.length]:s,origin:i||(l?"paste":e.state.cutIncoming>a?"cut":"+input")};mo(e.doc,g),hn(e,"inputRead",e,g)}t&&!l&&Ha(e,t),Wr(e),e.curOp.updateInput<2&&(e.curOp.updateInput=d),e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=-1}function Ia(e,t){var n=e.clipboardData&&e.clipboardData.getData("Text");if(n)return e.preventDefault(),t.isReadOnly()||t.options.disableInput||!t.hasFocus()||ii(t,function(){return Fa(t,n,0,null,"paste")}),!0}function Ha(e,t){if(e.options.electricChars&&e.options.smartIndent)for(var n=e.doc.sel,r=n.ranges.length-1;r>=0;r--){var i=n.ranges[r];if(!(i.head.ch>100||r&&n.ranges[r-1].head.line==i.head.line)){var o=e.getModeAt(i.head),a=!1;if(o.electricChars){for(var l=0;l<o.electricChars.length;l++)if(t.indexOf(o.electricChars.charAt(l))>-1){a=Da(e,i.head.line,"smart");break}}else o.electricInput&&o.electricInput.test(Ze(e.doc,i.head.line).text.slice(0,i.head.ch))&&(a=Da(e,i.head.line,"smart"));a&&hn(e,"electricInput",e,i.head.line)}}}function Ra(e){for(var t=[],n=[],r=0;r<e.doc.sel.ranges.length;r++){var i=e.doc.sel.ranges[r].head.line,o={anchor:ot(i,0),head:ot(i+1,0)};n.push(o),t.push(e.getRange(o.anchor,o.head))}return{text:t,ranges:n}}function ja(e,t,n,r){e.setAttribute("autocorrect",n?"on":"off"),e.setAttribute("autocapitalize",r?"on":"off"),e.setAttribute("spellcheck",!!t)}function Ba(){var e=O("textarea",null,null,"position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; min-height: 1em; outline: none"),t=O("div",[e],null,"overflow: hidden; position: relative; width: 3px; height: 0px;");return s?e.style.width="1000px":e.setAttribute("wrap","off"),g&&(e.style.border="1px solid black"),t}function qa(e,t,n,r,i){var o=t,a=n,l=Ze(e,t.line),s=i&&"rtl"==e.direction?-n:n;function c(o){var a,c;if("codepoint"==r){var u=l.text.charCodeAt(t.ch+(n>0?0:-1));if(isNaN(u))a=null;else{var d=n>0?u>=55296&&u<56320:u>=56320&&u<57343;a=new ot(t.line,Math.max(0,Math.min(l.text.length,t.ch+n*(d?2:1))),-n)}}else a=i?function(e,t,n,r){var i=pe(t,e.doc.direction);if(!i)return ia(t,n,r);n.ch>=t.text.length?(n.ch=t.text.length,n.sticky="before"):n.ch<=0&&(n.ch=0,n.sticky="after");var o=fe(i,n.ch,n.sticky),a=i[o];if("ltr"==e.doc.direction&&a.level%2==0&&(r>0?a.to>n.ch:a.from<n.ch))return ia(t,n,r);var l,s=function(e,n){return ra(t,e instanceof ot?e.ch:e,n)},c=function(n){return e.options.lineWrapping?(l=l||Fn(e,t),rr(e,t,l,n)):{begin:0,end:t.text.length}},u=c("before"==n.sticky?s(n,-1):n.ch);if("rtl"==e.doc.direction||1==a.level){var d=1==a.level==r<0,f=s(n,d?1:-1);if(null!=f&&(d?f<=a.to&&f<=u.end:f>=a.from&&f>=u.begin)){var h=d?"before":"after";return new ot(n.line,f,h)}}var p=function(e,t,r){for(var o=function(e,t){return t?new ot(n.line,s(e,1),"before"):new ot(n.line,e,"after")};e>=0&&e<i.length;e+=t){var a=i[e],l=t>0==(1!=a.level),c=l?r.begin:s(r.end,-1);if(a.from<=c&&c<a.to)return o(c,l);if(c=l?a.from:s(a.to,-1),r.begin<=c&&c<r.end)return o(c,l)}},m=p(o+r,r,u);if(m)return m;var g=r>0?u.end:s(u.begin,-1);return null==g||r>0&&g==t.text.length||!(m=p(r>0?0:i.length-1,r,c(g)))?null:m}(e.cm,l,t,n):ia(l,t,n);if(null==a){if(o||((c=t.line+s)<e.first||c>=e.first+e.size||(t=new ot(c,t.ch,t.sticky),!(l=Ze(e,c)))))return!1;t=oa(i,e.cm,l,t.line,s)}else t=a;return!0}if("char"==r||"codepoint"==r)c();else if("column"==r)c(!0);else if("word"==r||"group"==r)for(var u=null,d="group"==r,f=e.cm&&e.cm.getHelper(t,"wordChars"),h=!0;!(n<0)||c(!h);h=!1){var p=l.text.charAt(t.ch)||"\n",m=oe(p,f)?"w":d&&"\n"==p?"n":!d||/\s/.test(p)?null:"p";if(!d||h||m||(m="s"),u&&u!=m){n<0&&(n=1,c(),t.sticky="after");break}if(m&&(u=m),n>0&&!c(!h))break}var g=uo(e,t,o,a,!0);return lt(o,g)&&(g.hitSide=!0),g}function Ua(e,t,n,r){var i,o,a=e.doc,l=t.left;if("page"==r){var s=Math.min(e.display.wrapper.clientHeight,R(e).innerHeight||a(e).documentElement.clientHeight),c=Math.max(s-.5*sr(e.display),3);i=(n>0?t.bottom:t.top)+n*c}else"line"==r&&(i=n>0?t.bottom+3:t.top-3);for(;(o=tr(e,l,i)).outside;){if(n<0?i<=0:i>=a.height){o.hitSide=!0;break}i+=5*n}return o}var Ka=function(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new U,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null};function Va(e,t){var n=Wn(e,t.line);if(!n||n.hidden)return null;var r=Ze(e.doc,t.line),i=Dn(n,r,t.line),o=pe(r,e.doc.direction),a="left";o&&(a=fe(o,t.ch)%2?"right":"left");var l=jn(i.map,t.ch,a);return l.offset="right"==l.collapse?l.end:l.start,l}function Ga(e,t){return t&&(e.bad=!0),e}function $a(e,t,n){var r;if(t==e.display.lineDiv){if(!(r=e.display.lineDiv.childNodes[n]))return Ga(e.clipPos(ot(e.display.viewTo-1)),!0);t=null,n=0}else for(r=t;;r=r.parentNode){if(!r||r==e.display.lineDiv)return null;if(r.parentNode&&r.parentNode==e.display.lineDiv)break}for(var i=0;i<e.display.view.length;i++){var o=e.display.view[i];if(o.node==r)return Ya(o,t,n)}}function Ya(e,t,n){var r=e.text.firstChild,i=!1;if(!t||!E(r,t))return Ga(ot(tt(e.line),0),!0);if(t==r&&(i=!0,t=r.childNodes[n],n=0,!t)){var o=e.rest?Q(e.rest):e.line;return Ga(ot(tt(o),o.text.length),i)}var a=3==t.nodeType?t:null,l=t;for(a||1!=t.childNodes.length||3!=t.firstChild.nodeType||(a=t.firstChild,n&&(n=a.nodeValue.length));l.parentNode!=r;)l=l.parentNode;var s=e.measure,c=s.maps;function u(t,n,r){for(var i=-1;i<(c?c.length:0);i++)for(var o=i<0?s.map:c[i],a=0;a<o.length;a+=3){var l=o[a+2];if(l==t||l==n){var u=tt(i<0?e.line:e.rest[i]),d=o[a]+r;return(r<0||l!=t)&&(d=o[a+(r?1:0)]),ot(u,d)}}}var d=u(a,l,n);if(d)return Ga(d,i);for(var f=l.nextSibling,h=a?a.nodeValue.length-n:0;f;f=f.nextSibling){if(d=u(f,f.firstChild,0))return Ga(ot(d.line,d.ch-h),i);h+=f.textContent.length}for(var p=l.previousSibling,m=n;p;p=p.previousSibling){if(d=u(p,p.firstChild,-1))return Ga(ot(d.line,d.ch+m),i);m+=p.textContent.length}}Ka.prototype.init=function(e){var t=this,n=this,r=n.cm,i=n.div=e.lineDiv;function o(e){for(var t=e.target;t;t=t.parentNode){if(t==i)return!0;if(/\bCodeMirror-(?:line)?widget\b/.test(t.className))break}return!1}function a(e){if(o(e)&&!we(r,e)){if(r.somethingSelected())Wa({lineWise:!1,text:r.getSelections()}),"cut"==e.type&&r.replaceSelection("",null,"cut");else{if(!r.options.lineWiseCopyCut)return;var t=Ra(r);Wa({lineWise:!0,text:t.text}),"cut"==e.type&&r.operation(function(){r.setSelections(t.ranges,0,G),r.replaceSelection("",null,"cut")})}if(e.clipboardData){e.clipboardData.clearData();var a=Pa.text.join("\n");if(e.clipboardData.setData("Text",a),e.clipboardData.getData("Text")==a)return void e.preventDefault()}var l=Ba(),s=l.firstChild;ja(s),r.display.lineSpace.insertBefore(l,r.display.lineSpace.firstChild),s.value=Pa.text.join("\n");var c=z(H(i));W(s),setTimeout(function(){r.display.lineSpace.removeChild(l),c.focus(),c==i&&n.showPrimarySelection()},50)}}i.contentEditable=!0,ja(i,r.options.spellcheck,r.options.autocorrect,r.options.autocapitalize),ge(i,"paste",function(e){!o(e)||we(r,e)||Ia(e,r)||l<=11&&setTimeout(oi(r,function(){return t.updateFromDOM()}),20)}),ge(i,"compositionstart",function(e){t.composing={data:e.data,done:!1}}),ge(i,"compositionupdate",function(e){t.composing||(t.composing={data:e.data,done:!1})}),ge(i,"compositionend",function(e){t.composing&&(e.data!=t.composing.data&&t.readFromDOMSoon(),t.composing.done=!0)}),ge(i,"touchstart",function(){return n.forceCompositionEnd()}),ge(i,"input",function(){t.composing||t.readFromDOMSoon()}),ge(i,"copy",a),ge(i,"cut",a)},Ka.prototype.screenReaderLabelChanged=function(e){e?this.div.setAttribute("aria-label",e):this.div.removeAttribute("aria-label")},Ka.prototype.prepareSelection=function(){var e=kr(this.cm,!1);return e.focus=z(H(this.div))==this.div,e},Ka.prototype.showSelection=function(e,t){e&&this.cm.display.view.length&&((e.focus||t)&&this.showPrimarySelection(),this.showMultipleSelections(e))},Ka.prototype.getSelection=function(){return this.cm.display.wrapper.ownerDocument.getSelection()},Ka.prototype.showPrimarySelection=function(){var e=this.getSelection(),t=this.cm,r=t.doc.sel.primary(),i=r.from(),o=r.to();if(t.display.viewTo==t.display.viewFrom||i.line>=t.display.viewTo||o.line<t.display.viewFrom)e.removeAllRanges();else{var a=$a(t,e.anchorNode,e.anchorOffset),l=$a(t,e.focusNode,e.focusOffset);if(!a||a.bad||!l||l.bad||0!=at(ut(a,l),i)||0!=at(ct(a,l),o)){var s=t.display.view,c=i.line>=t.display.viewFrom&&Va(t,i)||{node:s[0].measure.map[2],offset:0},u=o.line<t.display.viewTo&&Va(t,o);if(!u){var d=s[s.length-1].measure,f=d.maps?d.maps[d.maps.length-1]:d.map;u={node:f[f.length-1],offset:f[f.length-2]-f[f.length-3]}}if(c&&u){var h,p=e.rangeCount&&e.getRangeAt(0);try{h=L(c.node,c.offset,u.offset,u.node)}catch(e){}h&&(!n&&t.state.focused?(e.collapse(c.node,c.offset),h.collapsed||(e.removeAllRanges(),e.addRange(h))):(e.removeAllRanges(),e.addRange(h)),p&&null==e.anchorNode?e.addRange(p):n&&this.startGracePeriod()),this.rememberSelection()}else e.removeAllRanges()}}},Ka.prototype.startGracePeriod=function(){var e=this;clearTimeout(this.gracePeriod),this.gracePeriod=setTimeout(function(){e.gracePeriod=!1,e.selectionChanged()&&e.cm.operation(function(){return e.cm.curOp.selectionChanged=!0})},20)},Ka.prototype.showMultipleSelections=function(e){N(this.cm.display.cursorDiv,e.cursors),N(this.cm.display.selectionDiv,e.selection)},Ka.prototype.rememberSelection=function(){var e=this.getSelection();this.lastAnchorNode=e.anchorNode,this.lastAnchorOffset=e.anchorOffset,this.lastFocusNode=e.focusNode,this.lastFocusOffset=e.focusOffset},Ka.prototype.selectionInEditor=function(){var e=this.getSelection();if(!e.rangeCount)return!1;var t=e.getRangeAt(0).commonAncestorContainer;return E(this.div,t)},Ka.prototype.focus=function(){"nocursor"!=this.cm.options.readOnly&&(this.selectionInEditor()&&z(H(this.div))==this.div||this.showSelection(this.prepareSelection(),!0),this.div.focus())},Ka.prototype.blur=function(){this.div.blur()},Ka.prototype.getField=function(){return this.div},Ka.prototype.supportsTouch=function(){return!0},Ka.prototype.receivedFocus=function(){var e=this,t=this;this.selectionInEditor()?setTimeout(function(){return e.pollSelection()},20):ii(this.cm,function(){return t.cm.curOp.selectionChanged=!0}),this.polling.set(this.cm.options.pollInterval,function e(){t.cm.state.focused&&(t.pollSelection(),t.polling.set(t.cm.options.pollInterval,e))})},Ka.prototype.selectionChanged=function(){var e=this.getSelection();return e.anchorNode!=this.lastAnchorNode||e.anchorOffset!=this.lastAnchorOffset||e.focusNode!=this.lastFocusNode||e.focusOffset!=this.lastFocusOffset},Ka.prototype.pollSelection=function(){if(null==this.readDOMTimeout&&!this.gracePeriod&&this.selectionChanged()){var e=this.getSelection(),t=this.cm;if(v&&u&&this.cm.display.gutterSpecs.length&&function(e){for(var t=e;t;t=t.parentNode)if(/CodeMirror-gutter-wrapper/.test(t.className))return!0;return!1}(e.anchorNode))return this.cm.triggerOnKeyDown({type:"keydown",keyCode:8,preventDefault:Math.abs}),this.blur(),void this.focus();if(!this.composing){this.rememberSelection();var n=$a(t,e.anchorNode,e.anchorOffset),r=$a(t,e.focusNode,e.focusOffset);n&&r&&ii(t,function(){io(t.doc,Oi(n,r),G),(n.bad||r.bad)&&(t.curOp.selectionChanged=!0)})}}},Ka.prototype.pollContent=function(){null!=this.readDOMTimeout&&(clearTimeout(this.readDOMTimeout),this.readDOMTimeout=null);var e,t,n,r=this.cm,i=r.display,o=r.doc.sel.primary(),a=o.from(),l=o.to();if(0==a.ch&&a.line>r.firstLine()&&(a=ot(a.line-1,Ze(r.doc,a.line-1).length)),l.ch==Ze(r.doc,l.line).text.length&&l.line<r.lastLine()&&(l=ot(l.line+1,0)),a.line<i.viewFrom||l.line>i.viewTo-1)return!1;a.line==i.viewFrom||0==(e=mr(r,a.line))?(t=tt(i.view[0].line),n=i.view[0].node):(t=tt(i.view[e].line),n=i.view[e-1].node.nextSibling);var s,c,u=mr(r,l.line);if(u==i.view.length-1?(s=i.viewTo-1,c=i.lineDiv.lastChild):(s=tt(i.view[u+1].line)-1,c=i.view[u+1].node.previousSibling),!n)return!1;for(var d=r.doc.splitLines(function(e,t,n,r,i){var o="",a=!1,l=e.doc.lineSeparator(),s=!1;function c(){a&&(o+=l,s&&(o+=l),a=s=!1)}function u(e){e&&(c(),o+=e)}function d(t){if(1==t.nodeType){var n=t.getAttribute("cm-text");if(n)return void u(n);var o,f=t.getAttribute("cm-marker");if(f){var h=e.findMarks(ot(r,0),ot(i+1,0),(g=+f,function(e){return e.id==g}));return void(h.length&&(o=h[0].find(0))&&u(Je(e.doc,o.from,o.to).join(l)))}if("false"==t.getAttribute("contenteditable"))return;var p=/^(pre|div|p|li|table|br)$/i.test(t.nodeName);if(!/^br$/i.test(t.nodeName)&&0==t.textContent.length)return;p&&c();for(var m=0;m<t.childNodes.length;m++)d(t.childNodes[m]);/^(pre|p)$/i.test(t.nodeName)&&(s=!0),p&&(a=!0)}else 3==t.nodeType&&u(t.nodeValue.replace(/\u200b/g,"").replace(/\u00a0/g," "));var g}for(;d(t),t!=n;)t=t.nextSibling,s=!1;return o}(r,n,c,t,s)),f=Je(r.doc,ot(t,0),ot(s,Ze(r.doc,s).text.length));d.length>1&&f.length>1;)if(Q(d)==Q(f))d.pop(),f.pop(),s--;else{if(d[0]!=f[0])break;d.shift(),f.shift(),t++}for(var h=0,p=0,m=d[0],g=f[0],v=Math.min(m.length,g.length);h<v&&m.charCodeAt(h)==g.charCodeAt(h);)++h;for(var y=Q(d),b=Q(f),w=Math.min(y.length-(1==d.length?h:0),b.length-(1==f.length?h:0));p<w&&y.charCodeAt(y.length-p-1)==b.charCodeAt(b.length-p-1);)++p;if(1==d.length&&1==f.length&&t==a.line)for(;h&&h>a.ch&&y.charCodeAt(y.length-p-1)==b.charCodeAt(b.length-p-1);)h--,p++;d[d.length-1]=y.slice(0,y.length-p).replace(/^\u200b+/,""),d[0]=d[0].slice(h).replace(/\u200b+$/,"");var x=ot(t,h),k=ot(s,f.length?Q(f).length-p:0);return d.length>1||d[0]||at(x,k)?(wo(r.doc,d,x,k,"+input"),!0):void 0},Ka.prototype.ensurePolled=function(){this.forceCompositionEnd()},Ka.prototype.reset=function(){this.forceCompositionEnd()},Ka.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},Ka.prototype.readFromDOMSoon=function(){var e=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout(function(){if(e.readDOMTimeout=null,e.composing){if(!e.composing.done)return;e.composing=null}e.updateFromDOM()},80))},Ka.prototype.updateFromDOM=function(){var e=this;!this.cm.isReadOnly()&&this.pollContent()||ii(this.cm,function(){return gr(e.cm)})},Ka.prototype.setUneditable=function(e){e.contentEditable="false"},Ka.prototype.onKeyPress=function(e){0==e.charCode||this.composing||(e.preventDefault(),this.cm.isReadOnly()||oi(this.cm,Fa)(this.cm,String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),0))},Ka.prototype.readOnlyChanged=function(e){this.div.contentEditable=String("nocursor"!=e)},Ka.prototype.onContextMenu=function(){},Ka.prototype.resetPosition=function(){},Ka.prototype.needsContentAttribute=!0;var Xa=function(e){this.cm=e,this.prevInput="",this.pollingFast=!1,this.polling=new U,this.hasSelection=!1,this.composing=null,this.resetting=!1};Xa.prototype.init=function(e){var t=this,n=this,r=this.cm;this.createField(e);var i=this.textarea;function o(e){if(!we(r,e)){if(r.somethingSelected())Wa({lineWise:!1,text:r.getSelections()});else{if(!r.options.lineWiseCopyCut)return;var t=Ra(r);Wa({lineWise:!0,text:t.text}),"cut"==e.type?r.setSelections(t.ranges,null,G):(n.prevInput="",i.value=t.text.join("\n"),W(i))}"cut"==e.type&&(r.state.cutIncoming=+new Date)}}e.wrapper.insertBefore(this.wrapper,e.wrapper.firstChild),g&&(i.style.width="0px"),ge(i,"input",function(){a&&l>=9&&t.hasSelection&&(t.hasSelection=null),n.poll()}),ge(i,"paste",function(e){we(r,e)||Ia(e,r)||(r.state.pasteIncoming=+new Date,n.fastPoll())}),ge(i,"cut",o),ge(i,"copy",o),ge(e.scroller,"paste",function(t){if(!Mn(e,t)&&!we(r,t)){if(!i.dispatchEvent)return r.state.pasteIncoming=+new Date,void n.focus();var o=new Event("paste");o.clipboardData=t.clipboardData,i.dispatchEvent(o)}}),ge(e.lineSpace,"selectstart",function(t){Mn(e,t)||Se(t)}),ge(i,"compositionstart",function(){var e=r.getCursor("from");n.composing&&n.composing.range.clear(),n.composing={start:e,range:r.markText(e,r.getCursor("to"),{className:"CodeMirror-composing"})}}),ge(i,"compositionend",function(){n.composing&&(n.poll(),n.composing.range.clear(),n.composing=null)})},Xa.prototype.createField=function(e){this.wrapper=Ba(),this.textarea=this.wrapper.firstChild;var t=this.cm.options;ja(this.textarea,t.spellcheck,t.autocorrect,t.autocapitalize)},Xa.prototype.screenReaderLabelChanged=function(e){e?this.textarea.setAttribute("aria-label",e):this.textarea.removeAttribute("aria-label")},Xa.prototype.prepareSelection=function(){var e=this.cm,t=e.display,n=e.doc,r=kr(e);if(e.options.moveInputWithCursor){var i=Jn(e,n.sel.primary().head,"div"),o=t.wrapper.getBoundingClientRect(),a=t.lineDiv.getBoundingClientRect();r.teTop=Math.max(0,Math.min(t.wrapper.clientHeight-10,i.top+a.top-o.top)),r.teLeft=Math.max(0,Math.min(t.wrapper.clientWidth-10,i.left+a.left-o.left))}return r},Xa.prototype.showSelection=function(e){var t=this.cm.display;N(t.cursorDiv,e.cursors),N(t.selectionDiv,e.selection),null!=e.teTop&&(this.wrapper.style.top=e.teTop+"px",this.wrapper.style.left=e.teLeft+"px")},Xa.prototype.reset=function(e){if(!(this.contextMenuPending||this.composing&&e)){var t=this.cm;if(this.resetting=!0,t.somethingSelected()){this.prevInput="";var n=t.getSelection();this.textarea.value=n,t.state.focused&&W(this.textarea),a&&l>=9&&(this.hasSelection=n)}else e||(this.prevInput=this.textarea.value="",a&&l>=9&&(this.hasSelection=null));this.resetting=!1}},Xa.prototype.getField=function(){return this.textarea},Xa.prototype.supportsTouch=function(){return!1},Xa.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!y||z(H(this.textarea))!=this.textarea))try{this.textarea.focus()}catch(e){}},Xa.prototype.blur=function(){this.textarea.blur()},Xa.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},Xa.prototype.receivedFocus=function(){this.slowPoll()},Xa.prototype.slowPoll=function(){var e=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,function(){e.poll(),e.cm.state.focused&&e.slowPoll()})},Xa.prototype.fastPoll=function(){var e=!1,t=this;t.pollingFast=!0,t.polling.set(20,function n(){t.poll()||e?(t.pollingFast=!1,t.slowPoll()):(e=!0,t.polling.set(60,n))})},Xa.prototype.poll=function(){var e=this,t=this.cm,n=this.textarea,r=this.prevInput;if(this.contextMenuPending||this.resetting||!t.state.focused||Fe(n)&&!r&&!this.composing||t.isReadOnly()||t.options.disableInput||t.state.keySeq)return!1;var i=n.value;if(i==r&&!t.somethingSelected())return!1;if(a&&l>=9&&this.hasSelection===i||b&&/[\uf700-\uf7ff]/.test(i))return t.display.input.reset(),!1;if(t.doc.sel==t.display.selForContextMenu){var o=i.charCodeAt(0);if(8203!=o||r||(r=""),8666==o)return this.reset(),this.cm.execCommand("undo")}for(var s=0,c=Math.min(r.length,i.length);s<c&&r.charCodeAt(s)==i.charCodeAt(s);)++s;return ii(t,function(){Fa(t,i.slice(s),r.length-s,null,e.composing?"*compose":null),i.length>1e3||i.indexOf("\n")>-1?n.value=e.prevInput="":e.prevInput=i,e.composing&&(e.composing.range.clear(),e.composing.range=t.markText(e.composing.start,t.getCursor("to"),{className:"CodeMirror-composing"}))}),!0},Xa.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},Xa.prototype.onKeyPress=function(){a&&l>=9&&(this.hasSelection=null),this.fastPoll()},Xa.prototype.onContextMenu=function(e){var t=this,n=t.cm,r=n.display,i=t.textarea;t.contextMenuPending&&t.contextMenuPending();var o=pr(n,e),c=r.scroller.scrollTop;if(o&&!f){n.options.resetSelectionOnContextMenu&&-1==n.doc.sel.contains(o)&&oi(n,io)(n.doc,Oi(o),G);var u,d=i.style.cssText,h=t.wrapper.style.cssText,p=t.wrapper.offsetParent.getBoundingClientRect();if(t.wrapper.style.cssText="position: static",i.style.cssText="position: absolute; width: 30px; height: 30px;\n top: "+(e.clientY-p.top-5)+"px; left: "+(e.clientX-p.left-5)+"px;\n z-index: 1000; background: "+(a?"rgba(255, 255, 255, .05)":"transparent")+";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);",s&&(u=i.ownerDocument.defaultView.scrollY),r.input.focus(),s&&i.ownerDocument.defaultView.scrollTo(null,u),r.input.reset(),n.somethingSelected()||(i.value=t.prevInput=" "),t.contextMenuPending=v,r.selForContextMenu=n.doc.sel,clearTimeout(r.detectingSelectAll),a&&l>=9&&g(),S){Me(e);var m=function(){ye(window,"mouseup",m),setTimeout(v,20)};ge(window,"mouseup",m)}else setTimeout(v,50)}function g(){if(null!=i.selectionStart){var e=n.somethingSelected(),o=""+(e?i.value:"");i.value="⇚",i.value=o,t.prevInput=e?"":"",i.selectionStart=1,i.selectionEnd=o.length,r.selForContextMenu=n.doc.sel}}function v(){if(t.contextMenuPending==v&&(t.contextMenuPending=!1,t.wrapper.style.cssText=h,i.style.cssText=d,a&&l<9&&r.scrollbars.setScrollTop(r.scroller.scrollTop=c),null!=i.selectionStart)){(!a||a&&l<9)&&g();var e=0,o=function(){r.selForContextMenu==n.doc.sel&&0==i.selectionStart&&i.selectionEnd>0&&""==t.prevInput?oi(n,ho)(n):e++<10?r.detectingSelectAll=setTimeout(o,500):(r.selForContextMenu=null,r.input.reset())};r.detectingSelectAll=setTimeout(o,200)}}},Xa.prototype.readOnlyChanged=function(e){e||this.reset(),this.textarea.disabled="nocursor"==e,this.textarea.readOnly=!!e},Xa.prototype.setUneditable=function(){},Xa.prototype.needsContentAttribute=!1,function(e){var t=e.optionHandlers;function n(n,r,i,o){e.defaults[n]=r,i&&(t[n]=o?function(e,t,n){n!=Ma&&i(e,t,n)}:i)}e.defineOption=n,e.Init=Ma,n("value","",function(e,t){return e.setValue(t)},!0),n("mode",null,function(e,t){e.doc.modeOption=t,Pi(e)},!0),n("indentUnit",2,Pi,!0),n("indentWithTabs",!1),n("smartIndent",!0),n("tabSize",4,function(e){Wi(e),Kn(e),gr(e)},!0),n("lineSeparator",null,function(e,t){if(e.doc.lineSep=t,t){var n=[],r=e.doc.first;e.doc.iter(function(e){for(var i=0;;){var o=e.text.indexOf(t,i);if(-1==o)break;i=o+t.length,n.push(ot(r,o))}r++});for(var i=n.length-1;i>=0;i--)wo(e.doc,t,n[i],ot(n[i].line,n[i].ch+t.length))}}),n("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\u2066\u2067\u2069\ufeff\ufff9-\ufffc]/g,function(e,t,n){e.state.specialChars=new RegExp(t.source+(t.test("\t")?"":"|\t"),"g"),n!=Ma&&e.refresh()}),n("specialCharPlaceholder",rn,function(e){return e.refresh()},!0),n("electricChars",!0),n("inputStyle",y?"contenteditable":"textarea",function(){throw new Error("inputStyle can not (yet) be changed in a running editor")},!0),n("spellcheck",!1,function(e,t){return e.getInputField().spellcheck=t},!0),n("autocorrect",!1,function(e,t){return e.getInputField().autocorrect=t},!0),n("autocapitalize",!1,function(e,t){return e.getInputField().autocapitalize=t},!0),n("rtlMoveVisually",!x),n("wholeLineUpdateBefore",!0),n("theme","default",function(e){La(e),wi(e)},!0),n("keyMap","default",function(e,t,n){var r=ta(t),i=n!=Ma&&ta(n);i&&i.detach&&i.detach(e,r),r.attach&&r.attach(e,i||null)}),n("extraKeys",null),n("configureMouse",null),n("lineWrapping",!1,_a,!0),n("gutters",[],function(e,t){e.display.gutterSpecs=yi(t,e.options.lineNumbers),wi(e)},!0),n("fixedGutter",!0,function(e,t){e.display.gutters.style.left=t?dr(e.display)+"px":"0",e.refresh()},!0),n("coverGutterNextToScrollbar",!1,function(e){return Vr(e)},!0),n("scrollbarStyle","native",function(e){Yr(e),Vr(e),e.display.scrollbars.setScrollTop(e.doc.scrollTop),e.display.scrollbars.setScrollLeft(e.doc.scrollLeft)},!0),n("lineNumbers",!1,function(e,t){e.display.gutterSpecs=yi(e.options.gutters,t),wi(e)},!0),n("firstLineNumber",1,wi,!0),n("lineNumberFormatter",function(e){return e},wi,!0),n("showCursorWhenSelecting",!1,xr,!0),n("resetSelectionOnContextMenu",!0),n("lineWiseCopyCut",!0),n("pasteLinesPerSelection",!0),n("selectionsMayTouch",!1),n("readOnly",!1,function(e,t){"nocursor"==t&&(Or(e),e.display.input.blur()),e.display.input.readOnlyChanged(t)}),n("screenReaderLabel",null,function(e,t){t=""===t?null:t,e.display.input.screenReaderLabelChanged(t)}),n("disableInput",!1,function(e,t){t||e.display.input.reset()},!0),n("dragDrop",!0,Oa),n("allowDropFileTypes",null),n("cursorBlinkRate",530),n("cursorScrollMargin",0),n("cursorHeight",1,xr,!0),n("singleCursorHeightPerLine",!0,xr,!0),n("workTime",100),n("workDelay",100),n("flattenSpans",!0,Wi,!0),n("addModeClass",!1,Wi,!0),n("pollInterval",100),n("undoDepth",200,function(e,t){return e.doc.history.undoDepth=t}),n("historyEventDelay",1250),n("viewportMargin",10,function(e){return e.refresh()},!0),n("maxHighlightLength",1e4,Wi,!0),n("moveInputWithCursor",!0,function(e,t){t||e.display.input.resetPosition()}),n("tabindex",null,function(e,t){return e.display.input.getField().tabIndex=t||""}),n("autofocus",null),n("direction","ltr",function(e,t){return e.doc.setDirection(t)},!0),n("phrases",null)}(Ea),function(e){var t=e.optionHandlers,n=e.helpers={};e.prototype={constructor:e,focus:function(){R(this).focus(),this.display.input.focus()},setOption:function(e,n){var r=this.options,i=r[e];r[e]==n&&"mode"!=e||(r[e]=n,t.hasOwnProperty(e)&&oi(this,t[e])(this,n,i),be(this,"optionChange",this,e))},getOption:function(e){return this.options[e]},getDoc:function(){return this.doc},addKeyMap:function(e,t){this.state.keyMaps[t?"push":"unshift"](ta(e))},removeKeyMap:function(e){for(var t=this.state.keyMaps,n=0;n<t.length;++n)if(t[n]==e||t[n].name==e)return t.splice(n,1),!0},addOverlay:ai(function(t,n){var r=t.token?t:e.getMode(this.options,t);if(r.startState)throw new Error("Overlays may not be stateful.");(function(e,t,n){for(var r=0,i=n(t);r<e.length&&n(e[r])<=i;)r++;e.splice(r,0,t)})(this.state.overlays,{mode:r,modeSpec:t,opaque:n&&n.opaque,priority:n&&n.priority||0},function(e){return e.priority}),this.state.modeGen++,gr(this)}),removeOverlay:ai(function(e){for(var t=this.state.overlays,n=0;n<t.length;++n){var r=t[n].modeSpec;if(r==e||"string"==typeof e&&r.name==e)return t.splice(n,1),this.state.modeGen++,void gr(this)}}),indentLine:ai(function(e,t,n){"string"!=typeof t&&"number"!=typeof t&&(t=null==t?this.options.smartIndent?"smart":"prev":t?"add":"subtract"),rt(this.doc,e)&&Da(this,e,t,n)}),indentSelection:ai(function(e){for(var t=this.doc.sel.ranges,n=-1,r=0;r<t.length;r++){var i=t[r];if(i.empty())i.head.line>n&&(Da(this,i.head.line,e,!0),n=i.head.line,r==this.doc.sel.primIndex&&Wr(this));else{var o=i.from(),a=i.to(),l=Math.max(n,o.line);n=Math.min(this.lastLine(),a.line-(a.ch?0:1))+1;for(var s=l;s<n;++s)Da(this,s,e);var c=this.doc.sel.ranges;0==o.ch&&t.length==c.length&&c[r].from().ch>0&&to(this.doc,r,new Ai(o,c[r].to()),G)}}}),getTokenAt:function(e,t){return Ct(this,e,t)},getLineTokens:function(e,t){return Ct(this,ot(e),t,!0)},getTokenTypeAt:function(e){e=ft(this.doc,e);var t,n=vt(this,Ze(this.doc,e.line)),r=0,i=(n.length-1)/2,o=e.ch;if(0==o)t=n[2];else for(;;){var a=r+i>>1;if((a?n[2*a-1]:0)>=o)i=a;else{if(!(n[2*a+1]<o)){t=n[2*a+2];break}r=a+1}}var l=t?t.indexOf("overlay "):-1;return l<0?t:0==l?null:t.slice(0,l-1)},getModeAt:function(t){var n=this.doc.mode;return n.innerMode?e.innerMode(n,this.getTokenAt(t).state).mode:n},getHelper:function(e,t){return this.getHelpers(e,t)[0]},getHelpers:function(e,t){var r=[];if(!n.hasOwnProperty(t))return r;var i=n[t],o=this.getModeAt(e);if("string"==typeof o[t])i[o[t]]&&r.push(i[o[t]]);else if(o[t])for(var a=0;a<o[t].length;a++){var l=i[o[t][a]];l&&r.push(l)}else o.helperType&&i[o.helperType]?r.push(i[o.helperType]):i[o.name]&&r.push(i[o.name]);for(var s=0;s<i._global.length;s++){var c=i._global[s];c.pred(o,this)&&-1==K(r,c.val)&&r.push(c.val)}return r},getStateAfter:function(e,t){var n=this.doc;return yt(this,(e=dt(n,null==e?n.first+n.size-1:e))+1,t).state},cursorCoords:function(e,t){var n=this.doc.sel.primary();return Jn(this,null==e?n.head:"object"==typeof e?ft(this.doc,e):e?n.from():n.to(),t||"page")},charCoords:function(e,t){return Zn(this,ft(this.doc,e),t||"page")},coordsChar:function(e,t){return tr(this,(e=Xn(this,e,t||"page")).left,e.top)},lineAtHeight:function(e,t){return e=Xn(this,{top:e,left:0},t||"page").top,nt(this.doc,e+this.display.viewOffset)},heightAtLine:function(e,t,n){var r,i=!1;if("number"==typeof e){var o=this.doc.first+this.doc.size-1;e<this.doc.first?e=this.doc.first:e>o&&(e=o,i=!0),r=Ze(this.doc,e)}else r=e;return Yn(this,r,{top:0,left:0},t||"page",n||i).top+(i?this.doc.height-$t(r):0)},defaultTextHeight:function(){return sr(this.display)},defaultCharWidth:function(){return cr(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(e,t,n,r,i){var o,a,l,s=this.display,c=(e=Jn(this,ft(this.doc,e))).bottom,u=e.left;if(t.style.position="absolute",t.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(t),s.sizer.appendChild(t),"over"==r)c=e.top;else if("above"==r||"near"==r){var d=Math.max(s.wrapper.clientHeight,this.doc.height),f=Math.max(s.sizer.clientWidth,s.lineSpace.clientWidth);("above"==r||e.bottom+t.offsetHeight>d)&&e.top>t.offsetHeight?c=e.top-t.offsetHeight:e.bottom+t.offsetHeight<=d&&(c=e.bottom),u+t.offsetWidth>f&&(u=f-t.offsetWidth)}t.style.top=c+"px",t.style.left=t.style.right="","right"==i?(u=s.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==i?u=0:"middle"==i&&(u=(s.sizer.clientWidth-t.offsetWidth)/2),t.style.left=u+"px"),n&&(o=this,a={left:u,top:c,right:u+t.offsetWidth,bottom:c+t.offsetHeight},null!=(l=Dr(o,a)).scrollTop&&Rr(o,l.scrollTop),null!=l.scrollLeft&&Br(o,l.scrollLeft))},triggerOnKeyDown:ai(ma),triggerOnKeyPress:ai(va),triggerOnKeyUp:ga,triggerOnMouseDown:ai(xa),execCommand:function(e){if(aa.hasOwnProperty(e))return aa[e].call(null,this)},triggerElectric:ai(function(e){Ha(this,e)}),findPosH:function(e,t,n,r){var i=1;t<0&&(i=-1,t=-t);for(var o=ft(this.doc,e),a=0;a<t&&!(o=qa(this.doc,o,i,n,r)).hitSide;++a);return o},moveH:ai(function(e,t){var n=this;this.extendSelectionsBy(function(r){return n.display.shift||n.doc.extend||r.empty()?qa(n.doc,r.head,e,t,n.options.rtlMoveVisually):e<0?r.from():r.to()},Y)}),deleteH:ai(function(e,t){var n=this.doc.sel,r=this.doc;n.somethingSelected()?r.replaceSelection("",null,"+delete"):na(this,function(n){var i=qa(r,n.head,e,t,!1);return e<0?{from:i,to:n.head}:{from:n.head,to:i}})}),findPosV:function(e,t,n,r){var i=1,o=r;t<0&&(i=-1,t=-t);for(var a=ft(this.doc,e),l=0;l<t;++l){var s=Jn(this,a,"div");if(null==o?o=s.left:s.left=o,(a=Ua(this,s,i,n)).hitSide)break}return a},moveV:ai(function(e,t){var n=this,r=this.doc,i=[],o=!this.display.shift&&!r.extend&&r.sel.somethingSelected();if(r.extendSelectionsBy(function(a){if(o)return e<0?a.from():a.to();var l=Jn(n,a.head,"div");null!=a.goalColumn&&(l.left=a.goalColumn),i.push(l.left);var s=Ua(n,l,e,t);return"page"==t&&a==r.sel.primary()&&Pr(n,Zn(n,s,"div").top-l.top),s},Y),i.length)for(var a=0;a<r.sel.ranges.length;a++)r.sel.ranges[a].goalColumn=i[a]}),findWordAt:function(e){var t=Ze(this.doc,e.line).text,n=e.ch,r=e.ch;if(t){var i=this.getHelper(e,"wordChars");"before"!=e.sticky&&r!=t.length||!n?++r:--n;for(var o=t.charAt(n),a=oe(o,i)?function(e){return oe(e,i)}:/\s/.test(o)?function(e){return/\s/.test(e)}:function(e){return!/\s/.test(e)&&!oe(e)};n>0&&a(t.charAt(n-1));)--n;for(;r<t.length&&a(t.charAt(r));)++r}return new Ai(ot(e.line,n),ot(e.line,r))},toggleOverwrite:function(e){null!=e&&e==this.state.overwrite||((this.state.overwrite=!this.state.overwrite)?D(this.display.cursorDiv,"CodeMirror-overwrite"):M(this.display.cursorDiv,"CodeMirror-overwrite"),be(this,"overwriteToggle",this,this.state.overwrite))},hasFocus:function(){return this.display.input.getField()==z(I(this))},isReadOnly:function(){return!(!this.options.readOnly&&!this.doc.cantEdit)},scrollTo:ai(function(e,t){Fr(this,e,t)}),getScrollInfo:function(){var e=this.display.scroller;return{left:e.scrollLeft,top:e.scrollTop,height:e.scrollHeight-_n(this)-this.display.barHeight,width:e.scrollWidth-_n(this)-this.display.barWidth,clientHeight:zn(this),clientWidth:En(this)}},scrollIntoView:ai(function(e,t){null==e?(e={from:this.doc.sel.primary().head,to:null},null==t&&(t=this.options.cursorScrollMargin)):"number"==typeof e?e={from:ot(e,0),to:null}:null==e.from&&(e={from:e,to:null}),e.to||(e.to=e.from),e.margin=t||0,null!=e.from.line?function(e,t){Ir(e),e.curOp.scrollToPos=t}(this,e):Hr(this,e.from,e.to,e.margin)}),setSize:ai(function(e,t){var n=this,r=function(e){return"number"==typeof e||/^\d+$/.test(String(e))?e+"px":e};null!=e&&(this.display.wrapper.style.width=r(e)),null!=t&&(this.display.wrapper.style.height=r(t)),this.options.lineWrapping&&Un(this);var i=this.display.viewFrom;this.doc.iter(i,this.display.viewTo,function(e){if(e.widgets)for(var t=0;t<e.widgets.length;t++)if(e.widgets[t].noHScroll){vr(n,i,"widget");break}++i}),this.curOp.forceUpdate=!0,be(this,"refresh",this)}),operation:function(e){return ii(this,e)},startOperation:function(){return Zr(this)},endOperation:function(){return Jr(this)},refresh:ai(function(){var e=this.display.cachedTextHeight;gr(this),this.curOp.forceUpdate=!0,Kn(this),Fr(this,this.doc.scrollLeft,this.doc.scrollTop),pi(this.display),(null==e||Math.abs(e-sr(this.display))>.5||this.options.lineWrapping)&&hr(this),be(this,"refresh",this)}),swapDoc:ai(function(e){var t=this.doc;return t.cm=null,this.state.selectingText&&this.state.selectingText(),Ri(this,e),Kn(this),this.display.input.reset(),Fr(this,e.scrollLeft,e.scrollTop),this.curOp.forceScroll=!0,hn(this,"swapDoc",this,t),t}),phrase:function(e){var t=this.options.phrases;return t&&Object.prototype.hasOwnProperty.call(t,e)?t[e]:e},getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},Ce(e),e.registerHelper=function(t,r,i){n.hasOwnProperty(t)||(n[t]=e[t]={_global:[]}),n[t][r]=i},e.registerGlobalHelper=function(t,r,i,o){e.registerHelper(t,r,o),n[t]._global.push({pred:i,val:o})}}(Ea);var Za="iter insert remove copy getEditor constructor".split(" ");for(var Ja in Wo.prototype)Wo.prototype.hasOwnProperty(Ja)&&K(Za,Ja)<0&&(Ea.prototype[Ja]=function(e){return function(){return e.apply(this.doc,arguments)}}(Wo.prototype[Ja]));return Ce(Wo),Ea.inputStyles={textarea:Xa,contenteditable:Ka},Ea.defineMode=function(e){Ea.defaults.mode||"null"==e||(Ea.defaults.mode=e),Be.apply(this,arguments)},Ea.defineMIME=function(e,t){je[e]=t},Ea.defineMode("null",function(){return{token:function(e){return e.skipToEnd()}}}),Ea.defineMIME("text/plain","null"),Ea.defineExtension=function(e,t){Ea.prototype[e]=t},Ea.defineDocExtension=function(e,t){Wo.prototype[e]=t},Ea.fromTextArea=function(e,t){if((t=t?B(t):{}).value=e.value,!t.tabindex&&e.tabIndex&&(t.tabindex=e.tabIndex),!t.placeholder&&e.placeholder&&(t.placeholder=e.placeholder),null==t.autofocus){var n=z(H(e));t.autofocus=n==e||null!=e.getAttribute("autofocus")&&n==document.body}function r(){e.value=l.getValue()}var i;if(e.form&&(ge(e.form,"submit",r),!t.leaveSubmitMethodAlone)){var o=e.form;i=o.submit;try{var a=o.submit=function(){r(),o.submit=i,o.submit(),o.submit=a}}catch(e){}}t.finishInit=function(n){n.save=r,n.getTextArea=function(){return e},n.toTextArea=function(){n.toTextArea=isNaN,r(),e.parentNode.removeChild(n.getWrapperElement()),e.style.display="",e.form&&(ye(e.form,"submit",r),t.leaveSubmitMethodAlone||"function"!=typeof e.form.submit||(e.form.submit=i))}},e.style.display="none";var l=Ea(function(t){return e.parentNode.insertBefore(t,e.nextSibling)},t);return l},function(e){e.off=ye,e.on=ge,e.wheelEventPixels=Ti,e.Doc=Wo,e.splitLines=We,e.countColumn=q,e.findColumn=X,e.isWordChar=ie,e.Pass=V,e.signal=be,e.Line=Zt,e.changeEnd=_i,e.scrollbarModel=$r,e.Pos=ot,e.cmpPos=at,e.modes=Re,e.mimeModes=je,e.resolveMode=qe,e.getMode=Ue,e.modeExtensions=Ke,e.extendMode=Ve,e.copyState=Ge,e.startState=Ye,e.innerMode=$e,e.commands=aa,e.keyMap=$o,e.keyName=ea,e.isModifierKey=Jo,e.lookupKey=Zo,e.normalizeKeyMap=Xo,e.StringStream=Xe,e.SharedTextMarker=Eo,e.TextMarker=Oo,e.LineWidget=Mo,e.e_preventDefault=Se,e.e_stopPropagation=Te,e.e_stop=Me,e.addClass=D,e.contains=E,e.rmClass=M,e.keyNames=Uo}(Ea),Ea.version="5.65.20",Ea}()},6154(e,t,n){const r=n(4862),i=n(2325),o=n(2232),a=/\[(\w+)\]/g,l=/\[\]$/,s=document.getElementById("required-fields");function c(){o.getAll().forEach(function(e){if(e.name.length<=0)return;let t=e.name;if("checkbox"===e.type&&(t+="[]"),e.inFormContent=i.containsField(t),"address"===e.mailchimpType){void 0===e.originalRequiredValue&&(e.originalRequiredValue=e.forceRequired);const t=e.name.replace(a,"");i.query('[name^="'+t+'"]').length>0?e.forceRequired=!0:e.forceRequired=e.originalRequiredValue}}),function(){const e=o.getAll().filter(e=>!0===e.forceRequired).map(e=>e.name.toUpperCase().replace(a,".$1")),t=i.query("[required]");[].forEach.call(t,function(t){let n=t.name;if(!n||n.length<0||"_"===n[0])return;n=n.replace(a,".$1"),n=n.replace(l,"");let r=n.indexOf(".");r=r>0?r:n.length,n=n.substr(0,r).toUpperCase()+n.substr(r),-1===e.indexOf(n)&&e.push(n)}),s.value=e.join(",")}(),r.redraw()}function u(e,t){let n;return()=>{n&&clearTimeout(n),n=window.setTimeout(e,t)}}i.on("change",u(c,500)),o.on("change",u(c,100))},6423(e,t,n){const r=n(2325),i=n(2232),o=n(7785),a={};function l(e,t){a[e]=t,c()}function s(e){delete a[e],c()}function c(){const e=Object.values(a).map(e=>'<div class="notice notice-warning inline"><p>'+e+"</p></div>").join();let t=document.querySelector(".mc4wp-notices");if(!t){t=document.createElement("div"),t.className="mc4wp-notices";const e=document.querySelector("h1, h2");e.parentNode.insertBefore(t,e.nextSibling)}t.innerHTML=e}const u=function(){r.getValue().toLowerCase().indexOf('name="groupings')>-1?l("deprecated_groupings","Your form contains deprecated <code>GROUPINGS</code> fields. <br /><br />Please remove these fields from your form and then re-add them through the available field buttons to make sure your data is getting through to Mailchimp correctly."):s("deprecated_groupings")},d=function(){const e=i.getAll().filter(e=>!0===e.forceRequired&&!r.containsField(e.name.toUpperCase()));let t="<strong>Heads up!</strong> Your form is missing fields that are required in Mailchimp. Either add these fields to your form or mark them as optional in Mailchimp.";t+='<br /><ul class="ul-square" style="margin-bottom: 0;"><li>'+e.map(function(e){return e.title}).join("</li><li>")+"</li></ul>",e.length>0?l("required_fields_missing",t):s("required_fields_missing")};u(),r.on("focus",u),r.on("blur",u),d(),r.on("blur",d),r.on("focus",d),document.body.addEventListener("change",function(){o.getSelectedLists().length>0?s("no_lists_selected"):l("no_lists_selected",'<strong>Heads up!</strong> You have not yet selected a Mailchimp audience to subscribe people to. Please select at least one audience from the <a href="javascript:void(0)" data-tab="settings" class="tab-link">settings tab</a>.')})},6685(e,t,n){const r=n(8915),i=n(4862),o=function(e){e.dom.checked&&e.dom.setAttribute("checked","true"),e.dom.value&&e.dom.setAttribute("value",e.dom.value),e.dom.selected&&e.dom.setAttribute("selected","true")},a={select:function(e){const t={name:e.name,required:e.required};let n=!1;const r=e.choices.map(function(e){return e.selected&&(n=!0),i("option",{value:e.value!==e.label?e.value:void 0,selected:e.selected,oncreate:o},e.label)}),a=e.placeholder;return a.length>0&&r.unshift(i("option",{disabled:!0,value:"",selected:!n,oncreate:o},a)),i("select",t,r)},"terms-checkbox":function(e){let t;return t=e.link.length>0?i("a",{href:e.link,target:"_blank"},e.label):e.label,i("label",[i("input",{name:e.name,type:"checkbox",value:e.value,required:e.required})," ",t])},checkbox:function(e){return e.choices.map(function(t){const n=e.name+("checkbox"===e.type?"[]":""),r=e.required&&"radio"===e.type;return i("label",[i("input",{name:n,type:e.type,value:t.value,checked:t.selected,required:r,oncreate:o})," ",i("span",t.label)])})}};a.radio=a.checkbox,a.default=function(e){const t={type:e.type};return e.name&&(t.name=e.name),e.min&&(t.min=e.min),e.max&&(t.max=e.max),e.value.length>0&&(t.value=e.value),e.placeholder.length>0&&(t.placeholder=e.placeholder),t.required=e.required,t.oncreate=o,i("input",t)},a.procaptcha=function(e){return i("input",{type:"hidden",name:"procaptcha"})},e.exports=function(e){const t=e.label.length>0&&e.showLabel?i("label",{},e.label):"",n="function"==typeof a[e.type]?a[e.type](e):a.default(e),o=e.wrap?i("p",[t,n]):[t,n],l=document.createElement("div");return i.render(l,o),r.prettyPrint(l.innerHTML)+"\n"}},6753(e,t,n){!function(e){"use strict";var t=e.Pos;function n(e,t){return e.line-t.line||e.ch-t.ch}var r="A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD",i=new RegExp("<(/?)(["+r+"]["+r+"-:.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*)","g");function o(e,t,n,r){this.line=t,this.ch=n,this.cm=e,this.text=e.getLine(t),this.min=r?Math.max(r.from,e.firstLine()):e.firstLine(),this.max=r?Math.min(r.to-1,e.lastLine()):e.lastLine()}function a(e,n){var r=e.cm.getTokenTypeAt(t(e.line,n));return r&&/\btag\b/.test(r)}function l(e){if(!(e.line>=e.max))return e.ch=0,e.text=e.cm.getLine(++e.line),!0}function s(e){if(!(e.line<=e.min))return e.text=e.cm.getLine(--e.line),e.ch=e.text.length,!0}function c(e){for(;;){var t=e.text.indexOf(">",e.ch);if(-1==t){if(l(e))continue;return}if(a(e,t+1)){var n=e.text.lastIndexOf("/",t),r=n>-1&&!/\S/.test(e.text.slice(n+1,t));return e.ch=t+1,r?"selfClose":"regular"}e.ch=t+1}}function u(e){for(;;){var t=e.ch?e.text.lastIndexOf("<",e.ch-1):-1;if(-1==t){if(s(e))continue;return}if(a(e,t+1)){i.lastIndex=t,e.ch=t;var n=i.exec(e.text);if(n&&n.index==t)return n}else e.ch=t}}function d(e){for(;;){i.lastIndex=e.ch;var t=i.exec(e.text);if(!t){if(l(e))continue;return}if(a(e,t.index+1))return e.ch=t.index+t[0].length,t;e.ch=t.index+1}}function f(e){for(;;){var t=e.ch?e.text.lastIndexOf(">",e.ch-1):-1;if(-1==t){if(s(e))continue;return}if(a(e,t+1)){var n=e.text.lastIndexOf("/",t),r=n>-1&&!/\S/.test(e.text.slice(n+1,t));return e.ch=t+1,r?"selfClose":"regular"}e.ch=t}}function h(e,n){for(var r=[];;){var i,o=d(e),a=e.line,l=e.ch-(o?o[0].length:0);if(!o||!(i=c(e)))return;if("selfClose"!=i)if(o[1]){for(var s=r.length-1;s>=0;--s)if(r[s]==o[2]){r.length=s;break}if(s<0&&(!n||n==o[2]))return{tag:o[2],from:t(a,l),to:t(e.line,e.ch)}}else r.push(o[2])}}function p(e,n){for(var r=[];;){var i=f(e);if(!i)return;if("selfClose"!=i){var o=e.line,a=e.ch,l=u(e);if(!l)return;if(l[1])r.push(l[2]);else{for(var s=r.length-1;s>=0;--s)if(r[s]==l[2]){r.length=s;break}if(s<0&&(!n||n==l[2]))return{tag:l[2],from:t(e.line,e.ch),to:t(o,a)}}}else u(e)}}e.registerHelper("fold","xml",function(e,r){for(var i=new o(e,r.line,0);;){var a=d(i);if(!a||i.line!=r.line)return;var l=c(i);if(!l)return;if(!a[1]&&"selfClose"!=l){var s=t(i.line,i.ch),u=h(i,a[2]);return u&&n(u.from,s)>0?{from:s,to:u.from}:null}}}),e.findMatchingTag=function(e,r,i){var a=new o(e,r.line,r.ch,i);if(-1!=a.text.indexOf(">")||-1!=a.text.indexOf("<")){var l=c(a),s=l&&t(a.line,a.ch),d=l&&u(a);if(l&&d&&!(n(a,r)>0)){var f={from:t(a.line,a.ch),to:s,tag:d[2]};return"selfClose"==l?{open:f,close:null,at:"open"}:d[1]?{open:p(a,d[2]),close:f,at:"close"}:{open:f,close:h(a=new o(e,s.line,s.ch,i),d[2]),at:"open"}}}},e.findEnclosingTag=function(e,t,n,r){for(var i=new o(e,t.line,t.ch,n);;){var a=p(i,r);if(!a)break;var l=h(new o(e,t.line,t.ch,n),a.tag);if(l)return{open:a,close:l}}},e.scanForClosingTag=function(e,t,n,r){return h(new o(e,t.line,t.ch,r?{from:0,to:r}:null),n)}}(n(5237))},6792(e,t,n){!function(e){"use strict";e.defineMode("javascript",function(t,n){var r,i,o=t.indentUnit,a=n.statementIndent,l=n.jsonld,s=n.json||l,c=!1!==n.trackScope,u=n.typescript,d=n.wordCharacters||/[\w$\xa1-\uffff]/,f=function(){function e(e){return{type:e,style:"keyword"}}var t=e("keyword a"),n=e("keyword b"),r=e("keyword c"),i=e("keyword d"),o=e("operator"),a={type:"atom",style:"atom"};return{if:e("if"),while:t,with:t,else:n,do:n,try:n,finally:n,return:i,break:i,continue:i,new:e("new"),delete:r,void:r,throw:r,debugger:e("debugger"),var:e("var"),const:e("var"),let:e("var"),function:e("function"),catch:e("catch"),for:e("for"),switch:e("switch"),case:e("case"),default:e("default"),in:o,typeof:o,instanceof:o,true:a,false:a,null:a,undefined:a,NaN:a,Infinity:a,this:e("this"),class:e("class"),super:e("atom"),yield:r,export:e("export"),import:e("import"),extends:r,await:r}}(),h=/[+\-*&%=<>!?|~^@]/,p=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;function m(e,t,n){return r=e,i=n,t}function g(e,t){var n,r=e.next();if('"'==r||"'"==r)return t.tokenize=(n=r,function(e,t){var r,i=!1;if(l&&"@"==e.peek()&&e.match(p))return t.tokenize=g,m("jsonld-keyword","meta");for(;null!=(r=e.next())&&(r!=n||i);)i=!i&&"\\"==r;return i||(t.tokenize=g),m("string","string")}),t.tokenize(e,t);if("."==r&&e.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/))return m("number","number");if("."==r&&e.match(".."))return m("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(r))return m(r);if("="==r&&e.eat(">"))return m("=>","operator");if("0"==r&&e.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/))return m("number","number");if(/\d/.test(r))return e.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/),m("number","number");if("/"==r)return e.eat("*")?(t.tokenize=v,v(e,t)):e.eat("/")?(e.skipToEnd(),m("comment","comment")):Qe(e,t,1)?(function(e){for(var t,n=!1,r=!1;null!=(t=e.next());){if(!n){if("/"==t&&!r)return;"["==t?r=!0:r&&"]"==t&&(r=!1)}n=!n&&"\\"==t}}(e),e.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/),m("regexp","string-2")):(e.eat("="),m("operator","operator",e.current()));if("`"==r)return t.tokenize=y,y(e,t);if("#"==r&&"!"==e.peek())return e.skipToEnd(),m("meta","meta");if("#"==r&&e.eatWhile(d))return m("variable","property");if("<"==r&&e.match("!--")||"-"==r&&e.match("->")&&!/\S/.test(e.string.slice(0,e.start)))return e.skipToEnd(),m("comment","comment");if(h.test(r))return">"==r&&t.lexical&&">"==t.lexical.type||(e.eat("=")?"!"!=r&&"="!=r||e.eat("="):/[<>*+\-|&?]/.test(r)&&(e.eat(r),">"==r&&e.eat(r))),"?"==r&&e.eat(".")?m("."):m("operator","operator",e.current());if(d.test(r)){e.eatWhile(d);var i=e.current();if("."!=t.lastType){if(f.propertyIsEnumerable(i)){var o=f[i];return m(o.type,o.style,i)}if("async"==i&&e.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/,!1))return m("async","keyword",i)}return m("variable","variable",i)}}function v(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize=g;break}r="*"==n}return m("comment","comment")}function y(e,t){for(var n,r=!1;null!=(n=e.next());){if(!r&&("`"==n||"$"==n&&e.eat("{"))){t.tokenize=g;break}r=!r&&"\\"==n}return m("quasi","string-2",e.current())}function b(e,t){t.fatArrowAt&&(t.fatArrowAt=null);var n=e.string.indexOf("=>",e.start);if(!(n<0)){if(u){var r=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(e.string.slice(e.start,n));r&&(n=r.index)}for(var i=0,o=!1,a=n-1;a>=0;--a){var l=e.string.charAt(a),s="([{}])".indexOf(l);if(s>=0&&s<3){if(!i){++a;break}if(0==--i){"("==l&&(o=!0);break}}else if(s>=3&&s<6)++i;else if(d.test(l))o=!0;else if(/["'\/`]/.test(l))for(;;--a){if(0==a)return;if(e.string.charAt(a-1)==l&&"\\"!=e.string.charAt(a-2)){a--;break}}else if(o&&!i){++a;break}}o&&!i&&(t.fatArrowAt=a)}}var w={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,this:!0,import:!0,"jsonld-keyword":!0};function x(e,t,n,r,i,o){this.indented=e,this.column=t,this.type=n,this.prev=i,this.info=o,null!=r&&(this.align=r)}function k(e,t){if(!c)return!1;for(var n=e.localVars;n;n=n.next)if(n.name==t)return!0;for(var r=e.context;r;r=r.prev)for(n=r.vars;n;n=n.next)if(n.name==t)return!0}function C(e,t,n,r,i){var o=e.cc;for(S.state=e,S.stream=i,S.marked=null,S.cc=o,S.style=t,e.lexical.hasOwnProperty("align")||(e.lexical.align=!0);;)if((o.length?o.pop():s?B:R)(n,r)){for(;o.length&&o[o.length-1].lex;)o.pop()();return S.marked?S.marked:"variable"==n&&k(e,r)?"variable-2":t}}var S={state:null,column:null,marked:null,cc:null};function T(){for(var e=arguments.length-1;e>=0;e--)S.cc.push(arguments[e])}function L(){return T.apply(null,arguments),!0}function M(e,t){for(var n=t;n;n=n.next)if(n.name==e)return!0;return!1}function A(e){var t=S.state;if(S.marked="def",c){if(t.context)if("var"==t.lexical.info&&t.context&&t.context.block){var r=N(e,t.context);if(null!=r)return void(t.context=r)}else if(!M(e,t.localVars))return void(t.localVars=new E(e,t.localVars));n.globalVars&&!M(e,t.globalVars)&&(t.globalVars=new E(e,t.globalVars))}}function N(e,t){if(t){if(t.block){var n=N(e,t.prev);return n?n==t.prev?t:new _(n,t.vars,!0):null}return M(e,t.vars)?t:new _(t.prev,new E(e,t.vars),!1)}return null}function O(e){return"public"==e||"private"==e||"protected"==e||"abstract"==e||"readonly"==e}function _(e,t,n){this.prev=e,this.vars=t,this.block=n}function E(e,t){this.name=e,this.next=t}var z=new E("this",new E("arguments",null));function D(){S.state.context=new _(S.state.context,S.state.localVars,!1),S.state.localVars=z}function P(){S.state.context=new _(S.state.context,S.state.localVars,!0),S.state.localVars=null}function W(){S.state.localVars=S.state.context.vars,S.state.context=S.state.context.prev}function F(e,t){var n=function(){var n=S.state,r=n.indented;if("stat"==n.lexical.type)r=n.lexical.indented;else for(var i=n.lexical;i&&")"==i.type&&i.align;i=i.prev)r=i.indented;n.lexical=new x(r,S.stream.column(),e,null,n.lexical,t)};return n.lex=!0,n}function I(){var e=S.state;e.lexical.prev&&(")"==e.lexical.type&&(e.indented=e.lexical.indented),e.lexical=e.lexical.prev)}function H(e){return function t(n){return n==e?L():";"==e||"}"==n||")"==n||"]"==n?T():L(t)}}function R(e,t){return"var"==e?L(F("vardef",t),Se,H(";"),I):"keyword a"==e?L(F("form"),U,R,I):"keyword b"==e?L(F("form"),R,I):"keyword d"==e?S.stream.match(/^\s*$/,!1)?L():L(F("stat"),V,H(";"),I):"debugger"==e?L(H(";")):"{"==e?L(F("}"),P,se,I,W):";"==e?L():"if"==e?("else"==S.state.lexical.info&&S.state.cc[S.state.cc.length-1]==I&&S.state.cc.pop()(),L(F("form"),U,R,I,Oe)):"function"==e?L(De):"for"==e?L(F("form"),P,_e,R,W,I):"class"==e||u&&"interface"==t?(S.marked="keyword",L(F("form","class"==e?e:t),He,I)):"variable"==e?u&&"declare"==t?(S.marked="keyword",L(R)):u&&("module"==t||"enum"==t||"type"==t)&&S.stream.match(/^\s*\w/,!1)?(S.marked="keyword","enum"==t?L(Ze):"type"==t?L(We,H("operator"),he,H(";")):L(F("form"),Te,H("{"),F("}"),se,I,I)):u&&"namespace"==t?(S.marked="keyword",L(F("form"),B,R,I)):u&&"abstract"==t?(S.marked="keyword",L(R)):L(F("stat"),te):"switch"==e?L(F("form"),U,H("{"),F("}","switch"),P,se,I,I,W):"case"==e?L(B,H(":")):"default"==e?L(H(":")):"catch"==e?L(F("form"),D,j,R,I,W):"export"==e?L(F("stat"),qe,I):"import"==e?L(F("stat"),Ke,I):"async"==e?L(R):"@"==t?L(B,R):T(F("stat"),B,H(";"),I)}function j(e){if("("==e)return L(Fe,H(")"))}function B(e,t){return K(e,t,!1)}function q(e,t){return K(e,t,!0)}function U(e){return"("!=e?T():L(F(")"),V,H(")"),I)}function K(e,t,n){if(S.state.fatArrowAt==S.stream.start){var r=n?J:Z;if("("==e)return L(D,F(")"),ae(Fe,")"),I,H("=>"),r,W);if("variable"==e)return T(D,Te,H("=>"),r,W)}var i=n?$:G;return w.hasOwnProperty(e)?L(i):"function"==e?L(De,i):"class"==e||u&&"interface"==t?(S.marked="keyword",L(F("form"),Ie,I)):"keyword c"==e||"async"==e?L(n?q:B):"("==e?L(F(")"),V,H(")"),I,i):"operator"==e||"spread"==e?L(n?q:B):"["==e?L(F("]"),Xe,I,i):"{"==e?le(re,"}",null,i):"quasi"==e?T(Y,i):"new"==e?L(function(e){return function(t){return"."==t?L(e?ee:Q):"variable"==t&&u?L(xe,e?$:G):T(e?q:B)}}(n)):L()}function V(e){return e.match(/[;\}\)\],]/)?T():T(B)}function G(e,t){return","==e?L(V):$(e,t,!1)}function $(e,t,n){var r=0==n?G:$,i=0==n?B:q;return"=>"==e?L(D,n?J:Z,W):"operator"==e?/\+\+|--/.test(t)||u&&"!"==t?L(r):u&&"<"==t&&S.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/,!1)?L(F(">"),ae(he,">"),I,r):"?"==t?L(B,H(":"),i):L(i):"quasi"==e?T(Y,r):";"!=e?"("==e?le(q,")","call",r):"."==e?L(ne,r):"["==e?L(F("]"),V,H("]"),I,r):u&&"as"==t?(S.marked="keyword",L(he,r)):"regexp"==e?(S.state.lastType=S.marked="operator",S.stream.backUp(S.stream.pos-S.stream.start-1),L(i)):void 0:void 0}function Y(e,t){return"quasi"!=e?T():"${"!=t.slice(t.length-2)?L(Y):L(V,X)}function X(e){if("}"==e)return S.marked="string-2",S.state.tokenize=y,L(Y)}function Z(e){return b(S.stream,S.state),T("{"==e?R:B)}function J(e){return b(S.stream,S.state),T("{"==e?R:q)}function Q(e,t){if("target"==t)return S.marked="keyword",L(G)}function ee(e,t){if("target"==t)return S.marked="keyword",L($)}function te(e){return":"==e?L(I,R):T(G,H(";"),I)}function ne(e){if("variable"==e)return S.marked="property",L()}function re(e,t){return"async"==e?(S.marked="property",L(re)):"variable"==e||"keyword"==S.style?(S.marked="property","get"==t||"set"==t?L(ie):(u&&S.state.fatArrowAt==S.stream.start&&(n=S.stream.match(/^\s*:\s*/,!1))&&(S.state.fatArrowAt=S.stream.pos+n[0].length),L(oe))):"number"==e||"string"==e?(S.marked=l?"property":S.style+" property",L(oe)):"jsonld-keyword"==e?L(oe):u&&O(t)?(S.marked="keyword",L(re)):"["==e?L(B,ce,H("]"),oe):"spread"==e?L(q,oe):"*"==t?(S.marked="keyword",L(re)):":"==e?T(oe):void 0;var n}function ie(e){return"variable"!=e?T(oe):(S.marked="property",L(De))}function oe(e){return":"==e?L(q):"("==e?T(De):void 0}function ae(e,t,n){function r(i,o){if(n?n.indexOf(i)>-1:","==i){var a=S.state.lexical;return"call"==a.info&&(a.pos=(a.pos||0)+1),L(function(n,r){return n==t||r==t?T():T(e)},r)}return i==t||o==t?L():n&&n.indexOf(";")>-1?T(e):L(H(t))}return function(n,i){return n==t||i==t?L():T(e,r)}}function le(e,t,n){for(var r=3;r<arguments.length;r++)S.cc.push(arguments[r]);return L(F(t,n),ae(e,t),I)}function se(e){return"}"==e?L():T(R,se)}function ce(e,t){if(u){if(":"==e)return L(he);if("?"==t)return L(ce)}}function ue(e,t){if(u&&(":"==e||"in"==t))return L(he)}function de(e){if(u&&":"==e)return S.stream.match(/^\s*\w+\s+is\b/,!1)?L(B,fe,he):L(he)}function fe(e,t){if("is"==t)return S.marked="keyword",L()}function he(e,t){return"keyof"==t||"typeof"==t||"infer"==t||"readonly"==t?(S.marked="keyword",L("typeof"==t?q:he)):"variable"==e||"void"==t?(S.marked="type",L(we)):"|"==t||"&"==t?L(he):"string"==e||"number"==e||"atom"==e?L(we):"["==e?L(F("]"),ae(he,"]",","),I,we):"{"==e?L(F("}"),me,I,we):"("==e?L(ae(be,")"),pe,we):"<"==e?L(ae(he,">"),he):"quasi"==e?T(ve,we):void 0}function pe(e){if("=>"==e)return L(he)}function me(e){return e.match(/[\}\)\]]/)?L():","==e||";"==e?L(me):T(ge,me)}function ge(e,t){return"variable"==e||"keyword"==S.style?(S.marked="property",L(ge)):"?"==t||"number"==e||"string"==e?L(ge):":"==e?L(he):"["==e?L(H("variable"),ue,H("]"),ge):"("==e?T(Pe,ge):e.match(/[;\}\)\],]/)?void 0:L()}function ve(e,t){return"quasi"!=e?T():"${"!=t.slice(t.length-2)?L(ve):L(he,ye)}function ye(e){if("}"==e)return S.marked="string-2",S.state.tokenize=y,L(ve)}function be(e,t){return"variable"==e&&S.stream.match(/^\s*[?:]/,!1)||"?"==t?L(be):":"==e?L(he):"spread"==e?L(be):T(he)}function we(e,t){return"<"==t?L(F(">"),ae(he,">"),I,we):"|"==t||"."==e||"&"==t?L(he):"["==e?L(he,H("]"),we):"extends"==t||"implements"==t?(S.marked="keyword",L(he)):"?"==t?L(he,H(":"),he):void 0}function xe(e,t){if("<"==t)return L(F(">"),ae(he,">"),I,we)}function ke(){return T(he,Ce)}function Ce(e,t){if("="==t)return L(he)}function Se(e,t){return"enum"==t?(S.marked="keyword",L(Ze)):T(Te,ce,Ae,Ne)}function Te(e,t){return u&&O(t)?(S.marked="keyword",L(Te)):"variable"==e?(A(t),L()):"spread"==e?L(Te):"["==e?le(Me,"]"):"{"==e?le(Le,"}"):void 0}function Le(e,t){return"variable"!=e||S.stream.match(/^\s*:/,!1)?("variable"==e&&(S.marked="property"),"spread"==e?L(Te):"}"==e?T():"["==e?L(B,H("]"),H(":"),Le):L(H(":"),Te,Ae)):(A(t),L(Ae))}function Me(){return T(Te,Ae)}function Ae(e,t){if("="==t)return L(q)}function Ne(e){if(","==e)return L(Se)}function Oe(e,t){if("keyword b"==e&&"else"==t)return L(F("form","else"),R,I)}function _e(e,t){return"await"==t?L(_e):"("==e?L(F(")"),Ee,I):void 0}function Ee(e){return"var"==e?L(Se,ze):"variable"==e?L(ze):T(ze)}function ze(e,t){return")"==e?L():";"==e?L(ze):"in"==t||"of"==t?(S.marked="keyword",L(B,ze)):T(B,ze)}function De(e,t){return"*"==t?(S.marked="keyword",L(De)):"variable"==e?(A(t),L(De)):"("==e?L(D,F(")"),ae(Fe,")"),I,de,R,W):u&&"<"==t?L(F(">"),ae(ke,">"),I,De):void 0}function Pe(e,t){return"*"==t?(S.marked="keyword",L(Pe)):"variable"==e?(A(t),L(Pe)):"("==e?L(D,F(")"),ae(Fe,")"),I,de,W):u&&"<"==t?L(F(">"),ae(ke,">"),I,Pe):void 0}function We(e,t){return"keyword"==e||"variable"==e?(S.marked="type",L(We)):"<"==t?L(F(">"),ae(ke,">"),I):void 0}function Fe(e,t){return"@"==t&&L(B,Fe),"spread"==e?L(Fe):u&&O(t)?(S.marked="keyword",L(Fe)):u&&"this"==e?L(ce,Ae):T(Te,ce,Ae)}function Ie(e,t){return"variable"==e?He(e,t):Re(e,t)}function He(e,t){if("variable"==e)return A(t),L(Re)}function Re(e,t){return"<"==t?L(F(">"),ae(ke,">"),I,Re):"extends"==t||"implements"==t||u&&","==e?("implements"==t&&(S.marked="keyword"),L(u?he:B,Re)):"{"==e?L(F("}"),je,I):void 0}function je(e,t){return"async"==e||"variable"==e&&("static"==t||"get"==t||"set"==t||u&&O(t))&&S.stream.match(/^\s+#?[\w$\xa1-\uffff]/,!1)?(S.marked="keyword",L(je)):"variable"==e||"keyword"==S.style?(S.marked="property",L(Be,je)):"number"==e||"string"==e?L(Be,je):"["==e?L(B,ce,H("]"),Be,je):"*"==t?(S.marked="keyword",L(je)):u&&"("==e?T(Pe,je):";"==e||","==e?L(je):"}"==e?L():"@"==t?L(B,je):void 0}function Be(e,t){if("!"==t)return L(Be);if("?"==t)return L(Be);if(":"==e)return L(he,Ae);if("="==t)return L(q);var n=S.state.lexical.prev;return T(n&&"interface"==n.info?Pe:De)}function qe(e,t){return"*"==t?(S.marked="keyword",L(Ye,H(";"))):"default"==t?(S.marked="keyword",L(B,H(";"))):"{"==e?L(ae(Ue,"}"),Ye,H(";")):T(R)}function Ue(e,t){return"as"==t?(S.marked="keyword",L(H("variable"))):"variable"==e?T(q,Ue):void 0}function Ke(e){return"string"==e?L():"("==e?T(B):"."==e?T(G):T(Ve,Ge,Ye)}function Ve(e,t){return"{"==e?le(Ve,"}"):("variable"==e&&A(t),"*"==t&&(S.marked="keyword"),L($e))}function Ge(e){if(","==e)return L(Ve,Ge)}function $e(e,t){if("as"==t)return S.marked="keyword",L(Ve)}function Ye(e,t){if("from"==t)return S.marked="keyword",L(B)}function Xe(e){return"]"==e?L():T(ae(q,"]"))}function Ze(){return T(F("form"),Te,H("{"),F("}"),ae(Je,"}"),I,I)}function Je(){return T(Te,Ae)}function Qe(e,t,n){return t.tokenize==g&&/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(t.lastType)||"quasi"==t.lastType&&/\{\s*$/.test(e.string.slice(0,e.pos-(n||0)))}return D.lex=P.lex=!0,W.lex=!0,I.lex=!0,{startState:function(e){var t={tokenize:g,lastType:"sof",cc:[],lexical:new x((e||0)-o,0,"block",!1),localVars:n.localVars,context:n.localVars&&new _(null,null,!1),indented:e||0};return n.globalVars&&"object"==typeof n.globalVars&&(t.globalVars=n.globalVars),t},token:function(e,t){if(e.sol()&&(t.lexical.hasOwnProperty("align")||(t.lexical.align=!1),t.indented=e.indentation(),b(e,t)),t.tokenize!=v&&e.eatSpace())return null;var n=t.tokenize(e,t);return"comment"==r?n:(t.lastType="operator"!=r||"++"!=i&&"--"!=i?r:"incdec",C(t,n,r,i,e))},indent:function(t,r){if(t.tokenize==v||t.tokenize==y)return e.Pass;if(t.tokenize!=g)return 0;var i,l=r&&r.charAt(0),s=t.lexical;if(!/^\s*else\b/.test(r))for(var c=t.cc.length-1;c>=0;--c){var u=t.cc[c];if(u==I)s=s.prev;else if(u!=Oe&&u!=W)break}for(;("stat"==s.type||"form"==s.type)&&("}"==l||(i=t.cc[t.cc.length-1])&&(i==G||i==$)&&!/^[,\.=+\-*:?[\(]/.test(r));)s=s.prev;a&&")"==s.type&&"stat"==s.prev.type&&(s=s.prev);var d=s.type,f=l==d;return"vardef"==d?s.indented+("operator"==t.lastType||","==t.lastType?s.info.length+1:0):"form"==d&&"{"==l?s.indented:"form"==d?s.indented+o:"stat"==d?s.indented+(function(e,t){return"operator"==e.lastType||","==e.lastType||h.test(t.charAt(0))||/[,.]/.test(t.charAt(0))}(t,r)?a||o:0):"switch"!=s.info||f||0==n.doubleIndentSwitch?s.align?s.column+(f?0:1):s.indented+(f?0:o):s.indented+(/^(?:case|default)\b/.test(r)?o:2*o)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:s?null:"/*",blockCommentEnd:s?null:"*/",blockCommentContinue:s?null:" * ",lineComment:s?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:s?"json":"javascript",jsonldMode:l,jsonMode:s,expressionAllowed:Qe,skipExpression:function(t){C(t,"atom","atom","true",new e.StringStream("",2,null))}}}),e.registerHelper("wordChars","javascript",/[\w$]/),e.defineMIME("text/javascript","javascript"),e.defineMIME("text/ecmascript","javascript"),e.defineMIME("application/javascript","javascript"),e.defineMIME("application/x-javascript","javascript"),e.defineMIME("application/ecmascript","javascript"),e.defineMIME("application/json",{name:"javascript",json:!0}),e.defineMIME("application/x-json",{name:"javascript",json:!0}),e.defineMIME("application/manifest+json",{name:"javascript",json:!0}),e.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),e.defineMIME("text/typescript",{name:"javascript",typescript:!0}),e.defineMIME("application/typescript",{name:"javascript",typescript:!0})}(n(5237))},6843(e,t,n){"use strict";var r=n(5199);e.exports=n(3804)("undefined"!=typeof window?window:null,r)},7165(e){"use strict";function t(e,t,n,r,i,o){return{tag:e,key:t,attrs:n,children:r,text:i,dom:o,is:void 0,domSize:void 0,state:void 0,events:void 0,instance:void 0}}t.normalize=function(e){return Array.isArray(e)?t("[",void 0,void 0,t.normalizeChildren(e),void 0,void 0):null==e||"boolean"==typeof e?null:"object"==typeof e?e:t("#",void 0,void 0,String(e),void 0,void 0)},t.normalizeChildren=function(e){for(var n=new Array(e.length),r=0,i=0;i<e.length;i++)n[i]=t.normalize(e[i]),null!==n[i]&&null!=n[i].key&&r++;if(0!==r&&r!==e.length)throw new TypeError(n.includes(null)?"In fragments, vnodes must either all have keys or none have keys. You may wish to consider using an explicit keyed empty fragment, m.fragment({key: ...}), instead of a hole.":"In fragments, vnodes must either all have keys or none have keys.");return n},e.exports=t},7224(e,t,n){"use strict";var r=n(7755);e.exports=function(e){var t=e.indexOf("?"),n=e.indexOf("#"),i=n<0?e.length:n,o=t<0?i:t,a=e.slice(0,o).replace(/\/{2,}/g,"/");return a?"/"!==a[0]&&(a="/"+a):a="/",{path:a,params:t<0?{}:r(e.slice(t+1,i))}}},7755(e,t,n){"use strict";var r=n(8157);e.exports=function(e){if(""===e||null==e)return{};"?"===e.charAt(0)&&(e=e.slice(1));for(var t=e.split("&"),n={},i={},o=0;o<t.length;o++){var a=t[o].split("="),l=r(a[0]),s=2===a.length?r(a[1]):"";"true"===s?s=!0:"false"===s&&(s=!1);var c=l.split(/\]\[?|\[/),u=i;l.indexOf("[")>-1&&c.pop();for(var d=0;d<c.length;d++){var f=c[d],h=c[d+1],p=""==h||!isNaN(parseInt(h,10));if(""===f)null==n[l=c.slice(0,d).join()]&&(n[l]=Array.isArray(u)?u.length:0),f=n[l]++;else if("__proto__"===f)break;if(d===c.length-1)u[f]=s;else{var m=Object.getOwnPropertyDescriptor(u,f);null!=m&&(m=m.value),null==m&&(u[f]=m=p?[]:{}),u=m}}}return i}},7779(e,t,n){const r={},i=n(361),o=n(4862);function a(e){for(let t=0;t<e.length;t++)e[t]=o("div.mc4wp-margin-s",e[t]);return e}r.render=function(e){const t=e.type;return"function"==typeof r[t]?a(r[t](e)):["select","radio","checkbox"].indexOf(t)>-1?a(r.choice(e)):a(r.text(e))},r.text=function(e){return[i.label(e),i.placeholder(e),i.value(e),i.isRequired(e),i.useParagraphs(e)]},r.choice=function(e){const t=[i.label(e),i.choiceType(e),i.choices(e)];return"select"===e.type&&t.push(i.placeholder(e)),t.push(i.useParagraphs(e)),"select"!==e.type&&"radio"!==e.type||t.push(i.isRequired(e)),t},r.hidden=function(e){return e.placeholder="",e.label="",e.wrap=!1,[i.showType(e),i.value(e)]},r.submit=function(e){return e.label="",e.placeholder="",[i.value(e),i.useParagraphs(e)]},r["terms-checkbox"]=function(e){return[i.label(e),i.linkToTerms(e),i.isRequired(e),i.useParagraphs(e)]},r.number=function(e){return[r.text(e),i.numberMinMax(e)]},r.procaptcha=function(e){return[i.description(e)]},e.exports=r},7785(e,t,n){const r=document.getElementById("mc4wp-admin").querySelectorAll(".mc4wp-list-input"),i=window.mc4wp_vars.mailchimp.lists;let o=[];const a=new(n(9885));function l(){o=[];for(let e=0;e<r.length;e++){const t=r[e];("boolean"!=typeof t.checked||t.checked)&&"object"==typeof i[t.value]&&o.push(i[t.value])}return function(){const e=document.querySelectorAll(".lists--only-selected > *");for(let t=0;t<e.length;t++){const n=e[t].getAttribute("data-list-id"),r=o.filter(e=>e.id===n).length>0;e[t].style.display=r?"":"none"}}(),a.emit("selectedLists.change",[o]),o}const s=document.getElementById("mc4wp-lists");s&&s.addEventListener("change",l),l(),e.exports={getSelectedLists:function(){return o},on:a.on.bind(a)}},8147(e,t,n){"use strict";var r=n(7165),i=n(2965),o=n(9788),a=n(8885);e.exports=function(){var e,t,n={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"};function l(e){return e.ownerDocument}function s(e){return e.attrs&&e.attrs.xmlns||n[e.tag]}function c(e,t){if(e.state!==t)throw new Error("'vnode.state' must not be modified.")}function u(e){var t=e.state;try{return this.apply(t,arguments)}finally{c(e,t)}}function d(e){try{return l(e).activeElement}catch(e){return null}}function f(e,t,n,r,i,o,a){for(var l=n;l<r;l++){var s=t[l];null!=s&&h(e,s,i,a,o)}}function h(e,t,n,i,o){var a=t.tag;if("string"==typeof a)switch(t.state={},null!=t.attrs&&I(t.attrs,t,n),a){case"#":!function(e,t,n){t.dom=l(e).createTextNode(t.children),C(e,t.dom,n)}(e,t,o);break;case"<":m(e,t,i,o);break;case"[":!function(e,t,n,r,i){var o=l(e).createDocumentFragment();if(null!=t.children){var a=t.children;f(o,a,0,a.length,n,null,r)}t.dom=o.firstChild,t.domSize=o.childNodes.length,C(e,o,i)}(e,t,n,i,o);break;default:!function(e,t,n,r,i){var o=t.tag,a=t.attrs,c=t.is,u=(r=s(t)||r)?c?l(e).createElementNS(r,o,{is:c}):l(e).createElementNS(r,o):c?l(e).createElement(o,{is:c}):l(e).createElement(o);if(t.dom=u,null!=a&&function(e,t,n){for(var r in t)_(e,r,null,t[r],n)}(t,a,r),C(e,u,i),!S(t)&&null!=t.children){var d=t.children;f(u,d,0,d.length,n,null,r),"select"===t.tag&&null!=a&&function(e,t){if("value"in t)if(null===t.value)-1!==e.dom.selectedIndex&&(e.dom.value=null);else{var n=""+t.value;e.dom.value===n&&-1!==e.dom.selectedIndex||(e.dom.value=n)}"selectedIndex"in t&&_(e,"selectedIndex",null,t.selectedIndex,void 0)}(t,a)}}(e,t,n,i,o)}else!function(e,t,n,i,o){(function(e,t){var n;if("function"==typeof e.tag.view){if(e.state=Object.create(e.tag),null!=(n=e.state.view).$$reentrantLock$$)return;n.$$reentrantLock$$=!0}else{if(e.state=void 0,null!=(n=e.tag).$$reentrantLock$$)return;n.$$reentrantLock$$=!0,e.state=null!=e.tag.prototype&&"function"==typeof e.tag.prototype.view?new e.tag(e):e.tag(e)}if(I(e.state,e,t),null!=e.attrs&&I(e.attrs,e,t),e.instance=r.normalize(u.call(e.state.view,e)),e.instance===e)throw Error("A view cannot return the vnode it received as argument");n.$$reentrantLock$$=null})(t,n),null!=t.instance?(h(e,t.instance,n,i,o),t.dom=t.instance.dom,t.domSize=t.instance.domSize):t.domSize=0}(e,t,n,i,o)}var p={caption:"table",thead:"table",tbody:"table",tfoot:"table",tr:"tbody",th:"tr",td:"tr",colgroup:"table",col:"colgroup"};function m(e,t,n,r){var i=t.children.match(/^\s*?<(\w+)/im)||[],o=l(e).createElement(p[i[1]]||"div");"http://www.w3.org/2000/svg"===n?(o.innerHTML='<svg xmlns="http://www.w3.org/2000/svg">'+t.children+"</svg>",o=o.firstChild):o.innerHTML=t.children,t.dom=o.firstChild,t.domSize=o.childNodes.length;for(var a,s=l(e).createDocumentFragment();a=o.firstChild;)s.appendChild(a);C(e,s,r)}function g(e,t,n,r,i,o){if(t!==n&&(null!=t||null!=n))if(null==t||0===t.length)f(e,n,0,n.length,r,i,o);else if(null==n||0===n.length)T(e,t,0,t.length);else{var a=null!=t[0]&&null!=t[0].key,l=null!=n[0]&&null!=n[0].key,s=0,c=0;if(!a)for(;c<t.length&&null==t[c];)c++;if(!l)for(;s<n.length&&null==n[s];)s++;if(a!==l)T(e,t,c,t.length),f(e,n,s,n.length,r,i,o);else if(l){for(var u,d,p,m,g,b=t.length-1,C=n.length-1;b>=c&&C>=s&&(p=t[b],m=n[C],p.key===m.key);)p!==m&&v(e,p,m,r,i,o),null!=m.dom&&(i=m.dom),b--,C--;for(;b>=c&&C>=s&&(u=t[c],d=n[s],u.key===d.key);)c++,s++,u!==d&&v(e,u,d,r,x(t,c,i),o);for(;b>=c&&C>=s&&s!==C&&u.key===m.key&&p.key===d.key;)k(e,p,g=x(t,c,i)),p!==d&&v(e,p,d,r,g,o),++s<=--C&&k(e,u,i),u!==m&&v(e,u,m,r,i,o),null!=m.dom&&(i=m.dom),c++,p=t[--b],m=n[C],u=t[c],d=n[s];for(;b>=c&&C>=s&&p.key===m.key;)p!==m&&v(e,p,m,r,i,o),null!=m.dom&&(i=m.dom),C--,p=t[--b],m=n[C];if(s>C)T(e,t,c,b+1);else if(c>b)f(e,n,s,C+1,r,i,o);else{var S,L,M=i,N=C-s+1,O=new Array(N),_=0,E=0,z=2147483647,D=0;for(E=0;E<N;E++)O[E]=-1;for(E=C;E>=s;E--){null==S&&(S=y(t,c,b+1));var P=S[(m=n[E]).key];null!=P&&(z=P<z?P:-1,O[E-s]=P,p=t[P],t[P]=null,p!==m&&v(e,p,m,r,i,o),null!=m.dom&&(i=m.dom),D++)}if(i=M,D!==b-c+1&&T(e,t,c,b+1),0===D)f(e,n,s,C+1,r,i,o);else if(-1===z)for(L=function(e){var t=[0],n=0,r=0,i=0,o=w.length=e.length;for(i=0;i<o;i++)w[i]=e[i];for(i=0;i<o;++i)if(-1!==e[i]){var a=t[t.length-1];if(e[a]<e[i])w[i]=a,t.push(i);else{for(n=0,r=t.length-1;n<r;){var l=(n>>>1)+(r>>>1)+(n&r&1);e[t[l]]<e[i]?n=l+1:r=l}e[i]<e[t[n]]&&(n>0&&(w[i]=t[n-1]),t[n]=i)}}for(r=t[(n=t.length)-1];n-- >0;)t[n]=r,r=w[r];return w.length=0,t}(O),_=L.length-1,E=C;E>=s;E--)d=n[E],-1===O[E-s]?h(e,d,r,o,i):L[_]===E-s?_--:k(e,d,i),null!=d.dom&&(i=n[E].dom);else for(E=C;E>=s;E--)d=n[E],-1===O[E-s]&&h(e,d,r,o,i),null!=d.dom&&(i=n[E].dom)}}else{var W=t.length<n.length?t.length:n.length;for(s=s<c?s:c;s<W;s++)(u=t[s])===(d=n[s])||null==u&&null==d||(null==u?h(e,d,r,o,x(t,s+1,i)):null==d?A(e,u):v(e,u,d,r,x(t,s+1,i),o));t.length>W&&T(e,t,s,t.length),n.length>W&&f(e,n,s,n.length,r,i,o)}}}function v(e,t,n,i,o,l){var c=t.tag;if(c===n.tag&&t.is===n.is){if(n.state=t.state,n.events=t.events,function(e,t){do{var n;if(null!=e.attrs&&"function"==typeof e.attrs.onbeforeupdate&&void 0!==(n=u.call(e.attrs.onbeforeupdate,e,t))&&!n)break;if("string"!=typeof e.tag&&"function"==typeof e.state.onbeforeupdate&&void 0!==(n=u.call(e.state.onbeforeupdate,e,t))&&!n)break;return!1}while(0);return e.dom=t.dom,e.domSize=t.domSize,e.instance=t.instance,e.attrs=t.attrs,e.children=t.children,e.text=t.text,!0}(n,t))return;if("string"==typeof c)switch(null!=n.attrs&&H(n.attrs,n,i),c){case"#":!function(e,t){e.children.toString()!==t.children.toString()&&(e.dom.nodeValue=t.children),t.dom=e.dom}(t,n);break;case"<":!function(e,t,n,r,i){t.children!==n.children?(N(e,t),m(e,n,r,i)):(n.dom=t.dom,n.domSize=t.domSize)}(e,t,n,l,o);break;case"[":!function(e,t,n,r,i,o){g(e,t.children,n.children,r,i,o);var a=0,l=n.children;if(n.dom=null,null!=l)for(var s=0;s<l.length;s++){var c=l[s];null!=c&&null!=c.dom&&(null==n.dom&&(n.dom=c.dom),a+=c.domSize||1)}n.domSize=a}(e,t,n,i,o,l);break;default:!function(e,t,n,r){var i=t.dom=e.dom;r=s(t)||r,(e.attrs!=t.attrs||null!=t.attrs&&!a.get(t.attrs))&&function(e,t,n,r){var i;if(null!=t)for(var o in t!==n||a.has(n)||console.warn("Don't reuse attrs object, use new object for every redraw, this will throw in next major"),t)null==(i=t[o])||null!=n&&null!=n[o]||E(e,o,i,r);if(null!=n)for(var o in n)_(e,o,t&&t[o],n[o],r)}(t,e.attrs,t.attrs,r),S(t)||g(i,e.children,t.children,n,null,r)}(t,n,i,l)}else!function(e,t,n,i,o,a){if(n.instance=r.normalize(u.call(n.state.view,n)),n.instance===n)throw Error("A view cannot return the vnode it received as argument");H(n.state,n,i),null!=n.attrs&&H(n.attrs,n,i),null!=n.instance?(null==t.instance?h(e,n.instance,i,a,o):v(e,t.instance,n.instance,i,o,a),n.dom=n.instance.dom,n.domSize=n.instance.domSize):(null!=t.instance&&A(e,t.instance),n.domSize=0)}(e,t,n,i,o,l)}else A(e,t),h(e,n,i,l,o)}function y(e,t,n){for(var r=Object.create(null);t<n;t++){var i=e[t];if(null!=i){var o=i.key;null!=o&&(r[o]=t)}}return r}var b,w=[];function x(e,t,n){for(;t<e.length;t++)if(null!=e[t]&&null!=e[t].dom)return e[t].dom;return n}function k(e,t,n){if(null!=t.dom){var r;if(null==t.domSize||1===t.domSize)r=t.dom;else for(var i of(r=l(e).createDocumentFragment(),o(t)))r.appendChild(i);C(e,r,n)}}function C(e,t,n){null!=n?e.insertBefore(t,n):e.appendChild(t)}function S(e){if(null==e.attrs||null==e.attrs.contenteditable&&null==e.attrs.contentEditable)return!1;var t=e.children;if(null!=t&&1===t.length&&"<"===t[0].tag){var n=t[0].children;e.dom.innerHTML!==n&&(e.dom.innerHTML=n)}else if(null!=t&&0!==t.length)throw new Error("Child node of a contenteditable must be trusted.");return!0}function T(e,t,n,r){for(var i=n;i<r;i++){var o=t[i];null!=o&&A(e,o)}}function L(e,n,r,a){var l=n.state,s=u.call(r.onbeforeremove,n);if(null!=s){var d=t;for(var f of o(n))i.set(f,d);a.v++,Promise.resolve(s).finally(function(){c(n,l),M(e,n,a)})}}function M(e,t,n){0===--n.v&&(O(t),N(e,t))}function A(e,t){var n={v:1};"string"!=typeof t.tag&&"function"==typeof t.state.onbeforeremove&&L(e,t,t.state,n),t.attrs&&"function"==typeof t.attrs.onbeforeremove&&L(e,t,t.attrs,n),M(e,t,n)}function N(e,t){if(null!=t.dom)if(null==t.domSize||1===t.domSize)e.removeChild(t.dom);else for(var n of o(t))e.removeChild(n)}function O(e){if("string"!=typeof e.tag&&"function"==typeof e.state.onremove&&u.call(e.state.onremove,e),e.attrs&&"function"==typeof e.attrs.onremove&&u.call(e.attrs.onremove,e),"string"!=typeof e.tag)null!=e.instance&&O(e.instance);else{null!=e.events&&(e.events._=null);var t=e.children;if(Array.isArray(t))for(var n=0;n<t.length;n++){var r=t[n];null!=r&&O(r)}}}function _(e,t,n,r,i){if("key"!==t&&null!=r&&!z(t)&&(n!==r||function(e,t){return"value"===t||"checked"===t||"selectedIndex"===t||"selected"===t&&(e.dom===d(e.dom)||"option"===e.tag&&e.dom.parentNode===d(e.dom))}(e,t)||"object"==typeof r)){if("o"===t[0]&&"n"===t[1])return F(e,t,r);if("xlink:"===t.slice(0,6))e.dom.setAttributeNS("http://www.w3.org/1999/xlink",t.slice(6),r);else if("style"===t)P(e.dom,n,r);else if(D(e,t,i)){if("value"===t){if(("input"===e.tag||"textarea"===e.tag)&&e.dom.value===""+r)return;if("select"===e.tag&&null!==n&&e.dom.value===""+r)return;if("option"===e.tag&&null!==n&&e.dom.value===""+r)return;if("input"===e.tag&&"file"===e.attrs.type&&""+r!="")return void console.error("`value` is read-only on file inputs!")}"input"===e.tag&&"type"===t?e.dom.setAttribute(t,r):e.dom[t]=r}else"boolean"==typeof r?r?e.dom.setAttribute(t,""):e.dom.removeAttribute(t):e.dom.setAttribute("className"===t?"class":t,r)}}function E(e,t,n,r){if("key"!==t&&null!=n&&!z(t))if("o"===t[0]&&"n"===t[1])F(e,t,void 0);else if("style"===t)P(e.dom,n,null);else if(!D(e,t,r)||"className"===t||"title"===t||"value"===t&&("option"===e.tag||"select"===e.tag&&-1===e.dom.selectedIndex&&e.dom===d(e.dom))||"input"===e.tag&&"type"===t){var i=t.indexOf(":");-1!==i&&(t=t.slice(i+1)),!1!==n&&e.dom.removeAttribute("className"===t?"class":t)}else e.dom[t]=null}function z(e){return"oninit"===e||"oncreate"===e||"onupdate"===e||"onremove"===e||"onbeforeremove"===e||"onbeforeupdate"===e}function D(e,t,n){return void 0===n&&(e.tag.indexOf("-")>-1||e.is||"href"!==t&&"list"!==t&&"form"!==t&&"width"!==t&&"height"!==t)&&t in e.dom}function P(e,t,n){if(t===n);else if(null==n)e.style="";else if("object"!=typeof n)e.style=n;else if(null==t||"object"!=typeof t)for(var r in e.style="",n)null!=(i=n[r])&&(r.includes("-")?e.style.setProperty(r,String(i)):e.style[r]=String(i));else{for(var r in t)null!=t[r]&&null==n[r]&&(r.includes("-")?e.style.removeProperty(r):e.style[r]="");for(var r in n){var i;null!=(i=n[r])&&(i=String(i))!==String(t[r])&&(r.includes("-")?e.style.setProperty(r,i):e.style[r]=i)}}}function W(){this._=e}function F(t,n,r){if(null!=t.events){if(t.events._=e,t.events[n]===r)return;null==r||"function"!=typeof r&&"object"!=typeof r?(null!=t.events[n]&&t.dom.removeEventListener(n.slice(2),t.events,!1),t.events[n]=void 0):(null==t.events[n]&&t.dom.addEventListener(n.slice(2),t.events,!1),t.events[n]=r)}else null==r||"function"!=typeof r&&"object"!=typeof r||(t.events=new W,t.dom.addEventListener(n.slice(2),t.events,!1),t.events[n]=r)}function I(e,t,n){"function"==typeof e.oninit&&u.call(e.oninit,t),"function"==typeof e.oncreate&&n.push(u.bind(e.oncreate,t))}function H(e,t,n){"function"==typeof e.onupdate&&n.push(u.bind(e.onupdate,t))}return W.prototype=Object.create(null),W.prototype.handleEvent=function(e){var t,n=this["on"+e.type];"function"==typeof n?t=n.call(e.currentTarget,e):"function"==typeof n.handleEvent&&n.handleEvent(e);var r=this;null!=r._&&(!1!==e.redraw&&(0,r._)(),null!=t&&"function"==typeof t.then&&Promise.resolve(t).then(function(){null!=r._&&!1!==e.redraw&&(0,r._)()})),!1===t&&(e.preventDefault(),e.stopPropagation())},function(n,i,o){if(!n)throw new TypeError("DOM element being rendered to does not exist.");if(null!=b&&n.contains(b))throw new TypeError("Node is currently being rendered to and thus is locked.");var a=e,l=b,s=[],c=d(n),u=n.namespaceURI;b=n,e="function"==typeof o?o:void 0,t={};try{null==n.vnodes&&(n.textContent=""),i=r.normalizeChildren(Array.isArray(i)?i:[i]),g(n,n.vnodes,i,s,null,"http://www.w3.org/1999/xhtml"===u?void 0:u),n.vnodes=i,null!=c&&d(n)!==c&&"function"==typeof c.focus&&c.focus();for(var f=0;f<s.length;f++)s[f]()}finally{e=a,b=l}}}},8157(e){"use strict";var t=/%(?:[0-7]|(?!c[01]|e0%[89]|ed%[ab]|f0%8|f4%[9ab])(?:c|d|(?:e|f[0-4]%[89ab])[\da-f]%[89ab])[\da-f]%[89ab])[\da-f]/gi;e.exports=function(e){return String(e).replace(t,decodeURIComponent)}},8333(e,t,n){"use strict";var r=n(795),i=/^(?:key|oninit|oncreate|onbeforeupdate|onupdate|onbeforeremove|onremove)$/;e.exports=function(e,t){var n={};if(null!=t)for(var o in e)r.call(e,o)&&!i.test(o)&&t.indexOf(o)<0&&(n[o]=e[o]);else for(var o in e)r.call(e,o)&&!i.test(o)&&(n[o]=e[o]);return n}},8555(e,t,n){"use strict";var r=n(4224);e.exports=function(e,t){if(/:([^\/\.-]+)(\.{3})?:/.test(e))throw new SyntaxError("Template parameter names must be separated by either a '/', '-', or '.'.");if(null==t)return e;var n=e.indexOf("?"),i=e.indexOf("#"),o=i<0?e.length:i,a=n<0?o:n,l=e.slice(0,a),s={};Object.assign(s,t);var c=l.replace(/:([^\/\.-]+)(\.{3})?/g,function(e,n,r){return delete s[n],null==t[n]?e:r?t[n]:encodeURIComponent(String(t[n]))}),u=c.indexOf("?"),d=c.indexOf("#"),f=d<0?c.length:d,h=u<0?f:u,p=c.slice(0,h);n>=0&&(p+=e.slice(n,o)),u>=0&&(p+=(n<0?"?":"&")+c.slice(u,f));var m=r(s);return m&&(p+=(n<0&&u<0?"?":"&")+m),i>=0&&(p+=e.slice(i)),d>=0&&(p+=(i<0?"":"&")+c.slice(d)),p}},8656(e,t,n){!function(e){"use strict";function t(e){for(var t={},n=0;n<e.length;++n)t[e[n].toLowerCase()]=!0;return t}e.defineMode("css",function(t,n){var r=n.inline;n.propertyKeywords||(n=e.resolveMode("text/css"));var i,o,a=t.indentUnit,l=n.tokenHooks,s=n.documentTypes||{},c=n.mediaTypes||{},u=n.mediaFeatures||{},d=n.mediaValueKeywords||{},f=n.propertyKeywords||{},h=n.nonStandardPropertyKeywords||{},p=n.fontProperties||{},m=n.counterDescriptors||{},g=n.colorKeywords||{},v=n.valueKeywords||{},y=n.allowNested,b=n.lineComment,w=!0===n.supportsAtComponent,x=!1!==t.highlightNonStandardPropertyKeywords;function k(e,t){return i=t,e}function C(e,t){var n=e.next();if(l[n]){var r=l[n](e,t);if(!1!==r)return r}return"@"==n?(e.eatWhile(/[\w\\\-]/),k("def",e.current())):"="==n||("~"==n||"|"==n)&&e.eat("=")?k(null,"compare"):'"'==n||"'"==n?(t.tokenize=S(n),t.tokenize(e,t)):"#"==n?(e.eatWhile(/[\w\\\-]/),k("atom","hash")):"!"==n?(e.match(/^\s*\w*/),k("keyword","important")):/\d/.test(n)||"."==n&&e.eat(/\d/)?(e.eatWhile(/[\w.%]/),k("number","unit")):"-"!==n?/[,+>*\/]/.test(n)?k(null,"select-op"):"."==n&&e.match(/^-?[_a-z][_a-z0-9-]*/i)?k("qualifier","qualifier"):/[:;{}\[\]\(\)]/.test(n)?k(null,n):e.match(/^[\w-.]+(?=\()/)?(/^(url(-prefix)?|domain|regexp)$/i.test(e.current())&&(t.tokenize=T),k("variable callee","variable")):/[\w\\\-]/.test(n)?(e.eatWhile(/[\w\\\-]/),k("property","word")):k(null,null):/[\d.]/.test(e.peek())?(e.eatWhile(/[\w.%]/),k("number","unit")):e.match(/^-[\w\\\-]*/)?(e.eatWhile(/[\w\\\-]/),e.match(/^\s*:/,!1)?k("variable-2","variable-definition"):k("variable-2","variable")):e.match(/^\w+-/)?k("meta","meta"):void 0}function S(e){return function(t,n){for(var r,i=!1;null!=(r=t.next());){if(r==e&&!i){")"==e&&t.backUp(1);break}i=!i&&"\\"==r}return(r==e||!i&&")"!=e)&&(n.tokenize=null),k("string","string")}}function T(e,t){return e.next(),e.match(/^\s*[\"\')]/,!1)?t.tokenize=null:t.tokenize=S(")"),k(null,"(")}function L(e,t,n){this.type=e,this.indent=t,this.prev=n}function M(e,t,n,r){return e.context=new L(n,t.indentation()+(!1===r?0:a),e.context),n}function A(e){return e.context.prev&&(e.context=e.context.prev),e.context.type}function N(e,t,n){return E[n.context.type](e,t,n)}function O(e,t,n,r){for(var i=r||1;i>0;i--)n.context=n.context.prev;return N(e,t,n)}function _(e){var t=e.current().toLowerCase();o=v.hasOwnProperty(t)?"atom":g.hasOwnProperty(t)?"keyword":"variable"}var E={top:function(e,t,n){if("{"==e)return M(n,t,"block");if("}"==e&&n.context.prev)return A(n);if(w&&/@component/i.test(e))return M(n,t,"atComponentBlock");if(/^@(-moz-)?document$/i.test(e))return M(n,t,"documentTypes");if(/^@(media|supports|(-moz-)?document|import)$/i.test(e))return M(n,t,"atBlock");if(/^@(font-face|counter-style)/i.test(e))return n.stateArg=e,"restricted_atBlock_before";if(/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(e))return"keyframes";if(e&&"@"==e.charAt(0))return M(n,t,"at");if("hash"==e)o="builtin";else if("word"==e)o="tag";else{if("variable-definition"==e)return"maybeprop";if("interpolation"==e)return M(n,t,"interpolation");if(":"==e)return"pseudo";if(y&&"("==e)return M(n,t,"parens")}return n.context.type},block:function(e,t,n){if("word"==e){var r=t.current().toLowerCase();return f.hasOwnProperty(r)?(o="property","maybeprop"):h.hasOwnProperty(r)?(o=x?"string-2":"property","maybeprop"):y?(o=t.match(/^\s*:(?:\s|$)/,!1)?"property":"tag","block"):(o+=" error","maybeprop")}return"meta"==e?"block":y||"hash"!=e&&"qualifier"!=e?E.top(e,t,n):(o="error","block")},maybeprop:function(e,t,n){return":"==e?M(n,t,"prop"):N(e,t,n)},prop:function(e,t,n){if(";"==e)return A(n);if("{"==e&&y)return M(n,t,"propBlock");if("}"==e||"{"==e)return O(e,t,n);if("("==e)return M(n,t,"parens");if("hash"!=e||/^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(t.current())){if("word"==e)_(t);else if("interpolation"==e)return M(n,t,"interpolation")}else o+=" error";return"prop"},propBlock:function(e,t,n){return"}"==e?A(n):"word"==e?(o="property","maybeprop"):n.context.type},parens:function(e,t,n){return"{"==e||"}"==e?O(e,t,n):")"==e?A(n):"("==e?M(n,t,"parens"):"interpolation"==e?M(n,t,"interpolation"):("word"==e&&_(t),"parens")},pseudo:function(e,t,n){return"meta"==e?"pseudo":"word"==e?(o="variable-3",n.context.type):N(e,t,n)},documentTypes:function(e,t,n){return"word"==e&&s.hasOwnProperty(t.current())?(o="tag",n.context.type):E.atBlock(e,t,n)},atBlock:function(e,t,n){if("("==e)return M(n,t,"atBlock_parens");if("}"==e||";"==e)return O(e,t,n);if("{"==e)return A(n)&&M(n,t,y?"block":"top");if("interpolation"==e)return M(n,t,"interpolation");if("word"==e){var r=t.current().toLowerCase();o="only"==r||"not"==r||"and"==r||"or"==r?"keyword":c.hasOwnProperty(r)?"attribute":u.hasOwnProperty(r)?"property":d.hasOwnProperty(r)?"keyword":f.hasOwnProperty(r)?"property":h.hasOwnProperty(r)?x?"string-2":"property":v.hasOwnProperty(r)?"atom":g.hasOwnProperty(r)?"keyword":"error"}return n.context.type},atComponentBlock:function(e,t,n){return"}"==e?O(e,t,n):"{"==e?A(n)&&M(n,t,y?"block":"top",!1):("word"==e&&(o="error"),n.context.type)},atBlock_parens:function(e,t,n){return")"==e?A(n):"{"==e||"}"==e?O(e,t,n,2):E.atBlock(e,t,n)},restricted_atBlock_before:function(e,t,n){return"{"==e?M(n,t,"restricted_atBlock"):"word"==e&&"@counter-style"==n.stateArg?(o="variable","restricted_atBlock_before"):N(e,t,n)},restricted_atBlock:function(e,t,n){return"}"==e?(n.stateArg=null,A(n)):"word"==e?(o="@font-face"==n.stateArg&&!p.hasOwnProperty(t.current().toLowerCase())||"@counter-style"==n.stateArg&&!m.hasOwnProperty(t.current().toLowerCase())?"error":"property","maybeprop"):"restricted_atBlock"},keyframes:function(e,t,n){return"word"==e?(o="variable","keyframes"):"{"==e?M(n,t,"top"):N(e,t,n)},at:function(e,t,n){return";"==e?A(n):"{"==e||"}"==e?O(e,t,n):("word"==e?o="tag":"hash"==e&&(o="builtin"),"at")},interpolation:function(e,t,n){return"}"==e?A(n):"{"==e||";"==e?O(e,t,n):("word"==e?o="variable":"variable"!=e&&"("!=e&&")"!=e&&(o="error"),"interpolation")}};return{startState:function(e){return{tokenize:null,state:r?"block":"top",stateArg:null,context:new L(r?"block":"top",e||0,null)}},token:function(e,t){if(!t.tokenize&&e.eatSpace())return null;var n=(t.tokenize||C)(e,t);return n&&"object"==typeof n&&(i=n[1],n=n[0]),o=n,"comment"!=i&&(t.state=E[t.state](i,e,t)),o},indent:function(e,t){var n=e.context,r=t&&t.charAt(0),i=n.indent;return"prop"!=n.type||"}"!=r&&")"!=r||(n=n.prev),n.prev&&("}"!=r||"block"!=n.type&&"top"!=n.type&&"interpolation"!=n.type&&"restricted_atBlock"!=n.type?(")"!=r||"parens"!=n.type&&"atBlock_parens"!=n.type)&&("{"!=r||"at"!=n.type&&"atBlock"!=n.type)||(i=Math.max(0,n.indent-a)):i=(n=n.prev).indent),i},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:b,fold:"brace"}});var n=["domain","regexp","url","url-prefix"],r=t(n),i=["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"],o=t(i),a=["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid","orientation","device-pixel-ratio","min-device-pixel-ratio","max-device-pixel-ratio","pointer","any-pointer","hover","any-hover","prefers-color-scheme","dynamic-range","video-dynamic-range"],l=t(a),s=["landscape","portrait","none","coarse","fine","on-demand","hover","interlace","progressive","dark","light","standard","high"],c=t(s),u=["align-content","align-items","align-self","alignment-adjust","alignment-baseline","all","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backdrop-filter","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-position-x","background-position-y","background-repeat","background-size","baseline-shift","binding","bleed","block-size","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-content","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-family","font-feature-settings","font-kerning","font-language-override","font-optical-sizing","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-gap","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-gap","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","inset","inset-block","inset-block-end","inset-block-start","inset-inline","inset-inline-end","inset-inline-start","isolation","justify-content","justify-items","justify-self","left","letter-spacing","line-break","line-height","line-height-step","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","offset","offset-anchor","offset-distance","offset-path","offset-position","offset-rotate","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","place-content","place-items","place-self","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotate","rotation","rotation-point","row-gap","ruby-align","ruby-overhang","ruby-position","ruby-span","scale","scroll-behavior","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-type","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-skip-ink","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-orientation","text-outline","text-overflow","text-rendering","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","touch-action","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","translate","unicode-bidi","user-select","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","paint-order","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode"],d=t(u),f=["accent-color","aspect-ratio","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","content-visibility","margin-block","margin-block-end","margin-block-start","margin-inline","margin-inline-end","margin-inline-start","overflow-anchor","overscroll-behavior","padding-block","padding-block-end","padding-block-start","padding-inline","padding-inline-end","padding-inline-start","scroll-snap-stop","scrollbar-3d-light-color","scrollbar-arrow-color","scrollbar-base-color","scrollbar-dark-shadow-color","scrollbar-face-color","scrollbar-highlight-color","scrollbar-shadow-color","scrollbar-track-color","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","shape-inside","zoom"],h=t(f),p=t(["font-display","font-family","src","unicode-range","font-variant","font-feature-settings","font-stretch","font-weight","font-style"]),m=t(["additive-symbols","fallback","negative","pad","prefix","range","speak-as","suffix","symbols","system"]),g=["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"],v=t(g),y=["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","auto-flow","avoid","avoid-column","avoid-page","avoid-region","axis-pan","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","blur","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","brightness","bullets","button","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","color","color-burn","color-dodge","column","column-reverse","compact","condensed","conic-gradient","contain","content","contents","content-box","context-menu","continuous","contrast","copy","counter","counters","cover","crop","cross","crosshair","cubic-bezier","currentcolor","cursive","cyclic","darken","dashed","decimal","decimal-leading-zero","default","default-button","dense","destination-atop","destination-in","destination-out","destination-over","devanagari","difference","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","drop-shadow","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","exclusion","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fill-box","fixed","flat","flex","flex-end","flex-start","footnotes","forwards","from","geometricPrecision","georgian","grayscale","graytext","grid","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hard-light","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","hue","hue-rotate","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-grid","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","lighten","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","luminosity","malayalam","manipulation","match","matrix","matrix3d","media-play-button","media-slider","media-sliderthumb","media-volume-slider","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","multiple_mask_images","multiply","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","opacity","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","pinch-zoom","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeating-conic-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row","row-resize","row-reverse","rtl","run-in","running","s-resize","sans-serif","saturate","saturation","scale","scale3d","scaleX","scaleY","scaleZ","screen","scroll","scrollbar","scroll-position","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","self-start","self-end","semi-condensed","semi-expanded","separate","sepia","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","soft-light","solid","somali","source-atop","source-in","source-out","source-over","space","space-around","space-between","space-evenly","spell-out","square","square-button","start","static","status-bar","stretch","stroke","stroke-box","sub","subpixel-antialiased","svg_masks","super","sw-resize","symbolic","symbols","system-ui","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","transform","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","unidirectional-pan","unset","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","view-box","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","wrap","wrap-reverse","x-large","x-small","xor","xx-large","xx-small"],b=t(y),w=n.concat(i).concat(a).concat(s).concat(u).concat(f).concat(g).concat(y);function x(e,t){for(var n,r=!1;null!=(n=e.next());){if(r&&"/"==n){t.tokenize=null;break}r="*"==n}return["comment","comment"]}e.registerHelper("hintWords","css",w),e.defineMIME("text/css",{documentTypes:r,mediaTypes:o,mediaFeatures:l,mediaValueKeywords:c,propertyKeywords:d,nonStandardPropertyKeywords:h,fontProperties:p,counterDescriptors:m,colorKeywords:v,valueKeywords:b,tokenHooks:{"/":function(e,t){return!!e.eat("*")&&(t.tokenize=x,x(e,t))}},name:"css"}),e.defineMIME("text/x-scss",{mediaTypes:o,mediaFeatures:l,mediaValueKeywords:c,propertyKeywords:d,nonStandardPropertyKeywords:h,colorKeywords:v,valueKeywords:b,fontProperties:p,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(e,t){return e.eat("/")?(e.skipToEnd(),["comment","comment"]):e.eat("*")?(t.tokenize=x,x(e,t)):["operator","operator"]},":":function(e){return!!e.match(/^\s*\{/,!1)&&[null,null]},$:function(e){return e.match(/^[\w-]+/),e.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"]},"#":function(e){return!!e.eat("{")&&[null,"interpolation"]}},name:"css",helperType:"scss"}),e.defineMIME("text/x-less",{mediaTypes:o,mediaFeatures:l,mediaValueKeywords:c,propertyKeywords:d,nonStandardPropertyKeywords:h,colorKeywords:v,valueKeywords:b,fontProperties:p,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(e,t){return e.eat("/")?(e.skipToEnd(),["comment","comment"]):e.eat("*")?(t.tokenize=x,x(e,t)):["operator","operator"]},"@":function(e){return e.eat("{")?[null,"interpolation"]:!e.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i,!1)&&(e.eatWhile(/[\w\\\-]/),e.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"])},"&":function(){return["atom","atom"]}},name:"css",helperType:"less"}),e.defineMIME("text/x-gss",{documentTypes:r,mediaTypes:o,mediaFeatures:l,propertyKeywords:d,nonStandardPropertyKeywords:h,fontProperties:p,counterDescriptors:m,colorKeywords:v,valueKeywords:b,supportsAtComponent:!0,tokenHooks:{"/":function(e,t){return!!e.eat("*")&&(t.tokenize=x,x(e,t))}},name:"css",helperType:"gss"})}(n(5237))},8885(e,t,n){"use strict";var r=n(1640);e.exports=new Map([[r,!0]])},8915(e){e.exports={prettyPrint:function(e,t){var n,r,i,o,a,l;for(r=(t=t||{}).indent_size||4,i=t.indent_char||" ",a=t.brace_style||"collapse",o=0==t.max_char?1/0:t.max_char||70,l=t.unformatted||["a","span","bdo","em","strong","dfn","code","samp","kbd","var","cite","abbr","acronym","q","sub","sup","tt","i","b","big","small","u","s","strike","font","ins","del","pre","address","dt","h1","h2","h3","h4","h5","h6"],n=new function(){return this.pos=0,this.token="",this.current_mode="CONTENT",this.tags={parent:"parent1",parentcount:1,parent1:""},this.tag_type="",this.token_text=this.last_token=this.last_text=this.token_type="",this.Utils={whitespace:"\n\r\t ".split(""),single_token:"br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed,?php,?,?=".split(","),extra_liners:"head,body,/html".split(","),in_array:function(e,t){for(var n=0;n<t.length;n++)if(e===t[n])return!0;return!1}},this.get_content=function(){for(var e="",t=[],n=!1;"<"!==this.input.charAt(this.pos);){if(this.pos>=this.input.length)return t.length?t.join(""):["","TK_EOF"];if(e=this.input.charAt(this.pos),this.pos++,this.line_char_count++,this.Utils.in_array(e,this.Utils.whitespace))t.length&&(n=!0),this.line_char_count--;else{if(n){if(this.line_char_count>=this.max_char){t.push("\n");for(var r=0;r<this.indent_level;r++)t.push(this.indent_string);this.line_char_count=0}else t.push(" "),this.line_char_count++;n=!1}t.push(e)}}return t.length?t.join(""):""},this.get_contents_to=function(e){if(this.pos==this.input.length)return["","TK_EOF"];var t="",n=new RegExp("</"+e+"\\s*>","igm");n.lastIndex=this.pos;var r=n.exec(this.input),i=r?r.index:this.input.length;return this.pos<i&&(t=this.input.substring(this.pos,i),this.pos=i),t},this.record_tag=function(e){this.tags[e+"count"]?(this.tags[e+"count"]++,this.tags[e+this.tags[e+"count"]]=this.indent_level):(this.tags[e+"count"]=1,this.tags[e+this.tags[e+"count"]]=this.indent_level),this.tags[e+this.tags[e+"count"]+"parent"]=this.tags.parent,this.tags.parent=e+this.tags[e+"count"]},this.retrieve_tag=function(e){if(this.tags[e+"count"]){for(var t=this.tags.parent;t&&e+this.tags[e+"count"]!==t;)t=this.tags[t+"parent"];t&&(this.indent_level=this.tags[e+this.tags[e+"count"]],this.tags.parent=this.tags[t+"parent"]),delete this.tags[e+this.tags[e+"count"]+"parent"],delete this.tags[e+this.tags[e+"count"]],1==this.tags[e+"count"]?delete this.tags[e+"count"]:this.tags[e+"count"]--}},this.get_tag=function(){var e,t,n="",r=[],i=!1;do{if(this.pos>=this.input.length)return r.length?r.join(""):["","TK_EOF"];n=this.input.charAt(this.pos),this.pos++,this.line_char_count++,this.Utils.in_array(n,this.Utils.whitespace)?(i=!0,this.line_char_count--):("'"!==n&&'"'!==n||r[1]&&"!"===r[1]||(n+=this.get_unformatted(n),i=!0),"="===n&&(i=!1),r.length&&"="!==r[r.length-1]&&">"!==n&&i&&(this.line_char_count>=this.max_char?(this.print_newline(!1,r),this.line_char_count=0):(r.push(" "),this.line_char_count++),i=!1),"<"===n&&(e=this.pos-1),r.push(n))}while(">"!==n);var o,a=r.join("");o=-1!=a.indexOf(" ")?a.indexOf(" "):a.indexOf(">");var s=a.substring(1,o).toLowerCase();if("/"===a.charAt(a.length-2)||this.Utils.in_array(s,this.Utils.single_token))this.tag_type="SINGLE";else if("script"===s)this.record_tag(s),this.tag_type="SCRIPT";else if("style"===s)this.record_tag(s),this.tag_type="STYLE";else if(this.Utils.in_array(s,l)){var c=this.get_unformatted("</"+s+">",a);r.push(c),e>0&&this.Utils.in_array(this.input.charAt(e-1),this.Utils.whitespace)&&r.splice(0,0,this.input.charAt(e-1)),t=this.pos-1,this.Utils.in_array(this.input.charAt(t+1),this.Utils.whitespace)&&r.push(this.input.charAt(t+1)),this.tag_type="SINGLE"}else"!"===s.charAt(0)?-1!=s.indexOf("[if")?(-1!=a.indexOf("!IE")&&(c=this.get_unformatted("--\x3e",a),r.push(c)),this.tag_type="START"):-1!=s.indexOf("[endif")?(this.tag_type="END",this.unindent()):-1!=s.indexOf("[cdata[")?(c=this.get_unformatted("]]>",a),r.push(c),this.tag_type="SINGLE"):(c=this.get_unformatted("--\x3e",a),r.push(c),this.tag_type="SINGLE"):("/"===s.charAt(0)?(this.retrieve_tag(s.substring(1)),this.tag_type="END"):(this.record_tag(s),this.tag_type="START"),this.Utils.in_array(s,this.Utils.extra_liners)&&this.print_newline(!0,this.output));return r.join("")},this.get_unformatted=function(e,t){if(t&&-1!=t.toLowerCase().indexOf(e))return"";var n="",r="",i=!0;do{if(this.pos>=this.input.length)return r;if(n=this.input.charAt(this.pos),this.pos++,this.Utils.in_array(n,this.Utils.whitespace)){if(!i){this.line_char_count--;continue}if("\n"===n||"\r"===n){r+="\n",this.line_char_count=0;continue}}r+=n,this.line_char_count++,i=!0}while(-1==r.toLowerCase().indexOf(e));return r},this.get_token=function(){var e;if("TK_TAG_SCRIPT"===this.last_token||"TK_TAG_STYLE"===this.last_token){var t=this.last_token.substr(7);return"string"!=typeof(e=this.get_contents_to(t))?e:[e,"TK_"+t]}return"CONTENT"===this.current_mode?"string"!=typeof(e=this.get_content())?e:[e,"TK_CONTENT"]:"TAG"===this.current_mode?"string"!=typeof(e=this.get_tag())?e:[e,"TK_TAG_"+this.tag_type]:void 0},this.get_full_indent=function(e){return(e=this.indent_level+e||0)<1?"":Array(e+1).join(this.indent_string)},this.printer=function(e,t,n,r,i){this.input=e||"",this.output=[],this.indent_character=t,this.indent_string="",this.indent_size=n,this.brace_style=i,this.indent_level=0,this.max_char=r,this.line_char_count=0;for(var o=0;o<this.indent_size;o++)this.indent_string+=this.indent_character;this.print_newline=function(e,t){if(this.line_char_count=0,t&&t.length){if(!e)for(;this.Utils.in_array(t[t.length-1],this.Utils.whitespace);)t.pop();t.push("\n");for(var n=0;n<this.indent_level;n++)t.push(this.indent_string)}},this.print_token=function(e){this.output.push(e)},this.indent=function(){this.indent_level++},this.unindent=function(){this.indent_level>0&&this.indent_level--}},this},n.printer(e,i,r,o,a);;){var s=n.get_token();if(n.token_text=s[0],n.token_type=s[1],"TK_EOF"===n.token_type)break;switch(n.token_type){case"TK_TAG_START":n.print_newline(!1,n.output),n.print_token(n.token_text),n.indent(),n.current_mode="CONTENT";break;case"TK_TAG_STYLE":case"TK_TAG_SCRIPT":n.print_newline(!1,n.output),n.print_token(n.token_text),n.current_mode="CONTENT";break;case"TK_TAG_END":if("TK_CONTENT"===n.last_token&&""===n.last_text){var c=n.token_text.match(/\w+/)[0],u=n.output[n.output.length-1].match(/<\s*(\w+)/);null!==u&&u[1]===c||n.print_newline(!0,n.output)}n.print_token(n.token_text),n.current_mode="CONTENT";break;case"TK_TAG_SINGLE":var d=n.token_text.match(/^\s*<([a-z]+)/i);d&&n.Utils.in_array(d[1],l)||n.print_newline(!1,n.output),n.print_token(n.token_text),n.current_mode="CONTENT";break;case"TK_CONTENT":""!==n.token_text&&n.print_token(n.token_text),n.current_mode="TAG";break;case"TK_STYLE":case"TK_SCRIPT":if(""!==n.token_text){n.output.push("\n");var f=n.token_text;if("TK_SCRIPT"==n.token_type)var h="function"==typeof js_beautify&&js_beautify;else"TK_STYLE"==n.token_type&&(h="function"==typeof css_beautify&&css_beautify);if("keep"==t.indent_scripts)var p=0;else p="separate"==t.indent_scripts?-n.indent_level:1;var m=n.get_full_indent(p);if(h)f=h(f.replace(/^\s*/,m),t);else{var g=f.match(/^\s*/)[0].match(/[^\n\r]*$/)[0].split(n.indent_string).length-1,v=n.get_full_indent(p-g);f=f.replace(/^\s*/,m).replace(/\r\n|\r|\n/g,"\n"+v).replace(/\s*$/,"")}f&&(n.print_token(f),n.print_newline(!0,n.output))}n.current_mode="TAG"}n.last_token=n.token_type,n.last_text=n.token_text}return n.output.join("")}}},8995(e,t,n){"use strict";var r=n(7165),i=n(5178);e.exports=function(e,...t){var n=i(e,t);return null==n.attrs&&(n.attrs={}),n.tag="[",n.children=r.normalizeChildren(n.children),n}},9665(e,t,n){"use strict";var r=n(7165);e.exports=function(e){return null==e&&(e=""),r("<",void 0,void 0,e,void 0,void 0)}},9674(e,t,n){"use strict";var r=n(7165);e.exports=function(e,t,n){var i=[],o=!1,a=-1;function l(){for(a=0;a<i.length;a+=2)try{e(i[a],r(i[a+1]),s)}catch(e){n.error(e)}a=-1}function s(){o||(o=!0,t(function(){o=!1,l()}))}return s.sync=l,{mount:function(t,n){if(null!=n&&null==n.view&&"function"!=typeof n)throw new TypeError("m.mount expects a component, not a vnode.");var o=i.indexOf(t);o>=0&&(i.splice(o,2),o<=a&&(a-=2),e(t,[])),null!=n&&(i.push(t,n),e(t,r(n),s))},redraw:s}}},9788(e,t,n){"use strict";var r=n(2965);e.exports=function*(e){var t=e.dom,n=e.domSize,i=r.get(t);if(null!=t)do{var o=t.nextSibling;r.get(t)===i&&(yield t,n--),t=o}while(n)}},9885(e){function t(){this.listeners={}}t.prototype.emit=function(e,t){this.listeners[e]=this.listeners[e]??[],this.listeners[e].forEach(e=>e.apply(null,t))},t.prototype.on=function(e,t){this.listeners[e]=this.listeners[e]??[],this.listeners[e].push(t)},e.exports=t}},t={};function n(r){var i=t[r];if(void 0!==i)return i.exports;var o=t[r]={exports:{}};return e[r].call(o.exports,o,o.exports,n),o.exports}const r=n(2325);n(6154),n(4550),n(5051),n(6423),window.mc4wp.forms=window.mc4wp.forms||{},window.mc4wp.forms.editor=r})(); assets/js/forms.js 0000777 00000014617 15251522663 0010175 0 ustar 00 (()=>{var e={2076(e){var t=/^(?:submit|button|image|reset|file)$/i,n=/^(?:input|select|textarea|keygen)/i,r=/(\[[^\[\]]*\])/g;function i(e,t,n){if(0===t.length)return n;var r=t.shift(),o=r.match(/^\[(.+?)\]$/);if("[]"===r)return e=e||[],Array.isArray(e)?e.push(i(null,t,n)):(e._values=e._values||[],e._values.push(i(null,t,n))),e;if(o){var s=o[1],a=+s;isNaN(a)?(e=e||{})[s]=i(e[s],t,n):(e=e||[])[a]=i(e[a],t,n)}else e[r]=i(e[r],t,n);return e}function o(e,t,n){if(t.match(r))i(e,function(e){var t=[],n=new RegExp(r),i=/^([^\[\]]*)/.exec(e);for(i[1]&&t.push(i[1]);null!==(i=n.exec(e));)t.push(i[1]);return t}(t),n);else{var o=e[t];o?(Array.isArray(o)||(e[t]=[o]),e[t].push(n)):e[t]=n}return e}function s(e,t,n){return n=n.replace(/(\r)?\n/g,"\r\n"),n=(n=encodeURIComponent(n)).replace(/%20/g,"+"),e+(e?"&":"")+encodeURIComponent(t)+"="+n}e.exports=function(e,r){"object"!=typeof r?r={hash:!!r}:void 0===r.hash&&(r.hash=!0);for(var i=r.hash?{}:"",a=r.serializer||(r.hash?o:s),c=e&&e.elements?e.elements:[],l=Object.create(null),u=0;u<c.length;++u){var f=c[u];if((r.disabled||!f.disabled)&&f.name&&n.test(f.nodeName)&&!t.test(f.type)){var d=f.name,h=f.value;if("checkbox"!==f.type&&"radio"!==f.type||f.checked||(h=void 0),r.empty){if("checkbox"!==f.type||f.checked||(h=""),"radio"===f.type&&(l[f.name]||f.checked?f.checked&&(l[f.name]=!0):l[f.name]=!1),null==h&&"radio"==f.type)continue}else if(!h)continue;if("select-multiple"!==f.type)i=a(i,d,h);else{h=[];for(var p=f.options,m=!1,g=0;g<p.length;++g){var y=p[g],v=r.empty&&!y.value,w=y.value||v;y.selected&&w&&(m=!0,i=r.hash&&"[]"!==d.slice(d.length-2)?a(i,d+"[]",y.value):a(i,d,y.value))}!m&&r.empty&&(i=a(i,d,""))}}}if(r.empty)for(var d in l)l[d]||(i=a(i,d,""));return i}},5626(){function e(e){const t=!!e.getAttribute("data-show-if"),n=t?e.getAttribute("data-show-if").split(":"):e.getAttribute("data-hide-if").split(":"),r=n[0],i=(n.length>1?n[1]:"*").split("|"),o=function(e,t){const n=[],r=e.querySelectorAll('input[name="'+t+'"],select[name="'+t+'"],textarea[name="'+t+'"]');for(let e=0;e<r.length;e++)("radio"!==r[e].type&&"checkbox"!==r[e].type||r[e].checked)&&n.push(r[e].value);return n}(function(e){let t=e;for(;t.parentElement;)if(t=t.parentElement,"FORM"===t.tagName)return t;return null}(e),r);let s=!1;for(let e=0;e<o.length&&!s;e++)s=i.indexOf(o[e])>-1||i.indexOf("*")>-1&&o[e].length>0;e.style.display=t?s?"":"none":s?"none":"";const a=e.querySelectorAll("input,select,textarea");for(let e=0;e<a.length;e++)(s||t)&&a[e].getAttribute("data-was-required")&&(a[e].required=!0,a[e].removeAttribute("data-was-required")),s&&t||!a[e].required||(a[e].setAttribute("data-was-required","true"),a[e].required=!1)}function t(){const t=document.querySelectorAll(".mc4wp-form [data-show-if],.mc4wp-form [data-hide-if]");for(let n=0;n<t.length;n++)e(t[n])}function n(t){if(!t.target||!t.target.form||t.target.form.className.indexOf("mc4wp-form")<0)return;const n=t.target.form.querySelectorAll("[data-show-if],[data-hide-if]");for(let t=0;t<n.length;t++)e(n[t])}document.addEventListener("keyup",n,!0),document.addEventListener("change",n,!0),document.addEventListener("mc4wp-refresh",t,!0),window.addEventListener("load",t),t()},6564(e){e.exports&&(e.exports=function e(t,n,r){for(const i in n){if(!n.hasOwnProperty(i))continue;const o=i;let s=n[i];if(void 0===s&&(s=""),null===s&&(s=""),void 0!==r&&(o=r+"["+i+"]"),s.constructor===Array)o+="[]";else if("object"==typeof s){e(t,s,o);continue}const a=t.elements.namedItem(o);if(!a)continue;const c=a.type||a[0].type;switch(c){default:a.value=s;break;case"radio":case"checkbox":{const e=s.constructor===Array?s:[s];for(let t=0;t<a.length;t++)a[t].checked=e.indexOf(a[t].value)>-1}break;case"select-multiple":{const e=s.constructor===Array?s:[s];for(let t=0;t<a.options.length;t++)a.options[t].selected=e.indexOf(a.options[t].value)>-1}break;case"select":case"select-one":a.value=s.toString()||s;break;case"date":a.value=new Date(s).toISOString().split("T")[0]}const l=new Event("change",{bubbles:!0});switch(c){default:a.dispatchEvent(l);break;case"radio":case"checkbox":for(let e=0;e<a.length;e++)a[e].checked&&a[e].dispatchEvent(l)}}})},6942(e,t,n){const r=n(2076),i=n(6564),o=function(e,t){this.id=e,this.element=t||document.createElement("form"),this.name=this.element.getAttribute("data-name")||"Form #"+this.id,this.errors=[],this.started=!1};o.prototype.setData=function(e){try{i(this.element,e)}catch(e){console.error(e)}},o.prototype.getData=function(){return r(this.element,{hash:!0,empty:!0})},o.prototype.getSerializedData=function(){return r(this.element,{hash:!1,empty:!0})},o.prototype.setResponse=function(e){this.element.querySelector(".mc4wp-response").innerHTML=e},o.prototype.reset=function(){this.setResponse(""),this.element.querySelector(".mc4wp-form-fields").style.display="",this.element.reset()},e.exports=o},9685(e,t,n){const r=n(6942),i=[],o=new(n(9885));function s(e,t){t=t||parseInt(e.getAttribute("data-id"))||0;const n=new r(t,e);return i.push(n),n}e.exports={get:function(e){e=parseInt(e);for(let t=0;t<i.length;t++)if(i[t].id===e)return i[t];return s(document.querySelector(".mc4wp-form-"+e),e)},getByElement:function(e){const t=e.form||e;for(let e=0;e<i.length;e++)if(i[e].element===t)return i[e];return s(t)},on:function(e,t){o.on(e,t)},trigger:function(e,t){"submit"===e||e.indexOf(".submit")>0?(o.emit(t[0].id+"."+e,t),o.emit(e,t)):window.setTimeout(function(){o.emit(t[0].id+"."+e,t),o.emit(e,t)},10)}}},9885(e){function t(){this.listeners={}}t.prototype.emit=function(e,t){this.listeners[e]=this.listeners[e]??[],this.listeners[e].forEach(e=>e.apply(null,t))},t.prototype.on=function(e,t){this.listeners[e]=this.listeners[e]??[],this.listeners[e].push(t)},e.exports=t}},t={};function n(r){var i=t[r];if(void 0!==i)return i.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,n),o.exports}const r=window.mc4wp||{},i=n(9685);function o(e,t){document.addEventListener(e,e=>{if(!e.target)return;const n=e.target;("string"==typeof n.className&&n.className.indexOf("mc4wp-form")>-1||"function"==typeof n.matches&&n.matches(".mc4wp-form *"))&&t.call(e,e)},!0)}n(5626),o("submit",function(e){if(e.defaultPrevented)return;const t=i.getByElement(e.target);i.trigger("submit",[t,e])}),o("focus",function(e){const t=i.getByElement(e.target);t.started||(i.trigger("started",[t,e]),t.started=!0)}),o("change",function(e){const t=i.getByElement(e.target);i.trigger("change",[t,e])}),r.listeners&&([].forEach.call(r.listeners,function(e){i.on(e.event,e.callback)}),delete r.listeners),r.forms=i,window.mc4wp=r})(); assets/js/email-typo-checker.js 0000777 00000004233 15251522663 0012522 0 ustar 00 (()=>{const e=window.mc4wp_email_typo_checker&&window.mc4wp_email_typo_checker.domains?window.mc4wp_email_typo_checker.domains:[];function t(e,t){if(e===t)return 0;if(e.length>t.length){const n=e;e=t,t=n}let o=e.length,c=t.length;for(;o>0&&e.charCodeAt(o-1)===t.charCodeAt(c-1);)o--,c--;let r=0;for(;r<o&&e.charCodeAt(r)===t.charCodeAt(r);)r++;if(o-=r,c-=r,0===o||c<3)return c;let i,l,u,a,s,d,f,h,m,p,w,_,g=0;const C=[];for(i=0;i<o;i++)C.push(i+1),C.push(e.charCodeAt(r+i));const y=C.length-1;for(;g<c-3;)for(m=t.charCodeAt(r+(l=g)),p=t.charCodeAt(r+(u=g+1)),w=t.charCodeAt(r+(a=g+2)),_=t.charCodeAt(r+(s=g+3)),d=g+=4,i=0;i<y;i+=2)f=C[i],h=C[i+1],l=n(f,l,u,m,h),u=n(l,u,a,p,h),a=n(u,a,s,w,h),d=n(a,s,d,_,h),C[i]=d,s=a,a=u,u=l,l=f;for(;g<c;)for(m=t.charCodeAt(r+(l=g)),d=++g,i=0;i<y;i+=2)f=C[i],C[i]=d=n(f,l,d,m,C[i+1]),l=f;return d}function n(e,t,n,o,c){return e<t||n<t?e>n?n+1:e+1:o===c?t:t+1}function o(e){const t=e.parentElement.querySelector(".mc4wp-email-suggestion");t&&t.remove()}function c(n){const c=n.value.trim();if(o(n),!c||-1===c.indexOf("@"))return;const r=function(e){const t=e.split("@");return 2===t.length?t[1]:null}(c);if(!r)return;const i=function(n){if(!n)return null;const o=n.toLowerCase();let c=1/0,r=null;if(e.includes(o))return null;for(let n=0;n<e.length;n++){const i=e[n],l=t(o,i);l>0&&l<=2&&l<c&&(c=l,r=i)}return r}(r);if(i){const e=function(e,t){const n=document.createElement("div");n.className="mc4wp-email-suggestion";const c=document.createElement("a");c.setAttribute("href","#");const r=window.mc4wp_email_typo_checker&&window.mc4wp_email_typo_checker.suggestion_text?window.mc4wp_email_typo_checker.suggestion_text:"Did you mean %s?";return c.textContent=r.replace("%s",e),c.addEventListener("click",function(n){n.preventDefault(),t.value=e,o(t);const c=new Event("change",{bubbles:!0});t.dispatchEvent(c)}),n.appendChild(c),n}(c.split("@")[0]+"@"+i,n);n.after(e)}}function r(e){e.querySelectorAll('input[type="email"]').forEach(function(e){e.addEventListener("keyup",function(){c(e)}),e.addEventListener("blur",function(){c(e)})})}document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll('.mc4wp-form[data-typo-check="1"]').forEach(r)})})(); assets/js/integrations-admin.js 0000777 00000001041 15251522663 0012626 0 ustar 00 (()=>{const e=window.mc4wp_vars.ajaxurl,t=window.mc4wp.settings,n=document.getElementById("notice-additional-fields");function i(){const t=[].filter.call(document.querySelectorAll(".mc4wp-list-input"),e=>e.checked).map(e=>e.value).join(","),i=["EMAIL","FNAME","NAME","LNAME"];let l=!1;window.fetch(`${e}?action=mc4wp_get_list_details&ids=${t}`).then(e=>e.json()).then(e=>{e.forEach(e=>{e.merge_fields.forEach(e=>{e.required&&i.indexOf(e.tag)<0&&(l=!0)})})}).finally(()=>{n.style.display=l?"":"none"})}n&&(i(),t.on("selectedLists.change",i))})(); assets/js/forms-submitted.js 0000777 00000002556 15251522663 0012172 0 ustar 00 (()=>{var e={1419(e){e.exports=function(e){const t=window.pageXOffset||document.documentElement.scrollLeft,o=function(e){const t=document.body,o=document.documentElement,n=e.getBoundingClientRect(),r=o.clientHeight,i=Math.max(t.scrollHeight,t.offsetHeight,o.clientHeight,o.scrollHeight,o.offsetHeight),c=n.bottom-r/2-n.height/2,s=i-r;return Math.min(c+window.pageYOffset,s)}(e);window.scrollTo(t,o)}}},t={};function o(n){var r=t[n];if(void 0!==r)return r.exports;var i=t[n]={exports:{}};return e[n](i,i.exports,o),i.exports}o.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},o.d=(e,t)=>{for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{"use strict";var e=o(1419),t=o.n(e);const n=window.mc4wp_submitted_form,r=window.mc4wp.forms;if(n){const e=document.getElementById(n.element_id);!function(e,o,i,c){const s=Date.now(),d=document.body.clientHeight;i&&e.setData(c),window.scrollY<=10&&n.auto_scroll&&t()(e.element),window.addEventListener("load",function(){r.trigger("submitted",[e]),i?r.trigger("error",[e,i]):(r.trigger("success",[e,c]),r.trigger(o,[e,c]),"updated_subscriber"===o&&r.trigger("subscribed",[e,c,!0]));const l=Date.now()-s;n.auto_scroll&&l>1e3&&l<2e3&&document.body.clientHeight!==d&&t()(e.element)})}(r.getByElement(e),n.event,n.errors,n.data)}})()})(); assets/css/admin.css 0000777 00000024736 15251522663 0010472 0 ustar 00 #mc4wp-admin .main-content{width:100%}.mc4wp-row{display:flex}.mc4wp-col{padding:0 1em}.mc4wp-col-1{width:16.666%}.mc4wp-col-2{width:33.333%}.mc4wp-col-3{width:50%}.mc4wp-col-4{width:66.666%}.mc4wp-col-5{width:83.333%}.mc4wp-col-6{width:100%}.mc4wp-tab{display:none}.mc4wp-tab-active{display:block}.mc4wp-tab h2{margin-top:20px}.mc4wp-status{color:#fff;margin-left:1em;padding:3px 6px;font-weight:700;display:inline-block}.mc4wp-status.positive{background-color:#32cd32}.mc4wp-status.negative{background-color:red}.mc4wp-status.neutral{background:gray}.mc4wp-margin-l{margin-top:60px;margin-bottom:60px}.mc4wp-margin-m{margin-top:40px;margin-bottom:40px}.mc4wp-margin-s{margin-top:20px;margin-bottom:20px}.mc4wp-green{color:green}.mc4wp-red{color:red}.mc4wp-breadcrumbs{border-bottom:1px solid #ddd;padding-bottom:1em}.CodeMirror{border:1px solid #ddd;min-height:500px;padding:0 4px;font-weight:400}.CodeMirror-empty{color:#999}.dashicons{vertical-align:middle}#mc4wp-add-form-field h3{border-bottom:1px solid #ddd;margin-top:0;margin-bottom:12px;padding-bottom:12px}#mc4wp-add-form-field table{table-layout:fixed;border-collapse:collapse;border-spacing:0}#mc4wp-add-form-field code{margin-left:1em}#mc4wp-add-form-field label{display:block}#mc4wp-add-form-field tr,#mc4wp-add-form-field td{vertical-align:middle}#mc4wp-add-form-field .stretch{width:100%}#mc4wp-add-form-field .cb-wrap{font-weight:400}#mc4wp-add-form-field .cb-wrap input{margin-right:6px}#mc4wp-add-form-field .limit-height{border:1px solid #ddd;max-height:200px;padding:6px;overflow-y:scroll}#mc4wp-available-fields{background:#fff;border:1px solid #ddd;padding:20px}#mc4wp-available-fields .button{margin-bottom:.5em;margin-right:.5em}#mc4wp-available-fields .is-required:after{content:" *";color:red}#mc4wp-available-fields .is-required.not-in-form{-webkit-box-shadow:0 0 3px 1px red;-moz-box-shadow:0 0 3px 1px red;box-shadow:0 0 3px 1px red}#mc4wp-available-fields .in-form{opacity:.5}.mc4wp-form-editor-wrap{padding-right:0!important}.mc4wp-form-preview-wrap{margin-top:1em;padding-left:0!important}#mc4wp-form-preview{border:1px solid #ddd;width:100%;height:500px}.mc4wp-sidebar{border-left:1px solid #ddd;display:none}.mc4wp-sidebar h3,.mc4wp-sidebar h4{margin-bottom:0;font-size:16px}.mc4wp-box{border-bottom:1px solid #ddd;margin-bottom:20px;padding-bottom:20px}.mc4wp-box h3,.mc4wp-box h4{margin-top:0}.mc4wp-box:last-of-type{border-bottom:0}.mc4wp-page-title{background:url(../img/logo-white-on-red.svg) 0/32px no-repeat;padding-left:42px!important;line-height:32px!important}.rtl #mc4wp-page-title{background-position:100%;padding-left:0;padding-right:42px}.rtl .CodeMirror-scroll{overflow-y:hidden!important}.rtl .CodeMirror-vscrollbar{left:0!important;right:auto!important}.rtl .mc4wp-overlay .close{left:0;right:auto}.rtl .mc4wp-is-dismissible{padding-left:38px;padding-right:initial;position:relative}.mc4wp-overlay{z-index:99999;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;background:#fefefe;border:1px solid #ddd;width:100%;max-width:480px;max-height:100%;padding:20px;position:fixed;top:0;left:0;overflow-y:scroll}.mc4wp-overlay .close{cursor:pointer;opacity:.5;padding:10px;font-size:24px;position:absolute;top:0;right:0}.mc4wp-overlay .close:hover,.mc4wp-overlay .close:focus{opacity:1}.mc4wp-overlay-background{z-index:99998;background:#000000ab;position:fixed;inset:0}.hover-activated{opacity:.5}.hover-activated:hover{cursor:pointer;opacity:1}.mc4wp-notice{color:#31708f;background:#d9edf7;border:1px solid #bce8f1;padding:6px 12px;margin:1em 0!important}.mc4wp-is-dismissible{padding-right:38px;position:relative}.column-ID{width:10%}.mc4wp-log{resize:vertical;color:#fff;background:#262626;border:1px solid #ddd;height:200px;padding:6px;font-family:monaco,monospace,courier,courier new,Bitstream Vera Sans Mono;font-size:13px;line-height:140%;overflow-y:scroll}.mc4wp-log .time{color:#b58900}.mc4wp-log .level{color:#35aecd}.mc4wp-log .debug-log-empty{color:#ddd;font-style:italic}.mc4wp-log .hidden{display:none}.mc4wp-log a{color:#ddd;text-decoration:underline}.mc4wp-loader{text-indent:-10000000px;vertical-align:middle;border:3px solid #0003;border-left-color:#000;border-radius:50%;width:12px;height:12px;margin-bottom:3px;margin-left:3px;margin-right:3px;-webkit-animation:1.1s linear infinite load8;animation:1.1s linear infinite load8;display:inline-block;position:relative;overflow:hidden;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}@media (width>=1260px){.mc4wp-sidebar{width:33.333%;display:block}#mc4wp-admin .main-content{width:66.666%}.mc4wp-form-markup-wrap{display:flex}.mc4wp-form-editor-wrap,.mc4wp-form-preview-wrap{width:50%;margin-top:0}#mc4wp-form-preview{border-left:0}}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.CodeMirror{color:#000;direction:ltr;height:300px;font-family:monospace}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler{background-color:#fff}.CodeMirror-gutters{white-space:nowrap;background-color:#f7f7f7;border-right:1px solid #ddd}.CodeMirror-linenumber{text-align:right;color:#999;white-space:nowrap;min-width:20px;padding:0 3px 0 5px}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{background:#7e7;width:auto;border:0!important}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor-mark{background-color:#14ff1480;-webkit-animation:1.06s step-end infinite blink;-moz-animation:1.06s step-end infinite blink;animation:1.06s step-end infinite blink}.cm-animate-fat-cursor{background-color:#7e7;border:0;width:auto;-webkit-animation:1.06s step-end infinite blink;-moz-animation:1.06s step-end infinite blink;animation:1.06s step-end infinite blink}@-webkit-keyframes blink{0%{}50%{background-color:#0000}to{}}@-moz-keyframes blink{0%{}50%{background-color:#0000}to{}}@keyframes blink{0%{}50%{background-color:#0000}to{}}.cm-tab{text-decoration:inherit;display:inline-block}.CodeMirror-rulers{position:absolute;inset:-50px 0 -20px;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ddd;position:absolute;top:0;bottom:0}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3,.cm-s-default .cm-type{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error,.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:#ff96004d}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{background:#fff;position:relative;overflow:hidden}.CodeMirror-scroll{outline:none;height:100%;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;position:relative;overflow:scroll!important}.CodeMirror-sizer{border-right:30px solid #0000;position:relative}.CodeMirror-vscrollbar,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-gutter-filler{z-index:6;display:none;position:absolute}.CodeMirror-vscrollbar{top:0;right:0;overflow:hidden scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow:scroll hidden}.CodeMirror-scrollbar-filler{bottom:0;right:0}.CodeMirror-gutter-filler{bottom:0;left:0}.CodeMirror-gutters{z-index:3;min-height:100%;position:absolute;top:0;left:0}.CodeMirror-gutter{white-space:normal;vertical-align:top;height:100%;margin-bottom:-30px;display:inline-block}.CodeMirror-gutter-wrapper{z-index:4;position:absolute;background:0 0!important;border:none!important}.CodeMirror-gutter-background{z-index:4;position:absolute;top:0;bottom:0}.CodeMirror-gutter-elt{cursor:default;z-index:4;position:absolute}.CodeMirror-gutter-wrapper ::selection{background-color:#0000}.CodeMirror-gutter-wrapper ::selection{background-color:#0000}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{font-family:inherit;font-size:inherit;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual;background:0 0;border-width:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;margin:0;position:relative;overflow:visible}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{z-index:0;position:absolute;inset:0}.CodeMirror-linewidget{z-index:2;padding:.1px;position:relative}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:none}.CodeMirror-scroll,.CodeMirror-sizer,.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{visibility:hidden;width:100%;height:0;position:absolute;overflow:hidden}.CodeMirror-cursor{pointer-events:none;position:absolute}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;z-index:3;position:relative}div.CodeMirror-dragcursors,.CodeMirror-focused div.CodeMirror-cursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.cm-searching{background-color:#ff06}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:""}span.CodeMirror-selectedtext{background:0 0} assets/css/form-themes.css 0000777 00000015123 15251522663 0011616 0 ustar 00 .mc4wp-form input[name^=_mc4wp_honey]{display:none!important}.mc4wp-form-theme{margin:1em 0}.mc4wp-form-theme label,.mc4wp-form-theme input{box-sizing:border-box;cursor:auto;vertical-align:baseline;width:auto;height:auto;line-height:normal;display:block}.mc4wp-form-theme label:after,.mc4wp-form-theme input:after{content:"";clear:both;display:table}.mc4wp-form-theme label{margin-bottom:6px;font-weight:700;display:block}.mc4wp-form-theme input[type=text],.mc4wp-form-theme input[type=email],.mc4wp-form-theme input[type=tel],.mc4wp-form-theme input[type=url],.mc4wp-form-theme input[type=date],.mc4wp-form-theme textarea,.mc4wp-form-theme select{vertical-align:middle;width:100%;max-width:480px;height:auto;min-height:32px;text-shadow:none;background:#fff;border:1px solid #ccc;border-radius:2px;outline:0;padding:8px 16px;line-height:1.42857;color:#555!important}.mc4wp-form-theme textarea{height:auto}.mc4wp-form-theme input[readonly],.mc4wp-form-theme input[disabled]{background-color:#eee}.mc4wp-form-theme input[type=number]{min-width:40px}.mc4wp-form-theme input[type=checkbox],.mc4wp-form-theme input[type=radio]{border:0;width:13px;height:13px;margin:0 6px 0 0;padding:0;display:inline-block;position:relative}.mc4wp-form-theme input[type=checkbox]{-webkit-appearance:checkbox;-moz-appearance:checkbox;appearance:checkbox}.mc4wp-form-theme input[type=radio]{-webkit-appearance:radio;-moz-appearance:radio;appearance:radio}.mc4wp-form-theme button,.mc4wp-form-theme input[type=submit],.mc4wp-form-theme input[type=button]{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;text-align:center;white-space:nowrap;vertical-align:middle;user-select:none;text-shadow:none;filter:none;background:0 0;border:1px solid #0000;border-radius:2px;width:auto;height:auto;padding:8px 16px;font-weight:400;line-height:1.42857;display:inline-block}.mc4wp-form-theme button:hover,.mc4wp-form-theme input[type=submit]:hover,.mc4wp-form-theme input[type=button]:hover,.mc4wp-form-theme button:focus,.mc4wp-form-theme input[type=submit]:focus,.mc4wp-form-theme input[type=button]:focus{color:#333;background:0 0;outline:0;text-decoration:none}.mc4wp-form-theme label>span,.mc4wp-form-theme li>label{font-weight:400}.mc4wp-alert{color:#c09853;clear:both}.mc4wp-success{color:#468847}.mc4wp-notice{color:#3a87ad}.mc4wp-error{color:#cd5c5c}.rtl .mc4wp-form-theme input[type=checkbox],.rtl .mc4wp-form-theme input[type=radio]{margin:0 0 0 6px}.mc4wp-form-theme-dark button,.mc4wp-form-theme-dark input[type=submit],.mc4wp-form-theme-dark input[type=button]{border-color:#1e1e1e;color:#fff!important;background-color:#444!important}.mc4wp-form-theme-dark button:hover,.mc4wp-form-theme-dark input[type=submit]:hover,.mc4wp-form-theme-dark input[type=button]:hover,.mc4wp-form-theme-dark button:focus,.mc4wp-form-theme-dark input[type=submit]:focus,.mc4wp-form-theme-dark input[type=button]:focus{border-color:#000;color:#fff!important;background-color:#1e1e1e!important}.mc4wp-form-theme-dark input[type=text]:focus,.mc4wp-form-theme-dark input[type=email]:focus,.mc4wp-form-theme-dark input[type=tel]:focus,.mc4wp-form-theme-dark input[type=url]:focus,.mc4wp-form-theme-dark input[type=date]:focus,.mc4wp-form-theme-dark textarea:focus,.mc4wp-form-theme-dark select:focus{border-color:#6a6a6a}.mc4wp-form-theme-light button,.mc4wp-form-theme-light input[type=submit],.mc4wp-form-theme-light input[type=button]{border-color:#d9d9d9;color:#000!important;background-color:#fff!important}.mc4wp-form-theme-light button:hover,.mc4wp-form-theme-light input[type=submit]:hover,.mc4wp-form-theme-light input[type=button]:hover,.mc4wp-form-theme-light button:focus,.mc4wp-form-theme-light input[type=submit]:focus,.mc4wp-form-theme-light input[type=button]:focus{border-color:#b3b3b3;color:#000!important;background-color:#d9d9d9!important}.mc4wp-form-theme-light input[type=text]:focus,.mc4wp-form-theme-light input[type=email]:focus,.mc4wp-form-theme-light input[type=tel]:focus,.mc4wp-form-theme-light input[type=url]:focus,.mc4wp-form-theme-light input[type=date]:focus,.mc4wp-form-theme-light textarea:focus,.mc4wp-form-theme-light select:focus{border-color:#d9d9d9}.mc4wp-form-theme-red button,.mc4wp-form-theme-red input[type=submit],.mc4wp-form-theme-red input[type=button]{border-color:#b52b27;color:#fff!important;background-color:#d9534f!important}.mc4wp-form-theme-red button:hover,.mc4wp-form-theme-red input[type=submit]:hover,.mc4wp-form-theme-red input[type=button]:hover,.mc4wp-form-theme-red button:focus,.mc4wp-form-theme-red input[type=submit]:focus,.mc4wp-form-theme-red input[type=button]:focus{border-color:#761c19;color:#fff!important;background-color:#b52b27!important}.mc4wp-form-theme-red input[type=text]:focus,.mc4wp-form-theme-red input[type=email]:focus,.mc4wp-form-theme-red input[type=tel]:focus,.mc4wp-form-theme-red input[type=url]:focus,.mc4wp-form-theme-red input[type=date]:focus,.mc4wp-form-theme-red textarea:focus,.mc4wp-form-theme-red select:focus{border-color:#e7908e}.mc4wp-form-theme-blue button,.mc4wp-form-theme-blue input[type=submit],.mc4wp-form-theme-blue input[type=button]{border-color:#2a6496;color:#fff!important;background-color:#428bca!important}.mc4wp-form-theme-blue button:hover,.mc4wp-form-theme-blue input[type=submit]:hover,.mc4wp-form-theme-blue input[type=button]:hover,.mc4wp-form-theme-blue button:focus,.mc4wp-form-theme-blue input[type=submit]:focus,.mc4wp-form-theme-blue input[type=button]:focus{border-color:#193c5a;color:#fff!important;background-color:#2a6496!important}.mc4wp-form-theme-blue input[type=text]:focus,.mc4wp-form-theme-blue input[type=email]:focus,.mc4wp-form-theme-blue input[type=tel]:focus,.mc4wp-form-theme-blue input[type=url]:focus,.mc4wp-form-theme-blue input[type=date]:focus,.mc4wp-form-theme-blue textarea:focus,.mc4wp-form-theme-blue select:focus{border-color:#7eb0db}.mc4wp-form-theme-green button,.mc4wp-form-theme-green input[type=submit],.mc4wp-form-theme-green input[type=button]{border-color:#3d8b3d;color:#fff!important;background-color:#5cb85c!important}.mc4wp-form-theme-green button:hover,.mc4wp-form-theme-green input[type=submit]:hover,.mc4wp-form-theme-green input[type=button]:hover,.mc4wp-form-theme-green button:focus,.mc4wp-form-theme-green input[type=submit]:focus,.mc4wp-form-theme-green input[type=button]:focus{border-color:#255625;color:#fff!important;background-color:#3d8b3d!important}.mc4wp-form-theme-green input[type=text]:focus,.mc4wp-form-theme-green input[type=email]:focus,.mc4wp-form-theme-green input[type=tel]:focus,.mc4wp-form-theme-green input[type=url]:focus,.mc4wp-form-theme-green input[type=date]:focus,.mc4wp-form-theme-green textarea:focus,.mc4wp-form-theme-green select:focus{border-color:#91cf91} assets/css/form-basic.css 0000777 00000003124 15251522663 0011410 0 ustar 00 .mc4wp-form input[name^=_mc4wp_honey]{display:none!important}.mc4wp-form-basic{margin:1em 0}.mc4wp-form-basic label,.mc4wp-form-basic input{box-sizing:border-box;cursor:auto;vertical-align:baseline;width:auto;height:auto;line-height:normal;display:block}.mc4wp-form-basic label:after,.mc4wp-form-basic input:after{content:"";clear:both;display:table}.mc4wp-form-basic label{margin-bottom:6px;font-weight:700;display:block}.mc4wp-form-basic input[type=text],.mc4wp-form-basic input[type=email],.mc4wp-form-basic input[type=tel],.mc4wp-form-basic input[type=url],.mc4wp-form-basic input[type=date],.mc4wp-form-basic textarea,.mc4wp-form-basic select{width:100%;max-width:480px;min-height:32px}.mc4wp-form-basic input[type=number]{min-width:40px}.mc4wp-form-basic input[type=checkbox],.mc4wp-form-basic input[type=radio]{border:0;width:13px;height:13px;margin:0 6px 0 0;padding:0;display:inline-block;position:relative}.mc4wp-form-basic input[type=checkbox]{-webkit-appearance:checkbox;-moz-appearance:checkbox;appearance:checkbox}.mc4wp-form-basic input[type=radio]{-webkit-appearance:radio;-moz-appearance:radio;appearance:radio}.mc4wp-form-basic input[type=submit],.mc4wp-form-basic button,.mc4wp-form-basic input[type=button]{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;display:inline-block}.mc4wp-form-basic label>span,.mc4wp-form-basic li>label{font-weight:400}.mc4wp-alert{color:#c09853;clear:both}.mc4wp-success{color:#468847}.mc4wp-notice{color:#3a87ad}.mc4wp-error{color:#cd5c5c}.rtl .mc4wp-form-basic input[type=checkbox],.rtl .mc4wp-form-basic input[type=radio]{margin:0 0 0 6px} assets/css/checkbox-reset.css 0000777 00000000643 15251522663 0012277 0 ustar 00 .mc4wp-checkbox-__INTEGRATION_SLUG__{clear:both;width:auto;display:block;position:static}.mc4wp-checkbox-__INTEGRATION_SLUG__ input{float:none;vertical-align:middle;-webkit-appearance:checkbox;width:auto;max-width:21px;margin:0 6px 0 0;padding:0;position:static;display:inline-block!important}.mc4wp-checkbox-__INTEGRATION_SLUG__ label{float:none;cursor:pointer;width:auto;margin:0 0 16px;display:block;position:static} assets/img/icon.svg 0000777 00000004076 15251522663 0010320 0 ustar 00 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" version="1.1"> <g fill="#a0a5aa"> <path opacity="1" fill="#a0a5aa" fill-opacity="1" stroke="none" d="M 8.0097656 0.052734375 A 8 8 0 0 0 0.009765625 8.0527344 A 8 8 0 0 0 8.0097656 16.052734 A 8 8 0 0 0 16.009766 8.0527344 A 8 8 0 0 0 8.0097656 0.052734375 z M 9.2597656 4.171875 C 9.3205456 4.171875 9.9296146 5.0233822 10.611328 6.0664062 C 11.293041 7.1094313 12.296018 8.5331666 12.841797 9.2285156 L 13.833984 10.492188 L 13.316406 11.041016 C 13.031321 11.342334 12.708299 11.587891 12.599609 11.587891 C 12.253798 11.587891 11.266634 10.490156 10.349609 9.0859375 C 9.8610009 8.3377415 9.4126385 7.7229 9.3515625 7.71875 C 9.2904825 7.71455 9.2402344 8.3477011 9.2402344 9.1269531 L 9.2402344 10.544922 L 8.5839844 10.982422 C 8.2233854 11.223015 7.8735746 11.418294 7.8066406 11.417969 C 7.7397106 11.417644 7.4861075 10.997223 7.2421875 10.482422 C 6.9982675 9.9676199 6.6560079 9.3946444 6.4824219 9.2089844 L 6.1679688 8.8710938 L 6.0664062 9.34375 C 5.7203313 10.974656 5.6693219 11.090791 5.0917969 11.505859 C 4.5805569 11.873288 4.2347982 12.017623 4.1914062 11.882812 C 4.1839062 11.859632 4.1482681 11.574497 4.1113281 11.25 C 3.9708341 10.015897 3.5347399 8.7602861 2.8105469 7.5019531 C 2.5672129 7.0791451 2.5711235 7.0651693 2.9765625 6.8320312 C 3.2046215 6.7008903 3.5466561 6.4845105 3.7363281 6.3515625 C 4.0587811 6.1255455 4.1076376 6.1466348 4.4941406 6.6679688 C 4.8138896 7.0992628 4.9275606 7.166285 4.9941406 6.96875 C 5.0960956 6.666263 6.181165 5.8574219 6.484375 5.8574219 C 6.600668 5.8574219 6.8857635 6.1981904 7.1171875 6.6152344 C 7.3486105 7.0322784 7.5790294 7.3728809 7.6308594 7.3730469 C 7.7759584 7.3735219 7.9383234 5.8938023 7.8339844 5.5195312 C 7.7605544 5.2561423 7.8865035 5.0831575 8.4453125 4.6796875 C 8.8327545 4.3999485 9.1989846 4.171875 9.2597656 4.171875 z " id="path5822" /> </g> </svg> assets/img/logo-white-on-red.svg 0000777 00000002045 15251522663 0012622 0 ustar 00 <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"><circle cx="32" cy="32" r="32" style="opacity:1;fill:#c44;fill-opacity:1;stroke:none;stroke-opacity:1"/><path d="M16 47.325c-.03-.093-.175-1.23-.323-2.529-.562-4.936-2.305-9.96-5.202-14.994-.973-1.692-.959-1.751.663-2.684a48.828 48.828 0 0 0 3.038-1.92c1.29-.904 1.487-.822 3.033 1.263 1.28 1.725 1.732 1.999 1.998 1.209.408-1.21 4.748-4.45 5.961-4.45.465 0 1.603 1.364 2.529 3.032.926 1.669 1.853 3.034 2.06 3.035.58.002 1.226-5.916.808-7.413-.293-1.054.213-1.75 2.448-3.363 1.55-1.119 3.016-2.034 3.26-2.034.243 0 2.673 3.413 5.4 7.585 2.726 4.172 6.744 9.862 8.927 12.643l3.969 5.057-2.073 2.191c-1.14 1.206-2.43 2.192-2.864 2.192-1.383 0-5.331-4.39-9-10.007-1.954-2.993-3.753-5.455-3.997-5.471-.244-.017-.444 2.52-.444 5.637v5.667l-2.623 1.75c-1.442.962-2.841 1.748-3.109 1.747-.268-.001-1.285-1.687-2.26-3.746-.976-2.06-2.343-4.352-3.037-5.094l-1.263-1.35-.401 1.893c-1.385 6.524-1.593 6.986-3.904 8.646-2.045 1.47-3.42 2.047-3.594 1.508Z" style="fill:#fff;fill-opacity:1;stroke:none"/></svg> assets/img/logo-red-on-white.svg 0000777 00000002045 15251522663 0012622 0 ustar 00 <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"><circle cx="32" cy="32" r="32" style="opacity:1;fill:#fff;fill-opacity:1;stroke:none;stroke-opacity:1"/><path d="M16 47.325c-.03-.093-.175-1.23-.323-2.529-.562-4.936-2.305-9.96-5.202-14.994-.973-1.692-.959-1.751.663-2.684a48.828 48.828 0 0 0 3.038-1.92c1.29-.904 1.487-.822 3.033 1.263 1.28 1.725 1.732 1.999 1.998 1.209.408-1.21 4.748-4.45 5.961-4.45.465 0 1.603 1.364 2.529 3.032.926 1.669 1.853 3.034 2.06 3.035.58.002 1.226-5.916.808-7.413-.293-1.054.213-1.75 2.448-3.363 1.55-1.119 3.016-2.034 3.26-2.034.243 0 2.673 3.413 5.4 7.585 2.726 4.172 6.744 9.862 8.927 12.643l3.969 5.057-2.073 2.191c-1.14 1.206-2.43 2.192-2.864 2.192-1.383 0-5.331-4.39-9-10.007-1.954-2.993-3.753-5.455-3.997-5.471-.244-.017-.444 2.52-.444 5.637v5.667l-2.623 1.75c-1.442.962-2.841 1.748-3.109 1.747-.268-.001-1.285-1.687-2.26-3.746-.976-2.06-2.343-4.352-3.037-5.094l-1.263-1.35-.401 1.893c-1.385 6.524-1.593 6.986-3.904 8.646-2.045 1.47-3.42 2.047-3.594 1.508Z" style="fill:#c44;fill-opacity:1;stroke:none"/></svg> uninstall.php 0000777 00000001043 15251522663 0007302 0 ustar 00 <?php // if uninstall.php is not called by WordPress, die if (!defined('WP_UNINSTALL_PLUGIN')) { die; } global $wpdb; // Delete all MC4WP related options and transients $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name = 'mc4wp' OR option_name LIKE 'mc4wp_%' OR option_name LIKE '_transient_mc4wp_%' OR option_name LIKE '_transient_timeout_mc4wp_%';"); // Delete all MC4WP forms + settings $wpdb->query("DELETE p, pm FROM {$wpdb->posts} p LEFT JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID WHERE p.post_type = 'mc4wp-form';"); readme.txt 0000777 00000120752 15251522663 0006567 0 ustar 00 === MC4WP: Mailchimp for WordPress === Contributors: Ibericode, DvanKooten, hchouhan, lapzor Donate link: https://www.mc4wp.com/contribute/#utm_source=wp-plugin-repo&utm_medium=mailchimp-for-wp&utm_campaign=donate-link Tags: mailchimp, subscribe, email, newsletter, form Requires at least: 4.6 Tested up to: 6.9 Stable tag: 4.11.1 License: GPL-3.0-or-later License URI: http://www.gnu.org/licenses/gpl-3.0.html Requires PHP: 7.4 The #1 Mailchimp plugin for WordPress. Allows you to add a multitude of newsletter sign-up methods to your site. == Description == *Allowing your visitors to subscribe to your newsletter should be easy. With this plugin, it finally is.* This plugins helps you grow your email list in Mailchimp. You can use it to create good looking and accessible sign-up forms or integrate with any other existing form on your WordPress site, like your contact, comment or checkout form. [youtube https://www.youtube.com/watch?v=fZCYPnFybqU] #### Some (but not all) features - Connect with your Mailchimp account in seconds. - Sign-up forms which are good looking, user-friendly and mobile optimized. You have complete control over the form fields and can build your forms using native HTML. - Seamless integration with the following plugins: - WordPress Comment Form - WordPress Registration Form - Contact Form 7 - WooCommerce - Gravity Forms - Ninja Forms 3 - WPForms - BuddyPress - MemberPress - Events Manager - Easy Digital Downloads - Give - UltimateMember - HTML Forms - AffiliateWP - Is the plugin you want to integrate with not listed above? You can probably still use our [custom integration](https://www.mc4wp.com/kb/subscribe-mailchimp-custom-html-form/) feature. Alternatively, the plugin comes with a PHP API to programmatically add a new subscriber to Mailchimp. - [Mailchimp for WordPress Premium](https://www.mc4wp.com/): Send your WooCommerce orders to Mailchimp so you can see exactly what each subscriber purchased and how much revenue your email campaigns are generating. - A multitude of available add-on plugins and integrations: - [Mailchimp for WordPress Premium](https://www.mc4wp.com/) - [Mailchimp Top Bar](https://wordpress.org/plugins/mailchimp-top-bar/) - [Boxzilla Pop-ups](https://wordpress.org/plugins/boxzilla/) - Well documented through our [knowledge base](https://www.mc4wp.com/kb/). - Developer friendly. For some inspiration, check out our [repository of example code snippets](https://github.com/ibericode/mailchimp-for-wordpress/tree/main/sample-code-snippets). - Ready for PHP 8.5, but backwards-compatible all the way down to PHP 7.4. #### What is Mailchimp? Mailchimp is a newsletter service that allows you to send out email campaigns to a list of email subscribers. It is free for lists with up to 500 email subscribers, which is why it is the newsletter-service of choice for thousands of small businesses across the globe. If you are not yet using Mailchimp, [creating an account is 100% free and only takes you about 30 seconds](http://eepurl.com/igOGeX). == Installation == #### Installing the plugin 1. In your WordPress admin panel, go to *Plugins > New Plugin*, search for **Mailchimp for WordPress** and click "*Install now*" 1. Alternatively, download the plugin and upload the contents of `mailchimp-for-wp.zip` to your plugins directory, which usually is `/wp-content/plugins/`. 1. Activate the plugin 1. Set [your API key](https://admin.mailchimp.com/account/api) in the plugin settings. #### Configuring Sign-Up Form(s) 1. Go to *Mailchimp for WP > Forms* 2. Select at least one list to subscribe people to. 3. *(Optional)* Add more fields to your form. 4. Embed a sign-up form in pages or posts using the `[mc4wp_form]` shortcode or Gutenberg block. 5. Show a sign-up form in your widget areas using the "Mailchimp Sign-Up Form" widget. 6. Show a sign-up form from your theme files by using the `mc4wp_show_form()` PHP function. #### Need help? Please take a look at the [MC4WP knowledge base](https://www.mc4wp.com/kb/#utm_source=wp-plugin-repo&utm_medium=mailchimp-for-wp&utm_campaign=installation-instructions-link) first. If you can't find an answer there, please look through the [plugin support forums](https://wordpress.org/support/plugin/mailchimp-for-wp) or start your own topic. == Frequently Asked Questions == #### Where can I find my Mailchimp API key? You can [find your API key here](http://kb.mailchimp.com/accounts/management/about-api-keys#Find-or-Generate-Your-API-Key) #### How to display a form in posts or pages? Use the `[mc4wp_form]` shortcode or the Gutenberg block. #### How to display a form in widget areas like the sidebar or footer? Go to **Appearance > Widgets** and use the **Mailchimp for WP Form** widget that comes with the plugin. #### How to add a sign-up checkbox to my Contact Form 7 form? Use the following shortcode in your CF7 form to display a newsletter sign-up checkbox. ` [mc4wp_checkbox "Subscribe to our newsletter?"] ` Our knowledge base has more information on [connecting Contact Form 7 and Mailchimp](https://www.mc4wp.com/kb/connecting-contact-form-7-and-mailchimp/). #### The form shows a success message but subscribers are not added to my list(s)? If the form shows a success message, there is no doubt that the sign-up request succeeded. Mailchimp could have a slight delay sending the confirmation email though. Please check again in a few minutes (sometimes hours) and don't forget to check your junk folder too. When you have double opt-in disabled, new subscribers will be seen as *imports* by Mailchimp. They will not show up in your daily digest emails or statistics. [We always recommend leaving double opt-in enabled](http://blog.mailchimp.com/double-opt-in-vs-single-opt-in-stats/). #### How can I style the sign-up form? You can use custom CSS to style the sign-up form if you do not like the themes that come with the plugin. The following selectors can be used to target the various form elements. ` .mc4wp-form { ... } /* the form element */ .mc4wp-form p { ... } /* form paragraphs */ .mc4wp-form label { ... } /* labels */ .mc4wp-form input { ... } /* input fields */ .mc4wp-form input[type="checkbox"] { ... } /* checkboxes */ .mc4wp-form input[type="submit"] { ... } /* submit button */ .mc4wp-alert { ... } /* success & error messages */ .mc4wp-success { ... } /* success message */ .mc4wp-error { ... } /* error messages */ ` You can add your custom CSS to your theme stylesheet or (easier) by using a plugin like [Simple Custom CSS](https://wordpress.org/plugins/simple-custom-css/#utm_source=wp-plugin-repo&utm_medium=mailchimp-for-wp&utm_campaign=after-css-link) #### How do I show a sign-up form in a pop-up? We recommend the [Boxzilla pop-up plugin](https://wordpress.org/plugins/boxzilla/) for this. You can use the form shortcode in your pop-up box to show a sign-up form. ### How do I subscribe from my WooCommerce checkout form? You can use our WooCommerce integration for that. [How to subscribe to Mailchimp from the WooCommerce checkout form](https://www.mc4wp.com/kb/connect-woocommerce-store-mailchimp/). ### How to connect my WooCommerce store with Mailchimp? You can find instructions for [connecting your WooCommerce store with Mailchimp](https://www.mc4wp.com/kb/connect-woocommerce-store-mailchimp/) on our website. #### I'm getting an "HTTP Error" when trying to connect to Mailchimp. the "HTTP Error" type is usually because of a firewall configuration issue or outdated software on your web server. Please contact your webhost and ask them to check the following: - Whether remote HTTP requests to `https://api.mailchimp.com` are allowed. - Whether cURL and the PHP-cURL extension are installed and updated to a recent version. #### My question is not listed here. Please search through our [knowledge base](https://www.mc4wp.com/kb/#utm_source=wp-plugin-repo&utm_medium=mailchimp-for-wp&utm_campaign=faq). == Other Notes == #### Support If you need some help in setting up the plugin, you have various options: - Search through our [knowledge base](https://www.mc4wp.com/kb/#utm_source=wp-plugin-repo&utm_medium=mailchimp-for-wp&utm_campaign=description). - Open a topic in the [WordPress.org plugin support forums](https://wordpress.org/support/plugin/mailchimp-for-wp) - If you're a premium user, send an email to the email address listed inside the plugin. #### Translations You can [help translate this plugin into your language](https://translate.wordpress.org/projects/wp-plugins/mailchimp-for-wp/stable/) using your WordPress.org account. #### Development This plugin is being developed on GitHub. If you want to collaborate, please look at [ibericode/mailchimp-for-wordpress](https://github.com/ibericode/mailchimp-for-wordpress). #### Customizing the plugin The plugin provides various filter and action hooks that allow you to modify or extend the default behavior. We're also maintaining a [collection of sample code snippets](https://github.com/ibericode/mailchimp-for-wordpress/tree/main/sample-code-snippets). == Screenshots == 1. Example sign-up form in the TwentyTwenty theme. 2. Example sign-up integration with a contact form. 3. Settings page to connect with your Mailchimp account. 4. Overview of sign-up integrations. 5. Overview of sign-up forms. 6. Settings page to configure an integration. 7. Page where you edit your sign-up forms. 8. Page where you modify your form messages. 9. Settings page for e-commerce integration with Mailchimp. Requires [Mailchimp for WordPress Premium](https://www.mc4wp.com/). == Changelog == #### 4.11.0 - Jan 20, 2026 - Add form setting to remove tags from existing subscribers. - Add form setting to check for common email typos. - In Prosopo integration, link directly to API key screen instead of user profile. - Automatically convert string fields to a comma-separated string if an array value is received. - Fix undefined key warning for new setting that emails to site administrator on errors. #### 4.10.9 - Nov 28, 2025 - Specify `apiVersion` in call to `registerBlockType` so that WordPress 6.9 knows it can use the new iframe based editor. - Add new setting to send an email for critical errors, like API errors returned by Mailchimp. #### 4.10.8 - Oct 21, 2025 - Show warning to administrators if a form is showing but Mailchimp API key is not set. - Update third-party JS dependencies. #### 4.10.7 - Sep 05, 2025 - Handle renewing lists through server-side redirect instead of JS component. #### 4.10.6 - Jul 23, 2025 - [WooCommerce Checkout] Fix checkbox from showing up in order confirmation email if using Checkout Block. - [Forms] Fix `{response}` tag being escaped. #### 4.10.5 - Jun 25, 2025 - [Ninja Forms] Always show at least one list option so that onchange event fires properly (to load Audience fields). - Update third-party JS dependencies. - Optimize SVG icons for reduced file sizes. #### 4.10.4 - May 26, 2025 - Improved context-dependent escaping in dynamic content tags. #### 4.10.3 - Apr 16, 2025 - Update third-party JS dependencies. - Add message setting for when a form submission is marked as spam. - Log exact anti-spam rule when a form submission is marked as spam. - Handle potential Prosopo connection errors gracefully. #### 4.10.2 - Feb 28, 2025 - Fix WPForms parameter type change causing a fatal error if using WPForms with a Mailchimp sign-up field. - Add Mailchimp data to Personal Data exporter. Contributed by [David Anderson from UpdraftPlus](https://updraftplus.com/). - Prevent PHP notices in lists overview on general settings page. #### 4.10.1 - Feb 06, 2025 - Fix JS error breaking Ninja Forms edit form page when not connected to a Mailchimp account or account has no audiences. - Remove `sprintf` usage in hot path. - Lazy load `MC4WP_API_V3` class to save some memory and parse time. - Save a tiny bit of memory in autoloader implementation by not repeatedly storing plugin directory. - Remove unused setting key from default options. #### 4.10.0 - Jan 23, 2025 - Bump required PHP version to 7.4 or higher. - Obfuscate API key the same way as in the Mailchimp.com interface. - Delete all plugin data when plugin is uninstalled / deleted via WP Admin. - Fix several PHP 8.4 deprecation warnings. - Address warning about translations being loaded too early if using Ninja Forms integration. - Run stored setting values related to user-facing textual messages through i18n functions to allow translating them through plugins like Loco Translate or WPML. #### 4.9.21 - Jan 08, 2025 - [Forms] Rename "list choice" to "audience choice" in available form fields. - [Ninja Forms] Fix gettext being called too early warning in Ninja Forms base class. - [WooCommerce] Allow pre-checking of sign-up checkbox in Checkout Block. #### 4.9.20 - Dec 18, 2024 - Fix Ninja Forms integration field no longer showing up. - Fix "link is expired" message because of missing nonce on button to dismiss API key notice. - [WPML] Added text_no_lists_selected to the config file so it can be translated. Thanks [Diego Pereira](https://github.com/diiegopereira)! #### 4.9.19 - Nov 11, 2024 - Add integration with [Prosopo](https://prosopo.io/), a GDPR compliant anti-spam solution for protecting your sign-up forms against bot sign-ups. Thanks [Maxim Akimov](https://github.com/light-source)! #### 4.9.18 - Oct 21, 2024 - Bump required PHP version to 7.2. - Prevent non-functional checkbox from showing up on WooCommerce my account page if WooCommerce checkout integration is enabled. - Update default form content to include a "for" attribute on the label element. - Minor performance optimizations to `MC4WP_Form::get_subscriber_tags()` - Begrudgingly rename Mailchimp lists to Mailchimp audiences throughout the plugin's admin interfaces. #### 4.9.17 - Sep 17, 2024 - Fix compatibility with WooCommerce versions 8.5 to 8.8 because of private method that was later made public. - Fix potential reflected XSS by stripping and escaping all HTML from `{email}` tag replacements. Thanks to kauenavarro for responsibly disclosing. - Fix potential stored XSS for attackers with both administrator access and Mailchimp account access by escaping HTML from interest group name. Thanks to Jorge Diaz (ddiax) for responsibly disclosing. #### 4.9.16 - Sep 11, 2024 - Add support for WooCommerce Checkout Block in sign-up checkbox integration. #### 4.9.15 - Aug 13, 2024 - Improved anti-spam measures on the [custom form integration](https://www.mc4wp.com/kb/subscribe-mailchimp-custom-html-form/). If you are using the custom form integration (using the `mc4wp-subscribe` checkbox), please test your forms after upgrading and report any issues to us. - Improved anti-spam measures on all sign-up forms. - Remove unsupported filter hook from Gravity Forms integration. #### 4.9.14 - Jul 17, 2024 - Very minor code-size improvements to public forms related JavaScript. - Update third-party JS dependencies. - Bump tested WordPress version to 6.6. #### 4.9.13 - Apr 25, 2024 - Fix issue with Composer classmap throwing a fatal error when an older version of Composer is already loaded. #### 4.9.12 - Apr 22, 2024 - Fix last 10 Mailchimp lists not being pulled-in when having more than 10 lists. #### 4.9.11 - Jan 8, 2024 - Update third-party JS dependencies. - Bump tested WordPress version. #### 4.9.10 - Nov 20, 2023 - Integrations: Update CheckoutWC hook name for WooCommerce checkbox integration. - Forms: Don't show form preview to users without `edit_posts` capability. - Forms: Explicitly exclude form preview from search engine indexing. - General: Don't unnecessarily go through service contrainer while bootstrapping plugin. - General: Remove some unnecessary JavaScript now that browser support has caught up. #### 4.9.9 - Oct 3, 2023 - Fix class "MC4WP_Usage_Tracking" not found error for WP Cron / WP CLI processes. #### 4.9.8 - Oct 3, 2023 - Remove the opt-in usage tracking functionality as we're not really using it for decision making anymore. - Add missing label element to the select element for setting the logging level. - Our JavaScript assets are now transpiled to support the same set of browsers as WordPress core. This drops support for some very old browsers, but results in smaller bundle sizes for the supported set of browsers. - Update third-party JS dependencies to their latest versions. #### 4.9.7 - Aug 29, 2023 - Update third-party JS dependencies. - Minor textual improvements. - Bump tested WordPress version. #### 4.9.6 - Jul 12, 2023 - Update third-party JS dependencies. - Address some minor codestyle issues. #### 4.9.5 - Jun 7, 2023 - Fix generated HTML for list/audience choice fields. - Fix deprecation warning in includes/admin/class-review-notice.php. - Update JavaScript dependencies. #### 4.9.4 - May 2, 2023 - Fallback to default checkbox label if none given. Thanks to [Shojib Khan](https://github.com/kshojib). - Improve WooCommerce integration settings page by disabling position field if integration is disabled. Thanks to [Shojib Khan](https://github.com/kshojib). - Update JavaScript dependencies. #### 4.9.3 - Mar 31, 2023 - Defend against breaking change in latest WPForms update. #### 4.9.2 - Mar 21, 2023 - Add support for a field named `MARKETING_PERMISSIONS` to enable GDPR fields configured in Mailchimp. A [sample code snippet can be found here](https://github.com/ibericode/mailchimp-for-wordpress/blob/main/sample-code-snippets/forms/gdpr-marketing-permissions.md). - Remove Google reCaptcha feature. This was already disabled if you were not already using it. #### 4.9.1 - Feb 7, 2023 - Fix generated value attribute for fields of type choice (dropdown, checkboxes, radio fields). - Fix type of `marketing_permissions` field in API requests. Thanks to [George Korakas](https://github.com/gkorakas-eli). - Refactor list overview JS to not depend on Mithril.js anymore. - Simplify admin footer text asking for a plugin review. - When renewing lists, renew cached marketing permissions too. #### 4.9.0 - Jan 13, 2023 - Removed deprecated filter hook `mc4wp_settings_cap`, use `mc4wp_admin_required_capability` instead. - Removed deprecated filter hook `mc4wp_merge_vars`, use `mc4wp_form_data` or `mc4wp_integration_data` instead. - Removed deprecated filter hook `mc4wp_form_merge_vars`, use `mc4wp_form_data` instead. - Removed deprecated filter hook `mc4wp_integration_merge_vars`, use `mc4wp_integration_data` instead. - Removed deprecated filter hook `mc4wp_valid_form_request`, use `mc4wp_form_errors` instead. - Removed deprecated function `mc4wp_get_api()` and deprecated class `MC4WP_API`. - Removed deprecated function `mc4wp_checkbox()`. - Removed deprecated function `mc4wp_form()`, use `mc4wp_show_form()` instead. - Added filter `mc4wp_debug_log_message` to modify or disable messages that are written to the debug log. - Fix color of invalid Mailchimp API key notice. - Sanitize IP address value from `$_SERVER['REMOTE_ADDR']` too. - Fetch GDPR marketing permissions via first subscriber on list and show them in lists overview table. #### 4.8.12 - Dec 06, 2022 - Minor performance, memory usage & size optimizations for all JavaScript code bundled with this plugin. #### 4.8.11 - Nov 1, 2022 - Improved default styling for the WooCommerce sign-up checkbox integration. - Add `<strong>` to allowed HTML elements for GDPR disclaimer text on settings pages. - Remove all references to obsolete placeholders.js polyfill. - Move the GiveWP sign-up checkbox closer to the email input field. Thanks [Matthew Lewis](https://github.com/Matthew-Lewis). #### 4.8.10 - Sep 14, 2022 - Fix mc4wp_get_request_ip_address() to return an IP address that matches Mailchimp's validation format when X-Forwarded-For header contains a port component. #### 4.8.8 - Aug 25, 2022 - Fix mc4wp_get_request_ip_address() to pass new Mailchimp validation format. This fixes the "This value is not a valid IP." error some users using a proxy may have been seeing. #### 4.8.7 - Mar 2, 2022 - Fix PHP 8.1 deprecation warnings in `MC4WP_Container` class. - Fix name of action hook that fires before Mailchimp settings rows are displayed on the settings page. Thanks [LoonSongSoftware](https://github.com/LoonSongSoftware). - Improve WPML compatibility. Thanks [Sumit Singh](https://github.com/5um17). - Fix deprecated function for AMP integration. - Only allow unfiltered HTML if user has `unfiltered_html` capability. Please read the below. Despite extensive testing, we may have missed some more obscure HTML elements or attributes from our whitelist. If you notice that some of your form HTML is stripped after saving your form, please get in touch with our support team and provide the HTML you attempted to save. #### 4.8.6 - Jun 24, 2021 - Add nonce field to button for dismissing notice asking for plugin review. - Add strings from config/ directory to POT file. - Add nonce check to AJAX endpoint for refreshing cached Mailchimp lists. - Add capability check to AJAX endpoint for retrieving list details. - Schedule event to refresh cached Mailchimp list upon plugin activation. Thanks to the team over at [pluginvulnerabilities.com](https://www.pluginvulnerabilities.com/) for bringing some of these changes to our attention. #### 4.8.5 - Jun 1, 2021 Add nonce verification to all URL's using `_mc4wp_action` query parameter. This fixes a CSRF vulnerability where a malicious website could trick a logged-in admin user in performing unwanted actions. A special thanks to Erwan from [WPScan](https://wpscan.com/) for bringing this issue to our attention. #### 4.8.4 - May 7, 2021 - Add `defer` attribute to JS file, so page parsing isn't blocked at all. - Rewrite plugin CSS to optimize for selector performance and get rid of some duplication. After installing this update, make sure to also update any add-on plugins like [Mailchimp for WordPress Premium](https://www.mc4wp.com/premium-features/) and [Mailchimp Top Bar](https://wordpress.org/plugins/mailchimp-top-bar/). #### 4.8.3 - Jan 21, 2021 - Fix fatal error on older PHP versions when submitting form without any subscriber tags set in the form settings. - Minor performance improvement in bootstrap method of the plugin. #### 4.8.2 - Jan 20, 2021 - Allow short-circuiting `mc4wp_subscriber_data` filter by returning `null` or `false`. - Use a subdirectory for the default debug log file location, so that it's easier to protect using htaccess. - Improved reliability for fetching lists from mailchimp when lists have high stats.member_count property. #### 4.8.1 - Aug 25, 2020 - Fix notice by explicitly setting `permission_callback` on registered REST route. - Minor internal code improvements. #### 4.8 - Jul 9, 2020 - Plugin now requires PHP 5.3 or higher. - Prefix overlay classname to prevent styling collissions with other plugins. - Form sign-ups can now add tags to both new and existing subscribers. - Update JavaScript dependencies. - Register script early to work with Gutenberg preview. #### 4.7.8 - Jun 04, 2020 - Add `MC4WP_API_V3::add_template` method. - Minor code hardening to ensure a default form is always set. - Update JS dependencies to their latest versions. - Fix icon for Gutenberg block. #### 4.7.7 - Apr 28, 2020 - Update JS dependencies to their latest versions. - API client `add_list_member` method now has an additional parameter to skip merge field validation. - Simplify code for updating an existing form. #### 4.7.6 - Apr 9, 2020 - Update JS dependencies to their latest versions. - Check if className is of type string, fixes a console warning when clicking inside a SVG element. - Minor improvements to the AMP implementation to address harmless validation warnings. #### 4.7.5 - Feb 10, 2020 - Add AMP compatibility to sign-up forms, thanks to Claudiu Lodromanean. This uses the [official AMP plugin for WordPress](https://amp-wp.org). - Add settings key to WPML config so settings can easily by copied over to translated versions of a form. - Optimize size & performance of JavaScript code, resulting in a file that is 40% smaller. - Update CodeMirror to its latest version. - Escape all string translations. #### 4.7.4 - Dec 7, 2019 **Fixes** - htaccess config for servers running Apache 2.4 or later. #### 4.7.3 - Dec 4, 2019 **Fixes** - Top Bar & User Sync add-on using API v2 since version 4.7.1. - Revert change in formatter for date fields, breaking all forms with date fields in them. **Improvements** - Add getter method for raw (unmodified) data on form class. #### 4.7.2 - Nov 27, 2019 **Fixes** - Invalid .htaccess file in case there already is one in the uploads directory. #### 4.7.1 - Nov 26, 2019 **Improvements** - Update MemberPress hook names. Thanks [Ian Heggaton](https://github.com/pixelated-au)! - Use WordPress.org translations instead of bundling translation files in plugin itself. - Write .htaccess to directory of debug log file, to prevent file access. - Add some convenient hooks for Checkout for WooCommerce. - Stop parsing shortcodes in text widgets as WordPress core does this since version 4.9. #### 4.7 - Nov 7, 2019 **Improvements** - Add role=alert to form notices. - Add setting to pre-check sign-up checkbox for Gravity Forms integrations. - Add new position for WooCommerce integration: directly after the billing_email field. - Fix PHP notices for submitting a form and saving a form as an administrator. - Add link to [Koko Analytics plugin](https://wordpress.org/plugins/koko-analytics/). #### 4.6.2 - Oct 24, 2019 **Fixes** - Address fields in forms would always be required (even if really optional). **Improvements** - Add proper SVG admin menu icon. - Minor overall performance and memory usage improvements. #### 4.6.1 - Oct 7, 2019 **Fixes** - Fixed list cache usage for WPForms, Gravity Forms and Ninja Forms integrations. #### 4.6.0 - Oct 7, 2019 **Improvements** - Improved fetch and cache mechanism for retrieving Mailchimp account details, fetching data only when it is required. - Updated [Mithril](https://mithril.js.org/) and [CodeMirror](https://codemirror.net/) dependencies. - Decreased size of `forms.js` from 22KB to 9KB. - No longer requiring jQuery anywhere. - Increase API HTTP request timeout to 15 seconds. Please note that installing this update requires you to also update any add-ons like [Mailchimp Top Bar](https://wordpress.org/plugins/mailchimp-top-bar/) and [Mailchimp for WordPress Premium](https://www.mc4wp.com/premium-features/) (if installed). #### 4.5.5 - Sep 12, 2019 **Fixes** - Google reCAPTCHA script was still loading even if no forms have it enabled. #### 4.5.4 - Sep 11, 2019 **Improvements** - Removed custom color from menu item for improved accessibility. - Take birthday field format into account when sending data to Mailchimp. - Print Google reCAPTCHA script in footer. **Changes** - Changed plugin name to MC4WP instead of Mailchimp for WordPress. #### 4.5.3 - July 23, 2019 **Fixes** - Temporarily switch status of pending subscribers to "unsubscribe" versus deleting susbcriber before re-subscribing. - Deprecation notice for Gravity Forms version 2.4 and higher. **Improvements** - Filter out empty tags when applying tags to new subscribers. - Show all not installed integrations. - Show notice when form doesn't have a Mailchimp list selected to subscribe people to. - Check function existence for compatibility with WordPress 4.7 - Don't submit form when Google reCAPTCHA is enabled but errors. - Update third-party JavaScript dependencies. #### 4.5.2 - May 8, 2019 **Improvements** - Accept more truthy values in custom integration for improved compatibility with third-party forms. - Update JavaScript dependencies. - Load Google reCaptcha script in footer (if needed). #### 4.5.1 - April 8, 2019 **Additions** - Add sign-up integration for [Give](https://wordpress.org/plugins/give/) - Add sign-up integration for [UltimateMember](https://wordpress.org/plugins/ultimate-member/) **Improvements** - Write to debug log if Google reCAPTCHA secret key is incorrect. - Validate reCAPTCHA keys when savings form settings. - Allow setting an empty "successfully subscribed" message. #### 4.5.0 - March 27, 2019 **Additions** - Built-in integration with Google reCAPTCHA to prevent bots from subscribing to your Mailchimp lists. **Improvements** - Minor improvements to the JavaScript that is loaded on admin pages. #### 4.4.0 - March 1, 2019 **Fixes** - AffiliateWP integration subscribing the wrong user if affiliate ID differs from user ID. **Improvements** - Renamed "MailChimp" to "Mailchimp" to match Mailchimp's new branding. - More accurate handling of timeouts for accounts with many MailChimp lists. - UX improvements for integrations overview page. - Validate MailChimp API key format when it's entered. - Improved compatibility with Klarna Checkout in the WooCommerce checkout integration. - Bumped required PHP version to 5.3 (soft requirement for now). **Additions** - Added Gutenberg block for easily adding a form to a post or page. - Added subscriber tags setting to forms. #### 4.3.3 - December 31, 2018 **Fixes** - Update WPForms integration to properly detect if the WPForms plugin is activated. **Improvements** - Write API request parameters to the debug log in case of connection timeouts. - Update JavaScript dependencies. #### 4.3.2 - December 11, 2018 **Fixes** - Use of `readonly` function, which is only available in WordPress 4.9 or later. #### 4.3.1 - November 28, 2018 **Fixes** - Fatal error on PHP versions older than 5.5 #### 4.3 - November 28, 2018 **Additions** - Added `MC4WP_API_KEY` PHP constant which can be used to set your Mailchimp API key. - Add `mc4wp_mailchimp_list_limit` filter hook to modify the maximum number of Mailchimp lists to fetch. Defaults to 200. **Improvements** - Apply `mc4wp_integration_gravity-forms_options` filter hook on Gravity Forms integration options so the checkbox can be prechecked and the checkbox label text modified. - The `updated_subscriber` JS event is now fired forms not using AJAX as well (when applicable). #### 4.2.5 - Sep 11, 2018 **Improvements** - Only re-add subscriber to list if we want to re-trigger a double opt-in confirmation email. - Change Gravity Forms field name to "Mailchimp for WordPress" - Get rid of cached result of Mailchimp API connection. #### 4.2.4 - July 9, 2018 **Improvements** - Ensure type-safety on some global variables. - Stop showing trashed forms immediately. - Pre-check Mailchimp list when creating a new form if there is only 1 list. - Send `null` for unknown values in usage tracking data (only when opted-in). **Additions** - Add methods for accessing Mailchimp's e-commerce promo code endpoints to API class. #### 4.2.3 - June 11, 2018 **Fixes** - Don't wrap "agree to terms" input in hyperlink element. - Allow [ENTER] key again after field helper overlay is closed. **Improvements** - Fallback to meta-refresh if redirect fails because of "headers already sent" error. #### 4.2.2 - May 22, 2018 **Fixes** - Events Manager integration was not working with logged-in users. - Form preview URL should respect admin HTTP(S) scheme. - Removed use of PHP 5.4 function. **Improvements** - Add "agree to terms" checkbox to field helper. **Additions** - Add filter `mc4wp_http_request_args`. #### 4.2.1 - April 11, 2018 **Fixes** - Namespace usage warning when running PHP 5.2 **Improvements** - Remove obsolete `type` attribute from all `<script>` tags printed by the plugin. - Improved tooltips on settings pages. - Do not pre-check integration checkboxes by default. - Add textual warnings to settings that may affect [GDPR compliance](https://www.mc4wp.com/kb/gdpr-compliance/). - Update translation files. #### 4.2 - March 5, 2018 **Additions** - Live form preview while editing form. **Improvements** - Improved [conditional fields logic](https://www.mc4wp.com/kb/conditional-fields-elements/). - Debug log now includes request & response data. - [Form JavaScript events](https://www.mc4wp.com/kb/javascript-form-events/) are fired in an isolated thread now, to prevent errors in event callbacks from breaking form functionality. - Don't send empty field values to Mailchimp when updating subscribers. - Show interest grouping ID in list overview on settings page. **Fixes** - Ninja Forms export checkbox would always state "checked" when form contained a Mailchimp sign-up checkbox. #### 4.1.15 - February 7, 2018 **Fixes** - Dropdown fields with special characters were not properly passed to Mailchimp. - Interest groups with an all-numeric ID were not properly passed to Mailchimp. **Improvements** - Various minor code optimizations - Do not redirect when showing "already subscribed" warning. - Improved scroll to form handling after a form is submitted without AJAX. #### 4.1.14 - January 8, 2018 **Fixes** - Validate method was incorrectly checking required array fields. **Improvements** - Wrap some missing strings in translate calls. Thanks [morlor](https://github.com/morloi). - Make it clear that redirecting after successful form submissions will not show the "subscribed" message. #### 4.1.13 - December 28, 2017 **Fixes** - Array to string conversion in default form messages. **Additions** - Allow marking Gravity Forms sign-up checkbox as a required field. #### 4.1.12 - December 11, 2017 **Fixes** - Ninja Forms double opt-in setting was incorrectly inversed. **Improvements** - Simplified form processing & notice logic. - Prevent 404 errors by proactively replacing lowercased `name="name"` input attributes. - Updated JavaScript dependencies. **Additions** - Integration for AffiliateWP. #### 4.1.11 - November 2, 2017 **Fixes** - Filter out empty array values when overriding selected Mailchimp lists via `_mc4wp_lists`. **Improvements** - Updated JavaScript dependencies. **Additions** - Link to the [HTML Forms](https://www.htmlforms.io/) from the plugin settings pages. #### 4.1.10 - October 19, 2017 **Improvements** - Remove unused options from Ninja Forms integration. - Now logging all sign-ups from Ninja Forms integrations when using [Mailchimp for WordPress Premium](https://www.mc4wp.com/premium-features/). **Additions** - Added Gravity Forms integration. You can now integrate with Gravity Forms by adding the "Mailchimp" field to your forms. #### 4.1.9 - September 19, 2017 **Improvements** - Add `<label>` element to sign-up checkbox for WCAG compatibility. - Custom integration now works with Enfold theme's contact form element. #### 4.1.7 & 4.1.8 - September 8, 2017 **Fixes** - Properly escape the return value of `add_query_arg` when it is used in HTML attributes to prevent cross-site scripting. Thanks to [Karim Ouerghemmi of RIPS](https://www.ripstech.com/) for responsibly disclosing. - Now loading integrations after WPML so that String Translations work properly. **Additions** - Add sign-up integration for WPForms forms. **Improvements** - Updated internal JS dependencies. - Form tag `{data key="foo.bar"}` now allows you to access nested array values. #### 4.1.6 - July 31, 2017 **Fixes** - Method on API class for retrieving campaign data. **Improvements** - Show Akamai reference number when an API request is blocked by Mailchimp's firewall. - Minor output buffering improvements in form previewer. #### 4.1.5 - June 27, 2017 **Fixes** - Failsafe against outputting sign-up checkbox twice in registration forms. - Properly close HTML anchor element in French translation files. - Fix BuddyPress sign-ups when using WordPress Multisite. **Improvements** - Fire action hook `mc4wp_form_updated_subscriber` whenever a form was used to update a subscriber in Mailchimp. - Increase browser timeout for AJAX request when fetching Mailchimp lists. **Additions** - Added campaign & template methods to API client class. #### 4.1.4 - June 15, 2017 **Fixes** - Some form specific JS events were not firing due to incorrect event names. - Registration form integration now works with WooCommerce registration form. - Notice that asks for a plugin review would re-appear after dismissing it. #### 4.1.3 - May 24, 2017 **Improvements** - Randomise time of cron event that renews Mailchimp lists. - Always try to show Mailchimp list info when API key is given. #### 4.1.2 - May 8, 2017 **Fixes** - Use earlier hook priority for Ninja Forms 3 integration so action is registered on time. **Improvements** - Improved Mailchimp list fetching & memory usage for accounts with many lists. - Show error message when fetching lists fails. - Updated plugin translations. #### 4.1.1 - April 11, 2017 **Fixes** - WPML String Translation not working with the checkbox label for sign-up integrations. **Improvements** - Use updated order methods when using WooCommerce 3.0, thanks to Liam McArthur. - Updated JavaScript dependencies. #### 4.1.0 - March 14, 2017 **Improvements** - Updated all JavaScript dependencies in the plugin. - Failsafed filter hooks to prevent invalid variable types. - Explain that greyed out integrations means that specific plugin is not activated. - Conditional form elements now uses event delegation, so it works with forms in [Boxzilla pop-ups](https://boxzillaplugin.com/). - Updated language files. **Additions** - Added support for Ninja Forms 3. - Added `mc4wp_integration_show_checkbox` filter. #### 4.0.13 - February 8, 2017 **Improvements** - Ensure fields are HTML decoded before sending to Mailchimp. - Better OptimizePress compatibility. - Show all address-type fields as required when form contains 1 or more fields of the same address group. #### 4.0.12 - January 16, 2017 **Fixes** - Don't call `stripslashes` on POST data twice. **Improvements** - Plugin review notice is now dismissible over AJAX. - Improved formatting of birthday fields. - Updated Polish translations, thanks to Mateusz Lomber. - Updated German translations, thanks to Sven de Vries. **Additions** - Add `update_ecommerce_store_product` method to API class. - Throw form specific JavaScript events, like `15.subscribed` to hook into "subscribed" events for form with ID 15. #### 4.0.11 - December 9, 2016 **Fixes** - Unescaped request variable on integration settings page, allowing for authenticated XSS. Thanks to [dxwsecurity](https://security.dxw.com/) for responsibly disclosing. **Improvements** - Add `$args` parameter to `API::get_lists_activity` method. Relates to the [Mailchimp Activity](https://wordpress.org/plugins/mc4wp-activity/) plugin. #### 4.0.10 - December 6, 2016 **Improvements** - You can now enable or disable debug logging from the "Other" settings page. - No longer using deprecated function in Contact Form 7, thanks to [stodorovic](https://github.com/stodorovic). - Improved UI for adding hidden interest groupings fields to a form. #### 4.0.9 - November 23, 2016 **Fixes** - Issue with escaped HTML when using form tags introduced by previous update. #### 4.0.8 - November 23, 2016 **Improvements** - Improved handling of large debug logs. - Improved error messages when writing exceptions to debug log. - Show notice when form is missing required Mailchimp fields. - Custom form integration now handles arrays with 1-level depth. Thanks to [Mardari Igor](https://github.com/GarryOne). - You can now use nested tags in your form code, eg `{data key="utm_source" default="{current_path}"}` **Additions** - Add `data-hide-if` attribute logic to forms. See [conditionally hide form fields](https://www.mc4wp.com/kb/conditional-fields-elements/). Thanks to [Kurt Zenisek](http://kurtzenisek.com/). - Add hooks for delayed BuddyPress sign-up. Thanks to [Christian Wach](https://profiles.wordpress.org/needle). #### 4.0.7 - October 25, 2016 **Improvements** - Obfuscate all email addresses in debug log. Thanks [Sauli Lepola](https://twitter.com/SJLfi). - Ask for confirmation before disabling double opt-in, which we do not recommend. - Allow vertical resizing of debug log. - Failsafe against including JavaScript file twice. - No longer wrapping CF7 checkbox in paragraph tags. **Additions** - Added `mc4wp_form_api_error` action hook for API errors encountered by forms. - Added `element_class` argument to `[mc4wp_form]` shortcode for adding CSS classes. #### 4.0.6 - October 10, 2016 **Fixes** - Issue with lists not showing when using W3 Total Cache with APCu object cache enabled. **Improvements** - We're no longer stripping newlines from text fields. **Additions** - Added missing e-commerce related API methods to API class. #### 4.0.5 - September 29, 2016 **Fixes** - Allow checkbox option for the List Choice field (again). **Improvements** - Fetch Mailchimp lists over AJAX, to speed up perceived performance (especially when your account has many lists). - Periodically fetch Mailchimp lists, so cache is always fresh. - Improved `<label>` element accessibility for checkbox integrations. - Stop using double ... == Upgrade Notice == = 3.0.3 = Minor improvements and re-added support for Goodbye Captcha integration. languages/mailchimp-for-wp.pot 0000777 00000110160 15251522663 0012426 0 ustar 00 # Copyright (C) 2024 ibericode # This file is distributed under the GPL v3. msgid "" msgstr "" "Project-Id-Version: MC4WP: Mailchimp for WordPress 4.9.12\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/mailchimp-for-wp\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "POT-Creation-Date: 2024-04-25T16:06:39+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.10.0\n" "X-Domain: mailchimp-for-wp\n" #. Plugin Name of the plugin #: mailchimp-for-wp.php msgid "MC4WP: Mailchimp for WordPress" msgstr "" #. Plugin URI of the plugin #: mailchimp-for-wp.php msgid "https://www.mc4wp.com/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=plugins-page" msgstr "" #. Description of the plugin #: mailchimp-for-wp.php msgid "Mailchimp for WordPress by ibericode. Adds various highly effective sign-up methods to your site." msgstr "" #. Author of the plugin #: mailchimp-for-wp.php msgid "ibericode" msgstr "" #. Author URI of the plugin #: mailchimp-for-wp.php msgid "https://www.ibericode.com/" msgstr "" #: config/default-form-content.php:3 #: includes/class-mailchimp.php:250 #: includes/forms/class-admin.php:82 msgid "Email address" msgstr "" #: config/default-form-content.php:4 msgid "Your email address" msgstr "" #: config/default-form-content.php:5 msgid "Sign up" msgstr "" #: config/default-form-messages.php:5 msgid "Thank you, your sign-up request was successful! Please check your email inbox to confirm." msgstr "" #: config/default-form-messages.php:9 msgid "Thank you, your records have been updated!" msgstr "" #: config/default-form-messages.php:13 msgid "You were successfully unsubscribed." msgstr "" #: config/default-form-messages.php:17 msgid "Given email address is not subscribed." msgstr "" #: config/default-form-messages.php:21 msgid "Oops. Something went wrong. Please try again later." msgstr "" #: config/default-form-messages.php:25 msgid "Please provide a valid email address." msgstr "" #: config/default-form-messages.php:29 msgid "Given email address is already subscribed, thank you!" msgstr "" #: config/default-form-messages.php:33 msgid "Please fill in the required fields." msgstr "" #: config/default-form-messages.php:37 msgid "Please select at least one list." msgstr "" #: includes/admin/class-admin-texts.php:66 #: includes/forms/views/edit-form.php:6 msgid "Settings" msgstr "" #: includes/admin/class-admin-texts.php:84 msgid "Documentation" msgstr "" #: includes/admin/class-admin.php:209 msgid "Success! The cached configuration for your Mailchimp lists has been renewed." msgstr "" #: includes/admin/class-admin.php:289 msgid "The given value does not look like a valid Mailchimp API key." msgstr "" #: includes/admin/class-admin.php:290 msgid "This is a premium feature. Please upgrade to Mailchimp for WordPress Premium to be able to use it." msgstr "" #: includes/admin/class-admin.php:291 #: includes/forms/views/parts/add-fields-help.php:58 #: includes/views/parts/lists-overview.php:10 msgid "Renew Mailchimp lists" msgstr "" #: includes/admin/class-admin.php:292 msgid "Fetching Mailchimp lists" msgstr "" #: includes/admin/class-admin.php:293 msgid "Done! Mailchimp lists renewed." msgstr "" #: includes/admin/class-admin.php:294 msgid "Failed to renew your lists. An error occured." msgstr "" #: includes/admin/class-admin.php:320 msgid "Mailchimp API Settings" msgstr "" #: includes/admin/class-admin.php:327 #: includes/views/other-settings.php:14 #: includes/views/other-settings.php:24 msgid "Other Settings" msgstr "" #: includes/admin/class-admin.php:328 msgid "Other" msgstr "" #: includes/admin/class-admin.php:406 msgid "Error connecting to Mailchimp:" msgstr "" #: includes/admin/class-admin.php:409 msgid "Looks like your server is blocked by Mailchimp's firewall. Please contact Mailchimp support and include the following reference number: %s" msgstr "" #: includes/admin/class-admin.php:412 msgid "Here's some info on solving common connectivity issues." msgstr "" #: includes/admin/class-admin.php:417 msgid "Mailchimp returned the following error:" msgstr "" #: includes/admin/class-admin.php:456 msgid "Log successfully emptied." msgstr "" #: includes/admin/class-admin.php:486 msgid "To get started with Mailchimp for WordPress, please <a href=\"%s\">enter your Mailchimp API key on the settings page of the plugin</a>." msgstr "" #: includes/admin/class-ads.php:37 #: includes/admin/class-ads.php:38 msgid "Add-ons" msgstr "" #: includes/admin/class-ads.php:54 msgid "Want to customize the style of your form? <a href=\"%s\">Try our Styles Builder</a> & edit the look of your forms with just a few clicks." msgstr "" #: includes/admin/class-ads.php:69 msgid "Be notified whenever someone subscribes? <a href=\"%s\">Mailchimp for WordPress Premium</a> allows you to set up email notifications for your forms." msgstr "" #: includes/admin/class-ads.php:71 msgid "Increased conversions? <a href=\"%s\">Mailchimp for WordPress Premium</a> submits forms without reloading the entire page, resulting in a much better experience for your visitors." msgstr "" #: includes/admin/class-ads.php:85 msgid "Upgrade to Premium" msgstr "" #: includes/admin/class-ads.php:97 msgid "Do you want translated forms for all of your languages? <a href=\"%s\">Try Mailchimp for WordPress Premium</a>, which does just that plus more." msgstr "" #: includes/admin/class-ads.php:102 msgid "Do you want to create more than one form? Our Premium add-on does just that! <a href=\"%s\">Have a look at all Premium benefits</a>." msgstr "" #: includes/admin/class-ads.php:107 msgid "Are you enjoying this plugin? The Premium add-on unlocks several powerful features. <a href=\"%s\">Find out about all benefits now</a>." msgstr "" #: includes/admin/class-ads.php:145 msgid "Do you want to track all WooCommerce orders in Mailchimp so you can send emails based on the purchase activity of your subscribers?" msgstr "" #: includes/admin/class-ads.php:148 msgid "<a href=\"%1$s\">Upgrade to Mailchimp for WordPress Premium</a> or <a href=\"%2$s\">read more about Mailchimp's E-Commerce features</a>." msgstr "" #: includes/admin/class-review-notice.php:69 msgid "You've been using Mailchimp for WordPress for some time now; we hope you love it!" msgstr "" #: includes/admin/class-review-notice.php:70 msgid "If you do, please <a href=\"%s\">leave us a 5★ rating on WordPress.org</a>. It would be of great help to us." msgstr "" #: includes/admin/class-review-notice.php:72 msgid "Dismiss this notice." msgstr "" #: includes/admin/migrations/3.0.0-form-1-post-type.php:35 msgid "Default sign-up form" msgstr "" #: includes/class-dynamic-content-tags.php:27 msgid "Data from a cookie." msgstr "" #: includes/class-dynamic-content-tags.php:33 msgid "The email address of the current visitor (if known)." msgstr "" #: includes/class-dynamic-content-tags.php:38 msgid "The URL of the page." msgstr "" #: includes/class-dynamic-content-tags.php:43 msgid "The path of the page." msgstr "" #: includes/class-dynamic-content-tags.php:48 msgid "The current date. Example: %s." msgstr "" #: includes/class-dynamic-content-tags.php:53 msgid "The current time. Example: %s." msgstr "" #: includes/class-dynamic-content-tags.php:58 msgid "The site's language. Example: %s." msgstr "" #: includes/class-dynamic-content-tags.php:63 msgid "The visitor's IP address. Example: %s." msgstr "" #: includes/class-dynamic-content-tags.php:68 msgid "The property of the currently logged-in user." msgstr "" #: includes/class-dynamic-content-tags.php:74 msgid "Property of the current page or post." msgstr "" #: includes/forms/class-admin.php:70 msgid "Add to form" msgstr "" #: includes/forms/class-admin.php:71 msgid "I have read and agree to the terms & conditions" msgstr "" #: includes/forms/class-admin.php:72 msgid "Agree to terms" msgstr "" #: includes/forms/class-admin.php:73 msgid "Link to your terms & conditions page" msgstr "" #: includes/forms/class-admin.php:74 msgid "City" msgstr "" #: includes/forms/class-admin.php:75 msgid "Checkboxes" msgstr "" #: includes/forms/class-admin.php:76 msgid "Choices" msgstr "" #: includes/forms/class-admin.php:77 msgid "Choice type" msgstr "" #: includes/forms/class-admin.php:78 msgid "Choose a field to add to the form" msgstr "" #: includes/forms/class-admin.php:79 msgid "Close" msgstr "" #: includes/forms/class-admin.php:80 msgid "Country" msgstr "" #: includes/forms/class-admin.php:81 msgid "Dropdown" msgstr "" #: includes/forms/class-admin.php:83 msgid "Field type" msgstr "" #: includes/forms/class-admin.php:84 msgid "Field label" msgstr "" #: includes/forms/class-admin.php:85 msgid "Form action" msgstr "" #: includes/forms/class-admin.php:86 msgid "This field will allow your visitors to choose whether they would like to subscribe or unsubscribe" msgstr "" #: includes/forms/class-admin.php:87 msgid "Form fields" msgstr "" #: includes/forms/class-admin.php:88 msgid "This field is marked as required in Mailchimp." msgstr "" #: includes/forms/class-admin.php:89 msgid "Initial value" msgstr "" #: includes/forms/class-admin.php:90 msgid "Interest categories" msgstr "" #: includes/forms/class-admin.php:91 msgid "Is this field required?" msgstr "" #: includes/forms/class-admin.php:92 msgid "List choice" msgstr "" #: includes/forms/class-admin.php:93 msgid "This field will allow your visitors to choose a list to subscribe to." msgstr "" #: includes/forms/class-admin.php:94 msgid "List fields" msgstr "" #: includes/forms/class-admin.php:95 msgid "Min" msgstr "" #: includes/forms/class-admin.php:96 msgid "Max" msgstr "" #: includes/forms/class-admin.php:97 msgid "No available fields. Did you select a Mailchimp list in the form settings?" msgstr "" #: includes/forms/class-admin.php:98 msgid "Optional" msgstr "" #: includes/forms/class-admin.php:99 msgid "Placeholder" msgstr "" #: includes/forms/class-admin.php:100 msgid "Text to show when field has no value." msgstr "" #: includes/forms/class-admin.php:101 msgid "Preselect" msgstr "" #: includes/forms/class-admin.php:102 msgid "Remove" msgstr "" #: includes/forms/class-admin.php:103 msgid "Radio buttons" msgstr "" #: includes/forms/class-admin.php:104 msgid "Street Address" msgstr "" #: includes/forms/class-admin.php:105 msgid "State" msgstr "" #: includes/forms/class-admin.php:106 msgid "Subscribe" msgstr "" #: includes/forms/class-admin.php:107 msgid "Submit button" msgstr "" #: includes/forms/class-admin.php:108 msgid "Wrap in paragraph tags?" msgstr "" #: includes/forms/class-admin.php:109 msgid "Value" msgstr "" #: includes/forms/class-admin.php:110 msgid "Text to prefill this field with." msgstr "" #: includes/forms/class-admin.php:111 msgid "ZIP" msgstr "" #: includes/forms/class-admin.php:123 #: includes/forms/views/edit-form.php:24 msgid "Forms" msgstr "" #: includes/forms/class-admin.php:124 #: includes/forms/views/edit-form.php:26 msgid "Form" msgstr "" #: includes/forms/class-admin.php:161 #: includes/forms/class-admin.php:288 msgid "Form saved." msgstr "" #: includes/forms/class-admin.php:397 msgid "Form not found." msgstr "" #: includes/forms/class-admin.php:399 msgid "Go back" msgstr "" #: includes/forms/class-admin.php:462 #: includes/forms/class-widget.php:31 msgid "Mailchimp Sign-Up Form" msgstr "" #: includes/forms/class-admin.php:466 msgid "Select the form to show" msgstr "" #: includes/forms/class-form-amp.php:33 msgid "Submitting..." msgstr "" #: includes/forms/class-form-element.php:82 msgid "Leave this field empty if you're human:" msgstr "" #: includes/forms/class-form-manager.php:144 msgid "Resource does not exist." msgstr "" #: includes/forms/class-form-tags.php:34 msgid "Replaced with the form response (error or success messages)." msgstr "" #: includes/forms/class-form-tags.php:39 msgid "Data from the URL or a submitted form." msgstr "" #: includes/forms/class-form-tags.php:45 #: includes/integrations/class-integration-tags.php:30 msgid "Replaced with the number of subscribers on the selected list(s)" msgstr "" #: includes/forms/class-form.php:26 msgid "There is no form with ID %d, perhaps it was deleted?" msgstr "" #: includes/forms/class-widget.php:27 msgid "Newsletter" msgstr "" #: includes/forms/class-widget.php:33 msgid "Displays your Mailchimp for WordPress sign-up form" msgstr "" #: includes/forms/class-widget.php:79 msgid "Title:" msgstr "" #: includes/forms/class-widget.php:96 msgid "You can edit your sign-up form in the <a href=\"%s\">Mailchimp for WordPress form settings</a>." msgstr "" #: includes/forms/views/add-form.php:10 #: includes/forms/views/add-form.php:69 msgid "Add new form" msgstr "" #: includes/forms/views/add-form.php:26 msgid "What is the name of this form?" msgstr "" #: includes/forms/views/add-form.php:29 msgid "Enter your form title.." msgstr "" #: includes/forms/views/add-form.php:36 msgid "To which Mailchimp lists should this form subscribe?" msgstr "" #: includes/forms/views/add-form.php:61 msgid "No lists found. Did you <a href=\"%s\">connect with Mailchimp</a>?" msgstr "" #: includes/forms/views/edit-form.php:4 msgid "Fields" msgstr "" #: includes/forms/views/edit-form.php:5 msgid "Messages" msgstr "" #: includes/forms/views/edit-form.php:7 msgid "Appearance" msgstr "" #: includes/forms/views/edit-form.php:22 #: includes/integrations/views/integration-settings.php:8 #: includes/integrations/views/integrations.php:99 #: includes/views/general-settings.php:7 #: includes/views/other-settings.php:12 msgid "You are here: " msgstr "" #: includes/forms/views/edit-form.php:34 msgid "Edit Form" msgstr "" #: includes/forms/views/edit-form.php:59 msgid "Enter form title here" msgstr "" #: includes/forms/views/edit-form.php:63 msgid "Enter the title of your sign-up form" msgstr "" #: includes/forms/views/edit-form.php:67 #: includes/forms/views/tabs/form-fields.php:39 msgid "Use the shortcode %s to display this form inside a post, page or text widget." msgstr "" #: includes/forms/views/parts/add-fields-help.php:4 #: includes/forms/views/tabs/form-fields.php:10 msgid "Add more fields" msgstr "" #: includes/forms/views/parts/add-fields-help.php:9 msgid "To add more fields to your form, you will need to create those fields in Mailchimp first." msgstr "" #: includes/forms/views/parts/add-fields-help.php:12 msgid "Here's how:" msgstr "" #: includes/forms/views/parts/add-fields-help.php:17 msgid "Log in to your Mailchimp account." msgstr "" #: includes/forms/views/parts/add-fields-help.php:22 msgid "Add list fields to any of your selected lists." msgstr "" #: includes/forms/views/parts/add-fields-help.php:23 msgid "Clicking the following links will take you to the right screen." msgstr "" #: includes/forms/views/parts/add-fields-help.php:31 msgid "Edit list fields for" msgstr "" #: includes/forms/views/parts/add-fields-help.php:42 msgid "Click the following button to have Mailchimp for WordPress pick up on your changes." msgstr "" #: includes/forms/views/parts/dynamic-content-tags.php:6 msgid "Add dynamic form variable" msgstr "" #: includes/forms/views/parts/dynamic-content-tags.php:8 msgid "The following list of variables can be used to <a href=\"%s\">add some dynamic content to your form or success and error messages</a>." msgstr "" #: includes/forms/views/parts/dynamic-content-tags.php:8 msgid "This allows you to personalise your form or response messages." msgstr "" #: includes/forms/views/tabs/form-appearance.php:5 msgid "Inherit from %s theme" msgstr "" #: includes/forms/views/tabs/form-appearance.php:6 msgid "Basic" msgstr "" #: includes/forms/views/tabs/form-appearance.php:7 msgid "Form Themes" msgstr "" #: includes/forms/views/tabs/form-appearance.php:8 msgid "Light Theme" msgstr "" #: includes/forms/views/tabs/form-appearance.php:9 msgid "Dark Theme" msgstr "" #: includes/forms/views/tabs/form-appearance.php:10 msgid "Red Theme" msgstr "" #: includes/forms/views/tabs/form-appearance.php:11 msgid "Green Theme" msgstr "" #: includes/forms/views/tabs/form-appearance.php:12 msgid "Blue Theme" msgstr "" #: includes/forms/views/tabs/form-appearance.php:25 msgid "Form Appearance" msgstr "" #: includes/forms/views/tabs/form-appearance.php:29 msgid "Form Style" msgstr "" #: includes/forms/views/tabs/form-appearance.php:50 msgid "If you want to load some default CSS styles, select \"basic formatting styles\" or choose one of the color themes" msgstr "" #: includes/forms/views/tabs/form-fields.php:6 msgid "Form variables" msgstr "" #: includes/forms/views/tabs/form-fields.php:13 msgid "Form Fields" msgstr "" #: includes/forms/views/tabs/form-fields.php:20 msgid "Form code" msgstr "" #: includes/forms/views/tabs/form-fields.php:22 msgid "Enter the HTML code for your form fields.." msgstr "" #: includes/forms/views/tabs/form-fields.php:26 msgid "Form preview" msgstr "" #: includes/forms/views/tabs/form-fields.php:27 msgid "The form may look slightly different than this when shown in a post, page or widget area." msgstr "" #: includes/forms/views/tabs/form-messages.php:6 msgid "Form Messages" msgstr "" #: includes/forms/views/tabs/form-messages.php:16 msgid "Successfully subscribed" msgstr "" #: includes/forms/views/tabs/form-messages.php:19 msgid "The text that shows when an email address is successfully subscribed to the selected list(s)." msgstr "" #: includes/forms/views/tabs/form-messages.php:23 msgid "Invalid email address" msgstr "" #: includes/forms/views/tabs/form-messages.php:26 msgid "The text that shows when an invalid email address is given." msgstr "" #: includes/forms/views/tabs/form-messages.php:30 msgid "Required field missing" msgstr "" #: includes/forms/views/tabs/form-messages.php:33 msgid "The text that shows when a required field for the selected list(s) is missing." msgstr "" #: includes/forms/views/tabs/form-messages.php:37 msgid "Already subscribed" msgstr "" #: includes/forms/views/tabs/form-messages.php:40 msgid "The text that shows when the given email is already subscribed to the selected list(s)." msgstr "" #: includes/forms/views/tabs/form-messages.php:44 msgid "General error" msgstr "" #: includes/forms/views/tabs/form-messages.php:47 msgid "The text that shows when a general error occured." msgstr "" #: includes/forms/views/tabs/form-messages.php:51 msgid "Unsubscribed" msgstr "" #: includes/forms/views/tabs/form-messages.php:54 msgid "When using the unsubscribe method, this is the text that shows when the given email address is successfully unsubscribed from the selected list(s)." msgstr "" #: includes/forms/views/tabs/form-messages.php:58 msgid "Not subscribed" msgstr "" #: includes/forms/views/tabs/form-messages.php:61 msgid "When using the unsubscribe method, this is the text that shows when the given email address is not on the selected list(s)." msgstr "" #: includes/forms/views/tabs/form-messages.php:65 msgid "No list selected" msgstr "" #: includes/forms/views/tabs/form-messages.php:68 msgid "When offering a list choice, this is the text that shows when no lists were selected." msgstr "" #: includes/forms/views/tabs/form-messages.php:79 msgid "Updated" msgstr "" #: includes/forms/views/tabs/form-messages.php:82 msgid "The text that shows when an existing subscriber is updated." msgstr "" #: includes/forms/views/tabs/form-messages.php:94 msgid "HTML tags like %s are allowed in the message fields." msgstr "" #: includes/forms/views/tabs/form-settings.php:1 msgid "Form Settings" msgstr "" #: includes/forms/views/tabs/form-settings.php:5 msgid "Mailchimp specific settings" msgstr "" #: includes/forms/views/tabs/form-settings.php:15 msgid "Lists this form subscribes to" msgstr "" #: includes/forms/views/tabs/form-settings.php:20 #: includes/integrations/views/integration-settings.php:140 msgid "No lists found, <a href=\"%s\">are you connected to Mailchimp</a>?" msgstr "" #: includes/forms/views/tabs/form-settings.php:39 msgid "Select the list(s) to which people who submit this form should be subscribed." msgstr "" #: includes/forms/views/tabs/form-settings.php:47 #: integrations/ninja-forms/class-action.php:29 msgid "Use double opt-in?" msgstr "" #: includes/forms/views/tabs/form-settings.php:51 #: includes/forms/views/tabs/form-settings.php:66 #: includes/forms/views/tabs/form-settings.php:87 #: includes/forms/views/tabs/form-settings.php:135 #: includes/integrations/views/integration-settings.php:66 #: includes/integrations/views/integration-settings.php:90 #: includes/integrations/views/integration-settings.php:177 #: includes/integrations/views/integration-settings.php:210 #: includes/integrations/views/integration-settings.php:227 #: includes/integrations/views/integration-settings.php:250 #: includes/integrations/views/integration-settings.php:275 #: integrations/contact-form-7/class-contact-form-7.php:74 #: integrations/gravity-forms/class-gravity-forms.php:112 #: integrations/gravity-forms/class-gravity-forms.php:124 #: integrations/wpforms/class-field.php:247 msgid "Yes" msgstr "" #: includes/forms/views/tabs/form-settings.php:54 msgid "Are you sure you want to disable double opt-in?" msgstr "" #: includes/forms/views/tabs/form-settings.php:55 #: includes/forms/views/tabs/form-settings.php:70 #: includes/forms/views/tabs/form-settings.php:91 #: includes/forms/views/tabs/form-settings.php:139 #: includes/integrations/views/integration-settings.php:67 #: includes/integrations/views/integration-settings.php:91 #: includes/integrations/views/integration-settings.php:178 #: includes/integrations/views/integration-settings.php:211 #: includes/integrations/views/integration-settings.php:231 #: includes/integrations/views/integration-settings.php:254 #: includes/integrations/views/integration-settings.php:279 #: integrations/contact-form-7/class-contact-form-7.php:74 #: integrations/gravity-forms/class-gravity-forms.php:113 #: integrations/gravity-forms/class-gravity-forms.php:125 #: integrations/wpforms/class-field.php:247 msgid "No" msgstr "" #: includes/forms/views/tabs/form-settings.php:57 msgid "We strongly suggest keeping double opt-in enabled. Disabling double opt-in may affect your GDPR compliance." msgstr "" #: includes/forms/views/tabs/form-settings.php:62 #: includes/integrations/views/integration-settings.php:246 #: integrations/ninja-forms/class-action.php:48 msgid "Update existing subscribers?" msgstr "" #: includes/forms/views/tabs/form-settings.php:72 #: includes/integrations/views/integration-settings.php:256 msgid "Select \"yes\" if you want to update existing subscribers with the data that is sent." msgstr "" #: includes/forms/views/tabs/form-settings.php:83 #: includes/integrations/views/integration-settings.php:271 msgid "Replace interest groups?" msgstr "" #: includes/forms/views/tabs/form-settings.php:94 #: includes/integrations/views/integration-settings.php:282 msgid "Select \"no\" if you want to add the selected interests to any previously selected interests when updating a subscriber." msgstr "" #: includes/forms/views/tabs/form-settings.php:95 #: includes/integrations/views/integration-settings.php:283 msgid "What does this do?" msgstr "" #: includes/forms/views/tabs/form-settings.php:101 msgid "Subscriber tags" msgstr "" #: includes/forms/views/tabs/form-settings.php:103 msgid "Example: My tag, another tag" msgstr "" #: includes/forms/views/tabs/form-settings.php:105 msgid "The listed tags will be applied to all subscribers added or updated by this form." msgstr "" #: includes/forms/views/tabs/form-settings.php:106 msgid "Separate multiple values with a comma." msgstr "" #: includes/forms/views/tabs/form-settings.php:121 msgid "Form behaviour" msgstr "" #: includes/forms/views/tabs/form-settings.php:131 msgid "Hide form after a successful sign-up?" msgstr "" #: includes/forms/views/tabs/form-settings.php:142 msgid "Select \"yes\" to hide the form fields after a successful sign-up." msgstr "" #: includes/forms/views/tabs/form-settings.php:147 msgid "Redirect to URL after successful sign-ups" msgstr "" #: includes/forms/views/tabs/form-settings.php:149 msgid "Example: %s" msgstr "" #: includes/forms/views/tabs/form-settings.php:151 msgid "Leave empty or enter <code>0</code> for no redirect. Otherwise, use complete (absolute) URLs, including <code>http://</code>." msgstr "" #: includes/forms/views/tabs/form-settings.php:154 msgid "Your \"subscribed\" message will not show when redirecting to another page, so make sure to let your visitors know they were successfully subscribed." msgstr "" #: includes/integrations/class-admin.php:72 #: includes/integrations/class-admin.php:73 #: includes/integrations/views/integration-settings.php:10 #: includes/integrations/views/integrations.php:101 #: includes/integrations/views/integrations.php:109 #: includes/integrations/views/integrations.php:123 msgid "Integrations" msgstr "" #: includes/integrations/class-integration.php:79 msgid "Sign me up for the newsletter!" msgstr "" #: includes/integrations/views/integration-settings.php:20 msgid "%s integration" msgstr "" #: includes/integrations/views/integration-settings.php:27 msgid "The selected Mailchimp lists require non-default fields, which may prevent this integration from working." msgstr "" #: includes/integrations/views/integration-settings.php:28 msgid "Please ensure you <a href=\"%1$s\">configure the plugin to send all required fields</a> or <a href=\"%2$s\">log into your Mailchimp account</a> and make sure only the email & name fields are marked as required fields for the selected list(s)." msgstr "" #: includes/integrations/views/integration-settings.php:64 msgid "Enabled?" msgstr "" #: includes/integrations/views/integration-settings.php:68 msgid "Enable the %s integration? This will add a sign-up checkbox to the form." msgstr "" #: includes/integrations/views/integration-settings.php:88 msgid "Implicit?" msgstr "" #: includes/integrations/views/integration-settings.php:91 #: includes/integrations/views/integration-settings.php:178 msgid "(recommended)" msgstr "" #: includes/integrations/views/integration-settings.php:95 msgid "Select \"yes\" if you want to subscribe people without asking them explicitly." msgstr "" #: includes/integrations/views/integration-settings.php:100 #: includes/integrations/views/integration-settings.php:185 #: integrations/gravity-forms/class-gravity-forms.php:131 msgid "<strong>Warning: </strong> enabling this may affect your <a href=\"%s\">GDPR compliance</a>." msgstr "" #: includes/integrations/views/integration-settings.php:122 msgid "Mailchimp Lists" msgstr "" #: includes/integrations/views/integration-settings.php:136 #: integrations/gravity-forms/class-gravity-forms.php:104 msgid "Select the list(s) to which people who check the checkbox should be subscribed." msgstr "" #: includes/integrations/views/integration-settings.php:156 msgid "Checkbox label text" msgstr "" #: includes/integrations/views/integration-settings.php:159 msgid "HTML tags like %s are allowed in the label text." msgstr "" #: includes/integrations/views/integration-settings.php:175 #: integrations/gravity-forms/class-gravity-forms.php:121 msgid "Pre-check the checkbox?" msgstr "" #: includes/integrations/views/integration-settings.php:181 #: integrations/gravity-forms/class-gravity-forms.php:129 msgid "Select \"yes\" if the checkbox should be pre-checked." msgstr "" #: includes/integrations/views/integration-settings.php:208 msgid "Load some default CSS?" msgstr "" #: includes/integrations/views/integration-settings.php:212 msgid "Select \"yes\" if the checkbox appears in a weird place." msgstr "" #: includes/integrations/views/integration-settings.php:223 #: integrations/gravity-forms/class-gravity-forms.php:109 msgid "Double opt-in?" msgstr "" #: includes/integrations/views/integration-settings.php:234 #: integrations/gravity-forms/class-gravity-forms.php:116 msgid "Select \"yes\" if you want people to confirm their email address before being subscribed (recommended)" msgstr "" #: includes/integrations/views/integrations.php:20 msgid "Configure this integration" msgstr "" #: includes/integrations/views/integrations.php:36 msgid "Active" msgstr "" #: includes/integrations/views/integrations.php:38 msgid "Inactive" msgstr "" #: includes/integrations/views/integrations.php:40 msgid "Not installed" msgstr "" #: includes/integrations/views/integrations.php:60 msgid "Name" msgstr "" #: includes/integrations/views/integrations.php:61 msgid "Description" msgstr "" #: includes/integrations/views/integrations.php:62 #: includes/views/general-settings.php:34 msgid "Status" msgstr "" #: includes/integrations/views/integrations.php:115 msgid "The table below shows all available integrations." msgstr "" #: includes/integrations/views/integrations.php:116 msgid "Click on the name of an integration to edit all settings specific to that integration." msgstr "" #: includes/integrations/views/integrations.php:126 msgid "Greyed out integrations will become available after installing & activating the corresponding plugin." msgstr "" #: includes/views/general-settings.php:18 msgid "API Settings" msgstr "" #: includes/views/general-settings.php:40 msgid "CONNECTED" msgstr "" #: includes/views/general-settings.php:44 msgid "NOT CONNECTED" msgstr "" #: includes/views/general-settings.php:53 msgid "API Key" msgstr "" #: includes/views/general-settings.php:55 msgid "Your Mailchimp API key" msgstr "" #: includes/views/general-settings.php:57 msgid "The API key for connecting with your Mailchimp account." msgstr "" #: includes/views/general-settings.php:58 msgid "Get your API key here." msgstr "" #: includes/views/general-settings.php:63 msgid "You defined your Mailchimp API key using the <code>MC4WP_API_KEY</code> constant." msgstr "" #: includes/views/other-settings.php:42 msgid "Miscellaneous settings" msgstr "" #: includes/views/other-settings.php:45 msgid "Logging" msgstr "" #: includes/views/other-settings.php:48 msgid "Errors & warnings only" msgstr "" #: includes/views/other-settings.php:49 msgid "Everything" msgstr "" #: includes/views/other-settings.php:52 msgid "Determines what events should be written to <a href=\"%s\">the debug log</a> (see below)." msgstr "" #: includes/views/other-settings.php:71 msgid "Debug Log" msgstr "" #: includes/views/other-settings.php:71 msgid "Filter.." msgstr "" #: includes/views/other-settings.php:76 msgid "Log file is not writable." msgstr "" #: includes/views/other-settings.php:77 msgid "Please ensure %1$s has the proper <a href=\"%2$s\">file permissions</a>." msgstr "" #: includes/views/other-settings.php:98 msgid "Nothing here. Which means there are no errors!" msgstr "" #: includes/views/other-settings.php:108 msgid "Empty Log" msgstr "" #: includes/views/other-settings.php:116 msgid "Right now, the plugin is configured to only log errors and warnings." msgstr "" #. translators: %s links to the WordPress.org translation project #: includes/views/parts/admin-footer.php:13 msgid "Mailchimp for WordPress is in need of translations. Is the plugin not translated in your language or do you spot errors with the current translations? Helping out is easy! Please <a href=\"%s\">help translate the plugin using your WordPress.org account</a>." msgstr "" #: includes/views/parts/admin-footer.php:31 msgid "This plugin is not developed by or affiliated with Mailchimp in any way." msgstr "" #: includes/views/parts/admin-sidebar.php:11 msgid "Looking for help?" msgstr "" #: includes/views/parts/admin-sidebar.php:12 msgid "We have some resources available to help you in the right direction." msgstr "" #: includes/views/parts/admin-sidebar.php:14 msgid "Knowledge Base" msgstr "" #: includes/views/parts/admin-sidebar.php:15 msgid "Frequently Asked Questions" msgstr "" #: includes/views/parts/admin-sidebar.php:17 msgid "If your answer can not be found in the resources listed above, please use the <a href=\"%s\">support forums on WordPress.org</a>." msgstr "" #: includes/views/parts/admin-sidebar.php:18 msgid "Found a bug? Please <a href=\"%s\">open an issue on GitHub</a>." msgstr "" #: includes/views/parts/admin-sidebar.php:28 msgid "Other plugins by ibericode" msgstr "" #: includes/views/parts/admin-sidebar.php:34 msgid "Privacy-friendly analytics plugin that does not use any external services." msgstr "" #: includes/views/parts/admin-sidebar.php:40 msgid "Pop-ups or boxes that slide-in with a newsletter sign-up form. A sure-fire way to grow your email lists." msgstr "" #: includes/views/parts/admin-sidebar.php:46 msgid "Super flexible forms using native HTML. Just like Mailchimp for WordPress forms but for other purposes, like a contact form." msgstr "" #: includes/views/parts/lists-overview.php:1 msgid "Your Mailchimp Account" msgstr "" #: includes/views/parts/lists-overview.php:2 msgid "The table below shows your Mailchimp lists and their details. If you just applied changes to your Mailchimp lists, please use the following button to renew the cached lists configuration." msgstr "" #: includes/views/parts/lists-overview.php:19 msgid "No lists were found in your Mailchimp account" msgstr "" #: includes/views/parts/lists-overview.php:22 msgid "A total of %d lists were found in your Mailchimp account." msgstr "" #: includes/views/parts/lists-overview.php:27 msgid "List Name" msgstr "" #: includes/views/parts/lists-overview.php:28 msgid "ID" msgstr "" #: includes/views/parts/lists-overview.php:29 msgid "Subscribers" msgstr "" #: includes/views/parts/lists-overview.php:49 msgid "Edit this list in Mailchimp" msgstr "" #: includes/views/parts/lists-overview.php:50 msgid "Loading... Please wait." msgstr "" #: integrations/contact-form-7/admin-before.php:2 msgid "To integrate with Contact Form 7, configure the settings below and then add %s to your CF7 form mark-up." msgstr "" #: integrations/custom/admin-before.php:2 msgid "To get a custom integration to work, include the following HTML in the form you are trying to integrate with." msgstr "" #: integrations/custom/admin-before.php:9 msgid "Subscribe to our newsletter." msgstr "" #. translators: %s links to the Gravity Forms overview page #: integrations/gravity-forms/admin-before.php:4 msgid "To integrate with Gravity Forms, add the \"Mailchimp for WordPress\" field to <a href=\"%s\">one of your Gravity Forms forms</a>." msgstr "" #: integrations/gravity-forms/class-field.php:38 msgid "Mailchimp for WordPress" msgstr "" #: integrations/gravity-forms/class-gravity-forms.php:93 #: integrations/wpforms/class-field.php:79 msgid "Mailchimp list" msgstr "" #: integrations/gravity-forms/class-gravity-forms.php:96 msgid "Select a Mailchimp list" msgstr "" #: integrations/ninja-forms-2/admin-before.php:2 msgid "To integrate with Ninja Forms, add the \"Mailchimp\" field to your Ninja Forms forms." msgstr "" #: integrations/ninja-forms/admin-before.php:2 msgid "To integrate with Ninja Forms, add the \"Mailchimp\" action to <a href=\"%s\">one of your Ninja Forms forms</a>." msgstr "" #: integrations/ninja-forms/class-action.php:21 msgid "Mailchimp" msgstr "" #: integrations/ninja-forms/class-field.php:35 msgid "Mailchimp opt-in" msgstr "" #: integrations/woocommerce/admin-after.php:4 msgid "After email field" msgstr "" #: integrations/woocommerce/admin-after.php:5 msgid "After billing details" msgstr "" #: integrations/woocommerce/admin-after.php:6 msgid "After shipping details" msgstr "" #: integrations/woocommerce/admin-after.php:7 msgid "After customer details" msgstr "" #: integrations/woocommerce/admin-after.php:8 msgid "Before submit button" msgstr "" #: integrations/woocommerce/admin-after.php:9 msgid "After order notes" msgstr "" #: integrations/woocommerce/admin-after.php:13 msgid "Checkout for WooCommerce: Before complete order button" msgstr "" #: integrations/woocommerce/admin-after.php:14 msgid "Checkout for WooCommerce: After account info" msgstr "" #: integrations/woocommerce/admin-after.php:15 msgid "Checkout for WooCommerce: After customer info" msgstr "" #: integrations/woocommerce/admin-after.php:36 msgid "Position" msgstr "" #: integrations/woocommerce/class-woocommerce.php:179 msgid "Order #%d" msgstr "" #: integrations/wpforms/admin-before.php:2 msgid "Use this integration by adding the \"Mailchimp\" field to <a href=\"%s\">your WPForms forms</a>." msgstr "" #: integrations/wpforms/class-field.php:18 msgid "Sign-up to our newsletter?" msgstr "" #: integrations/wpforms/class-field.php:73 msgid "Select the Mailchimp list to subscribe to." msgstr "" #: integrations/wpforms/class-field.php:104 msgid "Set your sign-up label text and whether it should be pre-checked." msgstr "" #: integrations/wpforms/class-field.php:115 msgid "Sign-up checkbox" msgstr "" languages/index.php 0000777 00000000300 15251522663 0010341 0 ustar 00 <?php /** * Do not put custom translations here as they will be overwritten during plugin updates. * * @see https://translate.wordpress.org/projects/wp-plugins/mailchimp-for-wp/stable/ */ autoload.php 0000777 00000013165 15251522663 0007111 0 ustar 00 <?php require __DIR__ . '/includes/functions.php'; require __DIR__ . '/includes/deprecated-functions.php'; require __DIR__ . '/includes/forms/functions.php'; require __DIR__ . '/includes/forms/admin-functions.php'; require __DIR__ . '/includes/integrations/functions.php'; spl_autoload_register(function ($class) { static $classmap = [ 'MC4WP_API_Connection_Exception' => '/includes/api/class-connection-exception.php', 'MC4WP_API_Exception' => '/includes/api/class-exception.php', 'MC4WP_API_Resource_Not_Found_Exception' => '/includes/api/class-resource-not-found-exception.php', 'MC4WP_API_V3' => '/includes/api/class-api-v3.php', 'MC4WP_API_V3_Client' => '/includes/api/class-api-v3-client.php', 'MC4WP_Admin' => '/includes/admin/class-admin.php', 'MC4WP_Admin_Ads' => '/includes/admin/class-ads.php', 'MC4WP_Admin_Ajax' => '/includes/admin/class-admin-ajax.php', 'MC4WP_Admin_Messages' => '/includes/admin/class-admin-messages.php', 'MC4WP_Admin_Review_Notice' => '/includes/admin/class-review-notice.php', 'MC4WP_Admin_Texts' => '/includes/admin/class-admin-texts.php', 'MC4WP_Admin_Tools' => '/includes/admin/class-admin-tools.php', 'MC4WP_AffiliateWP_Integration' => '/integrations/affiliatewp/class-affiliatewp.php', 'MC4WP_BuddyPress_Integration' => '/integrations/buddypress/class-buddypress.php', 'MC4WP_Comment_Form_Integration' => '/integrations/wp-comment-form/class-comment-form.php', 'MC4WP_Contact_Form_7_Integration' => '/integrations/contact-form-7/class-contact-form-7.php', 'MC4WP_Container' => '/includes/class-container.php', 'MC4WP_Custom_Integration' => '/integrations/custom/class-custom.php', 'MC4WP_Debug_Log' => '/includes/class-debug-log.php', 'MC4WP_Debug_Log_Reader' => '/includes/class-debug-log-reader.php', 'MC4WP_Dynamic_Content_Tags' => '/includes/class-dynamic-content-tags.php', 'MC4WP_Easy_Digital_Downloads_Integration' => '/integrations/easy-digital-downloads/class-easy-digital-downloads.php', 'MC4WP_Events_Manager_Integration' => '/integrations/events-manager/class-events-manager.php', 'MC4WP_Personal_Data_Exporter' => '/includes/class-personal-data-exporter.php', 'MC4WP_Field_Formatter' => '/includes/class-field-formatter.php', 'MC4WP_Field_Guesser' => '/includes/class-field-guesser.php', 'MC4WP_Form' => '/includes/forms/class-form.php', 'MC4WP_Form_AMP' => '/includes/forms/class-form-amp.php', 'MC4WP_Form_Asset_Manager' => '/includes/forms/class-asset-manager.php', 'MC4WP_Form_Element' => '/includes/forms/class-form-element.php', 'MC4WP_Form_Listener' => '/includes/forms/class-form-listener.php', 'MC4WP_Form_Manager' => '/includes/forms/class-form-manager.php', 'MC4WP_Form_Notice' => '/includes/forms/class-form-message.php', 'MC4WP_Form_Output_Manager' => '/includes/forms/class-output-manager.php', 'MC4WP_Form_Previewer' => '/includes/forms/class-form-previewer.php', 'MC4WP_Form_Tags' => '/includes/forms/class-form-tags.php', 'MC4WP_Form_Widget' => '/includes/forms/class-widget.php', 'MC4WP_Forms_Admin' => '/includes/forms/class-admin.php', 'MC4WP_Give_Integration' => '/integrations/give/class-give.php', 'MC4WP_Gravity_Forms_Field' => '/integrations/gravity-forms/class-field.php', 'MC4WP_Gravity_Forms_Integration' => '/integrations/gravity-forms/class-gravity-forms.php', 'MC4WP_Integration' => '/includes/integrations/class-integration.php', 'MC4WP_Integration_Admin' => '/includes/integrations/class-admin.php', 'MC4WP_Integration_Fixture' => '/includes/integrations/class-integration-fixture.php', 'MC4WP_Integration_Manager' => '/includes/integrations/class-integration-manager.php', 'MC4WP_Integration_Tags' => '/includes/integrations/class-integration-tags.php', 'MC4WP_List_Data_Mapper' => '/includes/class-list-data-mapper.php', 'MC4WP_MailChimp' => '/includes/class-mailchimp.php', 'MC4WP_MailChimp_Subscriber' => '/includes/class-mailchimp-subscriber.php', 'MC4WP_MemberPress_Integration' => '/integrations/memberpress/class-memberpress.php', 'MC4WP_Ninja_Forms_Action' => '/integrations/ninja-forms/class-action.php', 'MC4WP_Ninja_Forms_Field' => '/integrations/ninja-forms/class-field.php', 'MC4WP_Ninja_Forms_Integration' => '/integrations/ninja-forms/class-ninja-forms.php', 'MC4WP_Ninja_Forms_V2_Integration' => '/integrations/ninja-forms-2/class-ninja-forms.php', 'MC4WP_Plugin' => '/includes/class-plugin.php', 'MC4WP_Procaptcha_Integration' => '/integrations/prosopo-procaptcha/class-procaptcha-integration.php', 'MC4WP_Procaptcha' => '/integrations/prosopo-procaptcha/class-procaptcha.php', 'MC4WP_Queue' => '/includes/class-queue.php', 'MC4WP_Queue_Job' => '/includes/class-queue-job.php', 'MC4WP_Registration_Form_Integration' => '/integrations/wp-registration-form/class-registration-form.php', 'MC4WP_Tools' => '/includes/class-tools.php', 'MC4WP_Upgrade_Routines' => '/includes/admin/class-upgrade-routines.php', 'MC4WP_User_Integration' => '/includes/integrations/class-user-integration.php', 'MC4WP_WPForms_Field' => '/integrations/wpforms/class-field.php', 'MC4WP_WPForms_Integration' => '/integrations/wpforms/class-wpforms.php', 'MC4WP_WooCommerce_Integration' => '/integrations/woocommerce/class-woocommerce.php', ]; if (isset($classmap[$class])) { require __DIR__ . $classmap[$class]; } }); mailchimp-for-wp.php 0000777 00000007167 15251522663 0010461 0 ustar 00 <?php /* Plugin Name: MC4WP: Mailchimp for WordPress Plugin URI: https://www.mc4wp.com/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=plugins-page Description: Mailchimp for WordPress by ibericode. Adds various highly effective sign-up methods to your site. Version: 4.11.1 Author: ibericode Author URI: https://www.ibericode.com/ Text Domain: mailchimp-for-wp Domain Path: /languages License: GPL-3.0-or-later License URI: http://www.gnu.org/licenses/gpl-3.0.html Mailchimp for WordPress Copyright (C) 2012 - 2025, Danny van Kooten, hi@dannyvankooten.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. phpcs:disable:PSR1.Files.SideEffects.FoundWithSymbols */ // Prevent direct file access defined('ABSPATH') or exit; // bootstrap main plugin add_action('plugins_loaded', function () { global $mc4wp; // don't run if Mailchimp for WP Pro 2.x is activated // don't run if PHP version is lower than 7.4.0 if (defined('MC4WP_VERSION') || PHP_VERSION_ID < 70400) { return; } // bootstrap the core plugin define('MC4WP_VERSION', '4.11.1'); define('MC4WP_PLUGIN_DIR', __DIR__); define('MC4WP_PLUGIN_FILE', __FILE__); require __DIR__ . '/autoload.php'; require __DIR__ . '/includes/default-actions.php'; require __DIR__ . '/includes/default-filters.php'; /** * @global MC4WP_Container $GLOBALS['mc4wp'] * @name $mc4wp */ $mc4wp = mc4wp(); $mc4wp['api'] = 'mc4wp_get_api_v3'; $mc4wp['log'] = 'mc4wp_get_debug_log'; // forms $form_manager = new MC4WP_Form_Manager(); $form_manager->add_hooks(); $mc4wp['forms'] = $form_manager; // integration core $integration_manager = new MC4WP_Integration_Manager(); $integration_manager->add_hooks(); $mc4wp['integrations'] = $integration_manager; // Initialize admin section of plugin if (is_admin()) { $admin_tools = new MC4WP_Admin_Tools(); if (defined('DOING_AJAX') && DOING_AJAX) { $ajax = new MC4WP_Admin_Ajax($admin_tools); $ajax->add_hooks(); } else { $messages = new MC4WP_Admin_Messages(); $mc4wp['admin.messages'] = $messages; $admin = new MC4WP_Admin($admin_tools, $messages); $admin->add_hooks(); $forms_admin = new MC4WP_Forms_Admin($messages); $forms_admin->add_hooks(); $integrations_admin = new MC4WP_Integration_Admin($integration_manager, $messages); $integrations_admin->add_hooks(); } } // bootstrap integrations require __DIR__ . '/integrations/bootstrap.php'; }, 8); // schedule the action hook to refresh the stored Mailchimp lists on a daily basis register_activation_hook(__FILE__, function () { $time_string = sprintf('tomorrow %d:%d am', rand(0, 7), rand(0, 59)); wp_schedule_event(strtotime($time_string), 'daily', 'mc4wp_refresh_mailchimp_lists'); }); // remove scheduled hook when plugin is deactivated register_deactivation_hook(__FILE__, function () { wp_clear_scheduled_hook('mc4wp_refresh_mailchimp_lists'); }); wpml-config.xml 0000777 00000002653 15251522663 0007534 0 ustar 00 <wpml-config> <custom-types> <custom-type translate="1">mc4wp-form</custom-type> </custom-types> <custom-fields> <custom-field action="copy-once">_mc4wp_settings</custom-field> <custom-field action="translate">text_subscribed</custom-field> <custom-field action="translate">text_error</custom-field> <custom-field action="translate">text_invalid_email</custom-field> <custom-field action="translate">text_already_subscribed</custom-field> <custom-field action="translate">text_required_field_missing</custom-field> <custom-field action="translate">text_unsubscribed</custom-field> <custom-field action="translate">text_not_subscribed</custom-field> <custom-field action="translate">text_subscribed</custom-field> <custom-field action="translate">text_no_lists_selected</custom-field> </custom-fields> <admin-texts> <key name="mc4wp_integrations"> <key name="woocommerce"> <key name="label" /> </key> <key name="easy-digital-downloads"> <key name="label" /> </key> <key name="contact-form-7"> <key name="label" /> </key> <key name="wp-registration-form"> <key name="label" /> </key> <key name="wp-comment-form"> <key name="label" /> </key> <key name="ninja-forms"> <key name="label" /> </key> <key name="events-manager"> <key name="label" /> </key> <key name="buddypress"> <key name="label" /> </key> </key> </admin-texts> </wpml-config> CHANGELOG.md 0000777 00000162673 15251522663 0006412 0 ustar 00 Changelog ========= #### 4.11.0 - Jan 20, 2026 - Add form setting to remove tags from existing subscribers. - Add form setting to check for common email typos. - In Prosopo integration, link directly to API key screen instead of user profile. - Automatically convert string fields to a comma-separated string if an array value is received. - Fix undefined key warning for new setting that emails to site administrator on errors. #### 4.10.9 - Nov 28, 2025 - Specify `apiVersion` in call to `registerBlockType` so that WordPress 6.9 knows it can use the new iframe based editor. - Add new setting to send an email for critical errors, like API errors returned by Mailchimp. #### 4.10.8 - Oct 21, 2025 - Show warning to administrators if a form is showing but Mailchimp API key is not set. - Update third-party JS dependencies. #### 4.10.7 - Sep 05, 2025 - Handle renewing lists through server-side redirect instead of JS component. #### 4.10.6 - Jul 23, 2025 - [WooCommerce Checkout] Fix checkbox from showing up in order confirmation email if using Checkout Block. - [Forms] Fix `{response}` tag being escaped. #### 4.10.5 - Jun 25, 2025 - [Ninja Forms] Always show at least one list option so that onchange event fires properly (to load Audience fields). - Update third-party JS dependencies. - Optimize SVG icons for reduced file sizes. #### 4.10.4 - May 26, 2025 - Improved context-dependent escaping in dynamic content tags. #### 4.10.3 - Apr 16, 2025 - Update third-party JS dependencies. - Add message setting for when a form submission is marked as spam. - Log exact anti-spam rule when a form submission is marked as spam. - Handle potential Prosopo connection errors gracefully. #### 4.10.2 - Feb 28, 2025 - Fix WPForms parameter type change causing a fatal error if using WPForms with a Mailchimp sign-up field. - Add Mailchimp data to Personal Data exporter. Contributed by [David Anderson from UpdraftPlus](https://updraftplus.com/). - Prevent PHP notices in lists overview on general settings page. #### 4.10.1 - Feb 06, 2025 - Fix JS error breaking Ninja Forms edit form page when not connected to a Mailchimp account or account has no audiences. - Remove `sprintf` usage in hot path. - Lazy load `MC4WP_API_V3` class to save some memory and parse time. - Save a tiny bit of memory in autoloader implementation by not repeatedly storing plugin directory. - Remove unused setting key from default options. #### 4.10.0 - Jan 23, 2025 - Bump required PHP version to 7.4 or higher. - Obfuscate API key the same way as in the Mailchimp.com interface. - Delete all plugin data when plugin is uninstalled / deleted via WP Admin. - Fix several PHP 8.4 deprecation warnings. - Address warning about translations being loaded too early if using Ninja Forms integration. - Run stored setting values related to user-facing textual messages through i18n functions to allow translating them through plugins like Loco Translate or WPML. #### 4.9.21 - Jan 08, 2025 - [Forms] Rename "list choice" to "audience choice" in available form fields. - [Ninja Forms] Fix gettext being called too early warning in Ninja Forms base class. - [WooCommerce] Allow pre-checking of sign-up checkbox in Checkout Block. #### 4.9.20 - Dec 18, 2024 - Fix Ninja Forms integration field no longer showing up. - Fix "link is expired" message because of missing nonce on button to dismiss API key notice. - [WPML] Added text_no_lists_selected to the config file so it can be translated. Thanks [Diego Pereira](https://github.com/diiegopereira)! #### 4.9.19 - Nov 11, 2024 - Add integration with [Prosopo](https://prosopo.io/), a GDPR compliant anti-spam solution for protecting your sign-up forms against bot sign-ups. Thanks [Maxim Akimov](https://github.com/light-source)! #### 4.9.18 - Oct 21, 2024 - Bump required PHP version to 7.2. - Prevent non-functional checkbox from showing up on WooCommerce my account page if WooCommerce checkout integration is enabled. - Update default form content to include a "for" attribute on the label element. - Minor performance optimizations to `MC4WP_Form::get_subscriber_tags()` - Begrudgingly rename Mailchimp lists to Mailchimp audiences throughout the plugin's admin interfaces. #### 4.9.17 - Sep 17, 2024 - Fix compatibility with WooCommerce versions 8.5 to 8.8 because of private method that was later made public. - Fix potential reflected XSS by stripping and escaping all HTML from `{email}` tag replacements. Thanks to kauenavarro for responsibly disclosing. - Fix potential stored XSS for attackers with both administrator access and Mailchimp account access by escaping HTML from interest group name. Thanks to Jorge Diaz (ddiax) for responsibly disclosing. #### 4.9.16 - Sep 11, 2024 - Add support for WooCommerce Checkout Block in sign-up checkbox integration. #### 4.9.15 - Aug 13, 2024 - Improved anti-spam measures on the [custom form integration](https://www.mc4wp.com/kb/subscribe-mailchimp-custom-html-form/). If you are using the custom form integration (using the `mc4wp-subscribe` checkbox), please test your forms after upgrading and report any issues to us. - Improved anti-spam measures on all sign-up forms. - Remove unsupported filter hook from Gravity Forms integration. #### 4.9.14 - Jul 17, 2024 - Very minor code-size improvements to public forms related JavaScript. - Update third-party JS dependencies. - Bump tested WordPress version to 6.6. #### 4.9.13 - Apr 25, 2024 - Fix issue with Composer classmap throwing a fatal error when an older version of Composer is already loaded. #### 4.9.12 - Apr 22, 2024 - Fix last 10 Mailchimp lists not being pulled-in when having more than 10 lists. #### 4.9.11 - Jan 8, 2024 - Update third-party JS dependencies. - Bump tested WordPress version. #### 4.9.10 - Nov 20, 2023 - Integrations: Update CheckoutWC hook name for WooCommerce checkbox integration. - Forms: Don't show form preview to users without `edit_posts` capability. - Forms: Explicitly exclude form preview from search engine indexing. - General: Don't unnecessarily go through service contrainer while bootstrapping plugin. - General: Remove some unnecessary JavaScript now that browser support has caught up. #### 4.9.9 - Oct 3, 2023 - Fix class "MC4WP_Usage_Tracking" not found error for WP Cron / WP CLI processes. #### 4.9.8 - Oct 3, 2023 - Remove the opt-in usage tracking functionality as we're not really using it for decision making anymore. - Add missing label element to the select element for setting the logging level. - Our JavaScript assets are now transpiled to support the same set of browsers as WordPress core. This drops support for some very old browsers, but results in smaller bundle sizes for the supported set of browsers. - Update third-party JS dependencies to their latest versions. #### 4.9.7 - Aug 29, 2023 - Update third-party JS dependencies. - Minor textual improvements. - Bump tested WordPress version. #### 4.9.6 - Jul 12, 2023 - Update third-party JS dependencies. - Address some minor codestyle issues. #### 4.9.5 - Jun 7, 2023 - Fix generated HTML for list/audience choice fields. - Fix deprecation warning in includes/admin/class-review-notice.php. - Update JavaScript dependencies. #### 4.9.4 - May 2, 2023 - Fallback to default checkbox label if none given. Thanks to [Shojib Khan](https://github.com/kshojib). - Improve WooCommerce integration settings page by disabling position field if integration is disabled. Thanks to [Shojib Khan](https://github.com/kshojib). - Update JavaScript dependencies. #### 4.9.3 - Mar 31, 2023 - Defend against breaking change in latest WPForms update. #### 4.9.2 - Mar 21, 2023 - Add support for a field named `MARKETING_PERMISSIONS` to enable GDPR fields configured in Mailchimp. A [sample code snippet can be found here](https://github.com/ibericode/mailchimp-for-wordpress/blob/main/sample-code-snippets/forms/gdpr-marketing-permissions.md). - Remove Google reCaptcha feature. This was already disabled if you were not already using it. #### 4.9.1 - Feb 7, 2023 - Fix generated value attribute for fields of type choice (dropdown, checkboxes, radio fields). - Fix type of `marketing_permissions` field in API requests. Thanks to [George Korakas](https://github.com/gkorakas-eli). - Refactor list overview JS to not depend on Mithril.js anymore. - Simplify admin footer text asking for a plugin review. - When renewing lists, renew cached marketing permissions too. #### 4.9.0 - Jan 13, 2023 - Removed deprecated filter hook `mc4wp_settings_cap`, use `mc4wp_admin_required_capability` instead. - Removed deprecated filter hook `mc4wp_merge_vars`, use `mc4wp_form_data` or `mc4wp_integration_data` instead. - Removed deprecated filter hook `mc4wp_form_merge_vars`, use `mc4wp_form_data` instead. - Removed deprecated filter hook `mc4wp_integration_merge_vars`, use `mc4wp_integration_data` instead. - Removed deprecated filter hook `mc4wp_valid_form_request`, use `mc4wp_form_errors` instead. - Removed deprecated function `mc4wp_get_api()` and deprecated class `MC4WP_API`. - Removed deprecated function `mc4wp_checkbox()`. - Removed deprecated function `mc4wp_form()`, use `mc4wp_show_form()` instead. - Added filter `mc4wp_debug_log_message` to modify or disable messages that are written to the debug log. - Fix color of invalid Mailchimp API key notice. - Sanitize IP address value from `$_SERVER['REMOTE_ADDR']` too. - Fetch GDPR marketing permissions via first subscriber on list and show them in lists overview table. #### 4.8.12 - Dec 06, 2022 - Minor performance, memory usage & size optimizations for all JavaScript code bundled with this plugin. #### 4.8.11 - Nov 1, 2022 - Improved default styling for the WooCommerce sign-up checkbox integration. - Add `<strong>` to allowed HTML elements for GDPR disclaimer text on settings pages. - Remove all references to obsolete placeholders.js polyfill. - Move the GiveWP sign-up checkbox closer to the email input field. Thanks [Matthew Lewis](https://github.com/Matthew-Lewis). #### 4.8.10 - Sep 14, 2022 - Fix mc4wp_get_request_ip_address() to return an IP address that matches Mailchimp's validation format when X-Forwarded-For header contains a port component. #### 4.8.8 - Aug 25, 2022 - Fix mc4wp_get_request_ip_address() to pass new Mailchimp validation format. This fixes the "This value is not a valid IP." error some users using a proxy may have been seeing. #### 4.8.7 - Mar 2, 2022 - Fix PHP 8.1 deprecation warnings in `MC4WP_Container` class. - Fix name of action hook that fires before Mailchimp settings rows are displayed on the settings page. Thanks [LoonSongSoftware](https://github.com/LoonSongSoftware). - Improve WPML compatibility. Thanks [Sumit Singh](https://github.com/5um17). - Fix deprecated function for AMP integration. - Only allow unfiltered HTML if user has `unfiltered_html` capability. Please read the below. Despite extensive testing, we may have missed some more obscure HTML elements or attributes from our whitelist. If you notice that some of your form HTML is stripped after saving your form, please get in touch with our support team and provide the HTML you attempted to save. #### 4.8.6 - Jun 24, 2021 - Add nonce field to button for dismissing notice asking for plugin review. - Add strings from config/ directory to POT file. - Add nonce check to AJAX endpoint for refreshing cached Mailchimp lists. - Add capability check to AJAX endpoint for retrieving list details. - Schedule event to refresh cached Mailchimp list upon plugin activation. Thanks to the team over at [pluginvulnerabilities.com](https://www.pluginvulnerabilities.com/) for bringing some of these changes to our attention. #### 4.8.5 - Jun 1, 2021 Add nonce verification to all URL's using `_mc4wp_action` query parameter. This fixes a CSRF vulnerability where a malicious website could trick a logged-in admin user in performing unwanted actions. A special thanks to Erwan from [WPScan](https://wpscan.com/) for bringing this issue to our attention. #### 4.8.4 - May 7, 2021 - Add `defer` attribute to JS file, so page parsing isn't blocked at all. - Rewrite plugin CSS to optimize for selector performance and get rid of some duplication. After installing this update, make sure to also update any add-on plugins like [Mailchimp for WordPress Premium](https://www.mc4wp.com/premium-features/) and [Mailchimp Top Bar](https://wordpress.org/plugins/mailchimp-top-bar/). #### 4.8.3 - Jan 21, 2021 - Fix fatal error on older PHP versions when submitting form without any subscriber tags set in the form settings. - Minor performance improvement in bootstrap method of the plugin. #### 4.8.2 - Jan 20, 2021 - Allow short-circuiting `mc4wp_subscriber_data` filter by returning `null` or `false`. - Use a subdirectory for the default debug log file location, so that it's easier to protect using htaccess. - Improved reliability for fetching lists from mailchimp when lists have high stats.member_count property. #### 4.8.1 - Aug 25, 2020 - Fix notice by explicitly setting `permission_callback` on registered REST route. - Minor internal code improvements. #### 4.8 - Jul 9, 2020 - Plugin now requires PHP 5.3 or higher. - Prefix overlay classname to prevent styling collissions with other plugins. - Form sign-ups can now add tags to both new and existing subscribers. - Update JavaScript dependencies. - Register script early to work with Gutenberg preview. #### 4.7.8 - Jun 04, 2020 - Add `MC4WP_API_V3::add_template` method. - Minor code hardening to ensure a default form is always set. - Update JS dependencies to their latest versions. - Fix icon for Gutenberg block. #### 4.7.7 - Apr 28, 2020 - Update JS dependencies to their latest versions. - API client `add_list_member` method now has an additional parameter to skip merge field validation. - Simplify code for updating an existing form. #### 4.7.6 - Apr 9, 2020 - Update JS dependencies to their latest versions. - Check if className is of type string, fixes a console warning when clicking inside a SVG element. - Minor improvements to the AMP implementation to address harmless validation warnings. #### 4.7.5 - Feb 10, 2020 - Add AMP compatibility to sign-up forms, thanks to Claudiu Lodromanean. This uses the [official AMP plugin for WordPress](https://amp-wp.org). - Add settings key to WPML config so settings can easily by copied over to translated versions of a form. - Optimize size & performance of JavaScript code, resulting in a file that is 40% smaller. - Update CodeMirror to its latest version. - Escape all string translations. #### 4.7.4 - Dec 7, 2019 **Fixes** - htaccess config for servers running Apache 2.4 or later. #### 4.7.3 - Dec 4, 2019 **Fixes** - Top Bar & User Sync add-on using API v2 since version 4.7.1. - Revert change in formatter for date fields, breaking all forms with date fields in them. **Improvements** - Add getter method for raw (unmodified) data on form class. #### 4.7.2 - Nov 27, 2019 **Fixes** - Invalid .htaccess file in case there already is one in the uploads directory. #### 4.7.1 - Nov 26, 2019 **Improvements** - Update MemberPress hook names. Thanks [Ian Heggaton](https://github.com/pixelated-au)! - Use WordPress.org translations instead of bundling translation files in plugin itself. - Write .htaccess to directory of debug log file, to prevent file access. - Add some convenient hooks for Checkout for WooCommerce. - Stop parsing shortcodes in text widgets as WordPress core does this since version 4.9. #### 4.7 - Nov 7, 2019 **Improvements** - Add role=alert to form notices. - Add setting to pre-check sign-up checkbox for Gravity Forms integrations. - Add new position for WooCommerce integration: directly after the billing_email field. - Fix PHP notices for submitting a form and saving a form as an administrator. - Add link to [Koko Analytics plugin](https://wordpress.org/plugins/koko-analytics/). #### 4.6.2 - Oct 24, 2019 **Fixes** - Address fields in forms would always be required (even if really optional). **Improvements** - Add proper SVG admin menu icon. - Minor overall performance and memory usage improvements. #### 4.6.1 - Oct 7, 2019 **Fixes** - Fixed list cache usage for WPForms, Gravity Forms and Ninja Forms integrations. #### 4.6.0 - Oct 7, 2019 **Improvements** - Improved fetch and cache mechanism for retrieving Mailchimp account details, fetching data only when it is required. - Updated [Mithril](https://mithril.js.org/) and [CodeMirror](https://codemirror.net/) dependencies. - Decreased size of `forms.js` from 22KB to 9KB. - No longer requiring jQuery anywhere. - Increase API HTTP request timeout to 15 seconds. Please note that installing this update requires you to also update any add-ons like [Mailchimp Top Bar](https://wordpress.org/plugins/mailchimp-top-bar/) and [Mailchimp for WordPress Premium](https://www.mc4wp.com/premium-features/) (if installed). #### 4.5.5 - Sep 12, 2019 **Fixes** - Google reCAPTCHA script was still loading even if no forms have it enabled. #### 4.5.4 - Sep 11, 2019 **Improvements** - Removed custom color from menu item for improved accessibility. - Take birthday field format into account when sending data to Mailchimp. - Print Google reCAPTCHA script in footer. **Changes** - Changed plugin name to MC4WP instead of Mailchimp for WordPress. #### 4.5.3 - July 23, 2019 **Fixes** - Temporarily switch status of pending subscribers to "unsubscribe" versus deleting susbcriber before re-subscribing. - Deprecation notice for Gravity Forms version 2.4 and higher. **Improvements** - Filter out empty tags when applying tags to new subscribers. - Show all not installed integrations. - Show notice when form doesn't have a Mailchimp list selected to subscribe people to. - Check function existence for compatibility with WordPress 4.7 - Don't submit form when Google reCAPTCHA is enabled but errors. - Update third-party JavaScript dependencies. #### 4.5.2 - May 8, 2019 **Improvements** - Accept more truthy values in custom integration for improved compatibility with third-party forms. - Update JavaScript dependencies. - Load Google reCaptcha script in footer (if needed). #### 4.5.1 - April 8, 2019 **Additions** - Add sign-up integration for [Give](https://wordpress.org/plugins/give/) - Add sign-up integration for [UltimateMember](https://wordpress.org/plugins/ultimate-member/) **Improvements** - Write to debug log if Google reCAPTCHA secret key is incorrect. - Validate reCAPTCHA keys when savings form settings. - Allow setting an empty "successfully subscribed" message. #### 4.5.0 - March 27, 2019 **Additions** - Built-in integration with Google reCAPTCHA to prevent bots from subscribing to your Mailchimp lists. **Improvements** - Minor improvements to the JavaScript that is loaded on admin pages. #### 4.4.0 - March 1, 2019 **Fixes** - AffiliateWP integration subscribing the wrong user if affiliate ID differs from user ID. **Improvements** - Renamed "MailChimp" to "Mailchimp" to match Mailchimp's new branding. - More accurate handling of timeouts for accounts with many MailChimp lists. - UX improvements for integrations overview page. - Validate MailChimp API key format when it's entered. - Improved compatibility with Klarna Checkout in the WooCommerce checkout integration. - Bumped required PHP version to 5.3 (soft requirement for now). **Additions** - Added Gutenberg block for easily adding a form to a post or page. - Added subscriber tags setting to forms. #### 4.3.3 - December 31, 2018 **Fixes** - Update WPForms integration to properly detect if the WPForms plugin is activated. **Improvements** - Write API request parameters to the debug log in case of connection timeouts. - Update JavaScript dependencies. #### 4.3.2 - December 11, 2018 **Fixes** - Use of `readonly` function, which is only available in WordPress 4.9 or later. #### 4.3.1 - November 28, 2018 **Fixes** - Fatal error on PHP versions older than 5.5 #### 4.3 - November 28, 2018 **Additions** - Added `MC4WP_API_KEY` PHP constant which can be used to set your Mailchimp API key. - Add `mc4wp_mailchimp_list_limit` filter hook to modify the maximum number of Mailchimp lists to fetch. Defaults to 200. **Improvements** - Apply `mc4wp_integration_gravity-forms_options` filter hook on Gravity Forms integration options so the checkbox can be prechecked and the checkbox label text modified. - The `updated_subscriber` JS event is now fired forms not using AJAX as well (when applicable). #### 4.2.5 - Sep 11, 2018 **Improvements** - Only re-add subscriber to list if we want to re-trigger a double opt-in confirmation email. - Change Gravity Forms field name to "Mailchimp for WordPress" - Get rid of cached result of Mailchimp API connection. #### 4.2.4 - July 9, 2018 **Improvements** - Ensure type-safety on some global variables. - Stop showing trashed forms immediately. - Pre-check Mailchimp list when creating a new form if there is only 1 list. - Send `null` for unknown values in usage tracking data (only when opted-in). **Additions** - Add methods for accessing Mailchimp's e-commerce promo code endpoints to API class. #### 4.2.3 - June 11, 2018 **Fixes** - Don't wrap "agree to terms" input in hyperlink element. - Allow [ENTER] key again after field helper overlay is closed. **Improvements** - Fallback to meta-refresh if redirect fails because of "headers already sent" error. #### 4.2.2 - May 22, 2018 **Fixes** - Events Manager integration was not working with logged-in users. - Form preview URL should respect admin HTTP(S) scheme. - Removed use of PHP 5.4 function. **Improvements** - Add "agree to terms" checkbox to field helper. **Additions** - Add filter `mc4wp_http_request_args`. #### 4.2.1 - April 11, 2018 **Fixes** - Namespace usage warning when running PHP 5.2 **Improvements** - Remove obsolete `type` attribute from all `<script>` tags printed by the plugin. - Improved tooltips on settings pages. - Do not pre-check integration checkboxes by default. - Add textual warnings to settings that may affect [GDPR compliance](https://www.mc4wp.com/kb/gdpr-compliance/). - Update translation files. #### 4.2 - March 5, 2018 **Additions** - Live form preview while editing form. **Improvements** - Improved [conditional fields logic](https://www.mc4wp.com/kb/conditional-fields-elements/). - Debug log now includes request & response data. - [Form JavaScript events](https://www.mc4wp.com/kb/javascript-form-events/) are fired in an isolated thread now, to prevent errors in event callbacks from breaking form functionality. - Don't send empty field values to Mailchimp when updating subscribers. - Show interest grouping ID in list overview on settings page. **Fixes** - Ninja Forms export checkbox would always state "checked" when form contained a Mailchimp sign-up checkbox. #### 4.1.15 - February 7, 2018 **Fixes** - Dropdown fields with special characters were not properly passed to Mailchimp. - Interest groups with an all-numeric ID were not properly passed to Mailchimp. **Improvements** - Various minor code optimizations - Do not redirect when showing "already subscribed" warning. - Improved scroll to form handling after a form is submitted without AJAX. #### 4.1.14 - January 8, 2018 **Fixes** - Validate method was incorrectly checking required array fields. **Improvements** - Wrap some missing strings in translate calls. Thanks [morlor](https://github.com/morloi). - Make it clear that redirecting after successful form submissions will not show the "subscribed" message. #### 4.1.13 - December 28, 2017 **Fixes** - Array to string conversion in default form messages. **Additions** - Allow marking Gravity Forms sign-up checkbox as a required field. #### 4.1.12 - December 11, 2017 **Fixes** - Ninja Forms double opt-in setting was incorrectly inversed. **Improvements** - Simplified form processing & notice logic. - Prevent 404 errors by proactively replacing lowercased `name="name"` input attributes. - Updated JavaScript dependencies. **Additions** - Integration for AffiliateWP. #### 4.1.11 - November 2, 2017 **Fixes** - Filter out empty array values when overriding selected Mailchimp lists via `_mc4wp_lists`. **Improvements** - Updated JavaScript dependencies. **Additions** - Link to the [HTML Forms](https://www.htmlforms.io/) from the plugin settings pages. #### 4.1.10 - October 19, 2017 **Improvements** - Remove unused options from Ninja Forms integration. - Now logging all sign-ups from Ninja Forms integrations when using [Mailchimp for WordPress Premium](https://www.mc4wp.com/premium-features/). **Additions** - Added Gravity Forms integration. You can now integrate with Gravity Forms by adding the "Mailchimp" field to your forms. #### 4.1.9 - September 19, 2017 **Improvements** - Add `<label>` element to sign-up checkbox for WCAG compatibility. - Custom integration now works with Enfold theme's contact form element. #### 4.1.7 & 4.1.8 - September 8, 2017 **Fixes** - Properly escape the return value of `add_query_arg` when it is used in HTML attributes to prevent cross-site scripting. Thanks to [Karim Ouerghemmi of RIPS](https://www.ripstech.com/) for responsibly disclosing. - Now loading integrations after WPML so that String Translations work properly. **Additions** - Add sign-up integration for WPForms forms. **Improvements** - Updated internal JS dependencies. - Form tag `{data key="foo.bar"}` now allows you to access nested array values. #### 4.1.6 - July 31, 2017 **Fixes** - Method on API class for retrieving campaign data. **Improvements** - Show Akamai reference number when an API request is blocked by Mailchimp's firewall. - Minor output buffering improvements in form previewer. #### 4.1.5 - June 27, 2017 **Fixes** - Failsafe against outputting sign-up checkbox twice in registration forms. - Properly close HTML anchor element in French translation files. - Fix BuddyPress sign-ups when using WordPress Multisite. **Improvements** - Fire action hook `mc4wp_form_updated_subscriber` whenever a form was used to update a subscriber in Mailchimp. - Increase browser timeout for AJAX request when fetching Mailchimp lists. **Additions** - Added campaign & template methods to API client class. #### 4.1.4 - June 15, 2017 **Fixes** - Some form specific JS events were not firing due to incorrect event names. - Registration form integration now works with WooCommerce registration form. - Notice that asks for a plugin review would re-appear after dismissing it. #### 4.1.3 - May 24, 2017 **Improvements** - Randomise time of cron event that renews Mailchimp lists. - Always try to show Mailchimp list info when API key is given. #### 4.1.2 - May 8, 2017 **Fixes** - Use earlier hook priority for Ninja Forms 3 integration so action is registered on time. **Improvements** - Improved Mailchimp list fetching & memory usage for accounts with many lists. - Show error message when fetching lists fails. - Updated plugin translations. #### 4.1.1 - April 11, 2017 **Fixes** - WPML String Translation not working with the checkbox label for sign-up integrations. **Improvements** - Use updated order methods when using WooCommerce 3.0, thanks to Liam McArthur. - Updated JavaScript dependencies. #### 4.1.0 - March 14, 2017 **Improvements** - Updated all JavaScript dependencies in the plugin. - Failsafed filter hooks to prevent invalid variable types. - Explain that greyed out integrations means that specific plugin is not activated. - Conditional form elements now uses event delegation, so it works with forms in [Boxzilla pop-ups](https://boxzillaplugin.com/). - Updated language files. **Additions** - Added support for Ninja Forms 3. - Added `mc4wp_integration_show_checkbox` filter. #### 4.0.13 - February 8, 2017 **Improvements** - Ensure fields are HTML decoded before sending to Mailchimp. - Better OptimizePress compatibility. - Show all address-type fields as required when form contains 1 or more fields of the same address group. #### 4.0.12 - January 16, 2017 **Fixes** - Don't call `stripslashes` on POST data twice. **Improvements** - Plugin review notice is now dismissible over AJAX. - Improved formatting of birthday fields. - Updated Polish translations, thanks to Mateusz Lomber. - Updated German translations, thanks to Sven de Vries. **Additions** - Add `update_ecommerce_store_product` method to API class. - Throw form specific JavaScript events, like `15.subscribed` to hook into "subscribed" events for form with ID 15. #### 4.0.11 - December 9, 2016 **Fixes** - Unescaped request variable on integration settings page, allowing for authenticated XSS. Thanks to [dxwsecurity](https://security.dxw.com/) for responsibly disclosing. **Improvements** - Add `$args` parameter to `API::get_lists_activity` method. Relates to the [Mailchimp Activity](https://wordpress.org/plugins/mc4wp-activity/) plugin. #### 4.0.10 - December 6, 2016 **Improvements** - You can now enable or disable debug logging from the "Other" settings page. - No longer using deprecated function in Contact Form 7, thanks to [stodorovic](https://github.com/stodorovic). - Improved UI for adding hidden interest groupings fields to a form. #### 4.0.9 - November 23, 2016 **Fixes** - Issue with escaped HTML when using form tags introduced by previous update. #### 4.0.8 - November 23, 2016 **Improvements** - Improved handling of large debug logs. - Improved error messages when writing exceptions to debug log. - Show notice when form is missing required Mailchimp fields. - Custom form integration now handles arrays with 1-level depth. Thanks to [Mardari Igor](https://github.com/GarryOne). - You can now use nested tags in your form code, eg `{data key="utm_source" default="{current_path}"}` **Additions** - Add `data-hide-if` attribute logic to forms. See [conditionally hide form fields](https://www.mc4wp.com/kb/conditional-fields-elements/). Thanks to [Kurt Zenisek](http://kurtzenisek.com/). - Add hooks for delayed BuddyPress sign-up. Thanks to [Christian Wach](https://profiles.wordpress.org/needle). #### 4.0.7 - October 25, 2016 **Improvements** - Obfuscate all email addresses in debug log. Thanks [Sauli Lepola](https://twitter.com/SJLfi). - Ask for confirmation before disabling double opt-in, which we do not recommend. - Allow vertical resizing of debug log. - Failsafe against including JavaScript file twice. - No longer wrapping CF7 checkbox in paragraph tags. **Additions** - Added `mc4wp_form_api_error` action hook for API errors encountered by forms. - Added `element_class` argument to `[mc4wp_form]` shortcode for adding CSS classes. #### 4.0.6 - October 10, 2016 **Fixes** - Issue with lists not showing when using W3 Total Cache with APCu object cache enabled. **Improvements** - We're no longer stripping newlines from text fields. **Additions** - Added missing e-commerce related API methods to API class. #### 4.0.5 - September 29, 2016 **Fixes** - Allow checkbox option for the List Choice field (again). **Improvements** - Fetch Mailchimp lists over AJAX, to speed up perceived performance (especially when your account has many lists). - Periodically fetch Mailchimp lists, so cache is always fresh. - Improved `<label>` element accessibility for checkbox integrations. - Stop using double underscore prefix in function names, as these are reserved in PHP 7. - `{post}` and `{user}` shortcodes now accept a `default` parameter. **Additions** - Add [MemberPress](https://www.memberpress.com/) integration. - Add missing e-commerce related API methods for next week's [WooCommerce Mailchimp e-commerce integration](https://www.mc4wp.com/kb/what-is-ecommerce/) release. #### 4.0.4 - September 7, 2016 **Improvements** - Allow re-running previous migrations by visiting a certain admin URL. - Do not show checkboxes option for fields that only accept a single value. - Write field specific errors to debug log when Mailchimp denies a sign-up request. - Write to debug log when custom integrations can not find an EMAIL field. - Differentiate between connection & authorization errors when testing connection to Mailchimp. - Bump limit of number of Mailchimp lists to fetch from 100 to 500. #### 4.0.3 - August 24, 2016 **Fixes** - Ninja Forms integration not working when using PayPal integration. **Improvements** - Show connection errors on Mailchimp settings page. **Additions** - Add pre-checked option to Ninja Forms integration. - You can now [conditionally hide fields or elements](https://www.mc4wp.com/kb/conditional-fields-elements/) using the `data-show-if` attribute. #### 4.0.2 - August 10, 2016 **Fixes** - Hidden fields which referenced interest groups by name were not sent to Mailchimp. - Adding hidden field to form would reset value on every change. **Improvements** - Decrease file size of JavaScript for forms by about 30%. #### 4.0 & 4.0.1 - August 9, 2016 This release updates the plugin to version 3 of the Mailchimp API. Please [read through the upgrade guide](https://www.mc4wp.com/kb/upgrading-to-4-0/) before updating to make sure things keep working as expected for you. **Changes** - "Send welcome email" is now handled from your list settings in Mailchimp. - Filter `mc4wp_form_merge_vars` is now called `mc4wp_form_data`. - Filter `mc4wp_integration_merge_vars` is now called `mc4wp_integration_data`. - New format for GROUPING fields in forms & filter hooks. - Value delimiter in hidden fields is now a pipe `|` character. **Additions** - New filter: `mc4wp_form_subscriber_data`. - New filter: `mc4wp_integration_subscriber_data`. - New form tag: `{cookie name="mycookie"}` **Improvements** - The plugin now communicates with the latest & greatest Mailchimp API. - Previously unsubscribed subscribers can now be re-added without errors. - Add `User-Agent` header to all API requests. - Available fields in form editor are now split-up by category. - Birthday fields now accept a broader range of values and delimiters. **Fixes** - Issue with only 10 Mailchimp lists / fields / interests being returned. - Incorrect form message showing when double opt-in is disabled. - Error in upgrade routine when API request fails. - List fields not fetched when list has just 1 non-default merge field. #### 3.1.12 - July 28, 2016 **Improvements** - Smarter scrolling after submitting form & reloading page. - Format output of `{subscriber_count}` tag. - You can now use `<img>` in your form messages. - Add Mailchimp API error code to debug log lines. - Add plugin name + version to User-Agent header for all Mailchimp API requests. - Make sure value of MC_LANGUAGE field is limited to 2 characters. #### 3.1.11 - July 5, 2016 **Improvements** - Update JavaScript dependencies for admin screens. - Test debug log & show notice when it's not writable. **Additions** - Add "placeholder" option for dropdown fields. #### 3.1.10 - June 21, 2016 **Fixes** - Styles Builder in Premium not building because of incorrect flag in core plugin. **Improvements** - Don't show position option for WooCommerce integration when sign-up is implicit. - Improvements to form previewer logic. - Make sure admin notifications are always shown exactly one time. #### 3.1.9 - June 7, 2016 **Fixes** - Placeholder polyfill wasn't loaded (only in IE8 and below). **Improvements** - Don't write to debug log if it is not writable. - Reset some CSS properties for commonly used class names in Form Editor & Debug Log. - Do not unnecessarily register styles which are then immediately enqueued. **Additions** - Add "is required field" option for dropdown & radio fields in Field Helper. - Link to [Boxzilla plugin](https://boxzillaplugin.com/) from admin sidebar. #### 3.1.8 - May 23, 2016 **Fixes** - Form Preview mode replaced all titles on that page with "Form Preview". - API class fix for [eCommerce360 functionality](https://www.mc4wp.com/kb/what-is-ecommerce/). **Improvements** - Show dismissible notice when API key is not set. - Show empty API key errors in plugin log. - Friendlier error message for re-subscribe failures. **Additions** - Add `form.reset()` method to JS API. #### 3.1.7 - May 9, 2016 **Fixes** - Shortcode wasn't accepting `element_id` as a valid attribute. - Take array style fields into account when checking if a form contains a given field. **Improvements** - Nested fields will now be properly validated when they're marked as required. - If plugin is installed using Composer, autoloader won't be loaded (again). #### 3.1.6 - April 12, 2016 **Fixes** - Form event for starting a form was named `start` where it should have been `started`. **Improvements** - Some preparations for the upcoming migration to the new Mailchimp API (version 3). - Consistent hook parameters for `mc4wp_form_subscribed` action. - Improved logic for rendering form response. **Additions** - New checkbox position for WooCommerce checkout integration. #### 3.1.5 - March 22, 2016 **Fixes** - Response message was shown for unsubmitted forms when using `{response}` in the form mark-up with multiple forms on the same page. **Improvements** - Scroll to form after form submission now uses native browser method `scrollIntoView()`. - Various improvements for right-to-left (RTL) sites. - The Mailchimp API key is now obfuscated on the settings page. - Contact Form 7 integration now uses an early hook priority to ensure we run before any page redirects. **Additions** - Add position option for WooCommerce integration. - Add `{post}` tag whch can be used in form mark-up to fetch properties of the current page or post. #### 3.1.4 - February 29, 2016 **Fixes** - Forms with address fields never passing validation. **Improvements** - Perform type checks on global variables to prevent issues with poorly coded plugins. - Add Interest Category ID to list overview table for easier debugging. - Updated Russian translations. #### 3.1.3 - February 17, 2016 **Fixes** - Issue with API array responses (for the [Mailchimp Activity add-on](https://wordpress.org/plugins/mc4wp-activity/), for example). **Improvements** - Updated Dutch, Portugese, Spanish and Italian translations. #### 3.1.2 - February 15, 2016 **Fixes** - Form JavaScript not working when another plugins loads Dojo framework. - [ENTER] not submitting form settings or creating new-line. - Internal fields marked as required not passing form validation. - Deselecting all Mailchimp lists wouldn't persist after saving form settings. - No sign-up request firing for lists with only an `EMAIL` field. **Improvements** - Show accepted choice values for dropdown and radio fields in lists overview. - Use all Mailchimp lists for Lists Choice field, instead of just the selected ones. - Failsafed JavaScript for when any other script loads RequireJS globally. **Additions** - Added support for [Shortcake](https://wordpress.org/plugins/shortcode-ui/) plugin. - Error message for when no list is selected can now be customized from the form message settings. #### 3.1.1 - February 1, 2016 **Fixes** - Field Helper not adding `type` attribute when building forms. - Field Helper not setting the correct `value` attribute for Hidden Groups. **Improvements** - Add sourcemaps to minified JavaScript files. - Add link to article on how to enable debug logging. - Field Helper now always shows both placeholder and value fields. #### 3.1 - January 26, 2016 **Fixes** - `<input>` fields being stripped from form when saving as a role other than "superadmin" on MultiSite installations. - Certain actions like "renew lists" not working for users other than admin (if they have explicit access to settings pages). **Improvements** - Show Akamai firewall reference number when site's IP address is blocked - Make sure integrations have a Mailchimp list selected before trying to subscribe. - Move less important settings to "Other" page. - When a field is required in Mailchimp, it has to be required in forms as well now. - Allow including a `_mc4wp_email_type` field in forms to set an explicit email type. - Miscellaneous overall performance improvements. **Additions** - Added [debug logging](https://www.mc4wp.com/kb/how-to-enable-log-debugging/), which shows all warnings & errors the plugin encountered in communicating with Mailchimp. - Add `get_lists_for_email( $email )` method to API class. - Add `MC4WP_Queue` class for better background processing of expensive operations. #### 3.0.12 - January 15, 2016 **Fixes** - Incorrect hooks being fired for successful and unsuccessful form sign-ups (which also broke the success redirect). #### 3.0.11 - January 14, 2016 **Improvements** - Allow splitting up "birthday" and "date" fields into separate fields with `day`, `month` and `year` index. - Improved algorithm for finding fields when integrating with Contact Form 7 or other custom forms. - Ninja Forms integration can now automatically find name-fields. - Ninja Forms integration can now use `mc4wp-` prefixed admin labels. **Additions** - `add_ecommerce_order()` and `delete_ecommerce_order()` methods to API class. #### 3.0.10 - January 6, 2016 **Fixes** - 500 server error for "already subscribed" on Windows servers. - Incorrect HTML being generated for hidden fields. - Duplicate sign-up request when using CF7 integration. **Improvements** - Stop logging "already subscribed" errors to PHP's error log. - Simplify `pattern` attribute for `date` fields. - Remove invalid `autofill` attribute from honeypot field. #### 3.0.9 - December 17, 2015 **Fixes** Not being able to select a list when creating a new form. #### 3.0.8 - December 15, 2015 **Fixes** - Make sure `mc4wp_show_form()` works without passing a form ID. **Improvements** - Remove UI for bulk-enabling integrations, as every integration needs specific settings anyway. - Do not print inline JavaScript for forms until it's surely needed. - Add `position` key to `mc4wp_admin_menu_items` filter to set a menu position. - Various minor code improvements. #### 3.0.7 - December 10, 2015 **Fixes** Workaround for [SSL certification bug in WordPress 4.4](https://core.trac.wordpress.org/ticket/34935), affecting servers with an older versions of OpenSSL installed. **Additions** Added `mc4wp_use_sslverify` filter to disable or explicitly enable SSL certificate verification. #### 3.0.4 - December 7, 2015 **Fixes** - Fixes compatibility issues with add-on plugins performing validation, like Goodbye Captcha and BWS Captcha. **Improvements** - Now using group ID's for interest grouping fields, so changing the group in Mailchimp does not require updating your form code. - Never load enabled integrations which are not installed. - Reintroduce support for automatically sending `OPTIN_IP` **Additions** - Add filter: `mc4wp_form_data`, filters form data before it is processed. #### 3.0.3 - November 30, 2015 **Fixes** - Added backwards compatibility for [Goodbye Captcha](https://wordpress.org/plugins/goodbye-captcha/) integration. **Improvements** - Prevented notice when saving Form widget settings for the first time. - Add `autofill="off"` to honeypot field. - Remove nonces from forms as they're not really useful for publicly available features. - Errors returned by Mailchimp are now logged for Forms as well. - Pre-select Mailchimp list if there's just one list in the connected account. - Added missing translation calls for Form Editor. #### 3.0.2 - November 25, 2015 **Fixes** - Redirect on success not working. - Forms overview page redirected to main WP Admin page (edge case). - Safari was always showing the leave-page confirmation dialog. **Improvements** - Add form-specific classes to preview form element. This allows the [Styles Builder](https://www.mc4wp.com/premium-features/) to work with the Form Preview. - Form events are now triggered _after_ the page has finished loading, so all scripts are loaded & ready to use. - Reset background-color in Form Themes stylesheets. #### 3.0.0 & 3.0.1 - November 23, 2015 Version 3.0 is a total revamp of the plugin. For a quick overview of the changes, please [read this post on our blog](https://www.mc4wp.com/blog/whats-new-in-mailchimp-for-wordpress-the-big-three-o/). Before upgrading, please go through the [upgrade guide](https://www.mc4wp.com/kb/upgrading-to-3-0/) as some things have changed. **Breaking Changes** - Captcha fields: `{captcha}` field is now handled by the [Captcha add-on plugin](https://wordpress.org/plugins/mc4wp-captcha/). - New dynamic content tags syntax: `{data_NAME}` is now `{data key="NAME"}` - Event binding: `jQuery(document).on('subscribe.mc4wp','.mc4wp-form', function(){ ... })` is now `mc4wp.forms.on('subscribed', function(form) { ... })` - Removed integrations: MultiSite & bbPress. **Improvements** - New form editor with syntax highlighting, more advanced field options & better visual feedback. - Better support for Mailchimp `address` fields. - Better support for choice fields (eg groupings, list choice & country fields). - All fields marked as `required` are now validated server-side as well (instead of just Mailchimp required fields). - All integrations have their own settings page now. - Events Manager: checkbox is now automatically added to booking forms. - Tons of usability & accessibility improvements. - Tons of code improvements: improved memory usage, 100+ new unit tests & better usage of various best practices. - The [premium plugin](https://www.mc4wp.com/) is now an add-on of this plugin. **Additions** - New "Preview Form" option, showing unsaved form changes. - Integrations can now be "implicit", thus no longer showing a checkbox option to visitors. - New JavaScript API, replacing jQuery event hooks. - Ninja Forms integration - Introduced various new filter & action hooks, please see the new [code reference for developers](http://developer.mc4wp.com/) for more information. #### 2.3.18 - November 2, 2015 **Fixes** - Incorrect number of parameters for `error_log` statement in integrations class. **Improvements** - Usage tracking is now scheduled once a week (instead of daily). - Preparations for [the upcoming Mailchimp for WordPress version 3.0 release](https://www.mc4wp.com/blog/breaking-backwards-compatibility-in-version-3-0/). - Tested compatibility with WordPress 4.4 #### 2.3.17 - October 22, 2015 **Fixes** - Honeypot field being autofilled in Chrome, causing a form error. **Improvements** - Updated Portugese translations. #### 2.3.16 - October 14, 2015 **Fixes** - Error in Russian translation, causing a broken link on the Mailchimp settings page. **Improvements** - Textual improvements to Mailchimp settings page. - Connectivity issues with Mailchimp will now _always_ show an error message. - Renewing Mailchimp lists will now also update the output of the `{subscriber_count}` tag. #### 2.3.15 - October 9, 2015 **Fixes** - Fixes JS error when form contains no submit button **Improvements** - Only prefix `url` fields with `http://` if it is filled. - Updated Spanish & Catalan translations, thanks to [Xavier Gimeno Torrent](http://www.xaviergimeno.net/). - Fix `mc4wp_form_before_fields` being applied twice. - Position honeypot field to the right for Right-To-Left sites. - `_mc4wp_lists` can now be a comma-separated string of Mailchimp list ID's to subscribe to (or an array). - Minor other defensive coding improvements to prevent clashes with other plugins. **Additions** - Added opt-in usage tracking to help us make the plugin better. No sensitive data is tracked. #### 2.3.14 - September 25 **Fixes** - Use of undefined constant in previous update. #### 2.3.13 - September 25, 2015 **Fixes** - Honeypot causing horizontal scrollbar on RTL sites. - List choice fields not showing when using one of the default form themes. **Improvements** - Minor styling improvements for RTL sites. - Mailchimp list fields of type "website" will now become HTML5 `url` type fields. - Auto-prefix fields of type `url` with `http://` #### 2.3.12 - September 21, 2015 **Fixes** - Issue with interest groupings not being fetched after updating to version 2.3.11 #### 2.3.11 - September 21, 2015 **Fixes** - Honeypot field being filled by browser's autocomplete. - Styling issue for submit buttons in Mobile Safari. - Empty response from Mailchimp API **Improvements** - Do not query Mailchimp API for interest groupings if list has none. - Integration errors are now logged to PHP's error log for easier debugging. **Additions** - You can now use shortcodes in the form content. #### 2.3.10 - September 7, 2015 **Fixes** - Showing "not connected" when the plugin was actually connected to Mailchimp. - Issue with `address` fields when `addr1` was not given. - Comment form checkbox not outputted for some older themes. **Improvements** - Do not flush Mailchimp cache on every settings save. - Add default CSS styles for `number` fields. - Placeholders will now work in older version of IE as well. #### 2.3.9 - September 1, 2015 **Improvements** - Mailchimp lists cache is now automatically flushed after changing your API key setting. - Better field population after submitting a form with errors. - More helpful error message when no list is selected. - Translate options when installing plugin from a language other than English. - Add form mark-up to WPML configuration file. - Sign-up checkbox in comment form is now shown before the "submit comment" button. - URL-encode variables in "Redirect URL" setting. - Better error message when connected to Mailchimp but account has no lists. **Additions** - Add `mc4wp_form_action` filter to set a custom `action` attribute on the form element. #### 2.3.8 - August 18, 2015 **Fixes** - Prevented JS error when outputting forms with no submit button. - Using `0` as a Redirect URL resulted in a blank page. - Sign-up checkbox was showing twice in the Easy Digital Downloads checkout when showing registration fields, thanks [Daniel Espinoza](https://github.com/growdev). - Default form was not automatically translated for languages other than English. **Improvements** - Better way to hide the honeypot field, which stops bots from subscribing to your lists. - role="form" is no longer needed, thanks [XhmikosR](https://github.com/XhmikosR)! - Filter `mc4wp_form_animate_scroll` now disables just the scroll animation, not the scroll itself. - Revamped UI for Mailchimp lists overview - Updated German & Greek translations. **Additions** - Added `mc4wp_form_is_submitted()` and `mc4wp_form_get_response_html()` functions. #### 2.3.7 - July 13, 2015 **Improvements** - Use the same order as Mailchimp.com, which is useful when you have over 100 Mailchimp lists. - Use `/* ... */` for inline JavaScript comments to prevent errors with minified HTML - props [Ed Gifford](https://github.com/egifford) **Additions** - Filter: `mc4wp_form_animate_scroll` to disable animated scroll-to after submitting a form. - Add `{current_path}` variable to use in form templates. - Add `default` attribute to `{data_name}` variables, usage: `{data_something default="The default value"}` #### 2.3.6 - July 6, 2015 **Fixes** - Undefined index notice when visitor's USER_AGENT is not set. **Improvements** - Relayed the browser's Accept-Language header to Mailchimp for auto-detecting a subscriber's language. - Better CSS for form reset - Updated HTML5 placeholder polyfill #### 2.3.5 - June 24, 2015 **Fixes** - Faulty update for v3.0 appearing for people running GitHub updater plugin. **Improvements** - Updated language files. - Now passing the form as a parameter to `mc4wp_form_css_classes` filter. #### 2.3.4 - May 29, 2015 **Fixes** - Issue with GROUPINGS not being sent to Mailchimp **Improvements** - Code preview in Field Builder is now read-only #### 2.3.3 - May 27, 2015 **Fixes** - Get correct IP address when using proxy like Cloudflare or Sucuri WAF. - Use strict type check for printing inline CSS that hides honeypot field **Improvements** - Add `contactemail` and `contactname` to field name guesses when integrating with third-party form. - Re-enable `sslverify` #### 2.3.2 - May 12, 2015 **Fixes** - Groupings not being sent to Mailchimp - Issue when using more than one `{data_xx}` replacement **Improvements** - IE8 compatibility for honeypot fallback script. #### 2.3.1 - May 6, 2015 **Fixes** - PHP notice in `includes/class-tools.php`, introduced by version 2.3. #### 2.3 - May 6, 2015 **Fixes** - The email address is no longer automatically added to the Redirect URL as this is against Google Analytics policy. To add it again, use `?email={email}` in your Redirect URL setting. - Registration type integrations were not correctly picking up on first- and last names. - JavaScript error in IE8 because of `setAttribute` call on honeypot field. - API class `subscribe` method now always returns a boolean. **Improvements** - Add `role` attribute to form elements - Major code refactoring for easier unit testing and improved code readability. - Use Composer for autoloading all plugin classes (PHP 5.2 compatible) - You can now use [form variables in both forms, messages as checkbox label texts](https://www.mc4wp.com/kb/using-variables-in-your-form-or-messages/). **Additions** - You can now handle unsubscribe calls with our forms too. - Added Portugese, Indonesian, German (CH) and Spanish (PR) translations. #### 2.2.9 - April 15, 2015 **Fixes** - Menu item for settings page not appearing on Google App Engine ([#88](https://github.com/ibericode/mailchimp-for-wordpress/issues/88)) **Improvements** - Updated Italian, Russian & Turkish translations. #### 2.2.8 - March 24, 2015 **Fixes** - API key field value was not properly escaped. - Background images were stripped from submit buttons. **Improvements** - Better sanitising of all settings - Updated all translations **Additions** - Added `mc4wp_before_checkbox` and `mc4wp_after_checkbox` filters to easily add more fields to sign-up checkbox integrations. - Added some helper methods related to interest groupings to `MC4WP_MailChimp` class. - Allow setting custom Mailchimp lists to subscribe to using `lists` attribute on shortcode. #### 2.2.7 - March 11, 2015 **Fixes** - Honeypot field was visible for themes or templates not calling `wp_head()` and `wp_footer()` **Improvements** - Various minor code improvements - Updated German, Spanish, Brazilian, French, Hungarian and Russian translations. **Additions** - Added [mc4wp_form_success](https://github.com/ibericode/mailchimp-for-wordpress/blob/06f0c833027f347a288d2cb9805e0614767409b6/includes/class-form-request.php#L292-L301) action hook to hook into successful sign-ups - Added [mc4wp_form_data](https://github.com/ibericode/mailchimp-for-wordpress/blob/06f0c833027f347a288d2cb9805e0614767409b6/includes/class-form-request.php#L138-L142) filter hook to modify all form data before processing #### 2.2.6 - February 26, 2015 **Fixes** - CSS reset wasn't working for WooCommerce checkout sign-up checkbox. - `mc4wp-submitted` class was not added in IE8 - Incorrect `action` attribute on form element for some server configurations **Improvements** - Anti-SPAM improvements: a better honeypot field and a timestamp field to prevent instant form submissions. - Reset `background-image` on submit buttons when using CSS themes - Smarter email detection when integrating with third-party forms - Updated all translations **Additions** - Custom fallback for browsers not supporting `input[type="date"]` #### 2.2.5 - February 13, 2015 **Fixed** - Issue where WooCommerce checkout sign-up was not working for cheque payments. - Translation were loaded too late to properly translate some strings, like the admin menu items. **Improvements** - The presence of required list fields in form mark-up is now checked as you type. - Number fields will now repopulate if an error occurred. - Updated all translations. - Make sure there is only one plugin instance. - Various other code improvements. **Additions** - Added support for [GitHub Updater Plugin](https://github.com/afragen/github-updater). - You can now specify whether you want to send a welcome email (only with double opt-in disabled). A huge thank you to [Stefan Oderbolz](http://metaodi.ch/) for various fixed and improvements related to translations in this release. #### 2.2.4 - February 4, 2015 **Fixed** - Textual fix as entering "0" for no redirection does not work. **Improvements** - Moved third-party scripts to their own directory for easier exclusion - All code is now adhering to the WP Code Standards - Updated Dutch, German, Spanish, Hungarian, French, Italian and Turkish translations. **Additions** - Now showing a heads up when at limit of 100 Mailchimp lists. ([#71](https://github.com/ibericode/mailchimp-for-wordpress/issues/71)) - Added `wpml-config.xml` file for better WPML compatibility - Added filter `mc4wp_menu_items` for adding & removing menu items from add-ons #### 2.2.3 - January 24, 2015 Minor improvements and additions for compatibility with the [Mailchimp User Sync plugin](https://www.mc4wp.com/premium-features/). #### 2.2.2 - January 13, 2015 **Fixes** - Plugin wasn't connecting to Mailchimp for users on Mailchimp server `us10` (API keys ending in `-us10`) #### 2.2.1 - January 12, 2015 **Improvements** - Use JS object to transfer lists data to Field Wizard. - Field Wizard strings are now translatable - Add `is_spam` method to checkbox integration to battle spam sign-ups - Minor code & code style improvements - Updated Danish, German, Spanish, French, Italian and Portugese (Brazil) translations **Additions** - You can now set `MC_LOCATION`, `MC_NOTES` and `MC_LANGUAGE` from your form HTML - The submit button now has a default value when generating HTML for it #### 2.2 - December 9, 2014 **Fixes** - "Select at least one list" notice appearing when unselecting any Mailchimp list in Form settings - If an error occurs, textareas will no longer lose their value **Improvements** - Improved the way form submissions are handled - Minor code & documentation improvements - Updated Dutch, French, Portugese and Spanish translations **Additions** - Added sign-up checkbox integration for [WooCommerce](https://wordpress.org/plugins/woocommerce/) checkout. - Added sign-up checkbox integration for [Easy Digital Downloads](https://wordpress.org/plugins/easy-digital-downloads/) checkout. - The entered email will now be appended to the URL when redirecting to another page integrations/prosopo-procaptcha/class-procaptcha-integration.php 0000777 00000002112 15251522663 0021370 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_Ninja_Forms_Integration * * @ignore */ class MC4WP_Procaptcha_Integration extends MC4WP_Integration { /** * @var string */ public $name = 'Procaptcha (by Prosopo)'; /** * @var string */ public $description = 'Privacy-friendly and GDPR-compliant anti-bot protection.'; /** * @return void */ protected function add_hooks() { } /** * @return bool */ public function is_installed() { return true; } /** * @return array */ public function get_ui_elements() { return [ 'procaptcha_site_key', 'procaptcha_secret_key', ]; } /** * @return array */ protected function get_default_options() { return [ 'enabled' => '0', 'css' => '0', 'site_key' => '', 'secret_key' => '', 'theme' => 'light', 'type' => 'frictionless', 'display_for_authorized' => '0', ]; } } integrations/prosopo-procaptcha/admin-after.php 0000777 00000013402 15251522663 0016013 0 ustar 00 <?php $opts = $opts ?? []; $opts = true === is_array($opts) ? $opts : []; $site_key = $opts['site_key'] ?? ''; $secret_key = $opts['secret_key'] ?? ''; $enabled = $opts['enabled'] ?? '0'; $display_for_authorized = $opts['display_for_authorized'] ?? '0'; $theme = $opts['theme'] ?? ''; $type = $opts['type'] ?? ''; $theme_options = [ 'light' => esc_html__('Light', 'mailchimp-for-wp'), 'dark' => esc_html__('Dark', 'mailchimp-for-wp'), ]; $type_options = [ 'frictionless' => esc_html__('Frictionless', 'mailchimp-for-wp'), 'pow' => esc_html__('Proof of Work', 'mailchimp-for-wp'), 'image' => esc_html__('Image Captcha', 'mailchimp-for-wp'), ]; ?> <?php if ('1' === $enabled) { ?> <p> <?php echo esc_html__('Preview: if the credentials are valid, you should be able to complete the captcha below:', 'mailchimp-for-wp'); ?> </p> <?php } $procaptcha_api = MC4WP_Procaptcha::get_instance(); echo $procaptcha_api->print_captcha_element(true, true); ?> <input class="prosopo-procaptcha__enabled-setting" type="hidden" name="mc4wp_integrations[prosopo-procaptcha][enabled]" value="<?php echo esc_attr($enabled); ?>"> <table class="form-table"> <tbody> <tr valign="top"> <th scope="row"><?php echo esc_html__('Site Key', 'mailchimp-for-wp'); ?></th> <td class="nowrap integration-toggles-wrap"> <label> <input class="widefat prosopo-procaptcha__site-key" type="text" name="mc4wp_integrations[prosopo-procaptcha][site_key]" placeholder="<?php echo esc_attr__('Enter your site key', 'mailchimp-for-wp'); ?>" value="<?php echo esc_attr($site_key); ?>"> </label> <p class="description"> <?php echo sprintf( // translators: %1$s: opening anchor tag, %2$s: closing anchor tag esc_html__('The API key for connecting with your Procaptcha account. %1$s Get your Site key here %2$s', 'mailchimp-for-wp'), '<a href="https://portal.prosopo.io/site-management" target="_blank">', '</a>' ); ?> </p> </td> </tr> <tr valign="top"> <th scope="row"><?php echo esc_html__('Secret Key', 'mailchimp-for-wp'); ?></th> <td class="nowrap integration-toggles-wrap"> <label> <input class="widefat prosopo-procaptcha__secret-key" type="password" name="mc4wp_integrations[prosopo-procaptcha][secret_key]" placeholder="<?php echo esc_attr__('Enter your secret key', 'mailchimp-for-wp'); ?>" value="<?php echo esc_attr($secret_key); ?>"> </label> </td> </tr> <tr valign="top"> <th scope="row"><?php echo esc_html__('Theme', 'mailchimp-for-wp'); ?></th> <td class="nowrap integration-toggles-wrap"> <label> <select name="mc4wp_integrations[prosopo-procaptcha][theme]" style="width:250px;"> <?php foreach ($theme_options as $value => $label) { $selected = $theme === $value ? ' selected' : ''; printf('<option value="%s"%s>%s</option>', esc_attr($value), esc_attr($selected), esc_html($label)); } ?> </select> </label> </td> </tr> <tr valign="top"> <th scope="row"><?php echo esc_html__('Type', 'mailchimp-for-wp'); ?></th> <td class="nowrap integration-toggles-wrap"> <label> <select name="mc4wp_integrations[prosopo-procaptcha][type]" style="width:250px;"> <?php foreach ($type_options as $value => $label) { $selected = $type === $value ? ' selected' : ''; printf('<option value="%s"%s>%s</option>', esc_attr($value), esc_attr($selected), esc_html($label)); } ?> </select> </label> </td> </tr> <tr valign="top"> <th scope="row"><?php echo esc_html__('Display for authorized users', 'mailchimp-for-wp'); ?></th> <td class="nowrap integration-toggles-wrap"> <label> <input type="radio" name="mc4wp_integrations[prosopo-procaptcha][display_for_authorized]" value="1" <?php checked($display_for_authorized, '1'); ?> />‏ <?php echo esc_html__('Yes', 'mailchimp-for-wp'); ?> </label> <label> <input type="radio" name="mc4wp_integrations[prosopo-procaptcha][display_for_authorized]" value="0" <?php checked($display_for_authorized, '0'); ?> />‏ <?php echo esc_html__('No', 'mailchimp-for-wp'); ?> </label> <p class="description"><?php echo esc_html__('Select "yes" to require the captcha even from authorized users.', 'mailchimp-for-wp'); ?></p> </td> </tr> </tbody> </table> <prosopo-procaptcha-settings></prosopo-procaptcha-settings> <script type="module"> class ProsopoProcaptchaSettings extends HTMLElement { connectedCallback(){ "loading" === document.readyState ? document.addEventListener("DOMContentLoaded", this.setup.bind(this)) : this.setup() } updateEnabledSetting(event){ let form = event.target; let enabledInput = form.querySelector('.prosopo-procaptcha__enabled-setting'); let siteKey= form.querySelector('.prosopo-procaptcha__site-key').value.trim(); let secretKey = form.querySelector('.prosopo-procaptcha__secret-key').value.trim(); enabledInput.value = '' !== siteKey && '' !== secretKey? 1: 0; } setup(){ this.closest('form').addEventListener('submit', this.updateEnabledSetting.bind(this)) } } customElements.define('prosopo-procaptcha-settings', ProsopoProcaptchaSettings); </script> integrations/prosopo-procaptcha/bootstrap.php 0000777 00000000211 15251522663 0015633 0 ustar 00 <?php mc4wp_register_integration('prosopo-procaptcha', 'MC4WP_Procaptcha_Integration'); MC4WP_Procaptcha::get_instance()->set_hooks(); integrations/prosopo-procaptcha/class-procaptcha.php 0000777 00000026734 15251522663 0017067 0 ustar 00 <?php /** * Class MC4WP_Procaptcha * * @private */ class MC4WP_Procaptcha { private const SCRIPT_URL = 'https://js.prosopo.io/js/procaptcha.bundle.js'; private const FORM_FIELD_NAME = 'procaptcha-response'; private const API_URL = 'https://api.prosopo.io/siteverify'; /** * @var MC4WP_Procaptcha */ private static $instance; /** * @var bool */ private $is_in_use; /** * @var bool */ private $is_enabled; /** * @var bool */ private $is_displayed_for_authorized; /** * @var string */ private $site_key; /** * @var string */ private $secret_key; /** * @var string */ private $theme; /** * @var string */ private $type; private function __construct() { $this->is_in_use = false; $this->is_enabled = false; $this->is_displayed_for_authorized = false; $this->site_key = ''; $this->secret_key = ''; $this->theme = ''; $this->type = ''; $this->read_settings(); } /** * @return void */ protected function read_settings() { $integrations = get_option('mc4wp_integrations', []); if ( false === is_array($integrations) || false === key_exists('prosopo-procaptcha', $integrations) || false === is_array($integrations['prosopo-procaptcha']) ) { return; } $settings = $integrations['prosopo-procaptcha']; $this->is_enabled = true === key_exists('enabled', $settings) && '1' === $settings['enabled']; $this->is_displayed_for_authorized = true === key_exists('display_for_authorized', $settings) && '1' === $settings['display_for_authorized']; $this->site_key = true === key_exists('site_key', $settings) && true === is_string($settings['site_key']) ? $settings['site_key'] : ''; $this->secret_key = true === key_exists('secret_key', $settings) && true === is_string($settings['secret_key']) ? $settings['secret_key'] : ''; $this->theme = true === key_exists('theme', $settings) && true === is_string($settings['theme']) ? $settings['theme'] : ''; $this->type = true === key_exists('type', $settings) && true === is_string($settings['type']) ? $settings['type'] : ''; } /** * @return MC4WP_Procaptcha */ public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } /** * @return void */ protected function print_captcha_js() { $attributes = [ 'siteKey' => $this->site_key, 'theme' => $this->theme, 'captchaType' => $this->type, ]; ?> <script data-name="prosopo-procaptcha-element" type="module"> let attributes = <?php echo json_encode($attributes); ?>; class MC4WPProcaptcha extends HTMLElement { constructor() { super(); this.isValid = false; this.validationErrorElement = null; } connectedCallback() { // wait window.load to make sure 'window.procaptcha' is available. "complete" !== document.readyState ? window.addEventListener("load", this.setup.bind(this)) : this.setup(); } validatedCallback(output) { this.isValid = true; // the element is optional. if (null !== this.validationErrorElement) { this.validationErrorElement.style.visibility = 'hidden'; } } maybePreventSubmission(event) { if (true === this.isValid || // the element is optional. null === this.validationErrorElement) { return; } event.preventDefault(); event.stopPropagation(); this.validationErrorElement.style.visibility = 'visible'; } setup() { this.validationErrorElement = this.querySelector('.mc4wp-procaptcha__validation-error') attributes.callback = this.validatedCallback.bind(this); window.procaptcha.render(this.querySelector('.mc4wp-procaptcha__captcha'), attributes); this.closest('form').addEventListener('submit', this.maybePreventSubmission.bind(this)); } } customElements.define("mc4wp-procaptcha", MC4WPProcaptcha); </script> <?php } /** * @return bool */ protected function is_human_made_request() { $token = $_POST[self::FORM_FIELD_NAME] ?? ''; $token = true === is_string($token) ? $token : ''; // bail early if the token is empty. if ('' === $token) { return false; } $response = wp_remote_post( self::API_URL, [ 'method' => 'POST', // limit waiting time to 20 seconds. 'timeout' => 20, 'headers' => [ 'Content-Type' => 'application/json', ], 'body' => (string) wp_json_encode( [ 'secret' => $this->secret_key, 'token' => $token, ] ), ] ); // Check if request failed, either locally or remotely if (true === is_wp_error($response) || wp_remote_retrieve_response_code($response) >= 400) { /** @var MC4WP_Debug_Log */ $logger = mc4wp('log'); $logger->error(sprintf('ProCaptcha request error: %d %s - %s', wp_remote_retrieve_response_code($response), wp_remote_retrieve_response_message($response), wp_remote_retrieve_body($response))); // the check failed, but we don't want to break the form in case of Prosopo having server issues // so we write to log and act as if this user is human... return true; } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); // check if Prosopo API returned a correct JSON response if ($data === null || !is_array($data)) { $logger = mc4wp('log'); $logger->error(sprintf('ProCaptcha returned a non-JSON response: %s', $body)); return true; } $is_verified = isset($data['verified']) && $data['verified']; return true === $is_verified; } public function maybe_add_type_module_attribute(string $tag, string $handle, string $src): string { if ( 'prosopo-procaptcha' !== $handle || // make sure we don't make it twice if other Procaptcha integrations are present. false !== strpos('type="module"', $tag) ) { return $tag; } // for old WP versions. $tag = str_replace(' type="text/javascript"', '', $tag); return str_replace(' src=', ' type="module" src=', $tag); } /** * @return bool */ public function is_enabled() { return $this->is_enabled; } /** * @param bool $is_without_validation_element * @param bool $is_forced_render E.g. if it's a preview. * * @return string */ public function print_captcha_element($is_without_validation_element = false, $is_forced_render = false) { if ( false === $this->is_displayed_for_authorized && true === is_user_logged_in() && false === $is_forced_render ) { return ''; } $this->is_in_use = true; $html = '<mc4wp-procaptcha class="mc4wp-procaptcha" style="display: block;">'; $html .= '<div class="mc4wp-procaptcha__captcha"></div>'; // The element is optional, e.g. should be missing on the settings page. if (false === $is_without_validation_element) { $html .= '<p class="mc4wp-procaptcha__validation-error" style="visibility: hidden;color:red;line-height:1;font-size: 12px;padding: 7px 0 10px 10px;margin:0;">'; $html .= esc_html__('Please verify that you are human.', 'mailchimp-for-wp'); $html .= '</p>'; } $html .= '</mc4wp-procaptcha>'; return $html; } /** * @return void */ public function maybe_enqueue_captcha_js() { if (false === $this->is_in_use) { return; } // do not use wp_enqueue_module() because it doesn't work on the login screens. wp_enqueue_script( 'prosopo-procaptcha', self::SCRIPT_URL, [], null, [ 'in_footer' => true, 'strategy' => 'defer', ] ); $this->print_captcha_js(); } /** * @param array<string,string> $messages * @return array<string,string> */ public function register_error_message(array $messages) { $messages['procaptcha_required'] = 'Please verify that you are human.'; return $messages; } /** * @param string[] $error_keys * @param MC4WP_Form $form * * @return string[] */ public function validate_form($error_keys, $form) { if ( false === strpos($form->content, $this->get_field_stub()) || (false === $this->is_displayed_for_authorized && true === is_user_logged_in()) || true === $this->is_human_made_request() ) { return $error_keys; } $error_keys[] = 'procaptcha_required'; return $error_keys; } /** * @param string $html * @return string */ public function inject_captcha_element($html) { $stub = $this->get_field_stub(); if (false === strpos($html, $stub)) { return $html; } $captcha_element = $this->print_captcha_element(); return str_replace($stub, $captcha_element, $html); } /** * @return string */ protected function get_field_stub() { return '<input type="hidden" name="procaptcha">'; } public function set_hooks(): void { if (false === $this->is_enabled) { return; } add_filter('mc4wp_form_messages', [$this, 'register_error_message']); add_action('mc4wp_form_content', [$this, 'inject_captcha_element']); add_filter('mc4wp_form_errors', [$this, 'validate_form'], 10, 2); add_filter('script_loader_tag', [$this, 'maybe_add_type_module_attribute'], 10, 3); $hook = true === is_admin() ? 'admin_print_footer_scripts' : 'wp_print_footer_scripts'; // priority must be less than 10, to make sure the wp_enqueue_script still has effect. add_action($hook, [$this, 'maybe_enqueue_captcha_js'], 9); } } integrations/prosopo-procaptcha/admin-before.php 0000777 00000000654 15251522663 0016161 0 ustar 00 <?php // translators: %1$s is opening anchor tag, %2$s is closing anchor tag echo sprintf( esc_html__( '%1$s Procaptcha (by Prosopo) %2$s is offering seamless bot protection without compromising user data. You can customize settings and algorithms, ensuring optimal defense against all types of malicious bots.', 'mailchimp-for-wp' ), '<a href="https://prosopo.io/" target="_blank">', '</a>' ); integrations/easy-digital-downloads/class-easy-digital-downloads.php 0000777 00000005274 15251522663 0022024 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_Easy_Digital_Downloads_Integration * * @ignore */ class MC4WP_Easy_Digital_Downloads_Integration extends MC4WP_Integration { /** * @var string */ public $name = 'Easy Digital Downloads'; /** * @var string */ public $description = 'Subscribes your Easy Digital Downloads customers.'; /** * */ public function add_hooks() { if (! $this->options['implicit']) { // TODO: Allow more positions add_action('edd_purchase_form_user_info_fields', [ $this, 'output_checkbox' ], 1); add_action('edd_payment_meta', [ $this, 'save_checkbox_value' ]); } add_action('edd_complete_purchase', [ $this, 'subscribe_from_edd' ], 50); } /** * @param array $meta * * @return array */ public function save_checkbox_value($meta) { // don't save anything if the checkbox was not checked if (! $this->checkbox_was_checked()) { return $meta; } $meta['_mc4wp_optin'] = 1; return $meta; } /** * {@inheritdoc} * * @param $object_id * * @return bool */ public function triggered($object_id = null) { if ($this->options['implicit']) { return true; } if (! $object_id) { return false; } $meta = edd_get_payment_meta($object_id); if (is_array($meta) && isset($meta['_mc4wp_optin']) && $meta['_mc4wp_optin']) { return true; } return false; } /** * @param int $payment_id The ID of the payment * * @return bool|string */ public function subscribe_from_edd($payment_id) { if (! $this->triggered($payment_id)) { return false; } $email = (string) edd_get_payment_user_email($payment_id); $data = [ 'EMAIL' => $email, ]; // add first and last name to merge vars, if given $user_info = (array) edd_get_payment_meta_user_info($payment_id); if (! empty($user_info['first_name']) && ! empty($user_info['last_name'])) { $data['NAME'] = $user_info['first_name'] . ' ' . $user_info['last_name']; } if (! empty($user_info['first_name'])) { $data['FNAME'] = $user_info['first_name']; } if (! empty($user_info['last_name'])) { $data['LNAME'] = $user_info['last_name']; } return $this->subscribe($data, $payment_id); } /** * @return bool */ public function is_installed() { return class_exists('Easy_Digital_Downloads'); } } integrations/woocommerce/admin-after.php 0000777 00000004512 15251522663 0014511 0 ustar 00 <?php $position_options = [ 'after_email_field' => __('After email field', 'mailchimp-for-wp'), 'checkout_billing' => __('After billing details', 'mailchimp-for-wp'), 'checkout_shipping' => __('After shipping details', 'mailchimp-for-wp'), 'checkout_after_customer_details' => __('After customer details', 'mailchimp-for-wp'), 'review_order_before_submit' => __('Before submit button', 'mailchimp-for-wp'), 'after_order_notes' => __('After order notes', 'mailchimp-for-wp'), ]; if (defined('CFW_NAME')) { $position_options['cfw_checkout_before_payment_method_tab_nav'] = __('Checkout for WooCommerce: Before complete order button', 'mailchimp-for-wp'); $position_options['cfw_after_customer_info_account_details'] = __('Checkout for WooCommerce: After account info', 'mailchimp-for-wp'); $position_options['cfw_checkout_after_customer_info_address'] = __('Checkout for WooCommerce: After customer info', 'mailchimp-for-wp'); } /** @var MC4WP_Integration $integration */ $body_config = [ 'element' => 'mc4wp_integrations[' . $integration->slug . '][enabled]', 'value' => '1', 'hide' => false, ]; $config = [ 'element' => 'mc4wp_integrations[' . $integration->slug . '][implicit]', 'value' => '0', ]; ?> <table class="form-table"> <tbody class="integration-toggled-settings" data-showif="<?php echo esc_attr(json_encode($body_config)); ?>"> <tr valign="top" data-showif="<?php echo esc_attr(json_encode($config)); ?>"> <th scope="row"> <?php _e('Position', 'mailchimp-for-wp'); ?> </th> <td> <select name="mc4wp_integrations[<?php echo $integration->slug; ?>][position]"> <?php foreach ($position_options as $value => $label) { printf('<option value="%s" %s>%s</option>', esc_attr($value), selected($value, $opts['position'], false), esc_html($label)); } ?> </select> <p class="description"><?php esc_html_e('Select the location where you would like to show the sign-up checkbox. Note that only works if not using WooCommerce Checkout Block.', 'mailchimp-for-wp'); ?></p> </td> </tr> </tbody> </table> integrations/woocommerce/class-woocommerce.php 0000777 00000017023 15251522663 0015745 0 ustar 00 <?php defined('ABSPATH') or exit; use Automattic\WooCommerce\Blocks\Package; use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields; /** * Class MC4WP_WooCommerce_Integration * * @ignore */ class MC4WP_WooCommerce_Integration extends MC4WP_Integration { /** * @var string */ public $name = 'WooCommerce Checkout'; /** * @var string */ public $description = "Subscribes people from WooCommerce's Checkout form or Checkout Block."; /** * @var string[] */ public $checkbox_classes = [ 'input-checkbox', ]; public $wrapper_classes = [ 'form-row', 'form-row-wide', ]; /** * Add hooks */ public function add_hooks() { if (!$this->options['implicit']) { if ($this->options['position'] !== 'after_email_field') { // create hook name based on position setting $hook = $this->options['position']; // prefix hook with woocommerce_ if not already properly prefixed // note: we check for cfw_ prefix here to not override the Checkout for WC hook names if (strpos($hook, 'cfw_') !== 0 && strpos($hook, 'woocommerce_') !== 0) { $hook = "woocommerce_{$hook}"; } add_action($hook, [$this, 'output_checkbox'], 20); } else { add_filter('woocommerce_form_field_email', [$this, 'add_checkbox_after_email_field'], 10, 4); } add_action('woocommerce_checkout_update_order_meta', [$this, 'save_woocommerce_checkout_checkbox_value']); // specific hooks for klarna add_filter('kco_create_order', [$this, 'add_klarna_field']); add_filter('klarna_after_kco_confirmation', [$this, 'subscribe_from_klarna_checkout'], 10, 2); // hooks for when using WooCommerce Checkout Block add_action('woocommerce_init', [$this, 'add_checkout_block_field']); } add_action('woocommerce_checkout_order_processed', [$this, 'subscribe_from_woocommerce_checkout']); add_action('woocommerce_store_api_checkout_order_processed', [$this, 'subscribe_from_woocommerce_checkout']); if ($this->options['precheck']) { add_filter('woocommerce_get_default_value_for_mc4wp/optin', function ($value) { return '1'; }); } } /** * Add default value for "position" setting * * @return array */ protected function get_default_options() { $defaults = parent::get_default_options(); $defaults['position'] = 'billing'; return $defaults; } public function add_checkout_block_field() { // for compatibility with older WooCommerce versions // check if function exists before calling if (!function_exists('woocommerce_register_additional_checkout_field')) { return; } woocommerce_register_additional_checkout_field( [ 'id' => 'mc4wp/optin', 'location' => 'order', 'type' => 'checkbox', 'label' => $this->get_label_text(), 'optionalLabel' => $this->get_label_text(), 'show_in_order_confirmation' => false, ] ); } public function add_klarna_field($create) { $create['options']['additional_checkbox']['text'] = $this->get_label_text(); $create['options']['additional_checkbox']['checked'] = (bool) $this->options['precheck']; $create['options']['additional_checkbox']['required'] = false; return $create; } public function add_checkbox_after_email_field($field, $key, $args, $value) { if ($key !== 'billing_email') { return $field; } return $field . PHP_EOL . $this->get_checkbox_html(); } /** * @param int $order_id */ public function save_woocommerce_checkout_checkbox_value($order_id) { $order = wc_get_order($order_id); if (!$order) { return; } $order->update_meta_data('_mc4wp_optin', $this->checkbox_was_checked()); $order->save(); } /** * {@inheritdoc} * * @param int|\WC_Order $order_id * @return bool|mixed */ public function triggered($order_id = null) { if ($this->options['implicit']) { return true; } $order = wc_get_order($order_id); if (!$order) { return false; } // value from default checkout form (shortcode) $a = $order->get_meta('_mc4wp_optin'); // alternatively, value from Checkout Block field $b = false; if (class_exists(Package::class) && class_exists(CheckoutFields::class)) { $checkout_fields = Package::container()->get(CheckoutFields::class); if ( $checkout_fields && method_exists($checkout_fields, 'get_field_from_object') // method was private in earlier versions of WooCommerce, so check if callable && is_callable([$checkout_fields, 'get_field_from_object']) ) { $b = $checkout_fields->get_field_from_object('mc4wp/optin', $order, 'contact'); } } return $a || $b; } public function subscribe_from_klarna_checkout($order_id, $klarna_order) { // $klarna_order is the returned object from Klarna if (false === (bool) $klarna_order['merchant_requested']['additional_checkbox']) { return; } $order = wc_get_order($order_id); if (!$order) { return; } // store _mc4wp_optin in order meta $order->update_meta_data('_mc4wp_optin', true); $order->save(); // continue in regular subscribe flow $this->subscribe_from_woocommerce_checkout($order_id); return; } /** * @param int|\WC_Order $order_id * @return boolean */ public function subscribe_from_woocommerce_checkout($order_id) { if (!$this->triggered($order_id)) { return false; } $order = wc_get_order($order_id); if (!$order) { return false; } if (method_exists($order, 'get_billing_email')) { $data = [ 'EMAIL' => $order->get_billing_email(), 'NAME' => "{$order->get_billing_first_name()} {$order->get_billing_last_name()}", 'FNAME' => $order->get_billing_first_name(), 'LNAME' => $order->get_billing_last_name(), ]; } else { // NOTE: for compatibility with WooCommerce < 3.0 $data = [ 'EMAIL' => $order->billing_email, 'NAME' => "{$order->billing_first_name} {$order->billing_last_name}", 'FNAME' => $order->billing_first_name, 'LNAME' => $order->billing_last_name, ]; } // TODO: add billing address fields, maybe by finding Mailchimp field of type "address"? return $this->subscribe($data, $order_id); } /** * @return bool */ public function is_installed() { return class_exists('WooCommerce'); } /** * {@inheritdoc} * * @return string */ public function get_object_link($object_id) { return sprintf('<a href="%s">%s</a>', get_edit_post_link($object_id), sprintf(__('Order #%d', 'mailchimp-for-wp'), $object_id)); } } integrations/buddypress/class-buddypress.php 0000777 00000012526 15251522663 0015462 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_BuddyPress_Integration * * @ignore */ class MC4WP_BuddyPress_Integration extends MC4WP_User_Integration { /** * @var string */ public $name = 'BuddyPress'; /** * @var string */ public $description = 'Subscribes users from BuddyPress registration forms.'; /** * Add hooks */ public function add_hooks() { if (! $this->options['implicit']) { add_action('bp_before_registration_submit_buttons', [ $this, 'output_checkbox' ], 20); } if (is_multisite()) { /** * Multisite signups are a two-stage process - the data is first added to * the 'signups' table and then converted into an actual user during the * activation process. * * To avoid all signups being subscribed to the Mailchimp list until they * have responded to the activation email, a value is stored in the signup * usermeta data which is retrieved on activation and acted upon. */ add_filter('bp_signup_usermeta', [ $this, 'store_usermeta' ], 10, 1); add_action('bp_core_activated_user', [ $this, 'subscribe_from_usermeta' ], 10, 3); } else { add_action('bp_core_signup_user', [ $this, 'subscribe_from_form' ], 10, 4); } /** * There is one further issue to consider, which is that many BuddyPress * installs have a user moderation plugin (e.g. BP Registration Options) * installed. This is because email activation on itself is sometimes not enough to ensure * that user signups are not spammers. There should therefore be a way for * plugins to delay the Mailchimp signup process. * * Plugins can hook into the 'mc4wp_integration_buddypress_should_subscribe' filter to prevent * subscriptions from taking place: * * add_filter( 'mc4wp_integration_buddypress_should_subscribe', '__return_false' ); * * The plugin would then then call: * * do_action( 'mc4wp_integration_buddypress_subscribe_user', $user_id ); * * to perform the subscription at a later point. */ add_action('mc4wp_integration_buddypress_subscribe_user', [ $this, 'subscribe_buddypress_user' ], 10, 1); } /** * Subscribes from BuddyPress Registration Form. * * @param int $user_id * @param string $user_login * @param string $user_password * @param string $user_email * @return bool */ public function subscribe_from_form($user_id, $user_login, $user_password, $user_email) { if (! $this->triggered()) { return false; } $subscribe = true; /** * Allow other plugins to prevent the Mailchimp sign-up. * * @param bool $subscribe False does not subscribe the user. * @param int $user_id The user ID to subscribe */ $subscribe = apply_filters('mc4wp_integration_buddypress_should_subscribe', $subscribe, $user_id); if (! $subscribe) { return false; } return $this->subscribe_buddypress_user($user_id); } /** * Stores subscription data from BuddyPress Registration Form. * * @param array $usermeta The existing usermeta * @return array $usermeta The modified usermeta */ public function store_usermeta($usermeta) { // only add meta if triggered (checked) if ($this->triggered()) { $usermeta['mc4wp_subscribe'] = '1'; } return $usermeta; } /** * Subscribes from BuddyPress Activation. * * @param int $user_id The activated user ID * @param string $key the activation key (not used) * @param array $userdata An array containing the activated user data * @return bool */ public function subscribe_from_usermeta($user_id, $key, $userdata) { // sanity check if (empty($user_id)) { return false; } // bail if our usermeta key is not switched on $meta = ( isset($userdata['meta']) ) ? $userdata['meta'] : []; if (empty($meta['mc4wp_subscribe'])) { return false; } $subscribe = true; /** * @ignore Documented elsewhere, see MC4WP_BuddyPress_Integration::subscribe_from_form. */ $subscribe = apply_filters('mc4wp_integration_buddypress_should_subscribe', $subscribe, $user_id); if (! $subscribe) { return false; } return $this->subscribe_buddypress_user($user_id); } /** * Subscribes a user to Mailchimp list(s). * * @param int $user_id The user ID to subscribe * @return bool */ public function subscribe_buddypress_user($user_id) { $user = get_userdata($user_id); // was a user found with the given ID? if (! $user instanceof WP_User) { return false; } // gather email address and name from user $data = $this->user_merge_vars($user); return $this->subscribe($data, $user_id); } /* End BuddyPress functions */ /** * @return bool */ public function is_installed() { return class_exists('BuddyPress'); } } integrations/bootstrap.php 0000777 00000004016 15251522663 0012017 0 ustar 00 <?php /** * Try to include a file before each integration's settings page * * @param MC4WP_Integration $integration * @param array $opts * @ignore */ function mc4wp_admin_before_integration_settings(MC4WP_Integration $integration, $opts) { $file = __DIR__ . '/' . $integration->slug . '/admin-before.php'; if (file_exists($file)) { include $file; } } /** * Try to include a file before each integration's settings page * * @param MC4WP_Integration $integration * @param array $opts * @ignore */ function mc4wp_admin_after_integration_settings(MC4WP_Integration $integration, $opts) { $file = __DIR__ . '/' . $integration->slug . '/admin-after.php'; if (file_exists($file)) { include $file; } } add_action('mc4wp_admin_before_integration_settings', 'mc4wp_admin_before_integration_settings', 30, 2); add_action('mc4wp_admin_after_integration_settings', 'mc4wp_admin_after_integration_settings', 30, 2); // Register core integrations mc4wp_register_integration('wp-comment-form', 'MC4WP_Comment_Form_Integration'); mc4wp_register_integration('wp-registration-form', 'MC4WP_Registration_Form_Integration'); mc4wp_register_integration('buddypress', 'MC4WP_BuddyPress_Integration'); mc4wp_register_integration('easy-digital-downloads', 'MC4WP_Easy_Digital_Downloads_Integration'); mc4wp_register_integration('contact-form-7', 'MC4WP_Contact_Form_7_Integration', true); mc4wp_register_integration('events-manager', 'MC4WP_Events_Manager_Integration'); mc4wp_register_integration('memberpress', 'MC4WP_MemberPress_Integration'); mc4wp_register_integration('affiliatewp', 'MC4WP_AffiliateWP_Integration'); mc4wp_register_integration('give', 'MC4WP_Give_Integration'); mc4wp_register_integration('custom', 'MC4WP_Custom_Integration', true); mc4wp_register_integration('woocommerce', 'MC4WP_WooCommerce_Integration'); require __DIR__ . '/prosopo-procaptcha/bootstrap.php'; require __DIR__ . '/wpforms/bootstrap.php'; require __DIR__ . '/gravity-forms/bootstrap.php'; require __DIR__ . '/ninja-forms/bootstrap.php'; integrations/wpforms/admin-before.php 0000777 00000000304 15251522663 0014023 0 ustar 00 <p> <?php printf(__('Use this integration by adding the "Mailchimp" field to <a href="%s">your WPForms forms</a>.', 'mailchimp-for-wp'), admin_url('admin.php?page=wpforms-overview')); ?> </p> integrations/wpforms/class-wpforms.php 0000777 00000003514 15251522663 0014301 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_WPForms_Integration * * @ignore */ class MC4WP_WPForms_Integration extends MC4WP_Integration { /** * @var string */ public $name = 'WPForms'; /** * @var string */ public $description = 'Subscribe visitors from your WPForms forms.'; /** * Add hooks */ public function add_hooks() { add_action('wpforms_process', [ $this, 'listen_to_wpforms' ], 20, 3); } /** * @return bool */ public function is_installed() { return defined('WPFORMS_VERSION'); } /** * @since 3.0 * @return array */ public function get_ui_elements() { return []; } public function listen_to_wpforms($fields, $entry, $form_data) { foreach ($fields as $field_id => $field) { if ($field['type'] === 'mailchimp' && (int) $field['value_raw'] === 1) { return $this->subscribe_from_wpforms($field_id, $fields, $form_data); } } } public function subscribe_from_wpforms($checkbox_field_id, $fields, $form_data) { foreach ($fields as $field) { if ($field['type'] === 'email') { $email_address = $field['value']; } } $mailchimp_list_id = $form_data['fields'][ $checkbox_field_id ]['mailchimp_list']; $this->options['lists'] = [ $mailchimp_list_id ]; if (! empty($email_address)) { return $this->subscribe([ 'EMAIL' => $email_address ], $form_data['id']); } } /** * @param int $form_id * @return string */ public function get_object_link($form_id) { return '<a href="' . admin_url(sprintf('admin.php?page=wpforms-builder&view=fields&form_id=%d', $form_id)) . '">WPForms</a>'; } } integrations/wpforms/bootstrap.php 0000777 00000000323 15251522663 0013511 0 ustar 00 <?php mc4wp_register_integration('wpforms', 'MC4WP_WPForms_Integration', true); add_action('plugins_loaded', function () { if (class_exists('WPForms_Field')) { new MC4WP_WPForms_Field(); } }); integrations/wpforms/class-field.php 0000777 00000022306 15251522663 0013667 0 ustar 00 <?php class MC4WP_WPForms_Field extends WPForms_Field { /** * Primary class constructor. * * @since 1.0.0 */ public function init() { $this->name = 'Mailchimp'; $this->type = 'mailchimp'; $this->icon = 'fa-envelope-o'; $this->order = 21; $this->defaults = [ [ 'label' => 'Sign-up to our newsletter?', 'value' => '1', 'default' => '', ], ]; add_action('init', [$this, 'translate_label']); } public function translate_label(): void { $this->defaults[0]['label'] = __('Sign-up to our newsletter?', 'mailchimp-for-wp'); } /** * Field options panel inside the builder. * * @since 1.0.0 * @param array $field */ public function field_options($field) { //--------------------------------------------------------------------// // Basic field options //--------------------------------------------------------------------// // Options open markup $this->field_option('basic-options', $field, [ 'markup' => 'open' ]); // Mailchimp list $this->field_option_mailchimp_list($field); // Choices $this->field_option_choices($field); // Description $this->field_option('description', $field); // Required toggle $this->field_option('required', $field); // Options close markup $this->field_option('basic-options', $field, [ 'markup' => 'close' ]); //--------------------------------------------------------------------// // Advanced field options //--------------------------------------------------------------------// // Options open markup $this->field_option('advanced-options', $field, [ 'markup' => 'open' ]); // Custom CSS classes $this->field_option('css', $field); // Options close markup $this->field_option('advanced-options', $field, [ 'markup' => 'close' ]); } private function field_option_mailchimp_list($field) { $mailchimp = new MC4WP_MailChimp(); // Field option label $tooltip = __('Select the Mailchimp list to subscribe to.', 'mailchimp-for-wp'); $option_label = $this->field_element( 'label', $field, [ 'slug' => 'mailchimp-list', 'value' => __('Mailchimp list', 'mailchimp-for-wp'), 'tooltip' => $tooltip, ], false ); $option_select = sprintf('<select name="fields[%s][mailchimp_list]" data-field-id="%d" data-field-type="%s">', $field['id'], $field['id'], $this->type); $lists = $mailchimp->get_lists(); foreach ($lists as $list) { $option_select .= sprintf('<option value="%s" %s>%s</option>', $list->id, selected($list->id, $field['mailchimp_list'], false), $list->name); } $option_select .= '</select>'; // Field option row (markup) including label and input. $output = $this->field_element( 'row', $field, [ 'slug' => 'mailchimp-list', 'content' => $option_label . $option_select, ] ); } private function field_option_choices($field) { $tooltip = __('Set your sign-up label text and whether it should be pre-checked.', 'mailchimp-for-wp'); $values = ! empty($field['choices']) ? $field['choices'] : $this->defaults; $class = ! empty($field['show_values']) && (int) $field['show_values'] === 1 ? 'show-values' : ''; $class .= ! empty($dynamic) ? ' wpforms-hidden' : ''; // Field option label $option_label = $this->field_element( 'label', $field, [ 'slug' => 'mailchimp-checkbox', 'value' => __('Sign-up checkbox', 'mailchimp-for-wp'), 'tooltip' => $tooltip, ], false ); // Field option choices inputs $option_choices = sprintf('<ul class="choices-list %s" data-field-id="%d" data-field-type="%s">', $class, $field['id'], $this->type); foreach ($values as $key => $value) { $default = ! empty($value['default']) ? $value['default'] : ''; $option_choices .= sprintf('<li data-key="%d">', $key); $option_choices .= sprintf('<input type="checkbox" name="fields[%s][choices][%s][default]" class="default" value="1" %s>', $field['id'], $key, checked('1', $default, false)); $option_choices .= sprintf('<input type="text" name="fields[%s][choices][%s][label]" value="%s" class="label">', $field['id'], $key, esc_attr($value['label'])); $option_choices .= sprintf('<input type="text" name="fields[%s][choices][%s][value]" value="%s" class="value">', $field['id'], $key, esc_attr($value['value'])); $option_choices .= '</li>'; } $option_choices .= '</ul>'; // Field option row (markup) including label and input. $output = $this->field_element( 'row', $field, [ 'slug' => 'choices', 'content' => $option_label . $option_choices, ] ); } /** * Field preview inside the builder. * * @since 1.0.0 * @param array $field */ public function field_preview($field) { $values = ! empty($field['choices']) ? $field['choices'] : $this->defaults; // Field checkbox elements echo '<ul class="primary-input">'; // Notify if currently empty if (empty($values)) { $values = [ 'label' => __('(empty)', 'wpforms') ]; } // Individual checkbox options foreach ($values as $key => $value) { $default = isset($value['default']) ? $value['default'] : ''; $selected = checked('1', $default, false); printf('<li><input type="checkbox" %s disabled>%s</li>', $selected, $value['label']); } echo '</ul>'; // Dynamic population is enabled and contains more than 20 items if (isset($total) && $total > 20) { echo '<div class="wpforms-alert-dynamic wpforms-alert wpforms-alert-warning">'; printf(__('Showing the first 20 choices.<br> All %d choices will be displayed when viewing the form.', 'wpforms'), absint($total)); echo '</div>'; } // Description $this->field_preview_option('description', $field); } /** * Field display on the form front-end. * * @since 1.0.0 * @param null $field (deprecated) * @param array $form_data */ public function field_display($field, $field_atts, $form_data) { // Setup some defaults because WPForms broke their integration in v1.8.1.1 $field_atts = array_merge([ 'input_class' => [], 'input_id' => [], ], is_array($field_atts) ? $field_atts : []); // Setup and sanitize the necessary data $field_required = ! empty($field['required']) ? ' required' : ''; $field_class = implode(' ', array_map('sanitize_html_class', (array) $field_atts['input_class'])); $field_id = implode(' ', array_map('sanitize_html_class', (array) $field_atts['input_id'])); $form_id = $form_data['id']; $choices = (array) $field['choices']; // List printf('<ul id="%s" class="%s">', $field_id, $field_class); foreach ($choices as $key => $choice) { $selected = isset($choice['default']) ? '1' : '0'; $depth = isset($choice['depth']) ? absint($choice['depth']) : 1; printf('<li class="choice-%d depth-%d">', $key, $depth); // Checkbox elements printf( '<input type="checkbox" id="wpforms-%d-field_%d_%d" name="wpforms[fields][%d]" value="%s" %s %s>', $form_id, $field['id'], $key, $field['id'], esc_attr($choice['value']), checked('1', $selected, false), $field_required ); printf('<label class="wpforms-field-label-inline" for="wpforms-%d-field_%d_%d">%s</label>', $form_id, $field['id'], $key, wp_kses_post($choice['label'])); echo '</li>'; } echo '</ul>'; } /** * Formats and sanitizes field. * * @since 1.0.2 * @param int $field_id * @param array $field_submit * @param array $form_data */ public function format($field_id, $field_submit, $form_data) { $field = $form_data['fields'][ $field_id ]; $choice = array_pop($field['choices']); $name = sanitize_text_field($choice['label']); $data = [ 'name' => $name, 'value' => empty($field_submit) ? __('No', 'mailchimp-for-wp') : __('Yes', 'mailchimp-for-wp'), 'value_raw' => $field_submit, 'id' => absint($field_id), 'type' => $this->type, ]; wpforms()->process->fields[ $field_id ] = $data; } } integrations/give/class-give.php 0000777 00000002227 15251522663 0012773 0 ustar 00 <?php defined('ABSPATH') or exit; /** * @ignore */ class MC4WP_Give_Integration extends MC4WP_Integration { public $name = 'Give'; public $description = 'Subscribes people from your Give donation forms.'; public $shown = false; public function add_hooks() { if (! $this->options['implicit']) { add_action('give_purchase_form_register_login_fields', [ $this, 'output_checkbox' ], 50); } add_action('give_checkout_before_gateway', [ $this, 'subscribe_from_give' ], 90, 2); } public function subscribe_from_give($posted, $user) { // was sign-up checkbox checked? if (true !== $this->triggered()) { return; } $merge_fields = [ 'EMAIL' => $user['email'], ]; if (! empty($user['first_name'])) { $merge_fields['FNAME'] = $user['first_name']; } if (! empty($user['last_name'])) { $merge_fields['LNAME'] = $user['last_name']; } return $this->subscribe($merge_fields); } public function is_installed() { return defined('GIVE_VERSION'); } } integrations/gravity-forms/admin-before.php 0000777 00000000463 15251522663 0015145 0 ustar 00 <p> <?php /* translators: %s links to the Gravity Forms overview page */ echo sprintf(__('To integrate with Gravity Forms, add the "Mailchimp for WordPress" field to <a href="%s">one of your Gravity Forms forms</a>.', 'mailchimp-for-wp'), admin_url('admin.php?page=gf_edit_forms')); ?> </p> integrations/gravity-forms/class-gravity-forms.php 0000777 00000013546 15251522663 0016537 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_Ninja_Forms_Integration * * @ignore */ class MC4WP_Gravity_Forms_Integration extends MC4WP_Integration { /** * @var string */ public $name = 'Gravity Forms'; /** * @var string */ public $description = 'Subscribe visitors from your Gravity Forms forms.'; /** * Add hooks */ public function add_hooks() { add_action('gform_field_standard_settings', [ $this, 'settings_fields' ], 10, 2); add_action('gform_editor_js', [ $this, 'editor_js' ]); add_action('gform_after_submission', [ $this, 'after_submission' ], 10, 2); } public function after_submission($submission, $form) { $subscribe = false; $email_address = ''; $mailchimp_list_id = ''; $double_optin = $this->options['double_optin']; // find email field & checkbox value foreach ($form['fields'] as $field) { if ($field->type === 'email' && empty($email_address) && ! empty($submission[ $field->id ])) { $email_address = $submission[ $field->id ]; } if ($field->type === 'mailchimp' && ! empty($submission[ $field->id ])) { $subscribe = true; $mailchimp_list_id = $field->mailchimp_list; if (isset($field->mailchimp_double_optin)) { $double_optin = $field->mailchimp_double_optin; } } } if (! $subscribe || empty($email_address)) { return; } // override integration settings with field options $orig_options = $this->options; $this->options['lists'] = [ $mailchimp_list_id ]; $this->options['double_optin'] = $double_optin; // perform the sign-up $this->subscribe([ 'EMAIL' => $email_address ], $submission['form_id']); // revert back to original options in case request lives on $this->options = $orig_options; } public function editor_js() { ?> <script type="text/javascript"> jQuery(document).on('gform_load_field_settings', function(evt, field) { jQuery('#field_mailchimp_list').val(field.mailchimp_list || ''); jQuery('#field_mailchimp_double_optin').val(field.mailchimp_double_optin || "1"); jQuery('#field_mailchimp_precheck').val(field.mailchimp_precheck || "0"); }); </script> <?php } public function settings_fields($pos, $form_id) { if ($pos !== 0) { return; } $mailchimp = new MC4WP_MailChimp(); $lists = $mailchimp->get_lists(); ?> <li class="mailchimp_list_setting field_setting"> <label for="field_mailchimp_list" class="section_label"> <?php esc_html_e('Mailchimp list', 'mailchimp-for-wp'); ?> </label> <select id="field_mailchimp_list" onchange="SetFieldProperty('mailchimp_list', this.value)"> <option value="" disabled><?php _e('Select a Mailchimp list', 'mailchimp-for-wp'); ?></option> <?php foreach ($lists as $list) { echo sprintf('<option value="%s">%s</option>', $list->id, $list->name); } ?> </select> <p class="help"> <?php echo __('Select the list(s) to which people who check the checkbox should be subscribed.', 'mailchimp-for-wp'); ?> </p> </li> <li class="mailchimp_double_optin field_setting"> <label for="field_mailchimp_double_optin" class="section_label"> <?php esc_html_e('Double opt-in?', 'mailchimp-for-wp'); ?> </label> <select id="field_mailchimp_double_optin" onchange="SetFieldProperty('mailchimp_double_optin', this.value)"> <option value="1"><?php echo __('Yes', 'mailchimp-for-wp'); ?></option> <option value="0"><?php echo __('No', 'mailchimp-for-wp'); ?></option> </select> <p class="help"> <?php _e('Select "yes" if you want people to confirm their email address before being subscribed (recommended)', 'mailchimp-for-wp'); ?> </p> </li> <li class="mailchimp_precheck field_setting"> <label for="field_mailchimp_precheck" class="section_label"> <?php esc_html_e('Pre-check the checkbox?', 'mailchimp-for-wp'); ?> </label> <select id="field_mailchimp_precheck" onchange="SetFieldProperty('mailchimp_precheck', this.value)"> <option value="1"><?php echo __('Yes', 'mailchimp-for-wp'); ?></option> <option value="0"><?php echo __('No', 'mailchimp-for-wp'); ?></option> </select> <p class="help"> <?php _e('Select "yes" if the checkbox should be pre-checked.', 'mailchimp-for-wp'); echo '<br />'; printf(__('<strong>Warning: </strong> enabling this may affect your <a href="%s">GDPR compliance</a>.', 'mailchimp-for-wp'), 'https://www.mc4wp.com/kb/gdpr-compliance/#utm_source=wp-plugin&utm_medium=mailchimp-for-wp&utm_campaign=integrations-page'); ?> </p> </li> <?php } /** * @return bool */ public function is_installed() { return class_exists('GF_Field') && class_exists('GF_Fields'); } /** * @since 3.0 * @return array */ public function get_ui_elements() { return []; } /** * @param int $form_id * @return string */ public function get_object_link($form_id) { return '<a href="' . admin_url(sprintf('admin.php?page=gf_edit_forms&id=%d', $form_id)) . '">Gravity Forms</a>'; } } integrations/gravity-forms/bootstrap.php 0000777 00000000423 15251522663 0014626 0 ustar 00 <?php defined('ABSPATH') or exit; mc4wp_register_integration('gravity-forms', 'MC4WP_Gravity_Forms_Integration', true); add_action('plugins_loaded', function () { if (class_exists('GF_Fields')) { GF_Fields::register(new MC4WP_Gravity_Forms_Field()); } }); integrations/gravity-forms/class-field.php 0000777 00000012404 15251522663 0015001 0 ustar 00 <?php class MC4WP_Gravity_Forms_Field extends GF_Field { public $type = 'mailchimp'; /** * Returns the field markup; including field label, description, validation, and the form editor admin buttons. * * The {FIELD} placeholder will be replaced in GFFormDisplay::get_field_content with the markup returned by GF_Field::get_field_input(). * * @param string|array $value The field value. From default/dynamic population, $_POST, or a resumed incomplete submission. * @param bool $force_frontend_label Should the frontend label be displayed in the admin even if an admin label is configured. * @param array $form The Form Object currently being processed. * * @return string */ public function get_field_content($value, $force_frontend_label, $form) { $validation_message = ( $this->failed_validation && ! empty($this->validation_message) ) ? sprintf("<div class='gfield_description validation_message'>%s</div>", $this->validation_message) : ''; $is_form_editor = $this->is_form_editor(); $is_entry_detail = $this->is_entry_detail(); $is_admin = $is_form_editor || $is_entry_detail; $admin_buttons = $this->get_admin_buttons(); $description = $this->get_description($this->description, 'gfield_description'); if ($this->is_description_above($form)) { $clear = $is_admin ? "<div class='gf_clear'></div>" : ''; $field_content = sprintf("%s%s{FIELD}%s$clear", $admin_buttons, $description, $validation_message); } else { $field_content = sprintf('%s{FIELD}%s%s', $admin_buttons, $description, $validation_message); } return $field_content; } public function get_form_editor_field_title() { return esc_attr__('Mailchimp for WordPress', 'mailchimp-for-wp'); } public function get_form_editor_field_settings() { return [ 'label_setting', 'description_setting', 'css_class_setting', 'mailchimp_list_setting', 'mailchimp_double_optin', 'mailchimp_precheck', 'rules_setting', ]; } public function get_field_input($form, $value = '', $entry = null) { $form_id = absint($form['id']); $is_entry_detail = $this->is_entry_detail(); $is_form_editor = $this->is_form_editor(); $id = $this->id; $field_id = $is_entry_detail || $is_form_editor || 0 === (int) $form_id ? "input_$id" : 'input_' . $form_id . "_$id"; $disabled_text = $is_form_editor ? 'disabled="disabled"' : ''; return sprintf("<div class='ginput_container ginput_container_checkbox'><ul class='gfield_checkbox' id='%s'>%s</ul></div>", esc_attr($field_id), $this->get_checkbox_choices($value, $disabled_text, $form_id)); } private function apply_mc4wp_options_filters($options) { $options = apply_filters('mc4wp_integration_gravity-forms_options', $options); return $options; } public function get_checkbox_choices($value, $disabled_text, $form_id = 0) { $choices = ''; $is_entry_detail = $this->is_entry_detail(); $is_form_editor = $this->is_form_editor(); $options = [ 'label' => $this->get_field_label(false, $value), 'precheck' => isset($this->mailchimp_precheck) ? $this->mailchimp_precheck : false, ]; $options = $this->apply_mc4wp_options_filters($options); // generate html $choice = [ 'text' => $options['label'], 'value' => '1', 'isSelected' => $options['precheck'], ]; $input_id = $this->id; if ($is_entry_detail || $is_form_editor || 0 === (int) $form_id) { $id = $this->id; } else { $id = $form_id . '_' . $this->id; } if (! isset($_GET['gf_token']) && empty($_POST) && rgar($choice, 'isSelected')) { $checked = "checked='checked'"; } elseif (is_array($value) && RGFormsModel::choice_value_match($this, $choice, rgget($input_id, $value))) { $checked = "checked='checked'"; } elseif (! is_array($value) && RGFormsModel::choice_value_match($this, $choice, $value)) { $checked = "checked='checked'"; } else { $checked = ''; } $tabindex = $this->get_tabindex(); $choice_value = $choice['value']; $choice_value = esc_attr($choice_value); $choice_markup = "<li class='gchoice_{$id}'> <input name='input_{$input_id}' type='checkbox' value='{$choice_value}' {$checked} id='choice_{$id}' {$tabindex} {$disabled_text} /> <label for='choice_{$id}' id='label_{$id}'>{$choice['text']}</label> </li>"; $choices .= gf_apply_filters( [ 'gform_field_choice_markup_pre_render', $this->formId, $this->id, ], $choice_markup, $choice, $this, $value ); return gf_apply_filters([ 'gform_field_choices', $this->formId, $this->id ], $choices, $this); } } integrations/custom/class-custom.php 0000777 00000006405 15251522663 0013735 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_Custom_Integration * @ignore */ class MC4WP_Custom_Integration extends MC4WP_Integration { /** * @var string */ protected $checkbox_name = 'mc4wp-subscribe'; /** * @var string */ public $name = 'Custom'; /** * @var string */ public $description = 'Integrate with custom third-party forms.'; /** * Add hooks */ public function add_hooks() { add_action('init', [ $this, 'listen' ], 50); } /** * Was the integration checkbox checked? * * @return bool */ public function checkbox_was_checked() { $data = $this->get_data(); $value = isset($data[ $this->checkbox_name ]) ? $data[ $this->checkbox_name ] : ''; $truthy_values = [ 1, '1', 'yes', true, 'true', 'y' ]; return in_array($value, $truthy_values, true); } /** * Maybe fire a general subscription request * * @return bool|string */ public function listen() { if (! $this->checkbox_was_checked()) { return false; } // ignore requests from bots, crawlers and link previews if (empty($_SERVER['HTTP_USER_AGENT']) || preg_match('/bot|crawl|spider|seo|lighthouse|facebookexternalhit|preview/i', $_SERVER['HTTP_USER_AGENT'])) { return false; } // ignore requests without an HTTP referrer if (empty($_SERVER['HTTP_REFERER'])) { return false; } // ignore requests where HTTP Referer does not contain hostname from home_url $site_hostname = parse_url(get_home_url(), PHP_URL_HOST); if (strpos($_SERVER['HTTP_REFERER'], $site_hostname) === false) { return false; } $data = $this->get_data(); // don't run for CF7 or Events Manager requests // (since they use the same "mc4wp-subscribe" trigger) $disable_triggers = [ '_wpcf7' => '', 'action' => 'booking_add', ]; foreach ($disable_triggers as $trigger => $trigger_value) { if (isset($data[ $trigger ])) { $value = $data[ $trigger ]; // do nothing if trigger value is optional // or if trigger value matches if (empty($trigger_value) || $value === $trigger_value) { return false; } } } // run! return $this->process(); } /** * Process custom form * * @return bool|string */ public function process() { $parser = new MC4WP_Field_Guesser($this->get_data()); $data = $parser->combine([ 'guessed', 'namespaced' ]); // do nothing if no email was found if (empty($data['EMAIL'])) { $this->get_log()->warning(sprintf('%s > Unable to find EMAIL field.', $this->name)); return false; } return $this->subscribe($data); } /** * @return bool */ public function is_installed() { return true; } /** * @return array */ public function get_ui_elements() { return [ 'lists', 'double_optin', 'update_existing', 'replace_interests' ]; } } integrations/custom/admin-before.php 0000777 00000001056 15251522663 0013645 0 ustar 00 <p> <?php _e('To get a custom integration to work, include the following HTML in the form you are trying to integrate with.', 'mailchimp-for-wp'); ?> </p> <?php ob_start(); ?> <p> <label> <input type="checkbox" name="mc4wp-subscribe" value="1" /> <?php _e('Subscribe to our newsletter.', 'mailchimp-for-wp'); ?> </label> </p> <?php $html = ob_get_clean(); ?> <textarea class="widefat code-sample" rows="<?php echo substr_count($html, PHP_EOL); ?>" readonly onfocus="this.select()"><?php echo esc_textarea($html); ?></textarea> integrations/affiliatewp/class-affiliatewp.php 0000777 00000003475 15251522663 0015703 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_AffiliateWP_Integration * * @ignore */ class MC4WP_AffiliateWP_Integration extends MC4WP_User_Integration { /** * @var string */ public $name = 'AffiliateWP'; /** * @var string */ public $description = 'Subscribes people from your AffiliateWP registration form.'; /** * @var bool */ public $shown = false; /** * Add hooks */ public function add_hooks() { if (! $this->options['implicit']) { add_action('affwp_register_fields_before_tos', [ $this, 'maybe_output_checkbox' ], 20); } add_action('affwp_register_user', [ $this, 'subscribe_from_registration' ], 90, 1); } /** * Output checkbox, once. */ public function maybe_output_checkbox() { if (! $this->shown) { $this->output_checkbox(); $this->shown = true; } } /** * Subscribes from WP Registration Form * * @param int $affiliate_id * * @return bool|string */ public function subscribe_from_registration($affiliate_id) { // was sign-up checkbox checked? if (! $this->triggered()) { return false; } // gather emailadress from user who WordPress registered $user_id = affwp_get_affiliate_user_id($affiliate_id); $user = get_userdata($user_id); // was a user found with the given ID? if (! $user instanceof WP_User) { return false; } $data = $this->user_merge_vars($user); return $this->subscribe($data, $user_id); } /* End registration form functions */ /** * @return bool */ public function is_installed() { return class_exists('Affiliate_WP'); } } integrations/memberpress/class-memberpress.php 0000777 00000003324 15251522663 0015756 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_MemberPress_Integration * * @ignore */ class MC4WP_MemberPress_Integration extends MC4WP_Integration { /** * @var string */ public $name = 'MemberPress'; /** * @var string */ public $description = 'Subscribes people from MemberPress register forms.'; /** * Add hooks */ public function add_hooks() { if (! $this->options['implicit']) { if (has_action('mepr_checkout_before_submit')) { add_action('mepr_checkout_before_submit', [ $this, 'output_checkbox' ]); } else { add_action('mepr-checkout-before-submit', [ $this, 'output_checkbox' ]); } } if (has_action('mepr_signup')) { add_action('mepr_signup', [ $this, 'subscribe_from_memberpress' ], 5); } else { add_action('mepr-signup', [ $this, 'subscribe_from_memberpress' ], 5); } } /** * Subscribe from MemberPress sign-up forms. * * @param MeprTransaction $txn * @return bool */ public function subscribe_from_memberpress($txn) { // Is this integration triggered? (checkbox checked or implicit) if (! $this->triggered()) { return false; } $user = get_userdata($txn->user_id); $data = [ 'EMAIL' => $user->user_email, 'FNAME' => $user->first_name, 'LNAME' => $user->last_name, ]; // subscribe using email and name return $this->subscribe($data, $txn->id); } /** * @return bool */ public function is_installed() { return defined('MEPR_VERSION'); } } integrations/wp-comment-form/class-comment-form.php 0000777 00000005571 15251522663 0016546 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_Comment_Form_Integration * * @ignore */ class MC4WP_Comment_Form_Integration extends MC4WP_Integration { /** * @var bool */ protected $added_through_filter = false; /** * @var string */ public $name = 'Comment Form'; /** * @var string */ public $description = 'Subscribes people from your WordPress comment form.'; /** * Add hooks */ public function add_hooks() { if (! $this->options['implicit']) { // hooks for outputting the checkbox add_filter('comment_form_submit_field', [ $this, 'add_checkbox_before_submit_button' ], 90); add_action('thesis_hook_after_comment_box', [ $this, 'maybe_output_checkbox' ], 90); add_action('comment_form', [ $this, 'maybe_output_checkbox' ], 90); } // hooks for checking if we should subscribe the commenter add_action('comment_post', [ $this, 'subscribe_from_comment' ], 40, 2); } /** * This adds the checkbox just before the submit button and sets a flag to prevent it from outputting twice * * @param $submit_button_html * * @return string */ public function add_checkbox_before_submit_button($submit_button_html) { $this->added_through_filter = true; return $this->get_checkbox_html() . $submit_button_html; } /** * Output fallback * Will output the checkbox if comment_form() function does not use `comment_form_submit_field` filter yet. */ public function maybe_output_checkbox() { if (! $this->added_through_filter) { $this->output_checkbox(); } } /** * Grabs data from WP Comment Form * * @param int $comment_id * @param string $comment_approved * * @return bool|string */ public function subscribe_from_comment($comment_id, $comment_approved = '') { // was sign-up checkbox checked? if (! $this->triggered()) { return false; } // is this a spam comment? if ($comment_approved === 'spam') { return false; } $comment = get_comment($comment_id); $data = [ 'EMAIL' => $comment->comment_author_email, 'NAME' => $comment->comment_author, 'OPTIN_IP' => $comment->comment_author_IP, ]; return $this->subscribe($data, $comment_id); } /** * @return bool */ public function is_installed() { return true; } /** * {@inheritdoc } */ public function get_object_link($object_id) { $comment = get_comment($object_id); if (! $comment) { return ''; } return sprintf('<a href="%s">Comment #%d</a>', get_edit_comment_link($object_id), $object_id); } } integrations/contact-form-7/admin-before.php 0000777 00000000407 15251522663 0015072 0 ustar 00 <p> <?php printf(__('To integrate with Contact Form 7, configure the settings below and then add %s to your CF7 form mark-up.', 'mailchimp-for-wp'), '<input type="text" onfocus="this.select()" readonly value="' . esc_attr('[mc4wp_checkbox]') . '">'); ?> </p> integrations/contact-form-7/class-contact-form-7.php 0000777 00000010536 15251522663 0016411 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_Contact_Form_7_Integration * * @ignore */ class MC4WP_Contact_Form_7_Integration extends MC4WP_Integration { /** * @var string */ public $name = 'Contact Form 7'; /** * @var string */ public $description = 'Subscribes people from Contact Form 7 forms.'; /** * Add hooks */ public function add_hooks() { add_action('wpcf7_init', [ $this, 'init' ]); add_action('wpcf7_mail_sent', [ $this, 'process' ], 1); add_action('wpcf7_posted_data', [ $this, 'alter_cf7_data' ]); } /** * Registers the CF7 shortcode * * @return boolean */ public function init() { if (function_exists('wpcf7_add_form_tag')) { wpcf7_add_form_tag('mc4wp_checkbox', [ $this, 'shortcode' ]); } else { wpcf7_add_shortcode('mc4wp_checkbox', [ $this, 'shortcode' ]); } return true; } /** * @{inheritdoc} * * Contact Form 7 listens to the following triggers. * * - _mc4wp_subscribe_contact-form-7 * - mc4wp-subscribe * * @return bool */ public function checkbox_was_checked() { $data = $this->get_data(); return ( isset($data[ $this->checkbox_name ]) && (int) $data[ $this->checkbox_name ] === 1 ) || ( isset($data['mc4wp-subscribe']) && (int) $data['mc4wp-subscribe'] === 1 ); } /** * Alter Contact Form 7 data. * * Adds mc4wp_checkbox to post data so users can use `mc4wp_checkbox` in their email templates * * @param array $data * @return array */ public function alter_cf7_data($data = []) { $data['mc4wp_checkbox'] = $this->checkbox_was_checked() ? __('Yes', 'mailchimp-for-wp') : __('No', 'mailchimp-for-wp'); return $data; } /** * Subscribe from Contact Form 7 Forms * * @todo improve smart guessing based on selected Mailchimp lists * * @param WPCF7_ContactForm $cf7_form * @return bool */ public function process($cf7_form) { // was sign-up checkbox checked? if (! $this->checkbox_was_checked()) { return false; } $parser = new MC4WP_Field_Guesser($this->get_data()); $data = $parser->combine([ 'guessed', 'namespaced' ]); // do nothing if no email was found if (empty($data['EMAIL'])) { $this->get_log()->warning(sprintf('%s > Unable to find EMAIL field.', $this->name)); return false; } return $this->subscribe($data, $cf7_form->id()); } /** * Return the shortcode output * * @return string */ public function shortcode($args = []) { if (! empty($args['labels'][0])) { $this->options['label'] = $args['labels'][0]; } if (isset($args['options'])) { // check for default:0 or default:1 to set the checked attribute if (in_array('default:1', $args['options'], true)) { $this->options['precheck'] = true; } elseif (in_array('default:0', $args['options'], true)) { $this->options['precheck'] = false; } } // disable paragraph wrap because CF7 defaults to `wpautop` $this->options['wrap_p'] = 0; return $this->get_checkbox_html(); } /** * @return bool */ public function is_installed() { return function_exists('wpcf7_contact_form'); } /** * @since 3.0 * @return array */ public function get_ui_elements() { return array_diff(parent::get_ui_elements(), [ 'enabled', 'implicit' ]); } /** * @param int $object_id * @since 3.0 * @return string */ public function get_object_link($object_id) { // for backwards compatibility, not all CF7 sign-ups have an object id if (empty($object_id)) { return ''; } // Return empty string if CF7 is no longer activated. if (! function_exists('wpcf7_contact_form')) { return ''; } $form = wpcf7_contact_form($object_id); if (! is_object($form)) { return ''; } return sprintf('<a href="%s">%s</a>', admin_url('admin.php?page=wpcf7&post=' . $object_id), $form->title()); } } integrations/wp-registration-form/class-registration-form.php 0000777 00000004400 15251522663 0020654 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_Registration_Form_Integration * * @ignore */ class MC4WP_Registration_Form_Integration extends MC4WP_User_Integration { /** * @var string */ public $name = 'Registration Form'; /** * @var string */ public $description = 'Subscribes people from your WordPress registration form.'; /** * @var bool */ public $shown = false; /** * Add hooks */ public function add_hooks() { if (! $this->options['implicit']) { add_action('login_head', [ $this, 'print_css_reset' ]); add_action('um_after_register_fields', [ $this, 'maybe_output_checkbox' ], 20); add_action('register_form', [ $this, 'maybe_output_checkbox' ], 20); add_action('woocommerce_register_form', [ $this, 'maybe_output_checkbox' ], 20); } add_action('um_user_register', [ $this, 'subscribe_from_registration' ], 90, 1); add_action('user_register', [ $this, 'subscribe_from_registration' ], 90, 1); if (defined('um_plugin') && class_exists('UM')) { $this->name = 'UltimateMember'; $this->description = 'Subscribes people from your UltimateMember registration form.'; } } /** * Output checkbox, once. */ public function maybe_output_checkbox() { if (! $this->shown) { $this->output_checkbox(); $this->shown = true; } } /** * Subscribes from WP Registration Form * * @param int $user_id * * @return bool|string */ public function subscribe_from_registration($user_id) { // was sign-up checkbox checked? if (! $this->triggered()) { return false; } // gather emailadress from user who WordPress registered $user = get_userdata($user_id); // was a user found with the given ID? if (! $user instanceof WP_User) { return false; } $data = $this->user_merge_vars($user); return $this->subscribe($data, $user_id); } /* End registration form functions */ /** * @return bool */ public function is_installed() { return true; } } integrations/events-manager/class-events-manager.php 0000777 00000003473 15251522663 0016743 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_Events_Manager_Integration * * @ignore */ class MC4WP_Events_Manager_Integration extends MC4WP_Integration { /** * @var string */ public $name = 'Events Manager'; /** * @var string */ public $description = 'Subscribes people from Events Manager booking forms.'; /** * Add hooks */ public function add_hooks() { if (! $this->options['implicit']) { add_action('em_booking_form_footer', [ $this, 'output_checkbox' ]); } add_action('em_bookings_added', [ $this, 'subscribe_from_events_manager' ], 5); } /** * Subscribe from Events Manager booking forms. * * @param EM_Booking $args * @return bool */ public function subscribe_from_events_manager($args) { // Is this integration triggered? (checkbox checked or implicit) if (! $this->triggered()) { return false; } $em_data = $this->get_data(); // logged-in users do not have these form fields, so grab from user object instead if (empty($em_data['user_email']) && is_user_logged_in()) { $user = wp_get_current_user(); $em_data['user_email'] = $user->user_email; $em_data['user_name'] = sprintf('%s %s', $user->first_name, $user->last_name); } if (empty($em_data['user_email'])) { return false; } $data = [ 'EMAIL' => $em_data['user_email'], 'NAME' => $em_data['user_name'], ]; // subscribe using email and name return $this->subscribe($data, $args->booking_id); } /** * @return bool */ public function is_installed() { return defined('EM_VERSION'); } } integrations/ninja-forms/admin-before.php 0000777 00000000325 15251522663 0014554 0 ustar 00 <p> <?php echo sprintf(__('To integrate with Ninja Forms, add the "Mailchimp" action to <a href="%s">one of your Ninja Forms forms</a>.', 'mailchimp-for-wp'), admin_url('admin.php?page=ninja-forms')); ?> </p> integrations/ninja-forms/class-field.php 0000777 00000006171 15251522663 0014417 0 ustar 00 <?php if (! defined('ABSPATH')) { exit; } /** * Class MC4WP_Ninja_Forms_Field */ class MC4WP_Ninja_Forms_Field extends NF_Abstracts_Input { protected $_name = 'mc4wp_optin'; protected $_nicename = 'Mailchimp opt-in'; protected $_section = 'misc'; protected $_type = 'checkbox'; protected $_icon = 'check-square-o'; protected $_templates = 'checkbox'; protected $_test_value = 0; protected $_settings = [ 'checkbox_default_value', 'checked_calc_value', 'unchecked_calc_value' ]; protected $_settings_exclude = [ 'default', 'placeholder', 'input_limit_set', 'checkbox_values' ]; /** * NF_Fields_Checkbox constructor. * @since 3.0 */ public function __construct() { parent::__construct(); $this->_settings['label_pos']['value'] = 'right'; add_filter('ninja_forms_custom_columns', [ $this, 'custom_columns' ], 10, 2); add_action('init', [$this, 'translate_nicename']); } public function translate_nicename() { $this->_nicename = __('Mailchimp opt-in', 'mailchimp-for-wp'); } /** * Admin Form Element * Display the checkbox on the edit submissions area. * @since 3.0 * * @param $id Field ID. * @param $value Field value. * @return string HTML used for display of checkbox. */ public function admin_form_element($id, $value) { // If the checkboxes value is one... if (1 === (int) $value) { // ...this variable to checked. $checked = 'checked'; } else { // ...else leave the variable empty. $checked = ''; } // Return HTML to be output to the submission edit page. return "<input type='hidden' name='fields[$id]' value='0' ><input type='checkbox' name='fields[$id]' value='1' id='' $checked>"; } /** * Custom Columns * Creates what is displayed in the columns on the submissions page. * @since 3.0 * * @param string $value checkbox value * @param MC4WP_Ninja_Forms_Field $field field model. * @return $value string|void */ public function custom_columns($value, $field) { // If the field type is equal to checkbox... if ('mc4wp_optin' === $field->get_setting('type')) { // Backwards compatibility check for the new checked value setting. if (null === $field->get_setting('checked_value') && 1 === (int) $value) { return __('Checked', 'ninja-forms'); } elseif (null === $field->get_setting('unchecked_value') && 0 === (int) $value) { return __('Unchecked', 'ninja-forms'); } // If the field value is set to 1.... if (1 === (int) $value) { // Set the value to the checked value setting. $value = $field->get_setting('checked_value'); } else { // Else set the value to the unchecked value setting. $value = $field->get_setting('unchecked_value'); } } return $value; } } integrations/ninja-forms/bootstrap.php 0000777 00000001005 15251522663 0014235 0 ustar 00 <?php mc4wp_register_integration('ninja-forms', 'MC4WP_Ninja_Forms_Integration', true); add_filter('ninja_forms_register_fields', function ($fields) { if (class_exists(NF_Abstracts_Input::class)) { $fields['mc4wp_optin'] = new MC4WP_Ninja_Forms_Field(); } return $fields; }); add_filter('ninja_forms_register_actions', function ($actions) { if (class_exists(NF_Abstracts_Action::class)) { $actions['mc4wp_subscribe'] = new MC4WP_Ninja_Forms_Action(); } return $actions; }); integrations/ninja-forms/class-ninja-forms.php 0000777 00000003413 15251522663 0015553 0 ustar 00 <?php defined('ABSPATH') or exit; /** * Class MC4WP_Ninja_Forms_Integration * * @ignore */ class MC4WP_Ninja_Forms_Integration extends MC4WP_Integration { /** * @var string */ public $name = 'Ninja Forms'; /** * @var string */ public $description = 'Subscribe visitors from your Ninja Forms forms.'; /** * Add hooks */ public function add_hooks() { add_action('mc4wp_integration_ninja_forms_subscribe', [ $this, 'subscribe_from_ninja_forms' ], 10, 7); } public function subscribe_from_ninja_forms($email_address, $merge_fields, $list_id, $double_optin = true, $update_existing = false, $replace_interests = false, $form_id = 0) { // set options from parameters (coming from action) $orig_options = $this->options; $this->options['double_optin'] = $double_optin; $this->options['update_existing'] = $update_existing; $this->options['replace_interests'] = $replace_interests; $this->options['lists'] = [ $list_id ]; $data = $merge_fields; $data['EMAIL'] = $email_address; $this->subscribe($data, $form_id); // revert to original options $this->options = $orig_options; } /** * @return bool */ public function is_installed() { return class_exists('Ninja_Forms'); } /** * @since 3.0 * @return array */ public function get_ui_elements() { return []; } /** * @param int $form_id * @return string */ public function get_object_link($form_id) { return '<a href="' . admin_url(sprintf('admin.php?page=ninja-forms&form_id=%d', $form_id)) . '">Ninja Forms</a>'; } } integrations/ninja-forms/class-action.php 0000777 00000015522 15251522663 0014611 0 ustar 00 <?php /** * Class MC4WP_Ninja_Forms_Action */ class MC4WP_Ninja_Forms_Action extends NF_Abstracts_Action { protected $_name = 'mc4wp_subscribe'; protected $_nicename = 'Mailchimp'; protected $_tags = [ 'newsletter' ]; protected $_timing = 'normal'; protected $_priority = '10'; protected $_settings = []; protected $_setting_labels = [ 'list' => 'List', 'fields' => 'List Field Mapping', ]; public function __construct() { $this->_settings['double_optin'] = [ 'name' => 'double_optin', 'type' => 'select', 'label' => 'Use double opt-in?', 'width' => 'full', 'group' => 'primary', 'value' => 1, 'options' => [ [ 'value' => 1, 'label' => 'Yes', ], [ 'value' => 0, 'label' => 'No', ], ], ]; $this->_settings['update_existing'] = [ 'name' => 'update_existing', 'type' => 'select', 'label' => 'Update existing subscribers?', 'width' => 'full', 'group' => 'primary', 'value' => 0, 'options' => [ [ 'value' => 1, 'label' => 'Yes', ], [ 'value' => 0, 'label' => 'No', ], ], ]; add_action('wp_ajax_nf_' . $this->_name . '_get_lists', [$this, '_get_lists']); add_action('init', [$this, 'translate_props']); add_action('init', [$this, 'get_list_settings']); } public function translate_props() { $this->_settings['double_optin']['label'] = __('Use double opt-in?', 'mailchimp-for-wp'); $this->_settings['update_existing']['label'] = __('Update existing subscribers?', 'mailchimp-for-wp'); if (isset($this->_settings[ $this->get_name() . 'newsletter_list_fields' ])) { $this->_settings[ $this->get_name() . 'newsletter_list_fields' ]['label'] = __('List Field Mapping', 'mailchimp-for-wp'); } } /* * PUBLIC METHODS */ public function save($action_settings) { } public function process($action_settings, $form_id, $data) { if (empty($action_settings['newsletter_list']) || empty($action_settings['EMAIL'])) { return; } // find "mc4wp_optin" type field, bail if not checked. foreach ($data['fields'] as $field_data) { if ($field_data['type'] === 'mc4wp_optin' && empty($field_data['value'])) { return; } } $list_id = $action_settings['newsletter_list']; $email_address = $action_settings['EMAIL']; $mailchimp = new MC4WP_MailChimp(); $merge_fields = $mailchimp->get_list_merge_fields($list_id); foreach ($merge_fields as $merge_field) { if (! empty($action_settings[ $merge_field->tag ])) { $merge_fields[ $merge_field->tag ] = $action_settings[ $merge_field->tag ]; } } $double_optin = (int) $action_settings['double_optin'] !== 0; $update_existing = (int) $action_settings['update_existing'] === 1; $replace_interests = isset($action_settings['replace_interests']) && (int) $action_settings['replace_interests'] === 1; do_action('mc4wp_integration_ninja_forms_subscribe', $email_address, $merge_fields, $list_id, $double_optin, $update_existing, $replace_interests, $form_id); } public function ajax_get_lists_handler() { check_ajax_referer('ninja_forms_builder_nonce', 'security'); $lists = $this->get_lists(); array_unshift($return, [ 'value' => 0, 'label' => '-', 'fields' => [], 'groups' => [] ]); echo wp_json_encode([ 'lists' => $return ]); wp_die(); } private function get_lists() { $mailchimp = new MC4WP_MailChimp(); /** @var array $lists */ $lists = $mailchimp->get_lists(); $return = [ [ 'label' => '-', 'value' => 0, 'fields' => [], ] ]; foreach ($lists as $list) { $list_fields = []; foreach ($mailchimp->get_list_merge_fields($list->id) as $merge_field) { $list_fields[] = [ 'value' => $merge_field->tag, 'label' => $merge_field->name, ]; } // TODO: Add support for groups once base class supports this. $return[] = [ 'value' => $list->id, 'label' => $list->name, 'fields' => $list_fields, ]; } return $return; } public function get_list_settings() { $label_defaults = [ 'list' => 'List', 'fields' => 'List Field Mapping', ]; $labels = array_merge($label_defaults, $this->_setting_labels); $prefix = $this->get_name(); $lists = $this->get_lists(); $this->_settings[ $prefix . 'newsletter_list' ] = [ 'name' => 'newsletter_list', 'type' => 'select', 'label' => $labels[ 'list' ] . ' <a class="js-newsletter-list-update extra"><span class="dashicons dashicons-update"></span></a>', 'width' => 'full', 'group' => 'primary', 'value' => '0', 'options' => [], ]; if (empty($lists)) { return; } $fields = []; foreach ($lists as $list) { $this->_settings[ $prefix . 'newsletter_list' ][ 'options' ][] = $list; //Check to see if list has fields array set. if (isset($list[ 'fields' ])) { foreach ($list[ 'fields' ] as $field) { $name = $list[ 'value' ] . '_' . $field[ 'value' ]; $fields[] = [ 'name' => $name, 'type' => 'textbox', 'label' => $field[ 'label' ], 'width' => 'full', 'use_merge_tags' => [ 'exclude' => [ 'user', 'post', 'system', 'querystrings', ], ], ]; } } } $this->_settings[ $prefix . 'newsletter_list_fields' ] = [ 'name' => 'newsletter_list_fields', 'label' => 'List Field Mapping', 'type' => 'fieldset', 'group' => 'primary', 'settings' => [], ]; } }
| ver. 1.6 |
Github
|
.
| PHP 8.1.34 | Генерация страницы: 0.03 |
proxy
|
phpinfo
|
Настройка