PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
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 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / Form / Widget.php
mailpoet / lib / Form Last commit date
Block 1 week ago Listing 1 month ago RestApi 1 month ago Templates 2 years ago Util 2 months ago ApiDataSanitizer.php 2 weeks ago AssetsController.php 2 months ago BlockStylesRenderer.php 3 years ago BlockWrapperRenderer.php 3 years ago BlocksRenderer.php 1 week ago DisplayFormInWPContent.php 2 months ago FormHtmlSanitizer.php 1 month ago FormMessageController.php 4 years ago FormSaveController.php 1 year ago FormsRepository.php 1 year ago PreviewPage.php 2 months ago PreviewWidget.php 1 year ago Renderer.php 2 months ago Widget.php 2 months ago index.php 3 years ago
Widget.php
320 lines
1 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
2
3 namespace MailPoet\Form;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\API\JSON\API;
9 use MailPoet\Config\Env;
10 use MailPoet\Config\RendererFactory;
11 use MailPoet\DI\ContainerWrapper;
12 use MailPoet\Entities\FormEntity;
13 use MailPoet\Form\Renderer as FormRenderer;
14 use MailPoet\Form\Util\CustomFonts;
15 use MailPoet\Settings\SettingsController;
16 use MailPoet\WP\Functions as WPFunctions;
17
18 // phpcs:disable Generic.Files.InlineHTML
19 class Widget extends \WP_Widget {
20 private $renderer;
21 private $wp;
22
23 /** @var AssetsController */
24 private $assetsController;
25
26 /** @var FormRenderer */
27 private $formRenderer;
28
29 /** @var FormsRepository */
30 private $formsRepository;
31
32 /** @var CustomFonts */
33 private $customFonts;
34
35 /** @var SettingsController */
36 private $settings;
37
38 public function __construct() {
39 parent::__construct(
40 'mailpoet_form',
41 __('MailPoet Form', 'mailpoet'),
42 ['description' => __('Add a newsletter subscription form', 'mailpoet')]
43 );
44 $this->wp = new WPFunctions;
45
46 $this->renderer = (new RendererFactory())->getRenderer();
47 $this->settings = SettingsController::getInstance();
48 $this->assetsController = new AssetsController($this->wp, $this->renderer, $this->settings);
49 $this->formRenderer = ContainerWrapper::getInstance()->get(FormRenderer::class);
50 $this->formsRepository = ContainerWrapper::getInstance()->get(FormsRepository::class);
51 $this->customFonts = ContainerWrapper::getInstance()->get(CustomFonts::class);
52
53 if (!$this->wp->isAdmin()) {
54 $this->setupIframe();
55 } else {
56 WPFunctions::get()->addAction('widgets_admin_page', [
57 $this->assetsController,
58 'setupAdminWidgetPageDependencies',
59 ]);
60 }
61 }
62
63 public function setupIframe() {
64 $formId = isset($_GET['mailpoet_form_iframe']) && is_numeric($_GET['mailpoet_form_iframe']) ? (int)$_GET['mailpoet_form_iframe'] : 0;
65 if (!$formId || !$this->formsRepository->findOneById($formId)) return;
66
67 $formHtml = $this->widget(
68 [
69 'form' => $formId,
70 'form_type' => 'iframe',
71 ]
72 );
73
74 $scripts = $this->assetsController->printScripts();
75
76 // language attributes
77 $languageAttributes = [];
78 $isRtl = (bool)(function_exists('is_rtl') && WPFunctions::get()->isRtl());
79
80 if ($isRtl) {
81 $languageAttributes[] = 'dir="rtl"';
82 }
83
84 if ($this->wp->getOption('html_type') === 'text/html') {
85 $languageAttributes[] = sprintf('lang="%s"', WPFunctions::get()->getBloginfo('language'));
86 }
87
88 $languageAttributes = WPFunctions::get()->applyFilters(
89 'language_attributes',
90 implode(' ', $languageAttributes)
91 );
92
93 $data = [
94 'language_attributes' => $languageAttributes,
95 'scripts' => $scripts,
96 'form' => $formHtml,
97 'mailpoet_form' => [
98 'ajax_url' => WPFunctions::get()->adminUrl('admin-ajax.php', 'absolute'),
99 'is_rtl' => $isRtl,
100 'collect_subscriber_timezones' => $this->settings->isSettingEnabled('collect_subscriber_timezones.enabled'),
101 ],
102 'fonts_link' => $this->customFonts->generateHtmlCustomFontLink(),
103 'mailpoet_public_css_url' => Env::$assetsUrl . '/dist/css/' . $this->renderer->getCssAsset('mailpoet-public.css'),
104 ];
105
106 try {
107 // We control the template and the data is sanitized
108 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
109 echo $this->renderer->render('form/iframe.html', $data);
110 } catch (\Exception $e) {
111 echo esc_html($e->getMessage());
112 }
113
114 exit();
115 }
116
117 /**
118 * Save the new widget's title.
119 */
120 public function update($newInstance, $oldInstance) {
121 $instance = $oldInstance;
122 $instance['title'] = strip_tags(is_string($newInstance['title']) ? $newInstance['title'] : '');
123 $instance['form'] = is_numeric($newInstance['form']) ? (int)$newInstance['form'] : null;
124 return $instance;
125 }
126
127 /**
128 * Output the widget's option form.
129 */
130 public function form($instance) {
131 $instance = WPFunctions::get()->wpParseArgs(
132 (array)$instance,
133 [
134 'title' => __('Subscribe to Our Newsletter', 'mailpoet'),
135 ]
136 );
137
138 $formEditUrl = WPFunctions::get()->adminUrl('admin.php?page=mailpoet-form-editor-template-selection');
139
140 // set title
141 $title = isset($instance['title']) ? strip_tags($instance['title']) : '';
142
143 // set form
144 $selectedForm = isset($instance['form']) ? (int)($instance['form']) : 0;
145
146 // get forms list
147 $forms = $this->formsRepository->findBy(['deletedAt' => null], ['name' => 'asc']);
148 ?><p>
149 <label for="<?php echo esc_attr($this->get_field_id('title')) ?>"><?php echo esc_html(__('Title:', 'mailpoet')); ?></label>
150 <input
151 type="text"
152 class="widefat"
153 id="<?php echo esc_attr($this->get_field_id('title')) ?>"
154 name="<?php echo esc_attr($this->get_field_name('title')); ?>"
155 value="<?php echo esc_attr($title); ?>"
156 />
157 </p>
158 <p>
159 <select class="widefat" id="<?php echo esc_attr($this->get_field_id('form')) ?>" name="<?php echo esc_attr($this->get_field_name('form')); ?>">
160 <?php
161 // Select the first one from the list if none selected
162 if ($selectedForm === 0 && !empty($forms)) $selectedForm = $forms[0]->getId();
163 foreach ($forms as $form) {
164 $formName = $form->getName() ? $this->wp->escHtml($form->getName()) : '(' . _x('no name', 'fallback for forms without a name in a form list', 'mailpoet') . ')';
165 $formName .= $form->getStatus() === FormEntity::STATUS_DISABLED ? ' (' . __('inactive', 'mailpoet') . ')' : '';
166 ?>
167 <option value="<?php echo esc_attr((string)$form->getId()); ?>" <?php echo ($selectedForm === $form->getId()) ? 'selected="selected"' : ''; ?>><?php echo esc_html($formName); ?></option>
168 <?php } ?>
169 </select>
170 </p>
171 <p>
172 <a href="<?php echo esc_url($formEditUrl); ?>" target="_blank" class="mailpoet_form_new"><?php echo esc_html(__('Create a new form', 'mailpoet')); ?></a>
173 </p>
174 <?php
175 return '';
176 }
177
178 /**
179 * @param array{form?: int|string, form_type?: string, before_widget?: string, after_widget?: string, before_title?: string, after_title?: string } $args Widget arguments.
180 * Output the widget itself.
181 */
182 public function widget($args, $instance = null) {
183 $this->assetsController->setupFrontEndDependencies();
184
185 $beforeWidget = !empty($args['before_widget']) ? $args['before_widget'] : '';
186 $afterWidget = !empty($args['after_widget']) ? $args['after_widget'] : '';
187 $beforeTitle = !empty($args['before_title']) ? $args['before_title'] : '';
188 $afterTitle = !empty($args['after_title']) ? $args['after_title'] : '';
189
190 if ($instance === null) {
191 $instance = $args;
192 }
193
194 $title = $this->wp->applyFilters(
195 'widget_title',
196 !empty($instance['title']) ? $instance['title'] : '',
197 $instance,
198 $this->id_base // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
199 );
200
201 // get form
202 if (!empty($instance['form'])) {
203 $form = $this->formsRepository->findOneById($instance['form']);
204 } else {
205 // Backwards compatibility for MAILPOET-3847
206 // Get first non deleted form
207 $forms = $this->formsRepository->findBy(['deletedAt' => null], ['name' => 'asc']);
208 if (empty($forms)) return '';
209 $form = $forms[0];
210 }
211
212 if (!$form) return '';
213 if ($form->getDeletedAt()) return '';
214 if ($form->getStatus() !== FormEntity::STATUS_ENABLED) return '';
215
216 $formType = 'widget';
217 if (
218 isset($instance['form_type']) && in_array(
219 $instance['form_type'],
220 [
221 'html',
222 'php',
223 'iframe',
224 'shortcode',
225 ]
226 )
227 ) {
228 $formType = $instance['form_type'];
229 }
230
231 $body = (!empty($form->getBody()) ? $form->getBody() : []);
232 $output = '';
233 $settings = $form->getSettings();
234
235 if (!empty($body) && is_array($settings)) {
236 $idBase = is_string($this->id_base) ? $this->id_base : 'mailpoet_form'; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
237 $formId = $idBase . '_' . $form->getId();
238 $data = [
239 'form_html_id' => $formId,
240 'form_id' => $form->getId(),
241 'form_type' => $formType,
242 'form_success_message' => $settings['success_message'],
243 'title' => $title,
244 'styles' => $this->formRenderer->renderStyles($form, '#' . $formId, FormEntity::DISPLAY_TYPE_OTHERS),
245 'html' => $this->formRenderer->renderHTML($form),
246 'before_widget' => $beforeWidget,
247 'after_widget' => $afterWidget,
248 'before_title' => $beforeTitle,
249 'after_title' => $afterTitle,
250 ];
251
252 // (POST) non ajax success/error variables
253 $data['success'] = (
254 isset($_GET['mailpoet_success'])
255 && is_numeric($_GET['mailpoet_success'])
256 && (int)$_GET['mailpoet_success'] === $form->getId()
257 );
258 $data['error'] = (
259 isset($_GET['mailpoet_error'])
260 && is_numeric($_GET['mailpoet_error'])
261 && (int)$_GET['mailpoet_error'] === $form->getId()
262 );
263
264 // generate security token
265 $data['token'] = $this->wp->wpCreateNonce('mailpoet_token');
266
267 // add API version
268 $data['api_version'] = API::CURRENT_VERSION;
269
270 // render form
271 $renderer = (new RendererFactory())->getRenderer();
272 try {
273 $output = $renderer->render('form/front_end_form.html', $data);
274 $output = WPFunctions::get()->doShortcode($output);
275
276 // Define the exact keys we want to keep for the filter context
277 $allowed_keys = [
278 'form_html_id' => null,
279 'form_id' => null,
280 'form_type' => null,
281 'form_success_message' => null,
282 'title' => null,
283 'styles' => null,
284 'html' => null,
285 'before_widget' => null,
286 'after_widget' => null,
287 'before_title' => null,
288 'after_title' => null,
289 ];
290
291 // Create a new context array for the filter, containing only the allowed keys.
292 // This automatically excludes 'success', 'error', 'token', and 'api_version'.
293 $filter_context_data = array_intersect_key($data, $allowed_keys);
294
295 /**
296 * Filters the rendered MailPoet form HTML after shortcodes are processed.
297 *
298 * @since TBD Added the $data context parameter.
299 *
300 * @param string $output Rendered form HTML.
301 * @param array<string, mixed> $filter_context_data Rendering context (form id, type, styles, and more).
302 * @return string Filtered HTML.
303 */
304 $output = $this->wp->applyFilters('mailpoet_form_widget_post_process', $output, $filter_context_data);
305 } catch (\Exception $e) {
306 $output = $e->getMessage();
307 }
308 }
309
310 if ($formType === 'widget') {
311 /** @var string $output */
312 // We control the template and the data is sanitized
313 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
314 echo $output;
315 } else {
316 return $output;
317 }
318 }
319 }
320