| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- <?php
- namespace MailPoet\Form;
- if (!defined('ABSPATH')) exit;
- use MailPoet\API\JSON\API;
- use MailPoet\Config\Renderer as TemplateRenderer;
- use MailPoet\Entities\FormEntity;
- use MailPoet\Util\Security;
- use MailPoet\WP\Functions as WPFunctions;
- class DisplayFormInWPContent {
- const NO_FORM_TRANSIENT_KEY = 'no_forms_displayed_bellow_content';
- const TYPES = [
- FormEntity::DISPLAY_TYPE_BELOW_POST,
- FormEntity::DISPLAY_TYPE_POPUP,
- FormEntity::DISPLAY_TYPE_FIXED_BAR,
- FormEntity::DISPLAY_TYPE_SLIDE_IN,
- ];
- const SUPPORTED_POST_TYPES = [
- 'post',
- 'product',
- 'job_listing',
- ];
- /** @var WPFunctions */
- private $wp;
- /** @var FormsRepository */
- private $formsRepository;
- /** @var Renderer */
- private $formRenderer;
- /** @var AssetsController */
- private $assetsController;
- /** @var TemplateRenderer */
- private $templateRenderer;
- public function __construct(
- WPFunctions $wp,
- FormsRepository $formsRepository,
- Renderer $formRenderer,
- AssetsController $assetsController,
- TemplateRenderer $templateRenderer
- ) {
- $this->wp = $wp;
- $this->formsRepository = $formsRepository;
- $this->formRenderer = $formRenderer;
- $this->assetsController = $assetsController;
- $this->templateRenderer = $templateRenderer;
- }
- /**
- * This takes input from an action and any plugin or theme can pass anything.
- * We return string for regular content otherwise we just pass thru what comes.
- * @param mixed $content
- * @return string|mixed
- */
- public function display($content = null) {
- if (!is_string($content) || !$this->shouldDisplay()) return $content;
- $forms = $this->getForms();
- if (count($forms) === 0) {
- return $content;
- }
- $this->assetsController->setupFrontEndDependencies();
- $result = $content;
- foreach ($forms as $displayType => $form) {
- $result .= $this->getContentBellow($form, $displayType);
- }
- return $result;
- }
- private function shouldDisplay(): bool {
- $result = true;
- // This is a fix Yoast plugin and Shapely theme compatibility
- // This is to make sure we only display once for each page
- // Yast plugin calls `get_the_excerpt` which also triggers hook `the_content` we don't want to include our form in that
- // Shapely calls the hook `the_content` multiple times on the page as well and we would display popup multiple times - not ideal
- if (!$this->wp->inTheLoop() || !$this->wp->isMainQuery()) {
- $result = $this->wp->applyFilters('mailpoet_display_form_is_main_loop', false);
- }
- // this code ensures that we display the form only on a page which is related to single post
- if (!$this->wp->isSingle() && !$this->wp->isPage()) $result = $this->wp->applyFilters('mailpoet_display_form_is_single', false);
- $noFormsCache = $this->wp->getTransient(DisplayFormInWPContent::NO_FORM_TRANSIENT_KEY);
- if ($noFormsCache === '1') $result = false;
- return $result;
- }
- private function saveNoForms() {
- $this->wp->setTransient(DisplayFormInWPContent::NO_FORM_TRANSIENT_KEY, '1');
- }
- /**
- * @return array<string, FormEntity>
- */
- private function getForms(): array {
- $forms = $this->formsRepository->findBy([
- 'deletedAt' => null,
- 'status' => FormEntity::STATUS_ENABLED,
- ], ['updatedAt' => 'ASC']);
- if (count($forms) === 0) {
- $this->saveNoForms();
- }
- $forms = $this->filterOneFormInEachDisplayType($forms);
- return $forms;
- }
- /**
- * @param FormEntity[] $forms
- * @return array<string, FormEntity>
- */
- private function filterOneFormInEachDisplayType($forms): array {
- $formsFiltered = [];
- foreach ($forms as $form) {
- foreach (self::TYPES as $displayType) {
- if ($this->shouldDisplayFormType($form, $displayType)) {
- $formsFiltered[$displayType] = $form;
- }
- }
- }
- return $formsFiltered;
- }
- private function getContentBellow(FormEntity $form, string $displayType): string {
- if (!$this->shouldDisplayFormType($form, $displayType)) return '';
- $formSettings = $form->getSettings();
- if (!is_array($formSettings)) return '';
- $htmlId = 'mp_form_' . $displayType . $form->getId();
- $templateData = [
- 'form_html_id' => $htmlId,
- 'form_id' => $form->getId(),
- 'form_success_message' => $formSettings['success_message'] ?? null,
- 'form_type' => $displayType,
- 'styles' => $this->formRenderer->renderStyles($form, '#' . $htmlId, $displayType),
- 'html' => $this->formRenderer->renderHTML($form),
- 'close_button_icon' => $formSettings['close_button'] ?? 'round_white',
- ];
- // (POST) non ajax success/error variables
- $templateData['success'] = (
- (isset($_GET['mailpoet_success']))
- &&
- ((int)$_GET['mailpoet_success'] === $form->getId())
- );
- $templateData['error'] = (
- (isset($_GET['mailpoet_error']))
- &&
- ((int)$_GET['mailpoet_error'] === $form->getId())
- );
- $templateData['delay'] = $formSettings['form_placement'][$displayType]['delay'] ?? 0;
- $templateData['position'] = $formSettings['form_placement'][$displayType]['position'] ?? '';
- $templateData['animation'] = $formSettings['form_placement'][$displayType]['animation'] ?? '';
- $templateData['fontFamily'] = $formSettings['font_family'] ?? '';
- $templateData['enableExitIntent'] = false;
- if (
- isset($formSettings['form_placement'][$displayType]['exit_intent_enabled'])
- && ($formSettings['form_placement'][$displayType]['exit_intent_enabled'] === '1')
- ) {
- $templateData['enableExitIntent'] = true;
- }
- // generate security token
- $templateData['token'] = Security::generateToken();
- // add API version
- $templateData['api_version'] = API::CURRENT_VERSION;
- return $this->templateRenderer->render('form/front_end_form.html', $templateData);
- }
- private function shouldDisplayFormType(FormEntity $form, string $formType): bool {
- $settings = $form->getSettings();
- // check the structure just to be sure
- if (!is_array($settings)
- || !isset($settings['form_placement'][$formType])
- || !is_array($settings['form_placement'][$formType])
- ) return false;
- $setup = $settings['form_placement'][$formType];
- if ($setup['enabled'] !== '1') {
- return false;
- }
- if ($this->wp->isSingular($this->wp->applyFilters('mailpoet_display_form_supported_post_types', self::SUPPORTED_POST_TYPES))) {
- if ($this->shouldDisplayFormOnPost($setup, 'posts')) return true;
- if ($this->shouldDisplayFormOnCategory($setup)) return true;
- if ($this->shouldDisplayFormOnTag($setup)) return true;
- return false;
- }
- if ($this->wp->isPage() && $this->shouldDisplayFormOnPost($setup, 'pages')) {
- return true;
- }
- return false;
- }
- private function shouldDisplayFormOnPost(array $setup, string $postsKey): bool {
- if (!isset($setup[$postsKey])) {
- return false;
- }
- if (isset($setup[$postsKey]['all']) && $setup[$postsKey]['all'] === '1') {
- return true;
- }
- $post = $this->wp->getPost(null, ARRAY_A);
- if (isset($setup[$postsKey]['selected']) && in_array($post['ID'], $setup[$postsKey]['selected'])) {
- return true;
- }
- return false;
- }
- private function shouldDisplayFormOnCategory(array $setup): bool {
- if (!isset($setup['categories'])) return false;
- if ($this->wp->hasCategory($setup['categories'])) return true;
- if ($this->wp->hasTerm($setup['categories'], 'product_cat')) return true;
- return false;
- }
- private function shouldDisplayFormOnTag(array $setup): bool {
- if (!isset($setup['tags'])) return false;
- if ($this->wp->hasTag($setup['tags'])) return true;
- if ($this->wp->hasTerm($setup['tags'], 'product_tag')) return true;
- return false;
- }
- }
|