Files
piratepoet/mailpoet/lib/Newsletter/Renderer/Renderer.php
Rodrigo Primo 5a85390655 Replace remaining calls to utf8_encode() with mb_convert_encoding()
In the previous commit, I removed all calls to the deprecated
utf8_encode() that seemed safe to remove. In this commit, I'm replacing
the calls to this function that I'm not sure if are same to remove or
not with mb_convert_encoding().

mb_convert_encoding() requires the extension mbstring to be enabled. It
should be enabled on most PHP install but not all. We are already using
mbstring functions in our code base and we provide a polyfill for PHP
installs where the extension is not enabled
(62bb75ed91/mailpoet/prefixer/composer.json (L25)).
So it should be safe to use it.

[MAILPOET-4865]
2023-04-28 10:26:03 +02:00

288 lines
8.6 KiB
PHP

<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Newsletter\Renderer;
use MailPoet\Config\Env;
use MailPoet\Config\ServicesChecker;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Logging\LoggerFactory;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Newsletter\Renderer\EscapeHelper as EHelper;
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
use MailPoet\NewsletterProcessingException;
use MailPoet\Tasks\Sending as SendingTask;
use MailPoet\Util\pQuery\DomNode;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Html2Text\Html2Text;
class Renderer {
const NEWSLETTER_TEMPLATE = 'Template.html';
const FILTER_POST_PROCESS = 'mailpoet_rendering_post_process';
/** @var Blocks\Renderer */
private $blocksRenderer;
/** @var Columns\Renderer */
private $columnsRenderer;
/** @var Preprocessor */
private $preprocessor;
/** @var \MailPoetVendor\CSS */
private $cSSInliner;
/** @var ServicesChecker */
private $servicesChecker;
/** @var WPFunctions */
private $wp;
/*** @var LoggerFactory */
private $loggerFactory;
/*** @var NewslettersRepository */
private $newslettersRepository;
/*** @var SendingQueuesRepository */
private $sendingQueuesRepository;
public function __construct(
Blocks\Renderer $blocksRenderer,
Columns\Renderer $columnsRenderer,
Preprocessor $preprocessor,
\MailPoetVendor\CSS $cSSInliner,
ServicesChecker $servicesChecker,
WPFunctions $wp,
LoggerFactory $loggerFactory,
NewslettersRepository $newslettersRepository,
SendingQueuesRepository $sendingQueuesRepository
) {
$this->blocksRenderer = $blocksRenderer;
$this->columnsRenderer = $columnsRenderer;
$this->preprocessor = $preprocessor;
$this->cSSInliner = $cSSInliner;
$this->servicesChecker = $servicesChecker;
$this->wp = $wp;
$this->loggerFactory = $loggerFactory;
$this->newslettersRepository = $newslettersRepository;
$this->sendingQueuesRepository = $sendingQueuesRepository;
}
public function render(NewsletterEntity $newsletter, SendingTask $sendingTask = null, $type = false) {
return $this->_render($newsletter, $sendingTask, $type);
}
public function renderAsPreview(NewsletterEntity $newsletter, $type = false, ?string $subject = null) {
return $this->_render($newsletter, null, $type, true, $subject);
}
private function _render(NewsletterEntity $newsletter, SendingTask $sendingTask = null, $type = false, $preview = false, $subject = null) {
$body = (is_array($newsletter->getBody()))
? $newsletter->getBody()
: [];
$content = (array_key_exists('content', $body))
? $body['content']
: [];
$styles = (array_key_exists('globalStyles', $body))
? $body['globalStyles']
: [];
if (
!$this->servicesChecker->isUserActivelyPaying() && !$preview
) {
$content = $this->addMailpoetLogoContentBlock($content, $styles);
}
$language = $this->wp->getBloginfo('language');
$metaRobots = $preview ? '<meta name="robots" content="noindex, nofollow" />' : '';
$renderedBody = "";
try {
$content = $this->preprocessor->process($newsletter, $content, $preview, $sendingTask);
$renderedBody = $this->renderBody($newsletter, $content);
} catch (NewsletterProcessingException $e) {
$this->loggerFactory->getLogger(LoggerFactory::TOPIC_COUPONS)->error(
$e->getMessage(),
['newsletter_id' => $newsletter->getId()]
);
$this->newslettersRepository->setAsCorrupt($newsletter);
if ($newsletter->getLatestQueue()) {
$this->sendingQueuesRepository->pause($newsletter->getLatestQueue());
}
}
$renderedStyles = $this->renderStyles($styles);
$customFontsLinks = StylesHelper::getCustomFontsLinks($styles);
$template = $this->injectContentIntoTemplate(
(string)file_get_contents(dirname(__FILE__) . '/' . self::NEWSLETTER_TEMPLATE),
[
$language,
$metaRobots,
htmlspecialchars($subject ?: $newsletter->getSubject()),
$renderedStyles,
$customFontsLinks,
EHelper::escapeHtmlText($newsletter->getPreheader()),
$renderedBody,
]
);
if ($template === null) {
$template = '';
}
$templateDom = $this->inlineCSSStyles($template);
$template = $this->postProcessTemplate($templateDom);
$renderedNewsletter = [
'html' => $template,
'text' => $this->renderTextVersion($template),
];
return ($type && !empty($renderedNewsletter[$type])) ?
$renderedNewsletter[$type] :
$renderedNewsletter;
}
/**
* @param NewsletterEntity $newsletter
* @param array $content
* @return string
*/
private function renderBody(NewsletterEntity $newsletter, array $content) {
$blocks = (array_key_exists('blocks', $content))
? $content['blocks']
: [];
$renderedContent = [];
foreach ($blocks as $contentBlock) {
$columnsData = $this->blocksRenderer->render($newsletter, $contentBlock);
$renderedContent[] = $this->columnsRenderer->render(
$contentBlock,
$columnsData
);
}
return implode('', $renderedContent);
}
/**
* @param array $styles
* @return string
*/
private function renderStyles(array $styles) {
$css = '';
foreach ($styles as $selector => $style) {
switch ($selector) {
case 'text':
$selector = 'td.mailpoet_paragraph, td.mailpoet_blockquote, li.mailpoet_paragraph';
break;
case 'body':
$selector = 'body, .mailpoet-wrapper';
break;
case 'link':
$selector = '.mailpoet-wrapper a';
break;
case 'wrapper':
$selector = '.mailpoet_content-wrapper';
break;
}
if (!is_array($style)) {
continue;
}
$css .= StylesHelper::setStyle($style, $selector);
}
return $css;
}
/**
* @param string $template
* @param string[] $content
* @return string|null
*/
private function injectContentIntoTemplate($template, $content) {
return preg_replace_callback('/{{\w+}}/', function($matches) use (&$content) {
return array_shift($content);
}, $template);
}
/**
* @param string $template
* @return DomNode
*/
private function inlineCSSStyles($template) {
return $this->cSSInliner->inlineCSS($template);
}
/**
* @param string $template
* @return string
*/
private function renderTextVersion($template) {
$template = (mb_detect_encoding($template, 'UTF-8', true)) ? $template : mb_convert_encoding($template, 'UTF-8', mb_list_encodings());
return @Html2Text::convert($template);
}
/**
* @param DomNode $templateDom
* @return string
*/
private function postProcessTemplate(DomNode $templateDom) {
// replace spaces in image tag URLs
foreach ($templateDom->query('img') as $image) {
$image->src = str_replace(' ', '%20', $image->src);
}
// because tburry/pquery contains a bug and replaces the opening non mso condition incorrectly we have to replace the opening tag with correct value
$template = $templateDom->__toString();
$template = str_replace('<!--[if !mso]><![endif]-->', '<!--[if !mso]><!-- -->', $template);
$template = $this->wp->applyFilters(
self::FILTER_POST_PROCESS,
$template
);
return $template;
}
/**
* @param array $content
* @param array $styles
* @return array
*/
private function addMailpoetLogoContentBlock(array $content, array $styles) {
if (empty($content['blocks'])) return $content;
$content['blocks'][] = [
'type' => 'container',
'orientation' => 'horizontal',
'styles' => [
'block' => [
'backgroundColor' => (!empty($styles['body']['backgroundColor'])) ?
$styles['body']['backgroundColor'] :
'transparent',
],
],
'blocks' => [
[
'type' => 'container',
'orientation' => 'vertical',
'styles' => [
],
'blocks' => [
[
'type' => 'image',
'link' => 'https://www.mailpoet.com/?ref=free-plan-user-email&utm_source=free_plan_user_email&utm_medium=email',
'src' => Env::$assetsUrl . '/img/mailpoet_logo_newsletter.png',
'fullWidth' => false,
'alt' => 'Email Marketing Powered by MailPoet',
'width' => '108px',
'height' => '65px',
'styles' => [
'block' => [
'textAlign' => 'center',
],
],
],
],
],
],
];
return $content;
}
}