PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.16.9
GiveWP – Donation Plugin and Fundraising Platform v4.16.9
4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 All 255 releases
give / src / DonationForms / Actions / ConvertDonationFormBlocksToFieldsApi.php

ConvertDonationFormBlocksToFieldsApi.php in GiveWP – Donation Plugin and Fundraising Platform 4.16.9, at src/DonationForms/Actions/ConvertDonationFormBlocksToFieldsApi.php

444 lines 15.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Give\DonationForms\Actions;
4
5 use Exception;
6 use Give\DonationForms\Repositories\DonationFormRepository;
7 use Give\DonationForms\Rules\AuthenticationRule;
8 use Give\DonationForms\Rules\BillingAddressCityRule;
9 use Give\DonationForms\Rules\BillingAddressStateRule;
10 use Give\DonationForms\Rules\BillingAddressZipRule;
11 use Give\DonationForms\Rules\GatewayRule;
12 use Give\DonationForms\Rules\PhoneIntlInputRule;
13 use Give\FormBuilder\BlockModels\DonationAmountBlockModel;
14 use Give\FormBuilder\BlockTypes\TextBlockType;
15 use Give\Framework\Blocks\BlockCollection;
16 use Give\Framework\Blocks\BlockModel;
17 use Give\Framework\FieldsAPI\Authentication;
18 use Give\Framework\FieldsAPI\BillingAddress;
19 use Give\Framework\FieldsAPI\Checkbox;
20 use Give\Framework\FieldsAPI\Contracts\Node;
21 use Give\Framework\FieldsAPI\DonationForm;
22 use Give\Framework\FieldsAPI\DonationSummary;
23 use Give\Framework\FieldsAPI\Email;
24 use Give\Framework\FieldsAPI\Exceptions\EmptyNameException;
25 use Give\Framework\FieldsAPI\Exceptions\NameCollisionException;
26 use Give\Framework\FieldsAPI\Exceptions\TypeNotSupported;
27 use Give\Framework\FieldsAPI\Field;
28 use Give\Framework\FieldsAPI\Name;
29 use Give\Framework\FieldsAPI\Paragraph;
30 use Give\Framework\FieldsAPI\PaymentGateways;
31 use Give\Framework\FieldsAPI\Phone;
32 use Give\Framework\FieldsAPI\Section;
33 use Give\Framework\FieldsAPI\Text;
34 use Give\Framework\FieldsAPI\Textarea;
35 use Give\Helpers\IntlTelInput;
36 use WP_User;
37
38 /**
39 * @since 3.0.0
40 */
41 class ConvertDonationFormBlocksToFieldsApi
42 {
43 /**
44 * @var int
45 */
46 protected $formId;
47 /**
48 * @var string
49 */
50 protected $currency;
51 /**
52 * @var array{blockClientId: {node: Node, block: BlockModel}}
53 */
54 protected $blockNodeRelationships = [];
55
56 /**
57 * @since 3.0.0
58 *
59 * @return array{form: DonationForm, array{clientId: string{node: Node, block: BlockModel}}}
60 * @throws TypeNotSupported|NameCollisionException
61 */
62 public function __invoke(BlockCollection $blocks, int $formId): array
63 {
64 $this->formId = $formId;
65 $this->currency = give_get_currency($formId);
66
67 $form = new DonationForm('donation-form');
68 $form->defaultCurrency($this->currency);
69
70 $blockIndex = 0;
71 foreach ($blocks->getBlocks() as $block) {
72 $blockIndex++;
73 $section = $this->convertTopLevelBlockToSection($block, $blockIndex);
74
75 if ($block->innerBlocks) {
76 $innerBlocks = $block->innerBlocks->getBlocks();
77 $nodes = array_filter(
78 array_map([$this, 'convertInnerBlockToNode'], $innerBlocks, array_keys($innerBlocks)),
79 static function ($node) {
80 return $node instanceof Node;
81 }
82 );
83
84 $section->append(
85 ...$nodes
86 );
87 }
88
89 $form->append($section);
90 }
91
92 return [$form, $this->blockNodeRelationships];
93 }
94
95 /**
96 * @since 3.0.0
97 */
98 protected function convertTopLevelBlockToSection(BlockModel $block, int $blockIndex): Section
99 {
100 $node = Section::make($block->getShortName() . '-' . $blockIndex)
101 ->label($block->getAttribute('title'))
102 ->description($block->getAttribute('description'));
103
104 $this->mapBlockToNodeRelationships($block, $node);
105
106 return $node;
107 }
108
109 /**
110 * @since 3.0.0
111 *
112 * @return Node|null
113 * @throws EmptyNameException|NameCollisionException
114 *
115 */
116 protected function convertInnerBlockToNode(BlockModel $block, int $blockIndex)
117 {
118 $node = $this->createNodeFromBlockWithUniqueAttributes($block, $blockIndex);
119
120 if (!$node instanceof Node) {
121 return null;
122 }
123
124 if ($node instanceof Field) {
125 $node = $this->mapGenericBlockAttributesToField($block, $node);
126 }
127
128 $this->mapBlockToNodeRelationships($block, $node);
129
130 return $node;
131 }
132
133 /**
134 * @since 3.21.0 updated to use TextBlockType
135 * @since 3.19.4 add max rule to company field
136 * @since 3.9.0 Add "givewp/donor-phone" block
137 * @since 3.0.0
138 *
139 * @return Node|null
140 * @throws NameCollisionException
141 *
142 * @throws EmptyNameException
143 * @throws Exception
144 */
145 protected function createNodeFromBlockWithUniqueAttributes(BlockModel $block, int $blockIndex)
146 {
147 $blockName = $block->name;
148
149 switch ($blockName) {
150 case "givewp/donation-amount":
151 return $this->createNodeFromAmountBlock($block);
152
153 case "givewp/donor-name":
154 return $this->createNodeFromDonorNameBlock($block);
155
156 case "givewp/donor-comments":
157 return Textarea::make('comment')
158 ->label($block->getAttribute('label'))
159 ->helpText($block->getAttribute('description'))
160 ->rules('max:5000');
161
162 case "givewp/billing-address":
163 return $this->createNodeFromBillingAddressBlock($block);
164
165 case "givewp/paragraph":
166 return Paragraph::make($block->getShortName() . '-' . $blockIndex)
167 ->content($block->getAttribute('content'));
168
169 case "givewp/email":
170 return Email::make('email')
171 ->emailTag('email')
172 ->rules('required', 'email')
173 ->tap(function ($email) use ($block) {
174 if (is_user_logged_in()) {
175 $email->defaultValue(wp_get_current_user()->user_email);
176 }
177
178 return $email;
179 });
180 case 'givewp/donor-phone':
181 return Phone::make('phone')
182 ->setIntlTelInputSettings(IntlTelInput::getSettings())
183 ->rules('max:50', (bool)$block->getAttribute('required') ? 'required' : 'optional',
184 new PhoneIntlInputRule());
185
186
187 case "givewp/payment-gateways":
188 $defaultGatewayId = give(DonationFormRepository::class)->getDefaultEnabledGatewayId($this->formId);
189
190 return PaymentGateways::make('gatewayId')
191 ->testMode(give_is_test_mode())
192 ->rules(new GatewayRule())
193 ->required()
194 ->defaultValue(!empty($defaultGatewayId) ? $defaultGatewayId : null);
195
196 case "givewp/donation-summary":
197 return DonationSummary::make('donation-summary');
198
199 case "givewp/company":
200 return Text::make('company')->rules('max:255');
201
202 case TextBlockType::name():
203 $textBlockType = new TextBlockType($block);
204
205 return Text::make($textBlockType->getFieldName($blockIndex))
206 ->storeAsDonorMeta($textBlockType->storeAsDonorMeta)
207 ->description($textBlockType->description)
208 ->defaultValue($textBlockType->defaultValue);
209
210 case "givewp/terms-and-conditions":
211 return $this->createNodeFromConsentBlock($block, $blockIndex)
212 ->required();
213
214 case "givewp/login":
215 return Authentication::make('login')
216 ->required($block->getAttribute('required'))
217 ->isAuthenticated(is_user_logged_in())
218 ->lostPasswordUrl(wp_lostpassword_url())
219 ->loginRedirect($block->getAttribute('loginRedirect'))
220 ->loginRedirectUrl(wp_login_url())
221 ->loginNotice($block->getAttribute('loginNotice'))
222 ->loginConfirmation($block->getAttribute('loginConfirmation'))
223 ->tapNode('login', function ($field) use ($block) {
224 if ($block->getAttribute('required')) {
225 if (!is_user_logged_in()) {
226 $field->required();
227 }
228
229 $field->rules(new AuthenticationRule());
230 }
231 });
232
233 case "givewp/anonymous":
234 return Checkbox::make('anonymous')
235 ->label($block->getAttribute('label'))
236 ->helpText($block->getAttribute('description'))
237 ->showInAdmin()
238 ->showInReceipt()
239 ->rules('boolean');
240
241 default:
242 $customField = apply_filters(
243 'givewp_donation_form_block_render',
244 null,
245 $block,
246 $blockIndex,
247 $this->formId
248 );
249
250 $customField = apply_filters(
251 "givewp_donation_form_block_render_{$blockName}",
252 $customField,
253 $block,
254 $blockIndex,
255 $this->formId
256 );
257
258 if ($customField instanceof Node) {
259 return $customField;
260 }
261
262 return null;
263 }
264 }
265
266 /**
267 * @since 3.17.0 updated honorific field with validation, global options, and user defaults
268 *
269 * @since 3.0.0
270 */
271 protected function createNodeFromDonorNameBlock(BlockModel $block): Node
272 {
273 return Name::make('name')->tap(function ($group) use ($block) {
274 $group->getNodeByName('firstName')
275 ->label($block->getAttribute('firstNameLabel'))
276 ->placeholder($block->getAttribute('firstNamePlaceholder'))
277 ->required($block->getAttribute('requireFirstName'))
278 ->rules('required', 'max:255');
279
280 $group->getNodeByName('lastName')
281 ->label($block->getAttribute('lastNameLabel'))
282 ->placeholder($block->getAttribute('lastNamePlaceholder'))
283 ->required($block->getAttribute('requireLastName'))
284 ->rules('max:255');
285
286 if (is_user_logged_in()) {
287 /** @var WP_User $user */
288 $user = wp_get_current_user();
289
290 if ($user->first_name) {
291 $group->getNodeByName('firstName')->defaultValue($user->first_name);
292 }
293
294 if ($user->last_name) {
295 $group->getNodeByName('lastName')->defaultValue($user->last_name);
296 }
297 }
298
299
300 if ($block->hasAttribute('showHonorific') && $block->getAttribute('showHonorific') === true) {
301 $options = array_filter(array_values((array)$block->getAttribute('honorifics')));
302 if ($block->hasAttribute('useGlobalSettings') && $block->getAttribute('useGlobalSettings') === true) {
303 $options = give_get_option('title_prefixes', give_get_default_title_prefixes());
304 }
305
306 if (!empty($options)){
307 $group->getNodeByName('honorific')
308 ->label(__('Title', 'give'))
309 ->options(...$options)
310 ->rules('max:255', 'in:' . implode(',', $options));
311 }
312 } else {
313 $group->remove('honorific');
314 }
315 });
316 }
317
318 /**
319 * @since 4.14.0 Add support for default country value in billing address field
320 * @since 3.4.0 updated fields to add optional rules last so they can be dynamically validated.
321 * @since 3.0.0
322 */
323 protected function createNodeFromBillingAddressBlock(BlockModel $block): Node
324 {
325 $countryList = [];
326 foreach (give_get_country_list() as $value => $label) {
327 $countryList[] = [$value, $label];
328 }
329
330 return BillingAddress::make('billingAddress')
331 ->setApiUrl(
332 give_get_ajax_url([
333 'action' => 'give_get_states',
334 'field_name' => 'state_selector',
335 ])
336 )
337 ->setGroupLabel(
338 $block->getAttribute('groupLabel')
339 )
340 ->tap(function ($group) use ($block, $countryList) {
341 $group->getNodeByName('country')
342 ->label($block->getAttribute('countryLabel'))
343 ->options(...$countryList)
344 ->defaultValue($block->getAttribute('defaultCountry'))
345 ->rules('required');
346
347 $group->getNodeByName('address1')
348 ->label($block->getAttribute('address1Label'))
349 ->placeholder($block->getAttribute('address1Placeholder'))
350 ->rules('required', 'max:255');
351
352 $group->getNodeByName('address2')
353 ->label($block->getAttribute('address2Label'))
354 ->placeholder($block->getAttribute('address2Placeholder'))
355 ->required($block->getAttribute('requireAddress2'))
356 ->rules('max:255');
357
358 $group->getNodeByName('city')
359 ->label($block->getAttribute('cityLabel'))
360 ->placeholder($block->getAttribute('cityPlaceholder'))
361 ->rules('max:255', new BillingAddressCityRule(), 'optional');
362
363 $group->getNodeByName('state')
364 ->label($block->getAttribute('stateLabel'))
365 ->rules('max:255', new BillingAddressStateRule(), 'optional');
366
367 $group->getNodeByName('zip')
368 ->label($block->getAttribute('zipLabel'))
369 ->placeholder($block->getAttribute('zipPlaceholder'))
370 ->rules('max:255', new BillingAddressZipRule(), 'optional');
371 });
372 }
373
374 /**
375 * @since 3.0.0
376 *
377 * @throws NameCollisionException
378 * @throws EmptyNameException
379 */
380 protected function createNodeFromAmountBlock(BlockModel $block): Node
381 {
382 $donationAmountBlockModel = new DonationAmountBlockModel($block);
383 return (new ConvertDonationAmountBlockToFieldsApi())($donationAmountBlockModel, $this->currency);
384 }
385
386 /**
387 * @since 3.0.0
388 */
389 protected function createNodeFromConsentBlock(BlockModel $block, int $blockIndex): Node
390 {
391 return (new ConvertConsentBlockToFieldsApi())($block, $blockIndex);
392 }
393
394 /**
395 * @since 4.14.2 add emailTag to field
396 * @since 3.4.1 updated to be field specific and prevent overwriting of existing values
397 * @since 3.0.0
398 */
399 protected function mapGenericBlockAttributesToField(BlockModel $block, Field $field): Node
400 {
401 // Label
402 if ($block->hasAttribute('label') && method_exists($field, 'label')) {
403 $field->label($block->getAttribute('label'));
404 }
405
406 // Placeholder
407 if ($block->hasAttribute('placeholder') && method_exists($field, 'placeholder')) {
408 $field->placeholder($block->getAttribute('placeholder'));
409 }
410
411 // Required
412 if ($block->hasAttribute('isRequired') && method_exists($field, 'required') && !$field->isRequired()) {
413 $field->required($block->getAttribute('isRequired'));
414 }
415
416 if ($block->hasAttribute('displayInAdmin') && $block->getAttribute('displayInAdmin')) {
417 $field->showInAdmin($block->getAttribute('displayInAdmin'));
418 }
419
420 if ($block->hasAttribute('displayInReceipt') && $block->getAttribute('displayInReceipt')) {
421 $field->showInReceipt($block->getAttribute('displayInReceipt'));
422 }
423
424 if ($block->hasAttribute('emailTag') && method_exists($field, 'emailTag')) {
425 $field->emailTag($block->getAttribute('emailTag'));
426 }
427
428 return $field;
429 }
430
431 /**
432 * @since 3.0.0
433 *
434 * @return void
435 */
436 private function mapBlockToNodeRelationships(BlockModel $block, Node $node)
437 {
438 $this->blockNodeRelationships[$block->clientId] = [
439 'block' => $block,
440 'node' => $node,
441 ];
442 }
443 }
444