PluginProbe ʕ •ᴥ•ʔ
JetFormBuilder — Dynamic Blocks Form Builder / trunk
JetFormBuilder — Dynamic Blocks Form Builder vtrunk
3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.1.0 2.1.1 2.1.10 2.1.11 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.0 3.0.0.1 3.0.0.2 3.0.0.3 3.0.1 3.0.1.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.0.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.3.1 3.3.4 3.3.4.1 3.3.4.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.5.1 3.4.5.2 3.4.6 3.4.7 3.4.7.1 3.5.0 3.5.1 3.5.1.1 3.5.1.2 3.5.2 3.5.2.1 3.5.3 3.5.4 3.5.5 3.5.6 3.5.6.1 3.5.6.2 3.5.6.3 3.6.0
jetformbuilder / compatibility / jet-engine / generators / get-from-je-query.php
jetformbuilder / compatibility / jet-engine / generators Last commit date
je-query-object-handlers 2 years ago get-from-field.php 2 months ago get-from-je-query.php 2 months ago
get-from-je-query.php
381 lines
1 <?php
2 /**
3 * JetEngine Query Generator with schema support.
4 *
5 * @package JFB_Compatibility\Jet_Engine\Generators
6 */
7
8 namespace JFB_Compatibility\Jet_Engine\Generators;
9
10 use Jet_Engine\Query_Builder\Queries\Base_Query;
11 use JFB_Compatibility\Jet_Engine\Generators\Je_Query_Object_Handlers\Base_Object_Handler;
12 use JFB_Compatibility\Jet_Engine\Generators\Je_Query_Object_Handlers\User_Object_Handler;
13 use Jet_Form_Builder\Generators\Base_V2;
14 use Jet_Engine\Query_Builder\Manager as Query_Manager;
15
16 // If this file is called directly, abort.
17 if ( ! defined( 'WPINC' ) ) {
18 die;
19 }
20
21 /**
22 * Get_From_Je_Query class.
23 *
24 * Enhanced JetEngine Query generator with structured settings schema
25 * and support for auto-update (cascading fields).
26 */
27 class Get_From_Je_Query extends Base_V2 {
28
29 /**
30 * Object handlers for different query result types.
31 *
32 * @var Base_Object_Handler[]
33 */
34 private $object_handlers;
35
36 /**
37 * Constructor.
38 */
39 public function __construct() {
40 $this->object_handlers = apply_filters(
41 'jet-form-builder/generators/get_from_query/handlers',
42 array(
43 new User_Object_Handler(),
44 new Base_Object_Handler(),
45 )
46 );
47 }
48
49 /**
50 * Returns generator ID.
51 *
52 * @return string
53 */
54 public function get_id() {
55 return 'get_from_query';
56 }
57
58 /**
59 * Returns generator name.
60 *
61 * @return string
62 */
63 public function get_name() {
64 return __( 'Get values list from JetEngine Query', 'jet-form-builder' );
65 }
66
67 /**
68 * Returns structured settings schema.
69 *
70 * @return array
71 */
72 public function get_settings_schema(): array {
73 return array(
74 'query_id' => array(
75 'type' => 'string',
76 'default' => '',
77 'label' => __( 'Query ID', 'jet-form-builder' ),
78 'control' => 'select',
79 'options' => $this->get_queries_for_select(),
80 'help' => __( 'Select a JetEngine Query to fetch options from.', 'jet-form-builder' ),
81 ),
82 'value_field' => array(
83 'type' => 'string',
84 'default' => '',
85 'label' => __( 'Option Value', 'jet-form-builder' ),
86 'control' => 'text',
87 'placeholder' => '',
88 'help' => __( 'Field to use as option value (e.g., ID, post_name, meta_key).', 'jet-form-builder' ),
89 ),
90 'label_field' => array(
91 'type' => 'string',
92 'default' => '',
93 'label' => __( 'Option Label', 'jet-form-builder' ),
94 'control' => 'text',
95 'placeholder' => '',
96 'help' => __( 'Field to use as option label (e.g., post_title, display_name).', 'jet-form-builder' ),
97 ),
98 'calc_field' => array(
99 'type' => 'string',
100 'default' => '',
101 'label' => __( 'Calculated Field', 'jet-form-builder' ),
102 'control' => 'text',
103 'placeholder' => '',
104 'help' => __( 'Optional. Field for calculated value (e.g., price, _regular_price).', 'jet-form-builder' ),
105 ),
106 );
107 }
108
109 /**
110 * Get available JetEngine queries for select control.
111 *
112 * @return array
113 */
114 private function get_queries_for_select(): array {
115 $options = array();
116
117 if ( ! class_exists( Query_Manager::class ) ) {
118 return $options;
119 }
120
121 // Use JetEngine's built-in method to get queries for options
122 // Returns array of [ query_id => query_name ]
123 $queries = Query_Manager::instance()->get_queries_for_options();
124
125 foreach ( $queries as $query_id => $query_name ) {
126 $options[] = array(
127 'value' => (string) $query_id,
128 'label' => $query_name,
129 );
130 }
131
132 return $options;
133 }
134
135 /**
136 * Parse settings from block attributes.
137 * Override to support legacy generator_args format.
138 *
139 * @param array $block_attrs Block attributes.
140 *
141 * @return array Parsed settings.
142 */
143 public function parse_settings( array $block_attrs ): array {
144 // Try parent's parse_settings first (looks for gen_get_from_query_* keys)
145 $settings = parent::parse_settings( $block_attrs );
146
147 // If empty, try legacy generator_args format
148 if ( empty( $settings['query_id'] ) && ! empty( $block_attrs['generator_args'] ) && is_array( $block_attrs['generator_args'] ) ) {
149 $settings['query_id'] = $block_attrs['generator_args']['query_id'] ?? '';
150 $settings['value_field'] = $block_attrs['generator_args']['value_field'] ?? 'ID';
151 $settings['label_field'] = $block_attrs['generator_args']['label_field'] ?? 'post_title';
152 $settings['calc_field'] = $block_attrs['generator_args']['calc_field'] ?? '';
153 }
154
155 // If still empty, try generator_field (pipe format)
156 if ( empty( $settings['query_id'] ) && ! empty( $block_attrs['generator_field'] ) ) {
157 $parts = explode( '|', $block_attrs['generator_field'] );
158 $settings['query_id'] = $parts[0] ?? '';
159 $settings['value_field'] = $parts[1] ?? 'ID';
160 $settings['label_field'] = $parts[2] ?? 'post_title';
161 $settings['calc_field'] = $parts[3] ?? '';
162 }
163
164 return $settings;
165 }
166
167 /**
168 * Enrich legacy pipe-delimited generator_field with calculated_value_from_key.
169 * Legacy blocks store calc field separately in block attr, not in the pipe string.
170 *
171 * @param string $generator_field Legacy pipe string: "query_id|value|label"
172 * @param array $block_attrs All block attributes.
173 *
174 * @return array Structured settings for generate().
175 */
176 protected function enrich_legacy_field( string $generator_field, array $block_attrs ) {
177 $parts = explode( '|', $generator_field );
178
179 $settings = array(
180 'query_id' => $parts[0] ?? '',
181 'value_field' => $parts[1] ?? 'ID',
182 'label_field' => $parts[2] ?? 'post_title',
183 'calc_field' => $parts[3] ?? '',
184 );
185
186 // Legacy blocks stored calc in a separate block attribute
187 if ( empty( $settings['calc_field'] ) && ! empty( $block_attrs['calculated_value_from_key'] ) ) {
188 $settings['calc_field'] = $block_attrs['calculated_value_from_key'];
189 }
190
191 return $settings;
192 }
193
194 /**
195 * Whether this generator supports auto-update.
196 *
197 * @return bool
198 */
199 public function supports_auto_update(): bool {
200 return true;
201 }
202
203 /**
204 * Returns context fields description for auto-update.
205 *
206 * @return array
207 */
208 public function get_auto_update_context_fields(): array {
209 return array(
210 array(
211 'description' => __( 'You can pass the Trigger Field value into your JetEngine Query.', 'jet-form-builder' ),
212 'example' => __( 'In Query Builder, use the Dynamic Tag: "JFB Auto-Update - Field Value".', 'jet-form-builder' ),
213 ),
214 );
215 }
216
217 /**
218 * Returns the auto-update value type supported by this generator.
219 *
220 * @return string
221 */
222 public function get_auto_update_value_type(): string {
223 return 'scalar';
224 }
225
226 /**
227 * Empty trigger should fall back to the static query configuration.
228 *
229 * @return string
230 */
231 public function get_auto_update_empty_context_policy(): string {
232 return 'fallback_to_static';
233 }
234
235 /**
236 * Generate options with context from dependent fields.
237 *
238 * @param array $settings Parsed settings.
239 * @param array $context Context from dependent fields.
240 *
241 * @return array Generated options.
242 */
243 public function generate_with_context( array $settings, array $context = array() ): array {
244 // Store context for JetEngine dynamic tags to access
245 if ( ! empty( $context ) ) {
246 foreach ( $context as $field_name => $field_value ) {
247 // Set global that JetEngine dynamic tags can read
248 $global_key = 'jfb_update_related_' . $field_name;
249 $GLOBALS[ $global_key ] = $field_value;
250 }
251 }
252
253 return $this->generate( $settings );
254 }
255
256 /**
257 * Returns generated options list.
258 *
259 * @param array|string $args Settings array with query_id, value_field, label_field, calc_field
260 * OR legacy pipe-delimited string.
261 *
262 * @return array
263 */
264 public function generate( $args ) {
265 $result = array();
266
267 // Handle legacy string format (pipe-delimited: "query_id|value|label|calc")
268 if ( is_string( $args ) ) {
269 $parts = explode( '|', $args );
270 $query_id = $parts[0] ?? '';
271 $value_field = $parts[1] ?? 'ID';
272 $label_field = $parts[2] ?? 'post_title';
273 $calc_field = $parts[3] ?? '';
274 } elseif ( is_array( $args ) ) {
275 // New structured format OR legacy array with generator_field
276 $query_id = $args['query_id'] ?? '';
277 $value_field = $args['value_field'] ?? 'ID';
278 $label_field = $args['label_field'] ?? 'post_title';
279 $calc_field = $args['calc_field'] ?? '';
280
281 // Legacy format support: check for generator_args object
282 if ( empty( $query_id ) && ! empty( $args['generator_args'] ) && is_array( $args['generator_args'] ) ) {
283 $query_id = $args['generator_args']['query_id'] ?? '';
284 $value_field = $args['generator_args']['value_field'] ?? 'ID';
285 $label_field = $args['generator_args']['label_field'] ?? 'post_title';
286 $calc_field = $args['generator_args']['calc_field'] ?? '';
287 }
288
289 // Legacy format support: check for generator_field with pipe delimiter
290 if ( empty( $query_id ) && ! empty( $args['generator_field'] ) ) {
291 $parts = explode( '|', $args['generator_field'] );
292 $query_id = $parts[0] ?? '';
293 $value_field = $parts[1] ?? 'ID';
294 $label_field = $parts[2] ?? 'post_title';
295 $calc_field = $parts[3] ?? '';
296 }
297 } else {
298 // Unknown format
299 return $result;
300 }
301
302 if ( empty( $query_id ) ) {
303 return $result;
304 }
305
306 /** @var Base_Query $query */
307 $query = Query_Manager::instance()->get_query_by_id( $query_id );
308
309 if ( ! $query ) {
310 return $result;
311 }
312
313 $query->setup_query();
314
315 // Store query type in block attributes if block is available
316 if ( $this->block ) {
317 $this->block->block_attrs['je_generator_query_type'] = $query->query_type;
318 }
319
320 do_action( 'jet-form-builder/generators/get_from_query/setup', $this, $query );
321
322 $objects = $query->get_items();
323
324 if ( empty( $objects ) ) {
325 return $result;
326 }
327
328 // Build fields array for handler
329 $fields = array( $query_id, $value_field, $label_field );
330 if ( ! empty( $calc_field ) ) {
331 $fields[] = $calc_field;
332 }
333
334 $handler = $this->get_handler( $objects[0] ?? array() );
335 $handler->set_fields( $fields );
336
337 foreach ( $objects as $object ) {
338 $item = $handler->to_array( $object );
339
340 if ( ! empty( $item ) ) {
341 $result[] = $item;
342 }
343 }
344
345 return $result;
346 }
347
348 /**
349 * Get appropriate handler for object type.
350 *
351 * @param mixed $current Current object to check.
352 *
353 * @return Base_Object_Handler
354 */
355 private function get_handler( $current ): Base_Object_Handler {
356 /** @var Base_Object_Handler $handler */
357 foreach ( $this->object_handlers as $handler ) {
358 if ( $handler->is_supported( $current ) ) {
359 return $handler;
360 }
361 }
362
363 wp_die(
364 sprintf(
365 /* translators: %s - class name */
366 esc_html__( '%s::is_supported must return TRUE', 'jet-form-builder' ),
367 esc_attr( Base_Object_Handler::class )
368 )
369 );
370 }
371
372 /**
373 * Check if generator can generate options.
374 *
375 * @return bool
376 */
377 public function can_generate() {
378 return class_exists( Query_Manager::class );
379 }
380 }
381