PluginProbe
Repeater Fields for Gravity Forms / trunk
Repeater Fields for Gravity Forms vtrunk
3.1.1 3.1.0 3.0.4 3.0.3 3.0.2 3.0.1 3.0.0 2.5.1 2.5.0 2.4.6 trunk 2.0.5 2.0.9 2.1.0 2.3.2 2.3.7 2.4.1 2.4.3 2.4.4 2.4.5
repeater-for-gravity-forms / fields / repeater_field.php

repeater_field.php in Repeater Fields for Gravity Forms trunk, at fields/repeater_field.php

939 lines 30.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // If Gravity Forms isn't loaded, bail.
3 if (!class_exists('GFForms')) {
4 die();
5 }
6 /**
7 * Class GF_Field_Phone
8 *
9 * Handles the behavior of Phone fields.
10 *
11 * @since Unknown
12 */
13 class Superaddons_GFRepeater_Field extends GF_Field
14 {
15 private $lead_id = null;
16 /**
17 * Defines the field type.
18 *
19 * @since Unknown
20 * @access public
21 *
22 * @var string The field type.
23 */
24 public $type = 'repeater_end';
25 public $list_fields_validate = array();
26 /**
27 * Defines the field title to be used in the form editor.
28 *
29 * @since Unknown
30 * @access public
31 *
32 * @used-by GFCommon::get_field_type_title()
33 *
34 * @return string The field title. Translatable and escaped.
35 */
36 public function get_form_editor_field_title()
37 {
38 return esc_attr__('Repeater end', 'repeater-for-gravity-forms');
39 }
40 public function get_form_editor_button()
41 {
42 return array(
43 'group' => 'advanced_fields',
44 'text' => $this->get_form_editor_field_title()
45 );
46 }
47 /**
48 * Defines the field settings available within the field editor.
49 *
50 * @since Unknown
51 * @access public
52 *
53 * @return array The field settings available for the field.
54 */
55 function get_form_editor_field_settings()
56 {
57 return array(
58 'conditional_logic_field_setting',
59 'prepopulate_field_setting',
60 'error_message_setting',
61 'label_setting',
62 'field_field_repeater_end_text_setting',
63 'field_field_repeater_initial_rows_setting',
64 'field_field_repeater_max_setting',
65 'label_placement_setting',
66 'admin_label_setting',
67 'size_setting',
68 'rules_setting',
69 'visibility_setting',
70 'duplicate_setting',
71 'placeholder_setting',
72 'description_setting',
73 'css_class_setting',
74 );
75 }
76 /**
77 * Defines if conditional logic is supported in this field type.
78 *
79 * @since Unknown
80 * @access public
81 *
82 * @used-by GFFormDetail::inline_scripts()
83 * @used-by GFFormSettings::output_field_scripts()
84 *
85 * @return bool true
86 */
87 public function is_conditional_logic_supported()
88 {
89 return false;
90 }
91 /**
92 * Returns the field input.
93 *
94 * @since Unknown
95 * @access public
96 *
97 * @used-by GFCommon::get_field_input()
98 * @uses GF_Field::is_entry_detail()
99 * @uses GF_Field::is_form_editor()
100 * @uses GF_Field_Phone::$failed_validation
101 * @uses GF_Field_Phone::get_phone_format()
102 * @uses GFFormsModel::is_html5_enabled()
103 * @uses GF_Field::get_field_placeholder_attribute()
104 * @uses GF_Field_Phone::$isRequired
105 * @uses GF_Field::get_tabindex()
106 *
107 * @param array $form The Form Object.
108 * @param string $value The value of the input. Defaults to empty string.
109 * @param null|array $entry The Entry Object. Defaults to null.
110 *
111 * @return string The HTML markup for the field.
112 */
113 public function get_field_input($form, $value = '', $entry = null)
114 {
115 if (is_array($value)) {
116 $value = '';
117 }
118 $is_entry_detail = $this->is_entry_detail();
119 $is_form_editor = $this->is_form_editor();
120 $form_id = $form['id'];
121 $id = intval($this->id);
122 $field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
123 $size = $this->size;
124 $disabled_text = $is_form_editor ? "disabled='disabled'" : '';
125 $class_suffix = $is_entry_detail ? '_admin' : '';
126 $class = $size . $class_suffix . " gf-field-repeater-data hidden";
127 $class = esc_attr($class);
128 $instruction_div = '';
129 $html_input_type = 'hidden';
130 $placeholder_attribute = $this->get_field_placeholder_attribute();
131 $required_attribute = $this->isRequired ? 'aria-required="true"' : '';
132 $invalid_attribute = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
133 $aria_describedby = $this->get_aria_describedby();
134 $tabindex = $this->get_tabindex();
135 $repeater_add_button = $this->field_repeater_end_text;
136 if ($repeater_add_button == "") {
137 $repeater_add_button = esc_attr__("Add more", "gravityforms-repeater");
138 }
139 $initial_rows = $this->repeater_initial_rows;
140 if ($initial_rows == "") {
141 $initial_rows = 1;
142 }
143 $limit = $this->repeater_max;
144 if ($limit == "" or $limit < 1) {
145 $limit = 9999;
146 }
147 $limit = apply_filters("yeeaddons_gf_repeater_limit", 5, $limit);
148 $initial_rows = apply_filters("yeeaddons_gf_repeater_initial_rows", 1, $initial_rows);
149 $input = "<input data-initial_rows_map_check='" . $this->repeater_initial_rows_map . "' data-initial_rows_map='input_{$form_id}_" . $this->repeater_initial_rows_map . "' data-map_id='field_" . $form_id . "_" . $id . "' name='input_{$id}' id='{$field_id}' type='{$html_input_type}' value='{$value}' class='{$class}' {$tabindex} {$placeholder_attribute} {$required_attribute} {$invalid_attribute} {$disabled_text}/>";
150 $html = '<div data-initial_rows_map_check="' . $this->repeater_initial_rows_map . '" class="repeater-field-warp-item-data" data-initial_rows="' . $initial_rows . '" data-limit="' . $limit . '" data-initial_rows_map="input_' . $form_id . '_' . $this->repeater_initial_rows_map . '" data-map_id="field_' . $form_id . '_' . $id . '">
151 <div class="repeater-field-warp-item">
152 </div>
153 <div class="repeater-field-footer"><a href="#"" class="gf-repeater-field-button-add" >' . $repeater_add_button . '</a></div>
154 ' . $input . '
155 <input type="hidden" class="gf-field-repeater-data-html hidden" />
156 </div>';
157 if (is_admin()) {
158 $html = '<hr>End Repeater<hr>';
159 return sprintf("<div class='ginput_container1'>%s</div>", $html);
160 } else {
161 return sprintf("<div class='ginput_container'>%s</div>", $html);
162 }
163 }
164 public static function remove_validation($form)
165 {
166 $zo = false;
167 $zo_datas = array();
168 foreach ($form["fields"] as $field) {
169 $type = $field->type;
170 if ($type == "repeater_start") {
171 $zo = true;
172 continue;
173 }
174 if ($type == "repeater_end") {
175 $zo = false;
176 continue;
177 }
178 if ($zo) {
179 if (!isset($field->repeater_validate)) {
180 $field->repeater_validate = array("isRequired" => $field->isRequired);
181 }
182 $field->isRequired = false;
183 $field->validateState = false;
184 }
185 }
186 return $form;
187 }
188 function validate($value, $form)
189 {
190 $datas = json_decode($value, true);
191 $list_fields_validate = array();
192 $failedValidation = false;
193 foreach ($form["fields"] as $field) {
194 if (is_array($field->repeater_validate)) {
195 foreach ($field->repeater_validate as $k => $v) {
196 if ($k == "isRequired" && $v == true) {
197 $list_fields_validate["input_" . $field->id] = $field->type;
198 }
199 }
200 }
201 }
202 if (isset($datas["id"]) && is_array($datas["id"])) {
203 // Check if file upload is attempted without the Pro version activated
204 if (!class_exists('Yeeaddons_Upgrade_GF_Repeater_Plugin')) {
205 $is_fileupload_attempt = false;
206 foreach ($datas["id"] as $id) {
207 foreach ($datas["fields"] as $field) {
208 if ($field == "") {
209 continue;
210 }
211 $field = str_replace('[]', '', $field);
212 $input_name = $field . "__" . $id;
213 // Standard file upload
214 if (isset($_FILES[$input_name]) && !empty($_FILES[$input_name]['name']) && (is_array($_FILES[$input_name]['name']) ? !empty(array_filter($_FILES[$input_name]['name'])) : true)) {
215 $is_fileupload_attempt = true;
216 break 2;
217 }
218 // Multi-file upload (Ajax/plupload)
219 if (strpos($field, 'gform_multifile_upload_') === 0 && !empty($_POST[$input_name])) {
220 $is_fileupload_attempt = true;
221 break 2;
222 }
223 }
224 }
225 if ($is_fileupload_attempt) {
226 $this->failed_validation = true;
227 $this->validation_message = esc_html__('File upload in repeater is only supported in the Pro version.', 'repeater-for-gravity-forms');
228 return;
229 }
230 }
231
232 foreach ($datas["id"] as $id) {
233 foreach ($datas["fields"] as $field) {
234 if ($field == "") {
235 continue;
236 }
237 $field = str_replace('[]', '', $field);
238 if (isset($list_fields_validate[$field])) {
239 $getInputData = rgpost($field . "__" . $id);
240 switch ($list_fields_validate[$field]) {
241 case "name":
242 $first_name = rgpost($field . "_3__" . $id);
243 $last_name = rgpost($field . "_6__" . $id);
244 if (empty($first_name) || empty($last_name)) {
245 $failedValidation = true;
246 }
247 break;
248 case 'address':
249 $address = rgpost($field . "_1__" . $id);
250 if (empty($address)) {
251 $failedValidation = true;
252 }
253 break;
254 case 'fileupload':
255 if (isset($_FILES[$field . "__" . $id]) && $_FILES[$field . "__" . $id]['name'][0]) {
256 //file uploaded
257 } else {
258 $failedValidation = true;
259 }
260 break;
261 default:
262 if (is_array($getInputData)) {
263 foreach ($getInputData as $vl) {
264 if (empty($vl)) {
265 $failedValidation = true;
266 }
267 }
268 } else {
269 if (empty($getInputData)) {
270 $failedValidation = true;
271 }
272 }
273 break;
274 }
275 }
276 }
277 }
278 if ($failedValidation) {
279 $this->failed_validation = true;
280 if ($this->errorMessage) {
281 $this->validation_message = $this->errorMessage;
282 } else {
283 $this->validation_message = esc_html__('This field is required.', 'gravityforms');
284 }
285 return;
286 } else {
287 $this->failed_validation = false;
288 }
289 }
290 }
291 function custom_validation($form)
292 {
293 $dataRepeater = array();
294 $zo = false;
295 $zo_datas = array();
296 foreach ($form["fields"] as $field) {
297 $type = $field->type;
298 if ($type == "repeater_start") {
299 $zo = true;
300 continue;
301 }
302 if ($zo) {
303 $zo_datas[$field->id] = array("isRequired" => $field->isRequired);
304 $field->isRequired = false;
305 }
306 if ($type == "repeater_end") {
307 $zo = false;
308 $zo_datas = array();
309 continue;
310 }
311 }
312 return $form;
313 }
314 /**
315 * Gets the value of the submitted field.
316 *
317 * @since Unknown
318 * @access public
319 *
320 * @used-by GFFormsModel::get_field_value()
321 * @uses GF_Field::get_value_submission()
322 * @uses GF_Field_Phone::sanitize_entry_value()
323 *
324 * @param array $field_values The dynamic population parameter names with their corresponding values to be populated.
325 * @param bool $get_from_post_global_var Whether to get the value from the $_POST array as opposed to $field_values. Defaults to true.
326 *
327 * @return array|string
328 */
329 public function get_value_submission($field_values, $get_from_post_global_var = true)
330 {
331 $value = parent::get_value_submission($field_values, $get_from_post_global_var);
332 $value = $this->sanitize_entry_value($value, $this->formId);
333 return $value;
334 }
335 /**
336 * Sanitizes the entry value.
337 *
338 * @since Unknown
339 * @access public
340 *
341 * @used-by GF_Field_Phone::get_value_save_entry()
342 * @used-by GF_Field_Phone::get_value_submission()
343 *
344 * @param string $value The value to be sanitized.
345 * @param int $form_id The form ID of the submitted item.
346 *
347 * @return string The sanitized value.
348 */
349 public function sanitize_entry_value($value, $form_id)
350 {
351 $value = is_array($value) ? array_map('sanitize_text_field', $value) : sanitize_text_field($value);
352 return $value;
353 }
354 /**
355 * Gets the field value when an entry is being saved.
356 *
357 * @since Unknown
358 * @access public
359 *
360 * @used-by GFFormsModel::prepare_value()
361 * @uses GF_Field_Phone::sanitize_entry_value()
362 * @uses GF_Field_Phone::$phoneFormat
363 *
364 * @param string $value The input value.
365 * @param array $form The Form Object.
366 * @param string $input_name The input name.
367 * @param int $lead_id The Entry ID.
368 * @param array $lead The Entry Object.
369 *
370 * @return string The field value.
371 */
372 public function get_value_save_entry($value, $form, $input_name, $lead_id, $lead)
373 {
374 $this->lead_id = $lead_id;
375 $datas = json_decode($value, true);
376 if (!is_array($datas) || !isset($datas["id"]) || !is_array($datas["id"])) {
377 return maybe_serialize(array());
378 }
379
380 $values = array();
381 $form_id = $this->formId;
382 $get_form = GFFormsModel::get_form_meta_by_id($form_id);
383 $form = $get_form[0];
384 $fields = array();
385 if (isset($datas["fields"]) && is_array($datas["fields"])) {
386 foreach ($datas["fields"] as $f) {
387 if (!is_string($f) || empty($f)) {
388 continue;
389 }
390 $datas_f = explode(".", $f);
391 $fields[] = $datas_f[0];
392 }
393 }
394 $fields = array_unique($fields);
395 foreach ($datas["id"] as $id_rand) {
396 $datas_step = array();
397 foreach ($fields as $field) {
398 $field = str_replace("[]", "", $field);
399 $inputs = $this->get_inputs($form, $field);
400 if (is_array($inputs)) {
401 $getInputData = array();
402 foreach ($inputs as $child_input) {
403 $getInputName = "input_" . $child_input["id"] . "__" . $id_rand;
404 $vl = rgpost(str_replace('.', '_', strval($getInputName)));
405 if ($vl !== "" && $vl !== false && $vl !== null) {
406 $child_field_type = $this->get_type($form, "input_" . $child_input["id"], $form_id);
407 if (is_string($vl)) {
408 if ($child_field_type === 'textarea') {
409 $vl = sanitize_textarea_field($vl);
410 } else {
411 $vl = sanitize_text_field($vl);
412 }
413 }
414 $getInputData[$child_input["id"]] = $vl;
415 }
416 }
417 $datas_step[$getInputName] = $getInputData;
418 } else {
419 $getInputName = $field . "__" . $id_rand;
420 $saved_url = '';
421
422 // 1. Check transient saved across multi-step pages by gform_unique_id or form_id
423 $unique_id = rgpost('gform_unique_id');
424 $transient_keys = array();
425 if (!empty($unique_id)) {
426 $transient_keys[] = 'gf_repeater_files_' . $unique_id;
427 }
428 $transient_keys[] = 'gf_repeater_files_' . $form_id;
429 $transient_keys[] = 'gf_repeater_files_1';
430
431 foreach ($transient_keys as $t_key) {
432 $transient_files = get_transient($t_key);
433 if (is_array($transient_files)) {
434 if (!empty($transient_files[$getInputName])) {
435 $saved_url = $transient_files[$getInputName];
436 break;
437 }
438 // Also check alternative key name format
439 foreach ($transient_files as $tk => $tv) {
440 if (strpos($tk, '__' . $id_rand) !== false && !empty($tv)) {
441 $clean_f = str_replace('gform_multifile_upload_' . $form_id . '_', '', $field);
442 $clean_f = str_replace('input_', '', $clean_f);
443 if (strpos($tk, '_' . $clean_f . '__') !== false || strpos($tk, 'input_' . $clean_f . '__') !== false) {
444 $saved_url = $tv;
445 break 2;
446 }
447 }
448 }
449 }
450 }
451
452
453 // 2. Check if $_POST contains a direct URL
454 if (empty($saved_url)) {
455 $post_val = rgpost(str_replace('.', '_', strval($getInputName)));
456 if (!empty($post_val) && is_string($post_val) && strpos($post_val, 'http') === 0) {
457 $saved_url = $post_val;
458 }
459 }
460
461 // 3. Check gform_uploaded_files (GF native temp file store)
462 if (empty($saved_url)) {
463 $uploaded_files_json = rgpost('gform_uploaded_files');
464 if (!empty($uploaded_files_json)) {
465 $uploaded_files = json_decode(stripslashes($uploaded_files_json), true);
466 if (is_array($uploaded_files) && isset($uploaded_files[$getInputName])) {
467 $file_info = $uploaded_files[$getInputName];
468 if (is_string($file_info) && strpos($file_info, 'http') === 0) {
469 $saved_url = $file_info;
470 }
471 }
472 }
473 }
474
475 // 4. Check $_FILES if uploaded on the current submit step
476 if (empty($saved_url) && isset($_FILES[$getInputName]) && !empty($_FILES[$getInputName]['name']) && (is_array($_FILES[$getInputName]['name']) ? !empty(array_filter($_FILES[$getInputName]['name'])) : ($_FILES[$getInputName]['error'] === UPLOAD_ERR_OK))) {
477 $res = apply_filters("yeeaddons_gf_repeater_file", "", $form_id, $_FILES[$getInputName]);
478 if ($res && $res !== "Upgrade to pro version") {
479 $saved_url = $res;
480 }
481 }
482
483 // 5. Fallback to $_POST value if available
484 if (empty($saved_url)) {
485 $saved_url = rgpost(str_replace('.', '_', strval($getInputName)));
486 }
487
488 // Sanitize theo kiểu trường trước khi lưu vào DB
489 $field_type = $this->get_type($form, $field, $form_id);
490 if (is_string($saved_url)) {
491 if ($field_type === 'textarea') {
492 $saved_url = sanitize_textarea_field($saved_url);
493 } elseif ($field_type === 'fileupload' || filter_var($saved_url, FILTER_VALIDATE_URL) !== false) {
494 $saved_url = esc_url_raw($saved_url);
495 } else {
496 $saved_url = sanitize_text_field($saved_url);
497 }
498 }
499
500 $datas_step[$getInputName] = $saved_url;
501 }
502 }
503 $values[$id_rand] = $datas_step;
504 }
505 return maybe_serialize($values);
506 }
507 public function upload_file($form_id, $file)
508 {
509 $target = GFFormsModel::get_file_upload_path($form_id, $file['name']);
510 if (!$target) {
511 return 'FAILED (Upload folder could not be created.)';
512 }
513 if (move_uploaded_file($file['tmp_name'], $target['path'])) {
514 $this->set_permissions($target['path']);
515 return $target['url'];
516 } else {
517 return 'FAILED (Temporary file could not be copied.)';
518 }
519 }
520 function set_permissions($path)
521 {
522 GFFormsModel::set_permissions($path);
523 }
524 public function get_value_entry_list($value, $entry, $field_id, $columns, $form)
525 {
526 if (empty($value)) {
527 return '';
528 } else {
529 $dataArray = GFFormsModel::unserialize($value);
530 $arrayCount = count($dataArray);
531 if ($arrayCount > 1) {
532 $returnText = $arrayCount . ' entries';
533 } else {
534 $returnText = $arrayCount . ' entry';
535 }
536 return $returnText;
537 }
538 }
539 function get_datas_field($format = "html", $value = '', $form_id = "")
540 {
541 global $wpdb;
542 $dataArray = GFFormsModel::unserialize($value);
543 $get_form = GFFormsModel::get_form_meta_by_id($form_id);
544 $form = $get_form[0];
545 if (isset($_GET['lid'])) {
546 $result = GFAPI::get_entry(absint($_GET['lid']));
547 } else {
548 $table = $wpdb->prefix . "gf_entry";
549 $mylink = $wpdb->get_row("SELECT id FROM $table ORDER BY id DESC");
550 $result = ($mylink && isset($mylink->id)) ? GFAPI::get_entry($mylink->id) : array();
551 }
552 if (!is_array($result) || is_wp_error($result)) {
553 $result = array();
554 }
555 if (!is_array($dataArray) || empty($dataArray)) {
556 return '';
557 }
558 if ($format === 'html') {
559 $html = '<ol>';
560 foreach ($dataArray as $step_datas) {
561 $html .= '<li><ul>';
562 foreach ($step_datas as $name => $vl) {
563 $type = $this->get_type($form, $name, $form_id);
564 $lb = $this->get_custom_field_label($form, $name, $type, false, $form_id);
565 if (is_array($vl)) {
566 switch ($type) {
567 case "address":
568 $vl_data = "";
569 foreach ($vl as $k => $v) {
570 $child_lb = $this->get_custom_field_label($form, "input_" . $k, $type, true);
571 $vl_data .= esc_html($child_lb) . ": " . esc_html($v) . "<br>";
572 }
573 $html .= '<li>' . esc_html($lb) . ": <br>" . $vl_data . "</li>";
574 break;
575 default:
576 $vl_data = implode(", ", array_map('esc_html', $vl));
577 $html .= '<li>' . esc_html($lb) . ": " . $vl_data . "</li>";
578 break;
579 }
580 } else {
581 $vl_data = $vl;
582
583 // Helper functions kiểm tra và render file/hình ảnh
584 $encode_url = function ($url) {
585 return preg_replace_callback('/[^\x20-\x7E]/u', function ($match) {
586 return rawurlencode($match[0]);
587 }, trim($url));
588 };
589
590 $is_valid_url = function ($url) use ($encode_url) {
591 if (empty($url))
592 return false;
593 $encoded = $encode_url($url);
594 return filter_var($encoded, FILTER_VALIDATE_URL) !== false;
595 };
596
597 $is_image_url = function ($url) {
598 if (!is_string($url) || empty($url))
599 return false;
600 $clean_path = parse_url($url, PHP_URL_PATH);
601 if (!$clean_path) {
602 $clean_path = $url;
603 }
604 $ext = strtolower(pathinfo($clean_path, PATHINFO_EXTENSION));
605 return in_array($ext, array('jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp', 'ico', 'avif', 'heic'), true);
606 };
607
608 $render_file_or_image = function ($file_url, $display_name = '') use ($is_image_url) {
609 $file_url = trim($file_url);
610 if (empty($file_url))
611 return '';
612 $filename = !empty($display_name) ? $display_name : basename($file_url);
613
614 if ($is_image_url($file_url)) {
615 return '<a href="' . esc_url($file_url) . '" target="_blank" class="repeater-image-preview" style="display:inline-block; margin: 4px 6px 4px 0;">'
616 . '<img src="' . esc_url($file_url) . '" alt="' . esc_attr($filename) . '" style="max-width: 150px; max-height: 150px; object-fit: contain; border-radius: 4px; border: 1px solid #e2e8f0; display: inline-block; vertical-align: middle;" />'
617 . '</a>';
618 } else {
619 return '<a href="' . esc_url($file_url) . '" download>' . esc_html($filename) . '</a>';
620 }
621 };
622
623 switch ($type) {
624 case "fileupload":
625 if ($vl_data === "Upgrade to pro version") {
626 $html .= '<li>' . esc_html($lb) . ": " . esc_html($vl_data) . "</li>";
627 break;
628 }
629
630 // Tách chuỗi theo dấu phẩy phòng trường hợp có nhiều file
631 $parts = array_filter(array_map('trim', explode(",", $vl_data)));
632 $content = array();
633
634 // TRƯỜNG HỢP 1: Tất cả các phần tử đều là URL hợp lệ
635 $all_are_urls = !empty($parts);
636 foreach ($parts as $part) {
637 if (!$is_valid_url($part)) {
638 $all_are_urls = false;
639 break;
640 }
641 }
642
643 if ($all_are_urls) {
644 foreach ($parts as $part) {
645 $filename = basename($part);
646 $content[] = $render_file_or_image($part, $filename);
647 }
648 $html .= '<li>' . esc_html($lb) . ': ' . implode(" ", $content) . "</li>";
649 break;
650 }
651
652 // TRƯỜNG HỢP 2: Chuỗi chứa tên file hoặc URL không hợp lệ -> Tìm trong $result
653 $main_name = explode("__", $name);
654 $main_name = explode("_", $main_name[0]);
655 $main_name_id = isset($main_name[4]) ? $main_name[4] : (isset($main_name[1]) ? $main_name[1] : null);
656
657 if ($main_name_id && isset($result[$main_name_id])) {
658 $raw_uploads = $result[$main_name_id];
659 $data_uploads = is_array($raw_uploads) ? $raw_uploads : json_decode($raw_uploads, true);
660
661 if (!is_array($data_uploads)) {
662 $data_uploads = array_filter(array_map('trim', explode(",", (string) $raw_uploads)));
663 }
664
665 foreach ($parts as $n) {
666 $clean_n = sanitize_file_name($n);
667 $name_s = preg_quote(pathinfo($clean_n, PATHINFO_FILENAME), '/');
668
669 foreach ($data_uploads as $upload_file) {
670 // Regex khớp chính xác tên file gốc hoặc tên file có đánh số thứ tự
671 if (preg_match('/' . $name_s . '(\d+)?\./i', $upload_file)) {
672 $content[] = $render_file_or_image($upload_file, $clean_n);
673 break;
674 }
675 }
676 }
677 }
678
679 $html .= '<li>' . esc_html($lb) . ': ' . (!empty($content) ? implode(" ", $content) : esc_html($vl_data)) . "</li>";
680 break;
681
682 default:
683 if (is_string($vl_data) && $is_valid_url($vl_data) && $is_image_url($vl_data)) {
684 $html .= '<li>' . esc_html($lb) . ': ' . $render_file_or_image($vl_data) . "</li>";
685 } else {
686 $html .= '<li>' . esc_html($lb) . ": " . esc_html($vl_data) . "</li>";
687 }
688 break;
689 }
690 }
691 }
692 $html .= '</ul></li>';
693 }
694 $html .= '</ol>';
695 $html = apply_filters("yeeadons_gravity_forms_repeater_html", $html, $dataArray, $form);
696 return $html;
697 } else {
698 $text = '';
699 foreach ($dataArray as $step_datas) {
700 if (!is_array($step_datas)) {
701 continue;
702 }
703 foreach ($step_datas as $name => $vl) {
704 $type = $this->get_type($form, $name, $form_id);
705 $lb = $this->get_custom_field_label($form, $name, $type, false, $form_id);
706 $lb = esc_html($lb);
707
708 if (is_array($vl)) {
709 switch ($type) {
710 case "address":
711 $vl_data = "";
712 foreach ($vl as $k => $v) {
713 $child_lb = $this->get_custom_field_label($form, "input_" . $k, $type, true);
714 $vl_data .= esc_html($child_lb) . ": " . esc_html($v) . "\n";
715 }
716 $text .= $lb . " : \n" . $vl_data;
717 break;
718 default:
719 $vl_escaped = array_map('esc_html', $vl);
720 $text .= $lb . ": " . implode(", ", $vl_escaped) . "\n";
721 break;
722 }
723 } else {
724 $vl_data = $vl;
725 switch ($type) {
726 case "fileupload":
727 if ($vl_data === "Upgrade to pro version") {
728 $text .= $lb . ": " . esc_html($vl_data) . "\n";
729 break;
730 }
731 $parts = array_filter(array_map('trim', explode(",", $vl_data)));
732 $content = array();
733
734 $all_are_urls = !empty($parts);
735 foreach ($parts as $part) {
736 if (filter_var($part, FILTER_VALIDATE_URL) === false) {
737 $all_are_urls = false;
738 break;
739 }
740 }
741
742 if ($all_are_urls) {
743 foreach ($parts as $part) {
744 $filename = basename($part);
745 $content[] = esc_html($filename) . ' (' . esc_url($part) . ')';
746 }
747 $text .= $lb . ': ' . implode(", ", $content) . "\n";
748 } else {
749 $main_name = explode("__", $name);
750 $main_name = explode("_", $main_name[0]);
751 $main_name_id = isset($main_name[4]) ? $main_name[4] : (isset($main_name[1]) ? $main_name[1] : null);
752
753 if ($main_name_id && isset($result[$main_name_id])) {
754 $raw_uploads = $result[$main_name_id];
755 $data_uploads = is_array($raw_uploads) ? $raw_uploads : json_decode($raw_uploads, true);
756 if (!is_array($data_uploads)) {
757 $data_uploads = array_filter(array_map('trim', explode(",", (string)$raw_uploads)));
758 }
759
760 foreach ($parts as $n) {
761 $clean_n = sanitize_file_name($n);
762 $name_s = preg_quote(pathinfo($clean_n, PATHINFO_FILENAME), '/');
763 foreach ($data_uploads as $upload_file) {
764 if (preg_match('/' . $name_s . '(\d+)?\./i', $upload_file)) {
765 $content[] = esc_html($clean_n) . ' (' . esc_url($upload_file) . ')';
766 break;
767 }
768 }
769 }
770 }
771 $text .= $lb . ': ' . (!empty($content) ? implode(", ", $content) : esc_html($vl_data)) . "\n";
772 }
773 break;
774
775 default:
776 $text .= $lb . ": " . esc_html($vl_data) . "\n";
777 break;
778 }
779 }
780 }
781 $text .= "\n";
782 }
783 $text = apply_filters("yeeadons_gravity_forms_repeater_text", $text, $dataArray, $form);
784 return $text;
785 }
786 }
787 public function get_value_export($entry, $input_id = '', $use_text = false, $is_csv = false)
788 {
789 //Export doesn’t require encoding, but field data may require some manipulation or formatting before it is exported
790 $form_id = $entry["form_id"];
791 $return = $this->get_datas_field("text", rgar($entry, $input_id), $form_id);
792 return $return;
793 }
794 public function get_value_merge_tag($value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br)
795 {
796 if (empty($value)) {
797 return '';
798 }
799 $form_id = isset($form['id']) ? absint($form['id']) : null;
800 $return = $this->get_datas_field($format, $value, $form_id);
801 return $return;
802 }
803 public function get_value_entry_detail($value, $currency = '', $use_text = false, $format = 'html', $media = 'screen')
804 {
805 global $wpdb;
806 if (empty($value)) {
807 return '';
808 } else {
809 $form_id = $this->formId;
810 $return = $this->get_datas_field($format, $value, $form_id);
811 return $return;
812 }
813 }
814 function get_custom_field_label($form, $name = '', $type = '', $child = false, $form_id = '')
815 {
816 if (is_array($form)) {
817 if (!array_key_exists('fields', $form)) {
818 return false;
819 }
820 } else {
821 return false;
822 }
823 $name = str_replace("gform_multifile_upload_" . $form_id, "input", $name);
824 $names = explode("__", $name);
825 $names = explode("_", $names[0]);
826 $name = isset($names[1]) ? $names[1] : $names[0];
827 foreach ($form['fields'] as $field_key => $field_value) {
828 if (is_array($field_value->inputs)) {
829 foreach ($field_value->inputs as $children_id) {
830 if ($children_id["id"] == $name) {
831 if ($child) {
832 return $children_id["label"];
833 } else {
834 return $field_value->label;
835 }
836 }
837 }
838 } else {
839 if ($field_value->id == $name) {
840 return $field_value->label;
841 }
842 }
843 }
844 return "";
845 }
846 function get_inputs($form, $name = '')
847 {
848 if (is_array($form)) {
849 if (!array_key_exists('fields', $form)) {
850 return false;
851 }
852 } else {
853 return false;
854 }
855 $names = explode("__", $name);
856 $names = explode("_", $names[0]);
857 $name = isset($names[1]) ? $names[1] : $names[0];
858 foreach ($form['fields'] as $field_key => $field_value) {
859 if ($field_value->id == $name) {
860 if ($field_value->type == "date") {
861 return $name;
862 }
863 if (is_array($field_value->inputs)) {
864 return $field_value->inputs;
865 }
866 }
867 }
868 return false;
869 }
870 function get_type($form, $name = '', $form_id = "")
871 {
872 if (is_array($form)) {
873 if (!array_key_exists('fields', $form)) {
874 return false;
875 }
876 } else {
877 return false;
878 }
879 $name = str_replace("gform_multifile_upload_" . $form_id, "input", $name);
880 $names = explode("__", $name);
881 $names = explode("_", $names[0]);
882 $name = isset($names[1]) ? $names[1] : $names[0];
883 foreach ($form['fields'] as $field_key => $field_value) {
884 if (is_array($field_value->inputs)) {
885 foreach ($field_value->inputs as $children_id) {
886 if ($children_id["id"] == $name) {
887 return $field_value->type;
888 }
889 }
890 } else {
891 if ($field_value->id == $name) {
892 return $field_value->type;
893 }
894 }
895 }
896 return "";
897 }
898
899 public static function remove_child_fields($form)
900 {
901 if (!is_admin()) {
902 return $form;
903 }
904
905 $page = isset($_GET['page']) ? $_GET['page'] : '';
906 $gf_page = isset($_GET['gf_page']) ? $_GET['gf_page'] : '';
907
908 $target_pages = array('gf_entries', 'gf_export');
909 $target_gf_pages = array('select_columns', 'print-entry');
910
911 if (in_array($page, $target_pages) || in_array($gf_page, $target_gf_pages)) {
912 $fields = array();
913 $zo = false;
914 foreach ($form["fields"] as $field) {
915 $type = $field->type;
916 if ($type == "repeater_start") {
917 $zo = true;
918 $fields[] = $field;
919 continue;
920 }
921 if ($type == "repeater_end") {
922 $zo = false;
923 $fields[] = $field;
924 continue;
925 }
926 if ($zo) {
927 continue;
928 }
929 $fields[] = $field;
930 }
931 $form["fields"] = $fields;
932 }
933
934 return $form;
935 }
936 }
937 // Register the phone field with the field framework.
938 GF_Fields::register(new Superaddons_GFRepeater_Field());
939