PageRenderTime 30ms CodeModel.GetById 2ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 1ms

/wp-content/plugins/wp-types/embedded/common/toolset-forms/classes/class.types.php

https://bitbucket.org/acipriani/madeinapulia.com
PHP | 538 lines | 248 code | 42 blank | 248 comment | 40 complexity | 7cf51882542673d43f9c8f2068ec07f3 MD5 | raw file
  1<?php
  2/**
  3 * Types fields specific
  4 *
  5 * $HeadURL: https://www.onthegosystems.com/misc_svn/common/tags/Views-1.6.4-CRED-1.3.2-Types-1.6.4-Acces-1.2.3/toolset-forms/classes/class.types.php $
  6 * $LastChangedDate: 2014-09-11 14:31:16 +0000 (Thu, 11 Sep 2014) $
  7 * $LastChangedRevision: 26983 $
  8 * $LastChangedBy: marcin $
  9 *
 10 */
 11
 12/**
 13 * Class description
 14 *
 15 * @author Srdjan
 16 */
 17class WPToolset_Types
 18{
 19
 20    /**
 21     * Filters Types field to match data structure needed for shared code.
 22     *
 23     * @global type $pagenow
 24     * @staticvar array $cache
 25     * @param type $field array|string $field settings array (as stored in DB) or field ID
 26     * @param type $post_id Post or user ID used for conditional
 27     * @return array
 28     */
 29    static function filterField($field, $post_id = null, $_post_wpcf = array())
 30    {
 31        // Get field settings (as when using get_option('wpcf-fields') from DB)
 32        $field = self::getConfig( $field );
 33        if ( is_null( $field ) ) return array();
 34
 35        // Caching
 36        static $cache = array();
 37        $cache_key = md5( serialize( $field ) . $post_id );
 38        if ( isset( $cache[$cache_key] ) ) {
 39            return $cache[$cache_key];
 40        }
 41
 42        // Prefix - used to construct ID of field @see at bottom 'General field settings'
 43        $prefix = self::getPrefix( $field );
 44
 45        /* Suffix - used to construct ID of this field and other fields connected
 46         * to it via conditionals.
 47         *
 48         * @see at bottom 'General field settings'
 49         *
 50         * Reason to use it - Types have child posts forms inside same form as
 51         * main fields. It's like having same sets of fields inside same form.
 52         * Main post fields do not have suffix.
 53         *
 54         * Example main field:
 55         * ID: wpcf-text
 56         * conditional: '$wpcf-date > DATE(01,02,2014)'
 57         *
 58         * Example child field:
 59         * ID: wpcf-text-123
 60         * conditional: '$wpcf-date-123 > DATE(01,02,2014)'
 61         * Suffix is child post ID (wpcf-text-$child_post_id).
 62         *
 63         * That way right triggers and conditional fields are mapped.
 64         */
 65        $suffix = isset( $field['suffix'] ) ? $field['suffix'] : '';
 66
 67        /* General field settings
 68         *
 69         * Main settings that are returned.
 70         */
 71        $_field = array(
 72            'id' => $prefix . $field['id'] . $suffix, // Used as main ID (raw date wpt-id), used to connect conditional relations
 73            'meta_key' => $prefix . $field['id'], // Used by Types (meta key of field saved to DB)
 74            'meta_type' => isset( $field['meta_type'] ) ? $field['meta_type'] : 'postmeta', // Used by Types (postmeta|usermeta)
 75            'type' => $field['type'], // Type of field (textfield, skype, email etc)
 76            'slug' => $field['id'], // Not sure if used by Types TODO REVISE
 77            'title' => self::translate( "field {$field['id']} name",
 78                    $field['name'] ), // Translated title
 79            'description' => !empty( $field['description'] ) ? self::translate( "field {$field['id']} description",
 80                    $field['description'] ) : '', // Translated description
 81            'name' => isset( $field['form_name'] ) ? $field['form_name'] : "wpcf[{$field['id']}]", // Form element name, default wpcf[$no-prefix-slug]
 82            'repetitive' => self::isRepetitive( $field ), // Is repetitive?
 83            'validation' => self::filterValidation( $field ), // Validation settings
 84            'conditional' => self::filterConditional( $field, $post_id, $_post_wpcf ), // Conditional settings
 85        );
 86
 87        /* Specific field settings
 88         *
 89         * There are some field types that needs extra data or adjusted data
 90         * for readibility.
 91         */
 92        switch( $field['type'] ) {
 93            // Checkbox set default_value
 94        case 'checkbox':
 95            $_field['default_value'] = $field['data']['set_value'];
 96            $_field['checked'] = array_key_exists( 'checked', $field['data'] )? $field['data']['checked']:false;
 97            break;
 98            // Checkboxes set field [options]
 99        case 'checkboxes':
100            if ( !empty( $field['data']['options'] ) ) {
101                global $pagenow;
102                foreach ( $field['data']['options'] as $option_key => $option ) {
103                    // Set value
104                    $_field['options'][$option_key] = array(
105                        'value' => $option['set_value'],
106                        'title' => self::translate( 'field ' . $field['id'] . ' option '
107                        . $option_key . ' title', $option['title'] ),
108                        'name' => 'wpcf[' . $field['id'] . '][' . $option_key . ']',
109                    );
110                    if ( $pagenow == 'post-new.php' && !empty( $option['checked'] ) ) {
111                        $_field['options'][$option_key]['checked'] = true;
112                    }
113                }
114            }
115            break;
116        case 'date':
117            $_field['add_time'] = !empty( $field['data']['date_and_time'] ) && $field['data']['date_and_time'] == 'and_time';
118            break;
119            // Radio and Select set field [options]
120        case 'radio':
121        case 'select':
122            if ( !empty( $field['data']['options'] ) ) {
123                foreach ( $field['data']['options'] as $k => $option ) {
124                    if ( $k == 'default' ) {
125                        continue;
126                    }
127                    if ( array_key_exists( 'default', $field['data']['options'] ) && $field['data']['options']['default'] == $k ) {
128                        $_field['default_value'] = $option['value'];
129                    }
130                    $_field['options'][] = array(
131                        'value' => $option['value'],
132                        'title' => self::translate( 'field ' . $field['id'] . ' option '
133                        . $k . ' title', $option['title'] ),
134                    );
135                }
136            }
137            break;
138        }
139        // Radio adjust type name because form_factory class name contains 'Radios'
140        if ( $field['type'] == 'radio' ) {
141            $_field['type'] = 'radios';
142        }
143        return $cache[$cache_key] = $_field;
144    }
145
146    /**
147     * Filters validation.
148     *
149     * Loop over validation settings and create array of validation rules.
150     * array( $rule => array( 'args' => array, 'message' => string ), ... )
151     *
152     * @param array|string $field settings array (as stored in DB) or field ID
153     * @return array array( $rule => array( 'args' => array, 'message' => string ), ... )
154     */
155    public static function filterValidation($config)
156    {
157        $config = self::getConfig( $config );
158        if ( is_null( $config ) ) return array();
159        /* Placeholder for field value '$value'.
160         *
161         * Used for validation settings.
162         * Field value is not processed here, instead string '$value' is used
163         * to be replaced with actual value when needed.
164         *
165         * For example:
166         * validation['rangelength'] = array(
167         *     'args' => array( '$value', 5, 12 ),
168         *     'message' => 'Value length between %s and %s required'
169         * );
170         * validation['reqiuired'] = array(
171         *     'args' => array( '$value', true ),
172         *     'message' => 'This field is required'
173         * );
174         *
175         * Types have default and custom messages defined on it's side.
176         */
177        $value = '$value';
178        $validation = array();
179        if ( isset( $config['data']['validate'] ) ) {
180            foreach ( $config['data']['validate'] as $rule => $settings ) {
181                if ( $settings['active'] ) {
182                    // Work out the id so we can get the translated message.
183                    $id = '';
184                    if (isset($config['slug'])) {
185                        $id = $config['slug'];
186                    } else {
187                        // This is on a cred from
188                        // try to find an appropriate id
189                        $id = $config['name'];
190                        if (strpos($id, 'wpcf-') === 0) {
191                            $id = substr($id, 5);
192                        }
193                    }
194                    $validation[$rule] = array(
195                        'args' => isset( $settings['args'] ) ? array_unshift( $value,
196                                        $settings['args'] ) : array($value, true),
197                        'message' => self::translate('field ' . $id . ' validation message ' . $rule, stripslashes( $settings['message']))
198                    );
199                }
200            }
201        }
202        return $validation;
203    }
204
205    /**
206     * Filters conditional.
207     *
208     * There are two types of conditionals:
209     * 1. Regular conditionals created using Types GUI
210     * 2. Custom onditionals (user entered manually)
211     *
212     * 1. Regular conditional
213     *
214     * Main properties:
215     * [relation] - AND|OR evaluate as true if all or any condition is TRUE
216     * [conditions] - array of conditions
217     * [values] - values to check against (used only by PHP), evaluate method
218     *      should not be aware if it's checking post meta or user meta,
219     *      instead array of needed values (or missing) are passed to method.
220     *      Types use filteres get_post_meta() and get_user_meta().
221     *
222     * [conditions]
223     * Each conditions is array with properties:
224     * id: ID of trigger field (this field value is checked) to evaluate
225     *      this field as TRUE or FALSE (corresponds to main IDs set here)
226     * type: type of trigger field. JS and PHP needs at least this information
227     *      when processing condtitional evaluation
228     * operator: which operation to perform (=|>|<|>=|<=|!=|between)
229     * args: arguments passed to checking functions
230     *
231     * Example of reguar conditional
232     *
233     * [conditional] => Array(
234            [relation] => OR
235            [conditions] => Array(
236                [0] => Array(
237                    [id] => wpcf-my-date
238                    [type] => date
239                    [operator] => =
240                    [args] => Array(
241                        [0] => 02/01/2014
242                    )
243                )
244                [1] => Array(
245                    [id] => wpcf-my-date
246                    [type] => date
247                    [operator] => between
248                    [args] => Array(
249                        [0] => 02/07/2014
250                        [1] => 02/10/2014
251                    )
252                 )
253            )
254      [values] => Array(
255        [wpcf-my-date] => 32508691200
256        )
257      )
258     *
259     *
260     * 2. Custom conditional
261     * Main properties:
262     * [custom] - custom statement made by user, note that $xxxx should match
263     *      IDs of fields that passed this filter.
264     * [values] - same as for regular conditional
265     *
266     * [conditional] => Array(
267            [custom] => ($wpcf-my-date = DATE(01,02,2014)) OR ($wpcf-my-date > DATE(07,02,2014))
268            [values] => Array(
269                [wpcf-my-date] => 32508691200
270            )
271      )
272     *
273     * @param array|string $field settings array (as stored in DB) or field ID
274     * @param int $post_id Post or user ID to fetch meta data to check against
275     * @return array
276     */
277    public static function filterConditional($field, $post_id, $_post_wpcf = array())
278    {
279        $field = self::getConfig( $field );
280        if ( is_null( $field ) ) return array();
281
282        // Caching
283        static $cache = array();
284        $cache_key = md5( serialize( $field ) . $post_id );
285        if ( isset( $cache[$cache_key] ) ) {
286            return $cache[$cache_key];
287        }
288
289        /* Suffix - used to construct ID of this field and other fields connected
290         * to it via conditionals.
291         *
292         * @see at bottom 'General field settings'
293         *
294         * Reason to use it - Types have child posts forms inside same form as
295         * main fields. It's like having same sets of fields inside same form.
296         * Main post fields do not have suffix.
297         *
298         * Example main field:
299         * ID: wpcf-text
300         * conditional: '$wpcf-date > DATE(01,02,2014)'
301         *
302         * Example child field:
303         * ID: wpcf-text-123
304         * conditional: '$wpcf-date-123 > DATE(01,02,2014)'
305         * Suffix is child post ID (wpcf-text-$child_post_id).
306         *
307         * That way right triggers and conditional fields are mapped.
308         */
309        $suffix = isset( $field['suffix'] ) ? $field['suffix'] : '';
310        $cond = array();
311        if ( empty( $field['meta_type'] ) ) {
312            $field['meta_type'] = 'postmeta';
313        }
314
315        // Get [values]
316        $cond_values = self::getConditionalValues($post_id, $field['meta_type']);
317        
318		if ( function_exists('wpcf_fields_get_field_by_slug') ){
319            // Update the conditional values according to what's being saved.
320            foreach ( $_post_wpcf as $field_slug => $field_value ) {
321                // Get field by slug
322                $field = wpcf_fields_get_field_by_slug( $field_slug );
323                if ( empty( $field ) ) {
324                    continue;
325                }
326                
327                $field_value = apply_filters( 'wpcf_fields_type_' . $field['type']
328                        . '_value_save', $field_value, $field, null );
329                
330                $cond_values[$field['meta_key']] = $field_value;                
331            }
332        }
333
334        // Set custom conditional
335        if ( !empty( $field['data']['conditional_display']['custom_use'] ) ) {
336            require_once 'class.conditional.php';
337            $custom = $field['data']['conditional_display']['custom'];
338
339            // Extract field values ('${$field_name}')
340            $cond = self::getCustomConditional($custom, $suffix, $cond_values);
341
342            // Regular conditional
343        } elseif ( !empty( $field['data']['conditional_display']['conditions'] ) ) {
344            $cond = array(
345                'relation' => $field['data']['conditional_display']['relation'],
346                'conditions' => array(),
347                'values' => array(),
348            );
349
350            // Loop over conditions and collect settings
351            foreach ( $field['data']['conditional_display']['conditions'] as $d ) {
352
353                // Get field settings
354                $c_field = self::getConfig( $d['field'] );
355
356                // If it's Types field
357                if ( !empty( $c_field ) ) {
358                    $_c = array(
359                        'id' => self::getPrefix( $c_field ) . $d['field'] . $suffix,
360                        'type' => $c_field['type'],
361                        'operator' => $d['operation'],
362                        'args' => array($d['value']),
363                    );
364                    $cond['conditions'][] = $_c;
365
366                    // Apply filters from field (that is why we set 'type' property)
367                    wptoolset_form_field_add_filters( $field['type'] );
368                    $key = $c_field['meta_key'];
369                    if ( isset( $cond_values[$key] ) ) {
370                        $cond['values'][$key . $suffix] = apply_filters( 'wptoolset_conditional_value_php',
371                                $cond_values[$key], $c_field['type'] );
372                    }
373
374                    // Otherwise do nothing add [values]
375                    // That allows checking for non-Types field
376                    // TODO REVIEW THIS
377                } elseif ( isset( $cond_values[$d['field']] ) ) {
378                    $cond['values'][$d['field'] . $suffix] = $cond_values[$d['field']];
379                }
380            }
381        }
382        unset( $cond_values, $c_values, $c_field );
383        return $cache[$cache_key] = $cond;
384    }
385    
386    public static function getConditionalValues($post_id, $meta_type = 'postmeta') {
387        $cond_values = array();
388        if ( !empty( $post_id ) ) {
389            $cond_values = $meta_type == 'usermeta' ? get_user_meta( $post_id ) : get_post_custom( $post_id );
390        }
391
392        // Unserialize [values] and do not allow array (take first value from array
393        if ( is_array( $cond_values ) ) {
394            foreach ( $cond_values as $k => &$v ) {
395                $v = maybe_unserialize( $v[0] );
396                $v = self::getStringFromArray($v);
397            }
398        }
399        
400        return $cond_values;
401    }
402    
403    public static function getCustomConditional($custom, $suffix = '', $cond_values = array()) {
404        $c_fields = WPToolset_Forms_Conditional::extractFields( $custom );
405        $c_values = array();
406
407        // Loop over extracted fields and adjust custom statement
408        foreach ( $c_fields as $c_field_id ) {
409
410            // Get field settings
411            $c_field = self::getConfig( $c_field_id );
412
413            // If it's Types field
414            if ( !empty( $c_field ) ) {
415
416                // Adjust custom statement
417                $custom = preg_replace( '/\$\(' . $c_field_id . '\)/',
418                        "\$({$c_field['meta_key']}{$suffix})", $custom );
419                $custom = preg_replace( '/\$' . $c_field_id . '[\s\)]/',
420                        "\${$c_field['meta_key']}{$suffix} ", $custom );
421
422                // Apply filters from field (that is why we set 'type' property)
423                wptoolset_form_field_add_filters( $c_field['type'] );
424                $c_key = $c_field['meta_key'];
425                if ( isset( $cond_values[$c_key] ) ) {
426                    $c_values[$c_key . $suffix] = apply_filters( 'wptoolset_conditional_value_php',
427                            $cond_values[$c_key], $c_field['type'] );
428                }
429
430                // Otherwise do nothing (leave statement as it is and just add [values])
431                // That allows checking for non-Types field
432            } elseif ( isset( $cond_values[$c_field_id] ) ) {
433                $c_values[$c_field_id . $suffix] = $cond_values[$c_field_id];
434            }
435        }
436
437        // Set conditional setting
438        $cond = array(
439            'custom' => $custom,
440            'values' => $c_values,
441        );
442        
443        return $cond;
444    }
445
446    /**
447     * Checks if field is repetitive.
448     *
449     * @param type $field
450     * @return null|boolean
451     */
452    public static function isRepetitive($config)
453    {
454        $config = self::getConfig( $config );
455        if ( is_null( $config ) ) return null;
456        return !empty( $config['data']['repetitive'] );
457    }
458
459    /**
460     * Returns all fields configurations created by Types.
461     *
462     * @return array Array of field settings
463     */
464    public static function getFields()
465    {
466        return get_option( 'wpcf-fields', array() );
467    }
468
469    /**
470     * Get specific field configuration created by Types.
471     *
472     * @param type $field_id
473     * @return array|null
474     */
475    public static function getConfig($field_id)
476    {
477        if ( !is_string( $field_id ) ) {
478            return is_array( $field_id ) ? $field_id : null;
479        }
480        $fields = self::getFields();
481        return isset( $fields[$field_id] ) ? $fields[$field_id] : null;
482    }
483
484    /**
485     * Returns prefix for specific field meta_key or ID.
486     *
487     * @param type $field
488     * @return string
489     */
490    public static function getPrefix($config)
491    {
492        return !empty( $config['data']['controlled'] ) ? '' : 'wpcf-';
493    }
494
495    /**
496     * Translates various strings connected to Types using WPML icl_t().
497     *
498     * @param type $name
499     * @param type $string
500     * @param type $context
501     * @return string
502     */
503    public static function translate($name, $string, $context = 'plugin Types')
504    {
505        if ( !function_exists( 'icl_t' ) ) {
506            return $string;
507        }
508        return icl_t( $context, $name, stripslashes( $string ) );
509    }
510
511    /**
512     * Returns field meta key.
513     *
514     * @param type $config
515     * @return type
516     */
517    public static function getMetakey($config)
518    {
519        return self::getPrefix( $config ) . $config['id'];
520    }
521
522    /**
523     * return first string value
524     *
525     * @param type $string
526     * @return string
527     */
528    private static function getStringFromArray($array)
529    {
530        if ( is_object( $array ) ) {
531            return $array;
532        }
533        if ( is_array( $array ) ) {
534            return self::getStringFromArray(array_shift($array));
535        }
536        return strval( $array );
537    }
538}