PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.17
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.17
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 / models / FrmEntryMeta.php

FrmEntryMeta.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.17, at classes/models/FrmEntryMeta.php

574 lines 17.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 class FrmEntryMeta {
7
8 /**
9 * @param int $entry_id
10 * @param int $field_id
11 * @param string $meta_key usually set to '' as this parameter is no longer used.
12 * @param mixed $meta_value
13 * @return int
14 */
15 public static function add_entry_meta( $entry_id, $field_id, $meta_key, $meta_value ) {
16 global $wpdb;
17
18 if ( FrmAppHelper::is_empty_value( $meta_value ) ) {
19 // don't save blank fields
20 return 0;
21 }
22
23 $new_values = array(
24 'meta_value' => is_array( $meta_value ) ? serialize( array_filter( $meta_value, 'FrmAppHelper::is_not_empty_value' ) ) : trim( $meta_value ),
25 'item_id' => $entry_id,
26 'field_id' => $field_id,
27 'created_at' => current_time( 'mysql', 1 ),
28 );
29
30 self::set_value_before_save( $new_values );
31 $new_values = apply_filters( 'frm_add_entry_meta', $new_values );
32
33 $query_results = $wpdb->insert( $wpdb->prefix . 'frm_item_metas', $new_values );
34
35 if ( $query_results ) {
36 self::clear_cache();
37 wp_cache_delete( $entry_id, 'frm_entry' );
38 $id = $wpdb->insert_id;
39 } else {
40 $id = 0;
41 }
42
43 return $id;
44 }
45
46 /**
47 * @param int $entry_id
48 * @param int $field_id
49 * @param string $meta_key Deprecated.
50 * @param array|string $meta_value
51 *
52 * @return bool|false|int
53 */
54 public static function update_entry_meta( $entry_id, $field_id, $meta_key, $meta_value ) {
55 if ( ! $field_id ) {
56 return false;
57 }
58
59 global $wpdb;
60
61 $values = array(
62 'item_id' => $entry_id,
63 'field_id' => $field_id,
64 );
65 $where_values = $values;
66 $values['meta_value'] = $meta_value;
67 self::set_value_before_save( $values );
68 $values = apply_filters( 'frm_update_entry_meta', $values );
69
70 if ( is_array( $values['meta_value'] ) ) {
71 $values['meta_value'] = array_filter( $values['meta_value'], 'FrmAppHelper::is_not_empty_value' );
72 }
73 $meta_value = maybe_serialize( $values['meta_value'] );
74
75 wp_cache_delete( $entry_id, 'frm_entry' );
76 self::clear_cache();
77
78 return $wpdb->update( $wpdb->prefix . 'frm_item_metas', array( 'meta_value' => $meta_value ), $where_values );
79 }
80
81 /**
82 * @since 3.0
83 */
84 private static function set_value_before_save( &$values ) {
85 $field = FrmField::getOne( $values['field_id'] );
86 if ( $field ) {
87 $field_obj = FrmFieldFactory::get_field_object( $field );
88
89 $values['meta_value'] = $field_obj->set_value_before_save( $values['meta_value'] );
90 }
91 }
92
93 /**
94 * @since 3.0
95 */
96 private static function get_value_to_save( $atts, &$value ) {
97 if ( is_object( $atts['field'] ) ) {
98 $field_obj = FrmFieldFactory::get_field_object( $atts['field'] );
99 $value = $field_obj->get_value_to_save(
100 $value,
101 array(
102 'entry_id' => $atts['entry_id'],
103 'field_id' => $atts['field_id'],
104 )
105 );
106 }
107
108 $value = apply_filters( 'frm_prepare_data_before_db', $value, $atts['field_id'], $atts['entry_id'], array( 'field' => $atts['field'] ) );
109 }
110
111 /**
112 * @param int|string $entry_id
113 * @param array $values Either indexed by field ID or field key.
114 * @return void
115 */
116 public static function update_entry_metas( $entry_id, $values ) {
117 global $wpdb;
118
119 $previous_field_ids = FrmDb::get_col(
120 'frm_item_metas',
121 array(
122 'item_id' => $entry_id,
123 'field_id !' => 0,
124 ),
125 'field_id'
126 );
127
128 $values_indexed_by_field_id = array();
129 foreach ( $values as $field_id_or_key => $meta_value ) {
130 $field_id = $field_id_or_key;
131 $field = null;
132
133 if ( $field_id_or_key ) {
134 $field = FrmField::getOne( $field_id_or_key );
135
136 if ( is_object( $field ) ) {
137 $field_id = $field->id;
138 }
139 }
140
141 $values_indexed_by_field_id[ $field_id ] = $meta_value;
142
143 self::get_value_to_save( compact( 'field', 'field_id', 'entry_id' ), $meta_value );
144
145 if ( $previous_field_ids && in_array( $field_id, $previous_field_ids ) ) {
146
147 if ( ( is_array( $meta_value ) && empty( $meta_value ) ) || ( ! is_array( $meta_value ) && trim( $meta_value ) == '' ) ) {
148 // Remove blank fields.
149 unset( $values_indexed_by_field_id[ $field_id ] );
150 } else {
151 // if value exists, then update it
152 self::update_entry_meta( $entry_id, $field_id, '', $meta_value );
153 }
154 } else {
155 // if value does not exist, then create it
156 self::add_entry_meta( $entry_id, $field_id, '', $meta_value );
157 }
158 }//end foreach
159
160 if ( empty( $previous_field_ids ) ) {
161 return;
162 }
163
164 $field_ids_to_remove = array_diff( $previous_field_ids, array_keys( $values_indexed_by_field_id ) );
165
166 if ( ! $field_ids_to_remove ) {
167 return;
168 }
169
170 // prepare the query
171 $where = array(
172 'item_id' => $entry_id,
173 'field_id' => $field_ids_to_remove,
174 );
175 FrmDb::get_where_clause_and_values( $where );
176
177 // Delete any leftovers
178 $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_item_metas ' . $where['where'], $where['values'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
179 self::clear_cache();
180 }
181
182 public static function duplicate_entry_metas( $old_id, $new_id ) {
183 $metas = self::get_entry_meta_info( $old_id );
184
185 /**
186 * Allows changing entry duplicate values before save.
187 *
188 * @since 5.4.4
189 *
190 * @param array $metas The list of entry meta values.
191 */
192 $metas = apply_filters( 'frm_before_duplicate_entry_values', $metas );
193 foreach ( $metas as $meta ) {
194 self::add_entry_meta( $new_id, $meta->field_id, '', $meta->meta_value );
195 unset( $meta );
196 }
197 self::clear_cache();
198 }
199
200 public static function delete_entry_meta( $entry_id, $field_id ) {
201 global $wpdb;
202 self::clear_cache();
203
204 return $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}frm_item_metas WHERE field_id=%d AND item_id=%d", $field_id, $entry_id ) );
205 }
206
207 /**
208 * Clear entry meta caching
209 * Called when a meta is added or changed
210 *
211 * @since 2.0.5
212 */
213 public static function clear_cache() {
214 FrmDb::cache_delete_group( 'frm_entry_meta' );
215 FrmDb::cache_delete_group( 'frm_item_meta' );
216 }
217
218 /**
219 * @since 2.0.9
220 *
221 * @param stdClass $entry
222 * @param int|string $field_id
223 * @return mixed
224 */
225 public static function get_meta_value( $entry, $field_id ) {
226 if ( isset( $entry->metas ) ) {
227 return isset( $entry->metas[ $field_id ] ) ? $entry->metas[ $field_id ] : false;
228 }
229 return self::get_entry_meta_by_field( $entry->id, $field_id );
230 }
231
232 /**
233 * @param int|object|string $entry_id
234 * @param int|string $field_id This function supports field keys as field id.
235 * @return mixed
236 */
237 public static function get_entry_meta_by_field( $entry_id, $field_id ) {
238 global $wpdb;
239
240 if ( is_object( $entry_id ) ) {
241 $entry = $entry_id;
242 $entry_id = $entry->id;
243 $cached = $entry;
244 } else {
245 $entry_id = (int) $entry_id;
246 $cached = FrmDb::check_cache( $entry_id, 'frm_entry' );
247 }
248
249 if ( $cached && isset( $cached->metas ) && isset( $cached->metas[ $field_id ] ) ) {
250 $result = $cached->metas[ $field_id ];
251
252 return wp_unslash( $result );
253 }
254
255 $get_table = $wpdb->prefix . 'frm_item_metas';
256 $query = array( 'item_id' => $entry_id );
257 if ( is_numeric( $field_id ) ) {
258 // Query by field ID.
259 $query['field_id'] = $field_id;
260 } else {
261 // Query by field key.
262 $get_table .= ' it JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id=fi.id';
263 $query['fi.field_key'] = $field_id;
264 }
265
266 $result = FrmDb::get_var( $get_table, $query, 'meta_value' );
267
268 $field_type = FrmField::get_type( $field_id );
269 FrmFieldsHelper::prepare_field_value( $result, $field_type );
270
271 $result = wp_unslash( $result );
272
273 return $result;
274 }
275
276 public static function get_entry_metas_for_field( $field_id, $order = '', $limit = '', $args = array() ) {
277 $defaults = array(
278 'value' => false,
279 'unique' => false,
280 'stripslashes' => true,
281 'is_draft' => false,
282 );
283 $args = wp_parse_args( $args, $defaults );
284
285 $query = array();
286 self::meta_field_query( $field_id, $order, $limit, $args, $query );
287 $query = implode( ' ', $query );
288
289 $cache_key = 'entry_metas_for_field_' . $field_id . $order . $limit . FrmAppHelper::maybe_json_encode( $args );
290 $values = FrmDb::check_cache( $cache_key, 'frm_entry', $query, 'get_col' );
291
292 if ( ! $args['stripslashes'] ) {
293 return $values;
294 }
295
296 foreach ( $values as $k => $v ) {
297 FrmAppHelper::unserialize_or_decode( $v );
298 $values[ $k ] = $v;
299 unset( $k, $v );
300 }
301
302 return wp_unslash( $values );
303 }
304
305 /**
306 * @param int|string $field_id
307 * @param string $order
308 * @param string $limit
309 * @param array $args
310 * @param array $query
311 */
312 private static function meta_field_query( $field_id, $order, $limit, $args, array &$query ) {
313 global $wpdb;
314 $query[] = 'SELECT';
315 $query[] = $args['unique'] ? 'DISTINCT(em.meta_value)' : 'em.meta_value';
316 $query[] = 'FROM ' . $wpdb->prefix . 'frm_item_metas em ';
317
318 if ( ! $args['is_draft'] ) {
319 $query[] = 'INNER JOIN ' . $wpdb->prefix . 'frm_items e ON (e.id=em.item_id)';
320 }
321
322 if ( is_numeric( $field_id ) ) {
323 $query[] = $wpdb->prepare( 'WHERE em.field_id=%d', $field_id );
324 } else {
325 $query[] = $wpdb->prepare( 'LEFT JOIN ' . $wpdb->prefix . 'frm_fields fi ON (em.field_id = fi.id) WHERE fi.field_key=%s', $field_id );
326 }
327
328 if ( ! $args['is_draft'] ) {
329 $query[] = 'AND e.is_draft=0';
330 }
331
332 if ( $args['value'] ) {
333 $query[] = $wpdb->prepare( ' AND meta_value=%s', $args['value'] );
334 }
335 $query[] = $order . $limit;
336 }
337
338 public static function get_entry_meta_info( $entry_id ) {
339 return FrmDb::get_results( 'frm_item_metas', array( 'item_id' => $entry_id ) );
340 }
341
342 /**
343 * @param array $where
344 * @param string $order_by
345 * @param string $limit
346 * @param bool $stripslashes
347 * @return array
348 */
349 public static function getAll( $where = array(), $order_by = '', $limit = '', $stripslashes = false ) {
350 global $wpdb;
351 $query = 'SELECT it.*, fi.type as field_type, fi.field_key as field_key,
352 fi.required as required, fi.form_id as field_form_id, fi.name as field_name, fi.options as fi_options
353 FROM ' . $wpdb->prefix . 'frm_item_metas it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id=fi.id' .
354 FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
355
356 $cache_key = 'all_' . FrmAppHelper::maybe_json_encode( $where ) . $order_by . $limit;
357 $results = FrmDb::check_cache( $cache_key, 'frm_entry', $query, ( $limit == ' LIMIT 1' ? 'get_row' : 'get_results' ) );
358
359 if ( ! $results || ! $stripslashes ) {
360 return $results;
361 }
362
363 foreach ( $results as $k => $result ) {
364 FrmAppHelper::unserialize_or_decode( $result->meta_value );
365 $results[ $k ]->meta_value = wp_unslash( $result->meta_value );
366 unset( $k, $result );
367 }
368
369 return $results;
370 }
371
372 public static function getEntryIds( $where = array(), $order_by = '', $limit = '', $unique = true, $args = array() ) {
373 $defaults = array(
374 'is_draft' => false,
375 'user_id' => '',
376 'group_by' => '',
377 );
378 $args = wp_parse_args( $args, $defaults );
379
380 $query = array();
381 self::get_ids_query( $where, $order_by, $limit, $unique, $args, $query );
382 $query = implode( ' ', $query );
383
384 $cache_key = 'ids_' . FrmAppHelper::maybe_json_encode( $where ) . $order_by . 'l' . $limit . 'u' . $unique . FrmAppHelper::maybe_json_encode( $args );
385 $type = 'get_' . ( ' LIMIT 1' === $limit ? 'var' : 'col' );
386 return FrmDb::check_cache( $cache_key, 'frm_entry', $query, $type );
387 }
388
389 /**
390 * Given a query including a form id and its child form ids, output an array of matching entry ids
391 * If a child entry id is matched, its parent will be returned in its place
392 *
393 * @param array $query
394 * @param array $args
395 * @return array
396 */
397 public static function get_top_level_entry_ids( $query, $args ) {
398 $args['return_parent_id_if_0_return_id'] = true;
399 return self::getEntryIds( $query, '', '', true, $args );
400 }
401
402 /**
403 * Returns true if the where clause refers to a field table column that is not form_id. It also updates
404 * the where clause to refer to the entry table for form_id if fields table should not be joined.
405 *
406 * @since 6.16.1
407 * @param array|string $where
408 * @return bool
409 */
410 private static function should_join_fields_table( &$where ) {
411 if ( is_string( $where ) ) {
412 if ( preg_match( '/\bfi\.(?!form_id)\w+/i', $where ) ) {
413 return true;
414 }
415 $where = str_ireplace( 'fi.form_id', 'e.form_id', $where );
416 return false;
417 }
418 $where_fields = array_keys( $where );
419 foreach ( $where_fields as $where_field ) {
420 if ( strpos( $where_field, 'fi.' ) === 0 && 'fi.form_id' !== $where_field ) {
421 return true;
422 }
423 }
424 if ( isset( $where['fi.form_id'] ) ) {
425 $where['e.form_id'] = $where['fi.form_id'];
426 unset( $where['fi.form_id'] );
427 }
428 return false;
429 }
430
431 /**
432 * @param array|string $where
433 * @param string $order_by
434 * @param string $limit
435 */
436 private static function get_ids_query( $where, $order_by, $limit, $unique, $args, array &$query ) {
437 global $wpdb;
438 $query[] = 'SELECT';
439 $defaults = array(
440 'return_parent_id' => false,
441 'return_parent_id_if_0_return_id' => false,
442 );
443 $args = array_merge( $defaults, $args );
444
445 if ( $unique ) {
446 $query[] = 'DISTINCT';
447 }
448
449 if ( $args['return_parent_id_if_0_return_id'] ) {
450 $query[] = 'IF ( e.parent_item_id = 0, it.item_id, e.parent_item_id )';
451 } elseif ( $args['return_parent_id'] ) {
452 $query[] = 'e.parent_item_id';
453 } else {
454 $query[] = 'it.item_id';
455 }
456
457 $from = 'FROM ' . $wpdb->prefix . 'frm_item_metas it';
458
459 $should_join_fields_table__where = self::should_join_fields_table( $where );
460 $should_join_fields_table__order_by = self::should_join_fields_table( $order_by );
461 if ( $should_join_fields_table__where || $should_join_fields_table__order_by ) {
462 $from .= ' LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id=fi.id';
463 }
464
465 $query[] = $from;
466 $query[] = 'INNER JOIN ' . $wpdb->prefix . 'frm_items e ON (e.id=it.item_id)';
467 if ( is_array( $where ) ) {
468 if ( ! $args['is_draft'] ) {
469 $where['e.is_draft'] = 0;
470 } elseif ( is_numeric( $args['is_draft'] ) ) {
471 if ( class_exists( 'FrmAbandonmentHooksController', false ) ) {
472 $where['e.is_draft'] = absint( $args['is_draft'] );
473 } else {
474 $where['e.is_draft'] = 1;
475 }
476 } elseif ( 'both' === $args['is_draft'] && class_exists( 'FrmAbandonmentHooksController', false ) ) {
477 $where['e.is_draft'] = array( 0, 1 );
478 } elseif ( false !== strpos( $args['is_draft'], ',' ) ) {
479 $is_draft = array_reduce(
480 explode( ',', $args['is_draft'] ),
481 function ( $total, $current ) {
482 if ( is_numeric( $current ) ) {
483 $total[] = absint( $current );
484 }
485 return $total;
486 },
487 array()
488 );
489 if ( $is_draft ) {
490 $where['e.is_draft'] = $is_draft;
491 }
492 }//end if
493
494 if ( ! empty( $args['user_id'] ) ) {
495 $where['e.user_id'] = $args['user_id'];
496 }
497 $query[] = FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
498
499 if ( $args['group_by'] ) {
500 $query[] = ' GROUP BY ' . sanitize_text_field( $args['group_by'] );
501 }
502
503 return;
504 }//end if
505
506 $draft_where = '';
507 $user_where = '';
508 if ( ! $args['is_draft'] ) {
509 $draft_where = $wpdb->prepare( ' AND e.is_draft=%d', 0 );
510 } elseif ( $args['is_draft'] == 1 ) {
511 $draft_where = $wpdb->prepare( ' AND e.is_draft=%d', 1 );
512 }
513
514 if ( ! empty( $args['user_id'] ) ) {
515 $user_where = $wpdb->prepare( ' AND e.user_id=%d', $args['user_id'] );
516 }
517
518 if ( strpos( $where, ' GROUP BY ' ) ) {
519 // don't inject WHERE filtering after GROUP BY
520 $parts = explode( ' GROUP BY ', $where );
521 $where = $parts[0];
522 $where .= $draft_where . $user_where;
523 $where .= ' GROUP BY ' . $parts[1];
524 } else {
525 $where .= $draft_where . $user_where;
526 }
527
528 // The query has already been prepared
529 $query[] = FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
530 }
531
532 public static function search_entry_metas( $search, $field_id, $operator ) {
533 $cache_key = 'search_' . FrmAppHelper::maybe_json_encode( $search ) . $field_id . $operator;
534 $results = wp_cache_get( $cache_key, 'frm_entry' );
535 if ( false !== $results ) {
536 return $results;
537 }
538
539 global $wpdb;
540 if ( is_array( $search ) ) {
541 $where = '';
542 foreach ( $search as $field => $value ) {
543 if ( $value <= 0 || ! in_array( $field, array( 'year', 'month', 'day' ) ) ) {
544 continue;
545 }
546
547 switch ( $field ) {
548 case 'year':
549 $value = '%' . $value;
550 break;
551 case 'month':
552 $value .= '%';
553 break;
554 case 'day':
555 $value = '%' . $value . '%';
556 }
557 $where .= $wpdb->prepare( ' meta_value ' . $operator . ' %s and', $value ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
558 }
559 $where .= $wpdb->prepare( ' field_id=%d', $field_id );
560 $query = 'SELECT DISTINCT item_id FROM ' . $wpdb->prefix . 'frm_item_metas' . FrmDb::prepend_and_or_where( ' WHERE ', $where );
561 } else {
562 if ( $operator === 'LIKE' ) {
563 $search = '%' . $search . '%';
564 }
565 $query = $wpdb->prepare( "SELECT DISTINCT item_id FROM {$wpdb->prefix}frm_item_metas WHERE meta_value {$operator} %s and field_id = %d", $search, $field_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
566 }//end if
567
568 $results = $wpdb->get_col( $query, 0 ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
569 FrmDb::set_cache( $cache_key, $results, 'frm_entry' );
570
571 return $results;
572 }
573 }
574