File manager - Edit - /home/monara/public_html/test.athavaneng.com/Editor.tar
Back
index.php 0000644 00000000006 15073230107 0006356 0 ustar 00 <?php MetaInformationManager.php 0000644 00000004342 15073230107 0011645 0 ustar 00 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing namespace MailPoet\Newsletter\Editor; if (!defined('ABSPATH')) exit; use MailPoet\WP\Functions as WPFunctions; class MetaInformationManager { public function appendMetaInformation($content, $post, $args) { // Append author and categories above and below contents foreach (['above', 'below'] as $position) { $positionField = $position . 'Text'; $text = []; if (isset($args['showAuthor']) && $args['showAuthor'] === $positionField) { $text[] = self::getPostAuthor( $post->post_author, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $args['authorPrecededBy'] ); } if (isset($args['showCategories']) && $args['showCategories'] === $positionField) { $text[] = self::getPostCategories( $post->ID, $post->post_type, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $args['categoriesPrecededBy'] ); } if (!empty($text)) { $text = '<p>' . implode('<br />', $text) . '</p>'; if ($position === 'above') $content = $text . $content; else if ($position === 'below') $content .= $text; } } return $content; } private static function getPostCategories($postId, $postType, $precededBy) { $precededBy = trim($precededBy); // Get categories $categories = WPFunctions::get()->wpGetPostTerms( $postId, ['category'], ['fields' => 'names'] ); if (!empty($categories)) { // check if the user specified a label to be displayed before the author's name if (strlen($precededBy) > 0) { $content = stripslashes($precededBy) . ' '; } else { $content = ''; } return $content . join(', ', $categories); } else { return ''; } } private static function getPostAuthor($authorId, $precededBy) { $authorName = WPFunctions::get()->getTheAuthorMeta('display_name', (int)$authorId); $precededBy = trim($precededBy); if (strlen($precededBy) > 0) { $authorName = stripslashes($precededBy) . ' ' . $authorName; } return $authorName; } } PostTransformer.php 0000644 00000012206 15073230107 0010424 0 ustar 00 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing namespace MailPoet\Newsletter\Editor; if (!defined('ABSPATH')) exit; class PostTransformer { /** @var PostTransformerContentsExtractor */ private $extractor; /** @var array */ private $args; /** @var bool */ private $withLayout; /** @var string */ private $imagePosition; public function __construct( $args, PostTransformerContentsExtractor $extractor = null ) { $this->args = $args; $this->withLayout = isset($args['withLayout']) ? (bool)filter_var($args['withLayout'], FILTER_VALIDATE_BOOLEAN) : false; $this->imagePosition = 'left'; if ($extractor === null) { $extractor = new PostTransformerContentsExtractor($args); } $this->extractor = $extractor; } public function getDivider() { if (empty($this->withLayout)) { return $this->args['divider']; } return LayoutHelper::row([ LayoutHelper::col([$this->args['divider']]), ]); } public function transform($post) { if (empty($this->withLayout)) { return $this->getStructure($post); } return $this->getStructureWithLayout($post); } private function getStructure($post) { $content = $this->extractor->getContent($post, true, $this->args['displayType']); $title = $this->extractor->getTitle($post); $featuredImage = $this->extractor->getFeaturedImage($post); $featuredImagePosition = $this->getFeaturedImagePosition($this->extractor->isProduct($post)); if ( $featuredImage && $featuredImagePosition === 'belowTitle' && ( $this->args['displayType'] !== 'titleOnly' || $this->extractor->isProduct($post) ) ) { array_unshift($content, $title, $featuredImage); return $content; } if ($content[0]['type'] === 'text') { $content[0]['text'] = $title['text'] . $content[0]['text']; } else { array_unshift($content, $title); } if ($featuredImage && $this->args['displayType'] !== 'titleOnly') { array_unshift($content, $featuredImage); } return $content; } private function getStructureWithLayout($post) { $withPostClass = $this->args['displayType'] === 'full' || $this->args['displayType'] === 'excerpt'; $content = $this->extractor->getContent($post, $withPostClass, $this->args['displayType']); $title = $this->extractor->getTitle($post); $featuredImage = $this->extractor->getFeaturedImage($post); $featuredImagePosition = $this->getFeaturedImagePosition($this->extractor->isProduct($post)); if ( !$featuredImage || $featuredImagePosition === 'none' || ( $this->args['displayType'] === 'titleOnly' && !$this->extractor->isProduct($post) ) ) { array_unshift($content, $title); return [ LayoutHelper::row([ LayoutHelper::col($content), ]), ]; } $titlePosition = isset($this->args['titlePosition']) ? $this->args['titlePosition'] : ''; if ($featuredImagePosition === 'aboveTitle' || $featuredImagePosition === 'belowTitle') { $featuredImagePosition = 'centered'; } if ($featuredImagePosition === 'centered') { if ($titlePosition === 'aboveExcerpt') { array_unshift($content, $featuredImage, $title); } else { array_unshift($content, $title, $featuredImage); } return [ LayoutHelper::row([ LayoutHelper::col($content), ]), ]; } if ($titlePosition === 'aboveExcerpt') { array_unshift($content, $title); } if ($featuredImagePosition === 'alternate') { $featuredImagePosition = $this->nextImagePosition(); } $content = ($featuredImagePosition === 'left') ? [ LayoutHelper::col([$featuredImage]), LayoutHelper::col($content), ] : [ LayoutHelper::col($content), LayoutHelper::col([$featuredImage]), ]; $result = [ LayoutHelper::row($content), ]; if ($titlePosition !== 'aboveExcerpt') { array_unshift( $result, LayoutHelper::row( [ LayoutHelper::col([$title]), ] ) ); } return $result; } private function nextImagePosition() { $this->imagePosition = ($this->imagePosition === 'left') ? 'right' : 'left'; return $this->imagePosition; } private function getFeaturedImagePosition(bool $isProduct) { if ($this->args['displayType'] !== 'full') { return $this->args['featuredImagePosition']; } // For products with display type 'full' use 'featuredImagePosition' if 'fullPostFeaturedImagePosition' not set. // This is because products always supported images, even for 'full' post display type. if ($isProduct && empty($this->args['fullPostFeaturedImagePosition'])) { return $this->args['featuredImagePosition']; } // For posts with display type 'full' use 'fullPostFeaturedImagePosition'. This is for back compatibility // with posts that don't have featured image but contain some value for 'featuredImagePosition' in the DB. return $this->args['fullPostFeaturedImagePosition'] ?? 'none'; } } LayoutHelper.php 0000644 00000001463 15073230107 0007674 0 ustar 00 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing namespace MailPoet\Newsletter\Editor; if (!defined('ABSPATH')) exit; class LayoutHelper { public static function row($blocks, $styles = []) { if (empty($styles['backgroundColor'])) { $styles['backgroundColor'] = 'transparent'; } return [ 'type' => 'container', 'orientation' => 'horizontal', 'styles' => ['block' => $styles], 'blocks' => $blocks, ]; } public static function col($blocks, $styles = []) { if (empty($styles['backgroundColor'])) { $styles['backgroundColor'] = 'transparent'; } return [ 'type' => 'container', 'orientation' => 'vertical', 'styles' => ['block' => $styles], 'blocks' => $blocks, ]; } } TitleListTransformer.php 0000644 00000002400 15073230107 0011407 0 ustar 00 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing namespace MailPoet\Newsletter\Editor; if (!defined('ABSPATH')) exit; use MailPoet\WP\Functions as WPFunctions; class TitleListTransformer { private $args; public function __construct( $args ) { $this->args = $args; } public function transform($posts) { $results = array_map(function($post) { return $this->getPostTitle($post); }, $posts); return [ $this->wrap([ 'type' => 'text', 'text' => '<ul>' . implode('', $results) . '</ul>', ])]; } private function wrap($block) { return LayoutHelper::row([ LayoutHelper::col([$block]), ]); } private function getPostTitle($post) { $title = $post->post_title; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $alignment = $this->args['titleAlignment']; $alignment = (in_array($alignment, ['left', 'right', 'center'])) ? $alignment : 'left'; if ($this->args['titleIsLink']) { $title = '<a data-post-id="' . $post->ID . '" href="' . WPFunctions::get()->getPermalink($post->ID) . '">' . $title . '</a>'; } return '<li style="text-align: ' . $alignment . ';">' . $title . '</li>'; } } PostListTransformer.php 0000644 00000001404 15073230107 0011256 0 ustar 00 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing namespace MailPoet\Newsletter\Editor; if (!defined('ABSPATH')) exit; class PostListTransformer { private $args; private $transformer; public function __construct( $args ) { $this->args = $args; $this->transformer = new PostTransformer($args); } public function transform($posts) { $results = []; $useDivider = filter_var($this->args['showDivider'], FILTER_VALIDATE_BOOLEAN); foreach ($posts as $index => $post) { if ($useDivider && $index > 0) { $results[] = $this->transformer->getDivider(); } $results = array_merge($results, $this->transformer->transform($post)); } return $results; } } PostTransformerContentsExtractor.php 0000644 00000015753 15073230107 0014050 0 ustar 00 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing namespace MailPoet\Newsletter\Editor; if (!defined('ABSPATH')) exit; use MailPoet\Config\Env; use MailPoet\WooCommerce\Helper as WooCommerceHelper; use MailPoet\WP\Functions as WPFunctions; class PostTransformerContentsExtractor { private $args; /** @var WPFunctions */ private $wp; /** @var WooCommerceHelper */ private $woocommerceHelper; public function __construct( $args ) { $this->args = $args; $this->wp = new WPFunctions(); $this->woocommerceHelper = new WooCommerceHelper($this->wp); } public function getContent($post, $withPostClass, $displayType) { $contentManager = new PostContentManager(); $metaManager = new MetaInformationManager(); $content = $contentManager->getContent($post, $this->args['displayType']); $content = $metaManager->appendMetaInformation($content, $post, $this->args); $content = $contentManager->filterContent($content, $displayType, $withPostClass); $structureTransformer = new StructureTransformer(); $content = $structureTransformer->transform($content, $this->args['imageFullWidth'] === true); if ($this->isProduct($post)) { $content = $this->addProductDataToContent($content, $post); } $readMoreBtn = $this->getReadMoreButton($post); $blocksCount = count($content); if (!$readMoreBtn) { // Don't attach a button } else if ($readMoreBtn['type'] === 'text' && $blocksCount > 0 && $content[$blocksCount - 1]['type'] === 'text') { $content[$blocksCount - 1]['text'] .= $readMoreBtn['text']; } else { $content[] = $readMoreBtn; } return $content; } private function getImageInfo($id) { /* * In some cases wp_get_attachment_image_src ignore the second parameter * and use global variable $content_width value instead. * By overriding it ourselves when ensure a constant behaviour regardless * of the user setup. * * https://mailpoet.atlassian.net/browse/MAILPOET-1365 */ global $content_width; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps, default is NULL $contentWidthCopy = $content_width; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $content_width = Env::NEWSLETTER_CONTENT_WIDTH; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $imageInfo = $this->wp->wpGetAttachmentImageSrc($id, 'mailpoet_newsletter_max'); $content_width = $contentWidthCopy; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps return $imageInfo; } public function getFeaturedImage($post) { $postId = $post->ID; $postTitle = $this->sanitizeTitle($post->post_title); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $imageFullWidth = (bool)filter_var($this->args['imageFullWidth'], FILTER_VALIDATE_BOOLEAN); if (!has_post_thumbnail($postId)) { return false; } $thumbnailId = $this->wp->getPostThumbnailId($postId); $imageInfo = $this->getImageInfo($thumbnailId); // get alt text $altText = trim(strip_tags(get_post_meta( $thumbnailId, '_wp_attachment_image_alt', true ))); if (strlen($altText) === 0) { // if the alt text is empty then use the post title $altText = trim(strip_tags($postTitle)); } return [ 'type' => 'image', 'link' => $this->wp->getPermalink($postId), 'src' => $imageInfo[0], 'alt' => $altText, 'fullWidth' => $imageFullWidth, 'width' => $imageInfo[1], 'height' => $imageInfo[2], 'styles' => [ 'block' => [ 'textAlign' => 'center', ], ], ]; } private function getReadMoreButton($post) { if ($this->args['readMoreType'] === 'none') { return false; } if ($this->args['readMoreType'] === 'button') { $button = $this->args['readMoreButton']; $button['url'] = $this->wp->getPermalink($post->ID); return $button; } $readMoreText = sprintf( '<p><a href="%s">%s</a></p>', $this->wp->getPermalink($post->ID), $this->args['readMoreText'] ); return [ 'type' => 'text', 'text' => $readMoreText, ]; } public function getTitle($post) { $title = $post->post_title; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps if (filter_var($this->args['titleIsLink'], FILTER_VALIDATE_BOOLEAN)) { $title = '<a href="' . $this->wp->getPermalink($post->ID) . '">' . $title . '</a>'; } if (in_array($this->args['titleFormat'], ['h1', 'h2', 'h3'])) { $tag = $this->args['titleFormat']; } elseif ($this->args['titleFormat'] === 'ul') { $tag = 'li'; } else { $tag = 'h1'; } $alignment = (in_array($this->args['titleAlignment'], ['left', 'right', 'center'])) ? $this->args['titleAlignment'] : 'left'; $title = '<' . $tag . ' data-post-id="' . $post->ID . '" style="text-align: ' . $alignment . ';">' . $title . '</' . $tag . '>'; // The allowed HTML is based on all the possible ways we might construct a $title above $commonAttributes = [ 'data-post-id' => [], 'style' => [], ]; $allowedTitleHtml = [ 'a' => [ 'href' => [], ], 'li' => $commonAttributes, 'h1' => $commonAttributes, 'h2' => $commonAttributes, 'h3' => $commonAttributes, ]; return [ 'type' => 'text', 'text' => wp_kses($title, $allowedTitleHtml), ]; } private function getPrice($post) { $price = null; $product = null; if ($this->woocommerceHelper->isWooCommerceActive()) { $product = $this->woocommerceHelper->wcGetProduct($post->ID); } if ($product) { $price = '<h2>' . strip_tags($product->get_price_html(), '<span><del>') . '</h2>'; } return $price; } private function addProductDataToContent($content, $post) { if (!isset($this->args['pricePosition']) || $this->args['pricePosition'] === 'hidden') { return $content; } $price = $this->getPrice($post); $blocksCount = count($content); if ($blocksCount > 0 && $content[$blocksCount - 1]['type'] === 'text') { if ($this->args['pricePosition'] === 'below') { $content[$blocksCount - 1]['text'] = $content[$blocksCount - 1]['text'] . $price; } else { $content[$blocksCount - 1]['text'] = $price . $content[$blocksCount - 1]['text']; } } else { $content[] = [ 'type' => 'text', 'text' => $price, ]; } return $content; } public function isProduct($post) { return $post->post_type === 'product'; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps } /** * Replaces double quote character with a unicode * alternative to avoid problems when inlining CSS. * [MAILPOET-1937] * * @param string $title * @return string */ private function sanitizeTitle($title) { return str_replace('"', '"', $title); } } PostContentManager.php 0000644 00000011513 15073230107 0011027 0 ustar 00 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing namespace MailPoet\Newsletter\Editor; if (!defined('ABSPATH')) exit; use MailPoet\Util\pQuery\pQuery; use MailPoet\WooCommerce\Helper as WooCommerceHelper; use MailPoet\WP\Functions as WPFunctions; class PostContentManager { const WP_POST_CLASS = 'mailpoet_wp_post'; public $maxExcerptLength = 60; /** @var WooCommerceHelper */ private $woocommerceHelper; /** @var WPFunctions */ private $wp; public function __construct( WooCommerceHelper $woocommerceHelper = null ) { $this->wp = new WPFunctions; $this->maxExcerptLength = $this->wp->applyFilters('mailpoet_newsletter_post_excerpt_length', $this->maxExcerptLength); $this->woocommerceHelper = $woocommerceHelper ?: new WooCommerceHelper($this->wp); } public function getContent($post, $displayType) { if ($displayType === 'titleOnly') { return ''; } if ($this->woocommerceHelper->isWooCommerceActive() && $this->wp->getPostType($post) === 'product') { $product = $this->woocommerceHelper->wcGetProduct($post->ID); if ($product) { return $this->getContentForProduct($product, $displayType); } } if ($displayType === 'excerpt') { if ($this->wp->hasExcerpt($post)) { return self::stripShortCodes($this->wp->getTheExcerpt($post)); } return $this->generateExcerpt($post->post_content); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps } return self::stripShortCodes($post->post_content); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps } public function filterContent($content, $displayType, $withPostClass = true) { $content = self::convertEmbeddedContent($content); // convert h4 h5 h6 to h3 $content = preg_replace('/<([\/])?h[456](.*?)>/', '<$1h3$2>', $content); // convert currency signs $content = str_replace( ['$', '€', '£', '¥'], ['$', '€', '£', '¥'], $content ); // strip useless tags $tagsNotBeingStripped = [ '<p>', '<em>', '<span>', '<b>', '<strong>', '<i>', '<a>', '<ul>', '<ol>', '<li>', '<br>', '<blockquote>', ]; if ($displayType === 'full') { $tagsNotBeingStripped = array_merge($tagsNotBeingStripped, ['<figure>', '<img>', '<h1>', '<h2>', '<h3>', '<hr>']); } if (is_array($content)) { $content = implode(' ', $content); } $content = strip_tags($content, implode('', $tagsNotBeingStripped)); if ($withPostClass) { $dOMParser = new pQuery(); $DOM = $dOMParser->parseStr(WPFunctions::get()->wpautop($content)); $paragraphs = $DOM->query('p'); foreach ($paragraphs as $paragraph) { // We replace the class attribute to avoid conflicts in the newsletter editor $paragraph->removeAttr('class'); $paragraph->addClass(self::WP_POST_CLASS); } $content = $DOM->__toString(); } else { $content = WPFunctions::get()->wpautop($content); } $content = trim($content); return $content; } private function getContentForProduct($product, $displayType) { if ($displayType === 'excerpt') { return $product->get_short_description(); } return $product->get_description(); } private function generateExcerpt($content) { // remove image captions in gutenberg $content = preg_replace( "/<figcaption.*?>.*?<\/figcaption>/", '', $content ); // remove image captions in classic posts $content = preg_replace( "/\[caption.*?\](.*?)\[\/caption\]/", '', $content ); $content = self::stripShortCodes($content); // if excerpt is empty then try to find the "more" tag $excerpts = explode('<!--more-->', $content); if (count($excerpts) > 1) { // <!--more--> separator was present return $excerpts[0]; } else { // Separator not present, try to shorten long posts return WPFunctions::get()->wpTrimWords($content, $this->maxExcerptLength, ' …'); } } private function stripShortCodes($content) { // remove captions $content = preg_replace( "/\[caption.*?\](.*<\/a>)(.*?)\[\/caption\]/", '$1', $content ); // remove other shortcodes $content = preg_replace('/\[[^\[\]]*\]/', '', $content); return $content; } private function convertEmbeddedContent($content = '') { // remove embedded video and replace with links $content = preg_replace( '#<iframe.*?src=\"(.+?)\".*><\/iframe>#', '<a href="$1">' . __('Click here to view media.', 'mailpoet') . '</a>', $content ); // replace youtube links $content = preg_replace( '#http://www.youtube.com/embed/([a-zA-Z0-9_-]*)#Ui', 'http://www.youtube.com/watch?v=$1', $content ); return $content; } } Transformer.php 0000644 00000001161 15073230107 0007554 0 ustar 00 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing namespace MailPoet\Newsletter\Editor; if (!defined('ABSPATH')) exit; class Transformer { private $transformer; public function __construct( $args ) { $titleListOnly = $args['displayType'] === 'titleOnly' && $args['titleFormat'] === 'ul'; if ($titleListOnly) $transformer = new TitleListTransformer($args); else $transformer = new PostListTransformer($args); $this->transformer = $transformer; } public function transform($posts) { return $this->transformer->transform($posts); } } StructureTransformer.php 0000644 00000007664 15073230107 0011513 0 ustar 00 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing namespace MailPoet\Newsletter\Editor; if (!defined('ABSPATH')) exit; use MailPoet\Util\DOM as DOMUtil; use MailPoet\Util\pQuery\pQuery; use MailPoetVendor\pQuery\DomNode; class StructureTransformer { public function transform($content, $imageFullWidth) { $root = pQuery::parseStr($content); $this->hoistImagesToRoot($root); $structure = $this->transformTagsToBlocks($root, $imageFullWidth); $structure = $this->mergeNeighboringBlocks($structure); return $structure; } /** * Hoists images to root level, preserves order by splitting neighboring * elements and inserts tags as children of top ancestor */ protected function hoistImagesToRoot(DomNode $root) { foreach ($root->query('img') as $item) { $topAncestor = DOMUtil::findTopAncestor($item); $offset = $topAncestor->index(); if ($item->hasParent('a') || $item->hasParent('figure')) { $item = $item->parent; } DOMUtil::splitOn($item->getRoot(), $item); } } /** * Transforms HTML tags into their respective JSON objects, * turns other root children into text blocks */ private function transformTagsToBlocks(DomNode $root, $imageFullWidth) { $children = $this->filterOutFiguresWithoutImages($root->children); return array_map(function($item) use ($imageFullWidth) { if ($this->isImageElement($item)) { $image = $item->tag === 'img' ? $item : $item->query('img')[0]; $width = $image->getAttribute('width'); $height = $image->getAttribute('height'); return [ 'type' => 'image', 'link' => $item->getAttribute('href') ?: '', 'src' => $image->getAttribute('src'), 'alt' => $image->getAttribute('alt'), 'fullWidth' => $imageFullWidth, 'width' => $width === null ? 'auto' : $width, 'height' => $height === null ? 'auto' : $height, 'styles' => [ 'block' => [ 'textAlign' => $this->getImageAlignment($image), ], ], ]; } else { return [ 'type' => 'text', 'text' => $item->toString(), ]; } }, $children); } private function filterOutFiguresWithoutImages(array $items) { $items = array_filter($items, function (DomNode $item) { if ($item->tag === 'figure' && $item->query('img')->count() === 0) { return false; } return true; }); return array_values($items); } private function isImageElement(DomNode $item) { return $item->tag === 'img' || (in_array($item->tag, ['a', 'figure'], true) && $item->query('img')->count() > 0); } private function getImageAlignment(DomNode $image) { $alignItem = $image->hasParent('figure') ? $image->parent : $image; if ($alignItem->hasClass('aligncenter')) { $align = 'center'; } elseif ($alignItem->hasClass('alignleft')) { $align = 'left'; } elseif ($alignItem->hasClass('alignright')) { $align = 'right'; } else { $align = 'left'; } return $align; } /** * Merges neighboring blocks when possible. * E.g. 2 adjacent text blocks may be combined into one. */ private function mergeNeighboringBlocks(array $structure) { $updatedStructure = []; $textAccumulator = ''; foreach ($structure as $item) { if ($item['type'] === 'text') { $textAccumulator .= $item['text']; } if ($item['type'] !== 'text') { if (!empty($textAccumulator)) { $updatedStructure[] = [ 'type' => 'text', 'text' => trim($textAccumulator), ]; $textAccumulator = ''; } $updatedStructure[] = $item; } } if (!empty($textAccumulator)) { $updatedStructure[] = [ 'type' => 'text', 'text' => trim($textAccumulator), ]; } return $updatedStructure; } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0 |
proxy
|
phpinfo
|
Settings