PluginProbe
MailPoet – Newsletters, Email Marketing, and Automation / 3.65.0
MailPoet – Newsletters, Email Marketing, and Automation v3.65.0
5.38.0 5.37.0 5.36.1 5.36.0 5.35.1 5.35.0 5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 All 542 releases
mailpoet / lib / Form / DisplayFormInWPContent.php

DisplayFormInWPContent.php in MailPoet – Newsletters, Email Marketing, and Automation 3.65.0, at lib/Form/DisplayFormInWPContent.php

234 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace MailPoet\Form;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\API\JSON\API;
9 use MailPoet\Config\Renderer as TemplateRenderer;
10 use MailPoet\Entities\FormEntity;
11 use MailPoet\Util\Security;
12 use MailPoet\WP\Functions as WPFunctions;
13
14 class DisplayFormInWPContent {
15
16 const NO_FORM_TRANSIENT_KEY = 'no_forms_displayed_bellow_content';
17
18 const TYPES = [
19 FormEntity::DISPLAY_TYPE_BELOW_POST,
20 FormEntity::DISPLAY_TYPE_POPUP,
21 FormEntity::DISPLAY_TYPE_FIXED_BAR,
22 FormEntity::DISPLAY_TYPE_SLIDE_IN,
23 ];
24
25 /** @var WPFunctions */
26 private $wp;
27
28 /** @var FormsRepository */
29 private $formsRepository;
30
31 /** @var Renderer */
32 private $formRenderer;
33
34 /** @var AssetsController */
35 private $assetsController;
36
37 /** @var TemplateRenderer */
38 private $templateRenderer;
39
40 public function __construct(
41 WPFunctions $wp,
42 FormsRepository $formsRepository,
43 Renderer $formRenderer,
44 AssetsController $assetsController,
45 TemplateRenderer $templateRenderer
46 ) {
47 $this->wp = $wp;
48 $this->formsRepository = $formsRepository;
49 $this->formRenderer = $formRenderer;
50 $this->assetsController = $assetsController;
51 $this->templateRenderer = $templateRenderer;
52 }
53
54 /**
55 * This takes input from an action and any plugin or theme can pass anything.
56 * We return string for regular content otherwise we just pass thru what comes.
57 * @param mixed $content
58 * @return string|mixed
59 */
60 public function display($content = null) {
61 if (!is_string($content) || !$this->shouldDisplay()) return $content;
62
63 $forms = $this->getForms();
64 if (count($forms) === 0) {
65 return $content;
66 }
67
68 $this->assetsController->setupFrontEndDependencies();
69 $result = $content;
70 foreach ($forms as $displayType => $form) {
71 $result .= $this->getContentBellow($form, $displayType);
72 }
73 return $result;
74 }
75
76 private function shouldDisplay(): bool {
77 $result = true;
78 // This is a fix Yoast plugin and Shapely theme compatibility
79 // This is to make sure we only display once for each page
80 // Yast plugin calls `get_the_excerpt` which also triggers hook `the_content` we don't want to include our form in that
81 // Shapely calls the hook `the_content` multiple times on the page as well and we would display popup multiple times - not ideal
82 if (!$this->wp->inTheLoop() || !$this->wp->isMainQuery()) {
83 $result = $this->wp->applyFilters('mailpoet_display_form_is_main_loop', false);
84 }
85 // this code ensures that we display the form only on a page which is related to single post
86 if (!$this->wp->isSingle() && !$this->wp->isPage()) $result = $this->wp->applyFilters('mailpoet_display_form_is_single', false);
87 $noFormsCache = $this->wp->getTransient(DisplayFormInWPContent::NO_FORM_TRANSIENT_KEY);
88 if ($noFormsCache === '1') $result = false;
89 return $result;
90 }
91
92 private function saveNoForms() {
93 $this->wp->setTransient(DisplayFormInWPContent::NO_FORM_TRANSIENT_KEY, '1');
94 }
95
96 /**
97 * @return array<string, FormEntity>
98 */
99 private function getForms(): array {
100 $forms = $this->formsRepository->findBy([
101 'deletedAt' => null,
102 'status' => FormEntity::STATUS_ENABLED,
103 ], ['updatedAt' => 'ASC']);
104 if (count($forms) === 0) {
105 $this->saveNoForms();
106 }
107 $forms = $this->filterOneFormInEachDisplayType($forms);
108 return $forms;
109 }
110
111 /**
112 * @param FormEntity[] $forms
113 * @return array<string, FormEntity>
114 */
115 private function filterOneFormInEachDisplayType($forms): array {
116 $formsFiltered = [];
117 foreach ($forms as $form) {
118 foreach (self::TYPES as $displayType) {
119 if ($this->shouldDisplayFormType($form, $displayType)) {
120 $formsFiltered[$displayType] = $form;
121 }
122 }
123 }
124 return $formsFiltered;
125 }
126
127 private function getContentBellow(FormEntity $form, string $displayType): string {
128 if (!$this->shouldDisplayFormType($form, $displayType)) return '';
129 $formData = [
130 'body' => $form->getBody(),
131 'styles' => $form->getStyles(),
132 'settings' => $form->getSettings(),
133 ];
134 $formSettings = $form->getSettings();
135 if (!is_array($formSettings)) return '';
136 $htmlId = 'mp_form_' . $displayType . $form->getId();
137 $templateData = [
138 'form_html_id' => $htmlId,
139 'form_id' => $form->getId(),
140 'form_success_message' => $formSettings['success_message'] ?? null,
141 'form_type' => $displayType,
142 'styles' => $this->formRenderer->renderStyles($formData, '#' . $htmlId, $displayType),
143 'html' => $this->formRenderer->renderHTML($formData),
144 'close_button_icon' => $formSettings['close_button'] ?? 'round_white',
145 ];
146
147 // (POST) non ajax success/error variables
148 $templateData['success'] = (
149 (isset($_GET['mailpoet_success']))
150 &&
151 ((int)$_GET['mailpoet_success'] === $form->getId())
152 );
153 $templateData['error'] = (
154 (isset($_GET['mailpoet_error']))
155 &&
156 ((int)$_GET['mailpoet_error'] === $form->getId())
157 );
158
159 $templateData['delay'] = $formSettings['form_placement'][$displayType]['delay'] ?? 0;
160 $templateData['position'] = $formSettings['form_placement'][$displayType]['position'] ?? '';
161 $templateData['animation'] = $formSettings['form_placement'][$displayType]['animation'] ?? '';
162 $templateData['fontFamily'] = $formSettings['font_family'] ?? '';
163 $templateData['enableExitIntent'] = false;
164 if (
165 isset($formSettings['form_placement'][$displayType]['exit_intent_enabled'])
166 && ($formSettings['form_placement'][$displayType]['exit_intent_enabled'] === '1')
167 ) {
168 $templateData['enableExitIntent'] = true;
169 }
170
171 // generate security token
172 $templateData['token'] = Security::generateToken();
173
174 // add API version
175 $templateData['api_version'] = API::CURRENT_VERSION;
176 return $this->templateRenderer->render('form/front_end_form.html', $templateData);
177 }
178
179 private function shouldDisplayFormType(FormEntity $form, string $formType): bool {
180 $settings = $form->getSettings();
181 // check the structure just to be sure
182
183 if (!is_array($settings)
184 || !isset($settings['form_placement'][$formType])
185 || !is_array($settings['form_placement'][$formType])
186 ) return false;
187
188 $setup = $settings['form_placement'][$formType];
189 if ($setup['enabled'] !== '1') {
190 return false;
191 }
192
193 if ($this->wp->isSingular('post') || $this->wp->isSingular('product')) {
194 if ($this->shouldDisplayFormOnPost($setup, 'posts')) return true;
195 if ($this->shouldDisplayFormOnCategory($setup)) return true;
196 if ($this->shouldDisplayFormOnTag($setup)) return true;
197 return false;
198 }
199 if ($this->wp->isPage() && $this->shouldDisplayFormOnPost($setup, 'pages')) {
200 return true;
201 }
202
203 return false;
204 }
205
206 private function shouldDisplayFormOnPost(array $setup, string $postsKey): bool {
207 if (!isset($setup[$postsKey])) {
208 return false;
209 }
210 if (isset($setup[$postsKey]['all']) && $setup[$postsKey]['all'] === '1') {
211 return true;
212 }
213 $post = $this->wp->getPost(null, ARRAY_A);
214 if (isset($setup[$postsKey]['selected']) && in_array($post['ID'], $setup[$postsKey]['selected'])) {
215 return true;
216 }
217 return false;
218 }
219
220 private function shouldDisplayFormOnCategory(array $setup): bool {
221 if (!isset($setup['categories'])) return false;
222 if ($this->wp->hasCategory($setup['categories'])) return true;
223 if ($this->wp->hasTerm($setup['categories'], 'product_cat')) return true;
224 return false;
225 }
226
227 private function shouldDisplayFormOnTag(array $setup): bool {
228 if (!isset($setup['tags'])) return false;
229 if ($this->wp->hasTag($setup['tags'])) return true;
230 if ($this->wp->hasTerm($setup['tags'], 'product_tag')) return true;
231 return false;
232 }
233 }
234