PluginProbe
Repeater Fields for Gravity Forms / 2.3.2
Repeater Fields for Gravity Forms v2.3.2
3.2.0 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
← All changes | fields/repeater_field.php +0 -897 3.0.42.3.2 View file →
@@ -1,897 +1,0 @@
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 -
377 - $values = array();
378 - $form_id = $this->formId;
379 - $get_form = GFFormsModel::get_form_meta_by_id($form_id);
380 - $form = $get_form[0];
381 - $fields = array();
382 - if (isset($datas["fields"]) && is_array($datas["fields"])) {
383 - foreach ($datas["fields"] as $f) {
384 - if (!is_string($f) || empty($f)) {
385 - continue;
386 - }
387 - $datas_f = explode(".", $f);
388 - $fields[] = $datas_f[0];
389 - }
390 - }
391 - $fields = array_unique($fields);
392 - foreach ($datas["id"] as $id_rand) {
393 - $datas_step = array();
394 - foreach ($fields as $field) {
395 - $field = str_replace("[]", "", $field);
396 - $inputs = $this->get_inputs($form, $field);
397 - if (is_array($inputs)) {
398 - $getInputData = array();
399 - foreach ($inputs as $child_input) {
400 - $getInputName = "input_" . $child_input["id"] . "__" . $id_rand;
401 - $vl = rgpost(str_replace('.', '_', strval($getInputName)));
402 - if ($vl != "") {
403 - $getInputData[$child_input["id"]] = $vl;
404 - }
405 - }
406 - $datas_step[$getInputName] = $getInputData;
407 - } else {
408 - $getInputName = $field . "__" . $id_rand;
409 - $saved_url = '';
410 -
411 - // 1. Check transient saved across multi-step pages by gform_unique_id or form_id
412 - $unique_id = rgpost('gform_unique_id');
413 - $transient_keys = array();
414 - if (!empty($unique_id)) {
415 - $transient_keys[] = 'gf_repeater_files_' . $unique_id;
416 - }
417 - $transient_keys[] = 'gf_repeater_files_' . $form_id;
418 - $transient_keys[] = 'gf_repeater_files_1';
419 -
420 - foreach ($transient_keys as $t_key) {
421 - $transient_files = get_transient($t_key);
422 - if (is_array($transient_files)) {
423 - if (!empty($transient_files[$getInputName])) {
424 - $saved_url = $transient_files[$getInputName];
425 - break;
426 - }
427 - // Also check alternative key name format
428 - foreach ($transient_files as $tk => $tv) {
429 - if (strpos($tk, '__' . $id_rand) !== false && !empty($tv)) {
430 - $clean_f = str_replace('gform_multifile_upload_' . $form_id . '_', '', $field);
431 - $clean_f = str_replace('input_', '', $clean_f);
432 - if (strpos($tk, '_' . $clean_f . '__') !== false || strpos($tk, 'input_' . $clean_f . '__') !== false) {
433 - $saved_url = $tv;
434 - break 2;
435 - }
436 - }
437 - }
438 - }
439 - }
440 -
441 -
442 - // 2. Check if $_POST contains a direct URL
443 - if (empty($saved_url)) {
444 - $post_val = rgpost(str_replace('.', '_', strval($getInputName)));
445 - if (!empty($post_val) && is_string($post_val) && strpos($post_val, 'http') === 0) {
446 - $saved_url = $post_val;
447 - }
448 - }
449 -
450 - // 3. Check gform_uploaded_files (GF native temp file store)
451 - if (empty($saved_url)) {
452 - $uploaded_files_json = rgpost('gform_uploaded_files');
453 - if (!empty($uploaded_files_json)) {
454 - $uploaded_files = json_decode(stripslashes($uploaded_files_json), true);
455 - if (is_array($uploaded_files) && isset($uploaded_files[$getInputName])) {
456 - $file_info = $uploaded_files[$getInputName];
457 - if (is_string($file_info) && strpos($file_info, 'http') === 0) {
458 - $saved_url = $file_info;
459 - }
460 - }
461 - }
462 - }
463 -
464 - // 4. Check $_FILES if uploaded on the current submit step
465 - 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))) {
466 - $res = apply_filters("yeeaddons_gf_repeater_file", "", $form_id, $_FILES[$getInputName]);
467 - if ($res && $res !== "Upgrade to pro version") {
468 - $saved_url = $res;
469 - }
470 - }
471 -
472 - // 5. Fallback to $_POST value if available
473 - if (empty($saved_url)) {
474 - $saved_url = rgpost(str_replace('.', '_', strval($getInputName)));
475 - }
476 -
477 - $datas_step[$getInputName] = $saved_url;
478 - }
479 - }
480 - $values[$id_rand] = $datas_step;
481 - }
482 - return maybe_serialize($values);
483 - }
484 - public function upload_file($form_id, $file)
485 - {
486 - $target = GFFormsModel::get_file_upload_path($form_id, $file['name']);
487 - if (!$target) {
488 - return 'FAILED (Upload folder could not be created.)';
489 - }
490 - if (move_uploaded_file($file['tmp_name'], $target['path'])) {
491 - $this->set_permissions($target['path']);
492 - return $target['url'];
493 - } else {
494 - return 'FAILED (Temporary file could not be copied.)';
495 - }
496 - }
497 - function set_permissions($path)
498 - {
499 - GFFormsModel::set_permissions($path);
500 - }
501 - public function get_value_entry_list($value, $entry, $field_id, $columns, $form)
502 - {
503 - if (empty($value)) {
504 - return '';
505 - } else {
506 - $dataArray = GFFormsModel::unserialize($value);
507 - $arrayCount = count($dataArray);
508 - if ($arrayCount > 1) {
509 - $returnText = $arrayCount . ' entries';
510 - } else {
511 - $returnText = $arrayCount . ' entry';
512 - }
513 - return $returnText;
514 - }
515 - }
516 - function get_datas_field($format = "html", $value = '', $form_id = "")
517 - {
518 - global $wpdb;
519 - $dataArray = GFFormsModel::unserialize($value);
520 - $get_form = GFFormsModel::get_form_meta_by_id($form_id);
521 - $form = $get_form[0];
522 - if (isset($_GET['lid'])) {
523 - $result = GFAPI::get_entry($_GET['lid']);
524 - } else {
525 - $table = $wpdb->prefix . "gf_entry";
526 - $mylink = $wpdb->get_row("SELECT id FROM $table ORDER BY id DESC");
527 - $result = GFAPI::get_entry($mylink->id);
528 - }
529 - //var_dump($dataArray);
530 - if ($format === 'html') {
531 - $html = '<ol>';
532 - foreach ($dataArray as $step_datas) {
533 - $html .= '<li><ul>';
534 - foreach ($step_datas as $name => $vl) {
535 - $type = $this->get_type($form, $name, $form_id);
536 - $lb = $this->get_custom_field_label($form, $name, $type, false, $form_id);
537 - if (is_array($vl)) {
538 - switch ($type) {
539 - case "address":
540 - $vl_data = "";
541 - foreach ($vl as $k => $v) {
542 - $child_lb = $this->get_custom_field_label($form, "input_" . $k, $type, true);
543 - $vl_data .= $child_lb . ": " . $v . "<br>";
544 - }
545 - $html .= '<li>' . $lb . ": <br>" . $vl_data . "</li>";
546 - break;
547 - default:
548 - $vl_data = implode(", ", $vl);
549 - $html .= '<li>' . $lb . ": " . $vl_data . "</li>";
550 - break;
551 - }
552 - } else {
553 - $vl_data = $vl;
554 -
555 - // Helper functions kiểm tra và render file/hình ảnh
556 - $encode_url = function ($url) {
557 - return preg_replace_callback('/[^\x20-\x7E]/u', function ($match) {
558 - return rawurlencode($match[0]);
559 - }, trim($url));
560 - };
561 -
562 - $is_valid_url = function ($url) use ($encode_url) {
563 - if (empty($url))
564 - return false;
565 - $encoded = $encode_url($url);
566 - return filter_var($encoded, FILTER_VALIDATE_URL) !== false;
567 - };
568 -
569 - $is_image_url = function ($url) {
570 - if (!is_string($url) || empty($url))
571 - return false;
572 - $clean_path = parse_url($url, PHP_URL_PATH);
573 - if (!$clean_path) {
574 - $clean_path = $url;
575 - }
576 - $ext = strtolower(pathinfo($clean_path, PATHINFO_EXTENSION));
577 - return in_array($ext, array('jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp', 'ico', 'avif', 'heic'), true);
578 - };
579 -
580 - $render_file_or_image = function ($file_url, $display_name = '') use ($is_image_url) {
581 - $file_url = trim($file_url);
582 - if (empty($file_url)) return '';
583 - $filename = !empty($display_name) ? $display_name : basename($file_url);
584 -
585 - if ($is_image_url($file_url)) {
586 - return '<a href="' . esc_url($file_url) . '" target="_blank" class="repeater-image-preview" style="display:inline-block; margin: 4px 6px 4px 0;">'
587 - . '<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;" />'
588 - . '</a>';
589 - } else {
590 - return '<a href="' . esc_url($file_url) . '" download>' . esc_html($filename) . '</a>';
591 - }
592 - };
593 -
594 - switch ($type) {
595 - case "fileupload":
596 - if ($vl_data === "Upgrade to pro version") {
597 - $html .= '<li>' . esc_html($lb) . ": " . esc_html($vl_data) . "</li>";
598 - break;
599 - }
600 -
601 - // Tách chuỗi theo dấu phẩy phòng trường hợp có nhiều file
602 - $parts = array_filter(array_map('trim', explode(",", $vl_data)));
603 - $content = array();
604 -
605 - // TRƯỜNG HỢP 1: Tất cả các phần tử đều là URL hợp lệ
606 - $all_are_urls = !empty($parts);
607 - foreach ($parts as $part) {
608 - if (!$is_valid_url($part)) {
609 - $all_are_urls = false;
610 - break;
611 - }
612 - }
613 -
614 - if ($all_are_urls) {
615 - foreach ($parts as $part) {
616 - $filename = basename($part);
617 - $content[] = $render_file_or_image($part, $filename);
618 - }
619 - $html .= '<li>' . esc_html($lb) . ': ' . implode(" ", $content) . "</li>";
620 - break;
621 - }
622 -
623 - // TRƯỜNG HỢP 2: Chuỗi chứa tên file hoặc URL không hợp lệ -> Tìm trong $result
624 - $main_name = explode("__", $name);
625 - $main_name = explode("_", $main_name[0]);
626 - $main_name_id = isset($main_name[4]) ? $main_name[4] : (isset($main_name[1]) ? $main_name[1] : null);
627 -
628 - if ($main_name_id && isset($result[$main_name_id])) {
629 - $raw_uploads = $result[$main_name_id];
630 - $data_uploads = is_array($raw_uploads) ? $raw_uploads : json_decode($raw_uploads, true);
631 -
632 - if (!is_array($data_uploads)) {
633 - $data_uploads = array_filter(array_map('trim', explode(",", (string) $raw_uploads)));
634 - }
635 -
636 - foreach ($parts as $n) {
637 - $clean_n = sanitize_file_name($n);
638 - $name_s = preg_quote(pathinfo($clean_n, PATHINFO_FILENAME), '/');
639 -
640 - foreach ($data_uploads as $upload_file) {
641 - // Regex khớp chính xác tên file gốc hoặc tên file có đánh số thứ tự
642 - if (preg_match('/' . $name_s . '(\d+)?\./i', $upload_file)) {
643 - $content[] = $render_file_or_image($upload_file, $clean_n);
644 - break;
645 - }
646 - }
647 - }
648 - }
649 -
650 - $html .= '<li>' . esc_html($lb) . ': ' . (!empty($content) ? implode(" ", $content) : esc_html($vl_data)) . "</li>";
651 - break;
652 -
653 - default:
654 - if (is_string($vl_data) && $is_valid_url($vl_data) && $is_image_url($vl_data)) {
655 - $html .= '<li>' . esc_html($lb) . ': ' . $render_file_or_image($vl_data) . "</li>";
656 - } else {
657 - $html .= '<li>' . esc_html($lb) . ": " . esc_html($vl_data) . "</li>";
658 - }
659 - break;
660 - }
661 - }
662 - }
663 - $html .= '</ul></li>';
664 - }
665 - $html .= '<ol>';
666 - $html = apply_filters("yeeadons_gravity_forms_repeater_html", $html, $dataArray, $form);
667 - return $html;
668 - } else {
669 - $html = '';
670 - foreach ($dataArray as $step_datas) {
671 - foreach ($step_datas as $name => $vl) {
672 - $type = $this->get_type($form, $name, $form_id);
673 - $lb = $this->get_custom_field_label($form, $name, $type, false, $form_id);
674 - if (is_array($vl)) {
675 - switch ($type) {
676 - case "address":
677 - $vl_data = "";
678 - foreach ($vl as $k => $v) {
679 - $child_lb = $this->get_custom_field_label($form, "input_" . $k, $type, true);
680 - $vl_data .= $child_lb . ": " . $v . "\n";
681 - }
682 - $html .= $lb . " : " . $vl_data . "\n";
683 - break;
684 - default:
685 - $vl_data = implode(", ", $vl);
686 - $html .= $lb . ": " . $vl_data . "\n";
687 - break;
688 - }
689 - } else {
690 - $vl_data = $vl;
691 - switch ($type) {
692 - case "fileupload":
693 - if (filter_var($vl_data, FILTER_VALIDATE_URL) === FALSE) {
694 - $content = array();
695 - $parts = array_map('trim', explode(",", $vl_data));
696 - $is_urls = true;
697 - foreach ($parts as $part) {
698 - if (empty($part) || filter_var($part, FILTER_VALIDATE_URL) === FALSE) {
699 - $is_urls = false;
700 - break;
701 - }
702 - }
703 - if ($is_urls) {
704 - foreach ($parts as $part) {
705 - $filename = basename($part);
706 - $content[] = '<a href="' . esc_url($part) . '" download>' . esc_html($filename) . '</a>';
707 - }
708 - $html .= $lb . ': ' . implode(" | ", $content) . "\n";
709 - } else {
710 - $main_name = explode("__", $name);
711 - $main_name = explode("_", $main_name[0]);
712 - $main_name_id = $main_name[4];
713 - if (isset($result[$main_name_id])) {
714 - $data_uploads = json_decode($result[$main_name_id], true);
715 - foreach ($parts as $n) {
716 - $n = sanitize_file_name($n);
717 - foreach ($data_uploads as $name) {
718 - $name_s = explode(".", $n);
719 - $name_s = $name_s[0];
720 - $re = "/" . $name_s . "\.|" . $name_s . "[\d]\./";
721 - if (preg_match($re, $name)) {
722 - $content[] = '<a href="' . $name . '" download>' . $n . "</a> ";
723 - break;
724 - }
725 - }
726 - }
727 - }
728 - $html .= $lb . ': ' . implode(" | ", $content) . "\n";
729 - }
730 - } else {
731 - $html .= $lb . ':' . $vl_data . "\n";
732 - }
733 - break;
734 - default:
735 - $html .= $lb . ": " . $vl_data . "\n";
736 - break;
737 - }
738 - }
739 - }
740 - $html .= "\n";
741 - }
742 - $html = apply_filters("yeeadons_gravity_forms_repeater_text", $html, $dataArray, $form);
743 - return $html;
744 - }
745 - }
746 - public function get_value_export($entry, $input_id = '', $use_text = false, $is_csv = false)
747 - {
748 - //Export doesn’t require encoding, but field data may require some manipulation or formatting before it is exported
749 - $form_id = $entry["form_id"];
750 - $return = $this->get_datas_field("text", rgar($entry, $input_id), $form_id);
751 - return $return;
752 - }
753 - public function get_value_merge_tag($value, $input_id, $entry, $form, $modifier, $raw_value, $url_encode, $esc_html, $format, $nl2br)
754 - {
755 - if (empty($value)) {
756 - return '';
757 - }
758 - $form_id = isset($form['id']) ? absint($form['id']) : null;
759 - $return = $this->get_datas_field($format, $value, $form_id);
760 - return $return;
761 - }
762 - public function get_value_entry_detail($value, $currency = '', $use_text = false, $format = 'html', $media = 'screen')
763 - {
764 - global $wpdb;
765 - if (empty($value)) {
766 - return '';
767 - } else {
768 - $form_id = $this->formId;
769 - $return = $this->get_datas_field($format, $value, $form_id);
770 - return $return;
771 - }
772 - }
773 - function get_custom_field_label($form, $name = '', $type = '', $child = false, $form_id = '')
774 - {
775 - if (is_array($form)) {
776 - if (!array_key_exists('fields', $form)) {
777 - return false;
778 - }
779 - } else {
780 - return false;
781 - }
782 - $name = str_replace("gform_multifile_upload_" . $form_id, "input", $name);
783 - $names = explode("__", $name);
784 - $names = explode("_", $names[0]);
785 - $name = isset($names[1]) ? $names[1] : $names[0];
786 - foreach ($form['fields'] as $field_key => $field_value) {
787 - if (is_array($field_value->inputs)) {
788 - foreach ($field_value->inputs as $children_id) {
789 - if ($children_id["id"] == $name) {
790 - if ($child) {
791 - return $children_id["label"];
792 - } else {
793 - return $field_value->label;
794 - }
795 - }
796 - }
797 - } else {
798 - if ($field_value->id == $name) {
799 - return $field_value->label;
800 - }
801 - }
802 - }
803 - return "";
804 - }
805 - function get_inputs($form, $name = '')
806 - {
807 - if (is_array($form)) {
808 - if (!array_key_exists('fields', $form)) {
809 - return false;
810 - }
811 - } else {
812 - return false;
813 - }
814 - $names = explode("__", $name);
815 - $names = explode("_", $names[0]);
816 - $name = isset($names[1]) ? $names[1] : $names[0];
817 - foreach ($form['fields'] as $field_key => $field_value) {
818 - if ($field_value->id == $name) {
819 - if ($field_value->type == "date") {
820 - return $name;
821 - }
822 - if (is_array($field_value->inputs)) {
823 - return $field_value->inputs;
824 - }
825 - }
826 - }
827 - return false;
828 - }
829 - function get_type($form, $name = '', $form_id = "")
830 - {
831 - if (is_array($form)) {
832 - if (!array_key_exists('fields', $form)) {
833 - return false;
834 - }
835 - } else {
836 - return false;
837 - }
838 - $name = str_replace("gform_multifile_upload_" . $form_id, "input", $name);
839 - $names = explode("__", $name);
840 - $names = explode("_", $names[0]);
841 - $name = isset($names[1]) ? $names[1] : $names[0];
842 - foreach ($form['fields'] as $field_key => $field_value) {
843 - if (is_array($field_value->inputs)) {
844 - foreach ($field_value->inputs as $children_id) {
845 - if ($children_id["id"] == $name) {
846 - return $field_value->type;
847 - }
848 - }
849 - } else {
850 - if ($field_value->id == $name) {
851 - return $field_value->type;
852 - }
853 - }
854 - }
855 - return "";
856 - }
857 -
858 - public static function remove_child_fields($form)
859 - {
860 - if (!is_admin()) {
861 - return $form;
862 - }
863 -
864 - $page = isset($_GET['page']) ? $_GET['page'] : '';
865 - $gf_page = isset($_GET['gf_page']) ? $_GET['gf_page'] : '';
866 -
867 - $target_pages = array('gf_entries', 'gf_export');
868 - $target_gf_pages = array('select_columns', 'print-entry');
869 -
870 - if (in_array($page, $target_pages) || in_array($gf_page, $target_gf_pages)) {
871 - $fields = array();
872 - $zo = false;
873 - foreach ($form["fields"] as $field) {
874 - $type = $field->type;
875 - if ($type == "repeater_start") {
876 - $zo = true;
877 - $fields[] = $field;
878 - continue;
879 - }
880 - if ($type == "repeater_end") {
881 - $zo = false;
882 - $fields[] = $field;
883 - continue;
884 - }
885 - if ($zo) {
886 - continue;
887 - }
888 - $fields[] = $field;
889 - }
890 - $form["fields"] = $fields;
891 - }
892 -
893 - return $form;
894 - }
895 -}
896 -// Register the phone field with the field framework.
897 -GF_Fields::register(new Superaddons_GFRepeater_Field());