init
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\WP;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
/**
|
||||
* Class AutocompletePostListLoader is used to load data for the frontend autocomplete
|
||||
*/
|
||||
class AutocompletePostListLoader {
|
||||
/** @var Functions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
Functions $wp
|
||||
) {
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function getProducts() {
|
||||
global $wpdb;
|
||||
|
||||
$products = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT `ID`, `post_title` FROM {$wpdb->posts} WHERE `post_type` = %s ORDER BY `post_title` ASC;",
|
||||
'product'
|
||||
));
|
||||
return $this->formatPosts($products);
|
||||
}
|
||||
|
||||
public function getMembershipPlans() {
|
||||
global $wpdb;
|
||||
$products = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT `ID`, `post_title` FROM {$wpdb->posts} WHERE `post_type` = %s AND `post_status` = 'publish' ORDER BY `post_title` ASC;",
|
||||
'wc_membership_plan'
|
||||
));
|
||||
return $this->formatPosts($products);
|
||||
}
|
||||
|
||||
public function getSubscriptionProducts() {
|
||||
global $wpdb;
|
||||
$products = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT `ID`, `post_title` FROM {$wpdb->posts} AS p
|
||||
INNER JOIN {$wpdb->term_relationships} AS trel ON trel.object_id = p.id
|
||||
INNER JOIN {$wpdb->term_taxonomy} AS ttax ON ttax.term_taxonomy_id = trel.term_taxonomy_id
|
||||
INNER JOIN {$wpdb->terms} AS t ON ttax.term_id = t.term_id AND t.slug IN ('subscription', 'variable-subscription')
|
||||
WHERE `p`.`post_type` = %s ORDER BY `post_title` ASC;",
|
||||
'product'
|
||||
));
|
||||
return $this->formatPosts($products);
|
||||
}
|
||||
|
||||
public function getWooCommerceCategories() {
|
||||
return $this->formatTerms($this->wp->getCategories(['taxonomy' => 'product_cat', 'orderby' => 'name']));
|
||||
}
|
||||
|
||||
public function getPosts() {
|
||||
global $wpdb;
|
||||
$optionList = $wpdb->get_results('SELECT ID, post_title FROM ' . $wpdb->posts . " WHERE post_type='post' ORDER BY `post_title` ASC;");
|
||||
return $this->formatPosts($optionList);
|
||||
}
|
||||
|
||||
public function getPages() {
|
||||
global $wpdb;
|
||||
$optionList = $wpdb->get_results('SELECT ID, post_title FROM ' . $wpdb->posts . " WHERE post_type='page' ORDER BY `post_title` ASC;");
|
||||
return $this->formatPosts($optionList);
|
||||
}
|
||||
|
||||
public function getWooCommerceTags() {
|
||||
return $this->formatTerms($this->wp->getTerms('product_tag'));
|
||||
}
|
||||
|
||||
public function getCategories() {
|
||||
return $this->formatTerms($this->wp->getCategories());
|
||||
}
|
||||
|
||||
public function getTags() {
|
||||
return $this->formatTerms($this->wp->getTags());
|
||||
}
|
||||
|
||||
private function formatPosts($posts) {
|
||||
if (empty($posts)) return [];
|
||||
$result = [];
|
||||
foreach ($posts as $post) {
|
||||
$result[] = [
|
||||
'id' => (string)$post->ID,
|
||||
'name' => $post->post_title,// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function formatTerms($terms) {
|
||||
if (empty($terms)) return [];
|
||||
if (!is_array($terms)) return []; // there can be instance of WP_Error instead of list of terms if woo commerce is not active
|
||||
$result = [];
|
||||
foreach ($terms as $term) {
|
||||
$result[] = [
|
||||
'id' => (string)$term->term_id,// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
|
||||
'name' => $term->name,
|
||||
];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\WP;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class DateTime {
|
||||
|
||||
const DEFAULT_DATE_FORMAT = 'Y-m-d';
|
||||
const DEFAULT_TIME_FORMAT = 'H:i:s';
|
||||
const DEFAULT_DATE_TIME_FORMAT = 'Y-m-d H:i:s';
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp = null
|
||||
) {
|
||||
if ($wp === null) {
|
||||
$wp = new WPFunctions();
|
||||
}
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function getTimeFormat() {
|
||||
$timeFormat = $this->wp->getOption('time_format');
|
||||
if (empty($timeFormat)) $timeFormat = self::DEFAULT_TIME_FORMAT;
|
||||
return $timeFormat;
|
||||
}
|
||||
|
||||
public function getDateFormat() {
|
||||
$dateFormat = $this->wp->getOption('date_format');
|
||||
if (empty($dateFormat)) $dateFormat = self::DEFAULT_DATE_FORMAT;
|
||||
return $dateFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $format Type of time to retrieve. Accepts 'mysql', 'timestamp', 'U',
|
||||
* or PHP date format string (e.g. 'Y-m-d').
|
||||
*
|
||||
* @return int|string Integer if `$format` is 'timestamp' or 'U'
|
||||
*/
|
||||
public function getCurrentTime(string $format = '') {
|
||||
if (empty($format)) $format = $this->getTimeFormat();
|
||||
return $this->wp->currentTime($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $format Type of time to retrieve. Accepts 'mysql', 'timestamp', 'U',
|
||||
* or PHP date format string (e.g. 'Y-m-d').
|
||||
|
||||
* @return int|string Integer if `$format` is 'timestamp' or 'U'
|
||||
*/
|
||||
public function getCurrentDate(string $format = '') {
|
||||
if (empty($format)) $format = $this->getDateFormat();
|
||||
return $this->getCurrentTime($format);
|
||||
}
|
||||
|
||||
public function formatTime($timestamp, $format = false) {
|
||||
if (empty($format)) $format = $this->getTimeFormat();
|
||||
|
||||
return date($format, $timestamp);
|
||||
}
|
||||
|
||||
public function formatDate($timestamp, $format = false) {
|
||||
if (empty($format)) $format = $this->getDateFormat();
|
||||
|
||||
return date($format, $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a list of time strings within an interval,
|
||||
* formatted and mapped from DEFAULT_TIME_FORMAT to WordPress time strings.
|
||||
*/
|
||||
public function getTimeInterval(
|
||||
$startTime = '00:00:00',
|
||||
$timeStep = '+1 hour',
|
||||
$totalSteps = 24
|
||||
) {
|
||||
$steps = [];
|
||||
|
||||
$formattedTime = $startTime;
|
||||
$timestamp = strtotime($formattedTime);
|
||||
|
||||
for ($step = 0; $step < $totalSteps; $step += 1) {
|
||||
$formattedTime = $this->formatTime($timestamp, self::DEFAULT_TIME_FORMAT);
|
||||
$labelTime = $this->formatTime($timestamp);
|
||||
$steps[$formattedTime] = $labelTime;
|
||||
|
||||
$timestamp = strtotime($timeStep, $timestamp);
|
||||
}
|
||||
|
||||
return $steps;
|
||||
}
|
||||
|
||||
public function getCurrentDateTime(): \DateTime {
|
||||
return new \DateTime("now", wp_timezone());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\WP;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\DI\ContainerWrapper;
|
||||
use MailPoet\Form\FormsRepository;
|
||||
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class Emoji {
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
public function __construct(
|
||||
WPFunctions $wp = null
|
||||
) {
|
||||
if ($wp === null) {
|
||||
$wp = new WPFunctions();
|
||||
}
|
||||
$this->wp = $wp;
|
||||
}
|
||||
|
||||
public function encodeEmojisInBody($newsletterRenderedBody) {
|
||||
if (is_array($newsletterRenderedBody)) {
|
||||
return array_map([$this, 'encodeRenderedBodyForUTF8Column'], $newsletterRenderedBody);
|
||||
}
|
||||
return $this->encodeRenderedBodyForUTF8Column($newsletterRenderedBody);
|
||||
}
|
||||
|
||||
public function decodeEmojisInBody($newsletterRenderedBody) {
|
||||
if (is_array($newsletterRenderedBody)) {
|
||||
return array_map([$this, 'decodeEntities'], $newsletterRenderedBody);
|
||||
}
|
||||
return $this->decodeEntities($newsletterRenderedBody);
|
||||
}
|
||||
|
||||
public function sanitizeEmojisInFormBody(array $body): array {
|
||||
$formsTableName = ContainerWrapper::getInstance()->get(FormsRepository::class)->getTableName();
|
||||
$bodyJson = json_encode($body, JSON_UNESCAPED_UNICODE);
|
||||
$fixedJson = $this->encodeForUTF8Column($formsTableName, 'body', $bodyJson);
|
||||
return json_decode($fixedJson, true);
|
||||
}
|
||||
|
||||
private function encodeRenderedBodyForUTF8Column($value) {
|
||||
$sendingQueuesTableName = ContainerWrapper::getInstance()->get(SendingQueuesRepository::class)->getTableName();
|
||||
return $this->encodeForUTF8Column(
|
||||
$sendingQueuesTableName,
|
||||
'newsletter_rendered_body',
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
public function encodeForUTF8Column($table, $field, $value) {
|
||||
global $wpdb;
|
||||
$charset = $wpdb->get_col_charset($table, $field);
|
||||
// utf8 doesn't support emojis, so we need to encode them
|
||||
// utf8 was an alias for utf8mb3, but it was dropped in MySQL 8.0.28 so we need to check both
|
||||
if ($charset === 'utf8' || $charset === 'utf8mb3') {
|
||||
$value = $this->wp->wpEncodeEmoji($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function decodeEntities($content) {
|
||||
// Based on WPFunctions::get()->wpStaticizeEmoji()
|
||||
|
||||
// Loosely match the Emoji Unicode range.
|
||||
$regex = '/(&#x[2-3][0-9a-f]{3};|[1-6][0-9a-f]{2};)/';
|
||||
|
||||
$matches = [];
|
||||
if (preg_match_all($regex, $content, $matches)) {
|
||||
if (!empty($matches[1])) {
|
||||
foreach ($matches[1] as $emoji) {
|
||||
$entity = html_entity_decode($emoji, ENT_COMPAT, 'UTF-8');
|
||||
$content = str_replace($emoji, $entity, $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,90 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\WP;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class Notice {
|
||||
|
||||
const TYPE_ERROR = 'error';
|
||||
const TYPE_WARNING = 'warning';
|
||||
const TYPE_SUCCESS = 'success';
|
||||
const TYPE_INFO = 'info';
|
||||
|
||||
private $type;
|
||||
private $message;
|
||||
private $classes;
|
||||
private $dataNoticeName;
|
||||
private $renderInParagraph;
|
||||
|
||||
public function __construct(
|
||||
$type,
|
||||
$message,
|
||||
$classes = '',
|
||||
$dataNoticeName = '',
|
||||
$renderInParagraph = true
|
||||
) {
|
||||
$this->type = $type;
|
||||
$this->message = $message;
|
||||
$this->classes = $classes;
|
||||
$this->dataNoticeName = $dataNoticeName;
|
||||
$this->renderInParagraph = $renderInParagraph;
|
||||
}
|
||||
|
||||
public function getMessage() {
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
public static function displayError($message, $classes = '', $dataNoticeName = '', $renderInParagraph = true, $showErrorTitle = true) {
|
||||
if ($showErrorTitle) {
|
||||
$message = sprintf(
|
||||
"<b>%s </b> %s",
|
||||
__('MailPoet Error:', 'mailpoet'),
|
||||
$message
|
||||
);
|
||||
}
|
||||
return self::createNotice(self::TYPE_ERROR, $message, $classes, $dataNoticeName, $renderInParagraph);
|
||||
}
|
||||
|
||||
public static function displayWarning($message, $classes = '', $dataNoticeName = '', $renderInParagraph = true) {
|
||||
return self::createNotice(self::TYPE_WARNING, $message, $classes, $dataNoticeName, $renderInParagraph);
|
||||
}
|
||||
|
||||
public static function displaySuccess($message, $classes = '', $dataNoticeName = '', $renderInParagraph = true) {
|
||||
return self::createNotice(self::TYPE_SUCCESS, $message, $classes, $dataNoticeName, $renderInParagraph);
|
||||
}
|
||||
|
||||
public static function displayInfo($message, $classes = '', $dataNoticeName = '', $renderInParagraph = true) {
|
||||
return self::createNotice(self::TYPE_INFO, $message, $classes, $dataNoticeName, $renderInParagraph);
|
||||
}
|
||||
|
||||
protected static function createNotice($type, $message, $classes, $dataNoticeName, $renderInParagraph) {
|
||||
$notice = new Notice($type, $message, $classes, $dataNoticeName, $renderInParagraph);
|
||||
WPFunctions::get()->addAction('admin_notices', [$notice, 'displayWPNotice']);
|
||||
return $notice;
|
||||
}
|
||||
|
||||
public function displayWPNotice() {
|
||||
$class = sprintf('notice notice-%s mailpoet_notice_server %s', $this->type, $this->classes);
|
||||
$message = nl2br($this->message);
|
||||
|
||||
if ($this->renderInParagraph) {
|
||||
printf(
|
||||
'<div class="%1$s" %3$s><p>%2$s</p></div>',
|
||||
esc_attr($class),
|
||||
wp_kses_post($message),
|
||||
!empty($this->dataNoticeName) ? sprintf('data-notice="%s"', esc_attr($this->dataNoticeName)) : ''
|
||||
);
|
||||
} else {
|
||||
printf(
|
||||
'<div class="%1$s" %3$s>%2$s</div>',
|
||||
esc_attr($class),
|
||||
wp_kses_post($message),
|
||||
!empty($this->dataNoticeName) ? sprintf('data-notice="%s"', esc_attr($this->dataNoticeName)) : ''
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\WP;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
|
||||
class Posts {
|
||||
public static function getTypes($args = [], $output = 'names', $operator = 'and') {
|
||||
$defaults = [
|
||||
'exclude_from_search' => false,
|
||||
];
|
||||
$args = array_merge($defaults, $args);
|
||||
return WPFunctions::get()->getPostTypes($args, $output, $operator);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
|
||||
|
||||
namespace MailPoet\WP;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
class Readme {
|
||||
public static function parseChangelog($readmeTxt, $limit = null) {
|
||||
// Extract changelog section of the readme.txt
|
||||
preg_match('/== Changelog ==(.*?)(\n==|$)/is', $readmeTxt, $changelog);
|
||||
|
||||
if (empty($changelog[1])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get changelog entries
|
||||
$entries = preg_split('/\n(?=\=)/', trim($changelog[1]), -1, PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
if (empty($entries)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$c = 0;
|
||||
$changelog = [];
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
// Locate version header and changes list
|
||||
preg_match('/=(.*?)=(.*)/s', $entry, $parts);
|
||||
|
||||
if (empty($parts[1]) || empty($parts[2])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$header = trim($parts[1]);
|
||||
$list = trim($parts[2]);
|
||||
|
||||
// Get individual items from the list
|
||||
$list = preg_split('/(^|\n)[\* ]*/', $list, -1, PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
$changelog[] = [
|
||||
'version' => $header,
|
||||
'changes' => $list,
|
||||
];
|
||||
|
||||
if (++$c == $limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $changelog;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
Reference in New Issue
Block a user