index.php000064400000000006150732301070006356 0ustar00post_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 = '

' . implode('
', $text) . '

'; 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.php000064400000012206150732301070010424 0ustar00args = $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.php000064400000001463150732301070007674 0ustar00 '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.php000064400000002400150732301070011407 0ustar00args = $args; } public function transform($posts) { $results = array_map(function($post) { return $this->getPostTitle($post); }, $posts); return [ $this->wrap([ 'type' => 'text', 'text' => '', ])]; } 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 = '' . $title . ''; } return '
  • ' . $title . '
  • '; } } PostListTransformer.php000064400000001404150732301070011256 0ustar00args = $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.php000064400000015753150732301070014050 0ustar00args = $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( '

    %s

    ', $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 = '' . $title . ''; } 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 . ''; // 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 = '

    ' . strip_tags($product->get_price_html(), '') . '

    '; } 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.php000064400000011513150732301070011027 0ustar00wp = 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 = [ '

    ', '', '', '', '', '', '', '