PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / views / frm-form-actions / _gated_content_item_row.php

_gated_content_item_row.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More trunk, at classes/views/frm-form-actions/_gated_content_item_row.php

256 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Gated Content item row partial
4 *
5 * Renders a single <li class="frm_gc_item_row"> used both for existing saved
6 * items (PHP foreach loop) and for the hidden <template> element cloned by JS
7 * when "Add Item" is clicked.
8 *
9 * When $is_template is true:
10 * - Labels use data-frm-gc-for instead of for.
11 * - Selects use data-frm-gc-field instead of id/name — JS assigns both after cloning.
12 * - No selected() calls — JS selects the saved value after cloning.
13 * - The post type div is always visible (post is the default type).
14 *
15 * @package Formidable
16 *
17 * @since 6.33
18 *
19 * @var bool $is_template True when rendering the JS clone template.
20 * @var string $frm_gc_item_type Active type key ('post', 'frm_file', …). Always 'post' for template.
21 * @var int $frm_gc_item_id Saved item ID. 0 for template rows.
22 * @var string $frm_gc_item_base Field name prefix. Empty for template rows.
23 * @var string $frm_gc_type_sel_id Unique element ID for the type select. Empty for template rows.
24 * @var int $frm_gc_idx Zero-based item index. 0 for template rows.
25 * @var array $frm_gc_item Saved item data. Empty array for template rows.
26 * @var array $frm_gc_types All registered type configurations.
27 * @var array<string, list<object>> $frm_gc_posts Posts grouped by item type key.
28 * @var bool $frm_gc_use_autocomplete Whether to render autocomplete inputs.
29 * @var array<string, string> $frm_gc_posts_source JSON-encoded autocomplete source per type. Only set when $frm_gc_use_autocomplete.
30 * @var string $frm_gc_wrapper_id Unique wrapper element ID.
31 */
32
33 if ( ! defined( 'ABSPATH' ) ) {
34 die( 'You are not allowed to call this page directly.' );
35 }
36 ?>
37 <li class="frm_gc_item_row frm_grid_container">
38
39 <?php /* ── Col 1: Type (6/12) ──────────────────────── */ ?>
40 <div class="frm6">
41 <div class="frm_form_field frm-mt-xs frm-mb-xs">
42 <?php
43 $frm_gc_label_atts = $is_template
44 ? array( 'data-frm-gc-for' => 'type' )
45 : array( 'for' => $frm_gc_type_sel_id );
46 ?>
47 <label <?php FrmAppHelper::array_to_html_params( $frm_gc_label_atts, true ); ?>>
48 <?php esc_html_e( 'Type', 'formidable' ); ?>
49 </label>
50 <?php
51 $frm_gc_type_sel_atts = array( 'class' => 'frm-gc-item-type' );
52
53 if ( $is_template ) {
54 $frm_gc_type_sel_atts['data-frm-gc-field'] = 'type';
55 } else {
56 $frm_gc_type_sel_atts['id'] = $frm_gc_type_sel_id;
57 $frm_gc_type_sel_atts['name'] = $frm_gc_item_base . '[type]';
58 }
59 ?>
60 <select <?php FrmAppHelper::array_to_html_params( $frm_gc_type_sel_atts, true ); ?>>
61 <?php foreach ( $frm_gc_types as $frm_gc_type_key => $frm_gc_type ) : ?>
62 <option
63 value="<?php echo esc_attr( $frm_gc_type_key ); ?>"
64 <?php if ( ! $is_template ) : ?>
65 <?php selected( $frm_gc_item_type, $frm_gc_type_key ); ?>
66 <?php endif; ?>
67 <?php disabled( ! empty( $frm_gc_type['disabled'] ) ); ?>
68 >
69 <?php echo esc_html( $frm_gc_type['label'] ); ?>
70 </option>
71 <?php endforeach; ?>
72 </select>
73 </div><!-- .frm_form_field -->
74 </div><!-- .frm4 -->
75
76 <?php /* ── Col 2: Type-specific settings + delete (6/12) ── */ ?>
77 <div class="frm6 frm-gc-item-settings">
78
79 <?php
80 // Build args for inner/outer type-settings hooks once (all vars are available here).
81 $action_args = array(
82 'is_template' => $is_template,
83 'types' => $frm_gc_types,
84 );
85
86 if ( ! $is_template ) {
87 $action_args['active_type'] = $frm_gc_item_type;
88 $action_args['idx'] = $frm_gc_idx;
89 $action_args['item'] = $frm_gc_item;
90 $action_args['item_base'] = $frm_gc_item_base;
91 $action_args['wrapper_id'] = $frm_gc_wrapper_id;
92 }
93
94 // One settings div per post-type-backed item type.
95 // Existing rows: only the active type's div is visible; only it gets a name attribute.
96 // Template rows: JS shows/hides divs on type change and assigns id/name after cloning.
97 foreach ( $frm_gc_types as $frm_gc_pt_key => $frm_gc_pt_config ) :
98 if ( ! post_type_exists( $frm_gc_pt_key ) ) {
99 continue;
100 }
101 $frm_gc_pt_posts = $frm_gc_posts[ $frm_gc_pt_key ] ?? array();
102 $frm_gc_pt_sel_id = $is_template ? '' : $frm_gc_wrapper_id . '_id_' . $frm_gc_pt_key . '_' . $frm_gc_idx;
103 $frm_gc_pt_source = $frm_gc_use_autocomplete ? ( $frm_gc_posts_source[ $frm_gc_pt_key ] ?? '[]' ) : '';
104 $frm_gc_pt_is_first = ! isset( $frm_gc_first_pt_rendered );
105
106 if ( $frm_gc_pt_is_first ) {
107 $frm_gc_first_pt_rendered = true;
108 }
109 $frm_gc_pt_hidden = ! $is_template && $frm_gc_item_type !== $frm_gc_pt_key;
110
111 $frm_gc_div_atts = array(
112 'class' => 'frm-gc-type-settings',
113 'data-type' => $frm_gc_pt_key,
114 );
115
116 if ( $frm_gc_pt_hidden ) {
117 $frm_gc_div_atts['hidden'] = '';
118 }
119 ?>
120 <div <?php FrmAppHelper::array_to_html_params( $frm_gc_div_atts, true ); ?>>
121 <div class="frm_form_field frm-mt-xs frm-mb-xs">
122 <?php
123 $frm_gc_pt_label_atts = $is_template
124 ? array( 'data-frm-gc-for' => 'id' )
125 : array( 'for' => $frm_gc_pt_sel_id );
126 ?>
127 <label <?php FrmAppHelper::array_to_html_params( $frm_gc_pt_label_atts, true ); ?>>
128 <?php echo esc_html( $frm_gc_pt_config['label'] ); ?>
129 </label>
130 <?php if ( $frm_gc_use_autocomplete ) : ?>
131 <?php
132 $frm_gc_pt_selected_title = '';
133
134 if ( ! $is_template && $frm_gc_item_type === $frm_gc_pt_key ) {
135 foreach ( $frm_gc_pt_posts as $frm_gc_post ) {
136 if ( $frm_gc_item_id === $frm_gc_post->ID ) {
137 $frm_gc_pt_selected_title = $frm_gc_post->post_title;
138 break;
139 }
140 }
141 }
142
143 $frm_gc_ac_text_atts = array(
144 'type' => 'text',
145 'class' => 'frm-custom-search',
146 'data-source' => $frm_gc_pt_source,
147 'placeholder' => __( '— Select —', 'formidable' ),
148 'value' => $frm_gc_pt_selected_title,
149 );
150
151 if ( ! $is_template ) {
152 $frm_gc_ac_text_atts['id'] = $frm_gc_pt_sel_id;
153 }
154 ?>
155 <input <?php FrmAppHelper::array_to_html_params( $frm_gc_ac_text_atts, true ); ?> />
156 <?php
157 $frm_gc_ac_hidden_atts = array(
158 'type' => 'hidden',
159 'data-frm-gc-field' => 'id',
160 'class' => 'frm_autocomplete_value_input',
161 'value' => ! $is_template && $frm_gc_item_type === $frm_gc_pt_key && $frm_gc_item_id ? (string) $frm_gc_item_id : '',
162 );
163
164 if ( ! $is_template && $frm_gc_item_type === $frm_gc_pt_key ) {
165 $frm_gc_ac_hidden_atts['name'] = $frm_gc_item_base . '[id]';
166 }
167 ?>
168 <input <?php FrmAppHelper::array_to_html_params( $frm_gc_ac_hidden_atts, true ); ?> />
169 <?php else : ?>
170 <?php
171 $frm_gc_sel_atts = array( 'data-frm-gc-field' => 'id' );
172
173 if ( ! $is_template ) {
174 $frm_gc_sel_atts['id'] = $frm_gc_pt_sel_id;
175
176 if ( $frm_gc_item_type === $frm_gc_pt_key ) {
177 $frm_gc_sel_atts['name'] = $frm_gc_item_base . '[id]';
178 }
179 }
180 ?>
181 <select <?php FrmAppHelper::array_to_html_params( $frm_gc_sel_atts, true ); ?>>
182 <option value=""><?php esc_html_e( '— Select —', 'formidable' ); ?></option>
183 <?php foreach ( $frm_gc_pt_posts as $frm_gc_post ) : ?>
184 <option
185 value="<?php echo esc_attr( $frm_gc_post->ID ); ?>"
186 <?php if ( ! $is_template ) : ?>
187 <?php selected( $frm_gc_item_id, $frm_gc_post->ID ); ?>
188 <?php endif; ?>
189 >
190 <?php echo esc_html( $frm_gc_post->post_title ); ?>
191 </option>
192 <?php endforeach; ?>
193 </select>
194 <?php endif; ?>
195 </div><!-- .frm_form_field -->
196 <?php
197 /**
198 * Fires inside a post-type-backed type settings div, after the primary ID field.
199 *
200 * Use this to append extra fields (e.g. an entry selector) inside the same
201 * wrapper as the primary post selector. Fires for both existing rows and the
202 * JS <template> row.
203 *
204 * @since 6.33
205 *
206 * @param string $type Post-type key for this settings div (e.g. 'frm_display').
207 * @param array $row_args Same keys as the outer `frm_gated_content_item_type_settings` hook.
208 */
209 do_action( 'frm_gated_content_type_settings_inner', $frm_gc_pt_key, $action_args );
210 ?>
211 </div><!-- [data-type="<?php echo esc_attr( $frm_gc_pt_key ); ?>"] -->
212 <?php endforeach; ?>
213 <?php unset( $frm_gc_pt_key, $frm_gc_pt_config, $frm_gc_pt_posts, $frm_gc_pt_sel_id, $frm_gc_pt_source, $frm_gc_pt_is_first, $frm_gc_first_pt_rendered, $frm_gc_pt_hidden, $frm_gc_pt_selected_title, $frm_gc_post, $frm_gc_div_atts, $frm_gc_pt_label_atts, $frm_gc_ac_text_atts, $frm_gc_ac_hidden_atts, $frm_gc_sel_atts ); ?>
214
215 <?php
216 /**
217 * Fires after the built-in type settings for a gated content item row.
218 *
219 * Fires for both existing (PHP-rendered) rows and the JS-cloned <template> row.
220 * Use $args['is_template'] to distinguish between the two.
221 *
222 * Guidelines for hook callbacks:
223 * - Wrap each type's settings in `<div class="frm-gc-type-settings" data-type="{TYPE}">`.
224 * - In template mode: always add `hidden`; use `data-frm-gc-for` on labels; omit id/name on inputs.
225 * - In existing-row mode: add `hidden` when `$args['active_type'] !== '{TYPE}'`; use real for/id/name.
226 * - Add `data-frm-gc-field="{KEY}"` to each input so JS manages its name on type change.
227 *
228 * @since 6.33
229 *
230 * @param array $args {
231 *
232 * @type bool $is_template True when rendering inside the JS <template> element.
233 * @type array $types All registered type configurations.
234 * @type string $active_type Active type key for this item (existing rows only).
235 * @type int $idx Zero-based item index (existing rows only).
236 * @type array $item Saved item data (existing rows only).
237 * @type string $item_base Field name prefix for this item (existing rows only).
238 * @type string $wrapper_id Unique wrapper element ID (existing rows only).
239 * }
240 */
241 do_action( 'frm_gated_content_item_type_settings', $action_args );
242 ?>
243
244 <div class="frm-gc-item-delete">
245 <button
246 type="button"
247 class="frm_gc_remove_item button-link"
248 aria-label="<?php esc_attr_e( 'Remove item', 'formidable' ); ?>"
249 >
250 <?php FrmAppHelper::icon_by_class( 'frmfont frm_minus1_icon frm_svg15' ); ?>
251 </button>
252 </div><!-- .frm-gc-item-delete -->
253 </div><!-- .frm6 -->
254
255 </li>
256