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

538 lines 15.9 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 * @param array|string $where
404 * @param string $order_by
405 * @param string $limit
406 */
407 private static function get_ids_query( $where, $order_by, $limit, $unique, $args, array &$query ) {
408 global $wpdb;
409 $query[] = 'SELECT';
410 $defaults = array(
411 'return_parent_id' => false,
412 'return_parent_id_if_0_return_id' => false,
413 );
414 $args = array_merge( $defaults, $args );
415
416 if ( $unique ) {
417 $query[] = 'DISTINCT';
418 }
419
420 if ( $args['return_parent_id_if_0_return_id'] ) {
421 $query[] = 'IF ( e.parent_item_id = 0, it.item_id, e.parent_item_id )';
422 } elseif ( $args['return_parent_id'] ) {
423 $query[] = 'e.parent_item_id';
424 } else {
425 $query[] = 'it.item_id';
426 }
427
428 $query[] = 'FROM ' . $wpdb->prefix . 'frm_item_metas it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id=fi.id';
429
430 $query[] = 'INNER JOIN ' . $wpdb->prefix . 'frm_items e ON (e.id=it.item_id)';
431 if ( is_array( $where ) ) {
432 if ( ! $args['is_draft'] ) {
433 $where['e.is_draft'] = 0;
434 } elseif ( is_numeric( $args['is_draft'] ) ) {
435 if ( class_exists( 'FrmAbandonmentHooksController', false ) ) {
436 $where['e.is_draft'] = absint( $args['is_draft'] );
437 } else {
438 $where['e.is_draft'] = 1;
439 }
440 } elseif ( 'both' === $args['is_draft'] && class_exists( 'FrmAbandonmentHooksController', false ) ) {
441 $where['e.is_draft'] = array( 0, 1 );
442 } elseif ( false !== strpos( $args['is_draft'], ',' ) ) {
443 $is_draft = array_reduce(
444 explode( ',', $args['is_draft'] ),
445 function ( $total, $current ) {
446 if ( is_numeric( $current ) ) {
447 $total[] = absint( $current );
448 }
449 return $total;
450 },
451 array()
452 );
453 if ( $is_draft ) {
454 $where['e.is_draft'] = $is_draft;
455 }
456 }//end if
457
458 if ( ! empty( $args['user_id'] ) ) {
459 $where['e.user_id'] = $args['user_id'];
460 }
461 $query[] = FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
462
463 if ( $args['group_by'] ) {
464 $query[] = ' GROUP BY ' . sanitize_text_field( $args['group_by'] );
465 }
466
467 return;
468 }//end if
469
470 $draft_where = '';
471 $user_where = '';
472 if ( ! $args['is_draft'] ) {
473 $draft_where = $wpdb->prepare( ' AND e.is_draft=%d', 0 );
474 } elseif ( $args['is_draft'] == 1 ) {
475 $draft_where = $wpdb->prepare( ' AND e.is_draft=%d', 1 );
476 }
477
478 if ( ! empty( $args['user_id'] ) ) {
479 $user_where = $wpdb->prepare( ' AND e.user_id=%d', $args['user_id'] );
480 }
481
482 if ( strpos( $where, ' GROUP BY ' ) ) {
483 // don't inject WHERE filtering after GROUP BY
484 $parts = explode( ' GROUP BY ', $where );
485 $where = $parts[0];
486 $where .= $draft_where . $user_where;
487 $where .= ' GROUP BY ' . $parts[1];
488 } else {
489 $where .= $draft_where . $user_where;
490 }
491
492 // The query has already been prepared
493 $query[] = FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
494 }
495
496 public static function search_entry_metas( $search, $field_id, $operator ) {
497 $cache_key = 'search_' . FrmAppHelper::maybe_json_encode( $search ) . $field_id . $operator;
498 $results = wp_cache_get( $cache_key, 'frm_entry' );
499 if ( false !== $results ) {
500 return $results;
501 }
502
503 global $wpdb;
504 if ( is_array( $search ) ) {
505 $where = '';
506 foreach ( $search as $field => $value ) {
507 if ( $value <= 0 || ! in_array( $field, array( 'year', 'month', 'day' ) ) ) {
508 continue;
509 }
510
511 switch ( $field ) {
512 case 'year':
513 $value = '%' . $value;
514 break;
515 case 'month':
516 $value .= '%';
517 break;
518 case 'day':
519 $value = '%' . $value . '%';
520 }
521 $where .= $wpdb->prepare( ' meta_value ' . $operator . ' %s and', $value ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
522 }
523 $where .= $wpdb->prepare( ' field_id=%d', $field_id );
524 $query = 'SELECT DISTINCT item_id FROM ' . $wpdb->prefix . 'frm_item_metas' . FrmDb::prepend_and_or_where( ' WHERE ', $where );
525 } else {
526 if ( $operator === 'LIKE' ) {
527 $search = '%' . $search . '%';
528 }
529 $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
530 }//end if
531
532 $results = $wpdb->get_col( $query, 0 ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
533 FrmDb::set_cache( $cache_key, $results, 'frm_entry' );
534
535 return $results;
536 }
537 }
538