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 / FormsRepository.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
FormsRepository.php
265 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\Doctrine\Repository;
9 use MailPoet\Entities\FormEntity;
10
11 /**
12 * @extends Repository<FormEntity>
13 */
14 class FormsRepository extends Repository {
15 protected function getEntityClassName() {
16 return FormEntity::class;
17 }
18
19 /**
20 * @return FormEntity[]
21 */
22 public function findAllNotDeleted(): array {
23 return $this->entityManager
24 ->createQueryBuilder()
25 ->select('f')
26 ->from(FormEntity::class, 'f')
27 ->where('f.deletedAt IS NULL')
28 ->orderBy('f.updatedAt', 'desc')
29 ->getQuery()
30 ->getResult();
31 }
32
33 /**
34 * @return FormEntity[]
35 */
36 public function findAllActive(): array {
37 return $this->entityManager
38 ->createQueryBuilder()
39 ->select('f')
40 ->from(FormEntity::class, 'f')
41 ->where('f.deletedAt IS NULL')
42 ->andWhere('f.status = :status')
43 ->setParameter('status', FormEntity::STATUS_ENABLED)
44 ->orderBy('f.updatedAt', 'desc')
45 ->getQuery()
46 ->getResult();
47 }
48
49 public function getNamesOfFormsForSegments(): array {
50 $allNonDeletedForms = $this->findAllNotDeleted();
51
52 $nameMap = [];
53 foreach ($allNonDeletedForms as $form) {
54 $blockSegmentsIds = $form->getSettingsSegmentIds();
55 foreach ($blockSegmentsIds as $blockSegmentId) {
56 $nameMap[$blockSegmentId][] = $form->getName();
57 }
58 }
59
60 // Sort form names alphabetically for each segment
61 foreach ($nameMap as &$names) {
62 sort($names);
63 }
64
65 return $nameMap;
66 }
67
68 public function count(): int {
69 return (int)$this->doctrineRepository
70 ->createQueryBuilder('f')
71 ->select('count(f.id)')
72 ->getQuery()
73 ->getSingleScalarResult();
74 }
75
76 public function getActiveFormsCountByType(): array {
77 $forms = $this->findAllActive();
78 $formBlocks = $this->getActiveFormsBlocks();
79
80 $counts = [
81 'all' => count($forms),
82 FormEntity::DISPLAY_TYPE_BELOW_POST => 0,
83 FormEntity::DISPLAY_TYPE_FIXED_BAR => 0,
84 FormEntity::DISPLAY_TYPE_POPUP => 0,
85 FormEntity::DISPLAY_TYPE_SLIDE_IN => 0,
86 FormEntity::DISPLAY_TYPE_OTHERS => 0,
87 'with_first_name' => 0,
88 'with_last_name' => 0,
89 'with_custom_fields' => 0,
90 'min_custom_fields' => 0,
91 'max_custom_fields' => 0,
92 'average_custom_fields' => 0,
93 'median_custom_fields' => 0,
94 ];
95
96 foreach ($forms as $form) {
97 $settings = $form->getSettings();
98 if (!is_array($settings) || !isset($settings['form_placement'])) continue;
99
100 $hasAnyEnabled = false;
101 $formPlacement = $settings['form_placement'];
102
103 foreach (FormEntity::FORM_DISPLAY_TYPES as $type) {
104 if (isset($formPlacement[$type]['enabled']) && $formPlacement[$type]['enabled'] === '1') {
105 $counts[$type]++;
106 $hasAnyEnabled = true;
107 }
108 }
109
110 if (!$hasAnyEnabled) {
111 $counts[FormEntity::DISPLAY_TYPE_OTHERS]++;
112 }
113 }
114
115 $customFieldsCounts = [];
116 foreach ($formBlocks as $blocks) {
117 if (in_array('first_name', $blocks)) {
118 $counts['with_first_name']++;
119 }
120 if (in_array('last_name', $blocks)) {
121 $counts['with_last_name']++;
122 }
123
124 $customFieldsInForm = array_filter($blocks, function($block) {
125 return strpos($block, 'custom_') === 0;
126 });
127
128 if (!empty($customFieldsInForm)) {
129 $counts['with_custom_fields']++;
130 $customFieldsCounts[] = count($customFieldsInForm);
131 }
132 }
133
134 if (!empty($customFieldsCounts)) {
135 $counts['min_custom_fields'] = min($customFieldsCounts);
136 $counts['max_custom_fields'] = max($customFieldsCounts);
137 $counts['average_custom_fields'] = round(array_sum($customFieldsCounts) / count($customFieldsCounts), 1);
138 }
139
140 return $counts;
141 }
142
143 /**
144 * Get active forms with their placements and blocks for analytics tracking
145 * @return array
146 */
147 private function getActiveFormsBlocks(): array {
148 $forms = $this->findAllActive();
149 $formBlocks = [];
150
151 foreach ($forms as $form) {
152 $settings = $form->getSettings();
153 if (!is_array($settings)) continue;
154
155 $body = $form->getBody();
156 if (!is_array($body)) continue;
157
158 $formBlocks[] = $this->extractBlockTypes($body);
159 }
160
161 return $formBlocks;
162 }
163
164 /**
165 * Extract block types from form body recursively
166 * @param array $blocks
167 * @return array
168 */
169 private function extractBlockTypes(array $blocks): array {
170 $ignoredBlocks = ['columns', 'column', 'paragraph', 'heading', 'image', 'divider', 'submit', 'html'];
171 $fieldBlockIds = ['email', 'first_name', 'last_name', 'segments'];
172 $blockTypes = [];
173
174 foreach ($blocks as $block) {
175 if (in_array($block['id'], $fieldBlockIds)) {
176 $blockTypes[] = $block['id'];
177 } elseif (!in_array($block['type'], $ignoredBlocks)) {
178 $blockTypes[] = 'custom_' . $block['type'];
179 }
180
181 // Recursively check nested blocks (like in columns)
182 if (isset($block['body']) && is_array($block['body'])) {
183 $blockTypes = array_merge($blockTypes, $this->extractBlockTypes($block['body']));
184 }
185 }
186
187 return $blockTypes;
188 }
189
190 public function delete(FormEntity $form) {
191 $this->entityManager->remove($form);
192 $this->flush();
193 }
194
195 public function trash(FormEntity $form) {
196 $this->bulkTrash([$form->getId()]);
197 $this->entityManager->refresh($form);
198 }
199
200 public function restore(FormEntity $form) {
201 $this->bulkRestore([$form->getId()]);
202 $this->entityManager->refresh($form);
203 }
204
205 public function bulkTrash(array $ids): int {
206 if (empty($ids)) {
207 return 0;
208 }
209
210 $result = $this->entityManager->createQueryBuilder()
211 ->update(FormEntity::class, 'f')
212 ->set('f.deletedAt', 'CURRENT_TIMESTAMP()')
213 ->where('f.id IN (:ids)')
214 ->setParameter('ids', $ids)
215 ->getQuery()->execute();
216
217 // update was done via DQL, make sure the entities are also refreshed in the entity manager
218 $this->refreshAll(function (FormEntity $entity) use ($ids) {
219 return in_array($entity->getId(), $ids, true);
220 });
221
222 return $result;
223 }
224
225 public function bulkRestore(array $ids): int {
226 if (empty($ids)) {
227 return 0;
228 }
229
230 $result = $this->entityManager->createQueryBuilder()
231 ->update(FormEntity::class, 'f')
232 ->set('f.deletedAt', ':deletedAt')
233 ->where('f.id IN (:ids)')
234 ->setParameter('deletedAt', null)
235 ->setParameter('ids', $ids)
236 ->getQuery()->execute();
237
238 // update was done via DQL, make sure the entities are also refreshed in the entity manager
239 $this->refreshAll(function (FormEntity $entity) use ($ids) {
240 return in_array($entity->getId(), $ids, true);
241 });
242
243 return $result;
244 }
245
246 public function bulkDelete(array $ids): int {
247 if (empty($ids)) {
248 return 0;
249 }
250
251 $result = $this->entityManager->createQueryBuilder()
252 ->delete(FormEntity::class, 'f')
253 ->where('f.id IN (:ids)')
254 ->setParameter('ids', $ids)
255 ->getQuery()->execute();
256
257 // delete was done via DQL, make sure the entities are also detached from the entity manager
258 $this->detachAll(function (FormEntity $entity) use ($ids) {
259 return in_array($entity->getId(), $ids, true);
260 });
261
262 return $result;
263 }
264 }
265