PageRenderTime 50ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

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