PageRenderTime 56ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/robo-gallery/cmb2/includes/CMB2_Types.php

https://gitlab.com/hunt9310/ras
PHP | 995 lines | 716 code | 128 blank | 151 comment | 52 complexity | 7a60f42aa1ff21fcbab19a629f4fa765 MD5 | raw file
  1. <?php
  2. /**
  3. * CMB field type objects
  4. *
  5. * @todo Date/Time fields should store date format as data attribute for JS
  6. *
  7. * @since 1.0.0
  8. *
  9. * @category WordPress_Plugin
  10. * @package CMB2
  11. * @author WebDevStudios
  12. * @license GPL-2.0+
  13. * @link http://webdevstudios.com
  14. */
  15. if ( ! defined( 'ABSPATH' ) ) exit;
  16. class CMB2_Types {
  17. /**
  18. * An iterator value for repeatable fields
  19. * @var integer
  20. * @since 1.0.0
  21. */
  22. public $iterator = 0;
  23. /**
  24. * Current CMB2_Field field object
  25. * @var CMB2_Field object
  26. * @since 1.0.0
  27. */
  28. public $field;
  29. public function __construct( CMB2_Field $field ) {
  30. $this->field = $field;
  31. }
  32. /**
  33. * Default fallback. Allows rendering fields via "cmb2_render_$name" hook
  34. * @since 1.0.0
  35. * @param string $name Non-existent method name
  36. * @param array $arguments All arguments passed to the method
  37. */
  38. public function __call( $name, $arguments ) {
  39. /**
  40. * Pass non-existent field types through an action
  41. *
  42. * The dynamic portion of the hook name, $name, refers to the field type.
  43. *
  44. * @param array $field The passed in `CMB2_Field` object
  45. * @param mixed $escaped_value The value of this field escaped.
  46. * It defaults to `sanitize_text_field`.
  47. * If you need the unescaped value, you can access it
  48. * via `$field->value()`
  49. * @param int $object_id The ID of the current object
  50. * @param string $object_type The type of object you are working with.
  51. * Most commonly, `post` (this applies to all post-types),
  52. * but could also be `comment`, `user` or `options-page`.
  53. * @param object $field_type_object This `CMB2_Types` object
  54. */
  55. do_action( "cmb2_render_$name", $this->field, $this->field->escaped_value(), $this->field->object_id, $this->field->object_type, $this );
  56. }
  57. /**
  58. * Render a field (and handle repeatable)
  59. * @since 1.1.0
  60. */
  61. public function render() {
  62. if ( $this->field->args( 'repeatable' ) ) {
  63. $this->render_repeatable_field();
  64. } else {
  65. $this->_render();
  66. }
  67. }
  68. /**
  69. * Render a field type
  70. * @since 1.1.0
  71. */
  72. protected function _render() {
  73. $this->field->peform_param_callback( 'before_field' );
  74. echo $this->{$this->field->type()}();
  75. $this->field->peform_param_callback( 'after_field' );
  76. }
  77. /**
  78. * Checks if we can get a post object, and if so, uses `get_the_terms` which utilizes caching
  79. * @since 1.0.2
  80. * @return mixed Array of terms on success
  81. */
  82. public function get_object_terms() {
  83. $object_id = $this->field->object_id;
  84. $taxonomy = $this->field->args( 'taxonomy' );
  85. if ( ! $post = get_post( $object_id ) ) {
  86. $cache_key = "cmb-cache-{$taxonomy}-{$object_id}";
  87. // Check cache
  88. $cached = get_transient( $cache_key );
  89. if ( $cached ) {
  90. return $cached;
  91. }
  92. $cached = wp_get_object_terms( $object_id, $taxonomy );
  93. // Do our own (minimal) caching. Long enough for a page-load.
  94. set_transient( $cache_key, $cached, 60 );
  95. return $cached;
  96. }
  97. // WP caches internally so it's better to use
  98. return get_the_terms( $post, $taxonomy );
  99. }
  100. /**
  101. * Retrieve text parameter from field's options array (if it has one), or use fallback text
  102. * @since 2.0.0
  103. * @param string $option_key Key in field's options array
  104. * @param string $fallback Fallback text
  105. * @return string Text
  106. */
  107. public function _text( $option_key, $fallback ) {
  108. $has_string_param = $this->field->options( $option_key );
  109. return $has_string_param ? $has_string_param : $fallback;
  110. }
  111. /**
  112. * Determine a file's extension
  113. * @since 1.0.0
  114. * @param string $file File url
  115. * @return string|false File extension or false
  116. */
  117. public function get_file_ext( $file ) {
  118. $parsed = @parse_url( $file, PHP_URL_PATH );
  119. return $parsed ? strtolower( pathinfo( $parsed, PATHINFO_EXTENSION ) ) : false;
  120. }
  121. /**
  122. * Get the file name from a url
  123. * @since 2.0.0
  124. * @param string $value File url or path
  125. * @return string File name
  126. */
  127. public function get_file_name_from_path( $value ) {
  128. $parts = explode( '/', $value );
  129. return is_array( $parts ) ? end( $parts ) : $value;
  130. }
  131. /**
  132. * Determines if a file has a valid image extension
  133. * @since 1.0.0
  134. * @param string $file File url
  135. * @return bool Whether file has a valid image extension
  136. */
  137. public function is_valid_img_ext( $file ) {
  138. $file_ext = $this->get_file_ext( $file );
  139. $is_valid_types = (array) apply_filters( 'cmb2_valid_img_types', array( 'jpg', 'jpeg', 'png', 'gif', 'ico', 'icon' ) );
  140. return ( $file_ext && in_array( $file_ext, $is_valid_types ) );
  141. }
  142. /**
  143. * Handles parsing and filtering attributes while preserving any passed in via field config.
  144. * @since 1.1.0
  145. * @param array $args Override arguments
  146. * @param string $element Element for filter
  147. * @param array $defaults Default arguments
  148. * @return array Parsed and filtered arguments
  149. */
  150. public function parse_args( $args, $element, $defaults ) {
  151. return wp_parse_args( apply_filters( "cmb2_{$element}_attributes", $this->field->maybe_set_attributes( $args ), $defaults, $this->field, $this ), $defaults );
  152. }
  153. /**
  154. * Combines attributes into a string for a form element
  155. * @since 1.1.0
  156. * @param array $attrs Attributes to concatenate
  157. * @param array $attr_exclude Attributes that should NOT be concatenated
  158. * @return string String of attributes for form element
  159. */
  160. public function concat_attrs( $attrs, $attr_exclude = array() ) {
  161. $attributes = '';
  162. foreach ( $attrs as $attr => $val ) {
  163. $excluded = in_array( $attr, (array) $attr_exclude, true );
  164. $empty = false === $val && 'value' !== $attr;
  165. if ( ! $excluded && ! $empty ) {
  166. // if data attribute, use single quote wraps, else double
  167. $quotes = false !== stripos( $attr, 'data-' ) ? "'" : '"';
  168. $attributes .= sprintf( ' %1$s=%3$s%2$s%3$s', $attr, $val, $quotes );
  169. }
  170. }
  171. return $attributes;
  172. }
  173. /**
  174. * Generates html for concatenated items
  175. * @since 1.1.0
  176. * @param array $args Optional arguments
  177. * @return string Concatenated html items
  178. */
  179. public function concat_items( $args = array() ) {
  180. $method = isset( $args['method'] ) ? $args['method'] : 'select_option';
  181. unset( $args['method'] );
  182. $value = $this->field->escaped_value()
  183. ? $this->field->escaped_value()
  184. : $this->field->args( 'default' );
  185. $concatenated_items = ''; $i = 1;
  186. $options = array();
  187. if ( $option_none = $this->field->args( 'show_option_none' ) ) {
  188. $options[ '' ] = $option_none;
  189. }
  190. $options = $options + (array) $this->field->options();
  191. foreach ( $options as $opt_value => $opt_label ) {
  192. // Clone args & modify for just this item
  193. $a = $args;
  194. $a['value'] = $opt_value;
  195. $a['label'] = $opt_label;
  196. // Check if this option is the value of the input
  197. if ( $value == $opt_value ) {
  198. $a['checked'] = 'checked';
  199. }
  200. $concatenated_items .= $this->$method( $a, $i++ );
  201. }
  202. return $concatenated_items;
  203. }
  204. /**
  205. * Generates html for an option element
  206. * @since 1.1.0
  207. * @param array $args Arguments array containing value, label, and checked boolean
  208. * @return string Generated option element html
  209. */
  210. public function select_option( $args = array() ) {
  211. return sprintf( "\t" . '<option value="%s" %s>%s</option>', $args['value'], selected( isset( $args['checked'] ) && $args['checked'], true, false ), $args['label'] ) . "\n";
  212. }
  213. /**
  214. * Generates html for list item with input
  215. * @since 1.1.0
  216. * @param array $args Override arguments
  217. * @param int $i Iterator value
  218. * @return string Gnerated list item html
  219. */
  220. public function list_input( $args = array(), $i ) {
  221. $a = $this->parse_args( $args, 'list_input', array(
  222. 'type' => 'radio',
  223. 'class' => 'cmb2-option',
  224. 'name' => $this->_name(),
  225. 'id' => $this->_id( $i ),
  226. 'value' => $this->field->escaped_value(),
  227. 'label' => '',
  228. ) );
  229. return sprintf( "\t" . '<li><input%s/> <label for="%s">%s</label></li>' . "\n", $this->concat_attrs( $a, array( 'label' ) ), $a['id'], $a['label'] );
  230. }
  231. /**
  232. * Generates html for list item with checkbox input
  233. * @since 1.1.0
  234. * @param array $args Override arguments
  235. * @param int $i Iterator value
  236. * @return string Gnerated list item html
  237. */
  238. public function list_input_checkbox( $args, $i ) {
  239. $saved_value = $this->field->escaped_value();
  240. if ( is_array( $saved_value ) && in_array( $args['value'], $saved_value ) ) {
  241. $args['checked'] = 'checked';
  242. }
  243. $args['type'] = 'checkbox';
  244. return $this->list_input( $args, $i );
  245. }
  246. /**
  247. * Generates repeatable field table markup
  248. * @since 1.0.0
  249. */
  250. public function render_repeatable_field() {
  251. $table_id = $this->field->id() . '_repeat';
  252. $this->_desc( true, true, true );
  253. ?>
  254. <div id="<?php echo $table_id; ?>" class="cmb-repeat-table cmb-nested">
  255. <div class="cmb-tbody cmb-field-list">
  256. <?php $this->repeatable_rows(); ?>
  257. </div>
  258. </div>
  259. <p class="cmb-add-row">
  260. <button data-selector="<?php echo $table_id; ?>" class="cmb-add-row-button button"><?php echo esc_html( $this->_text( 'add_row_text', __( 'Add Row', 'cmb2' ) ) ); ?></button>
  261. </p>
  262. <?php
  263. // reset iterator
  264. $this->iterator = 0;
  265. }
  266. /**
  267. * Generates repeatable field rows
  268. * @since 1.1.0
  269. */
  270. public function repeatable_rows() {
  271. $meta_value = array_filter( (array) $this->field->escaped_value() );
  272. // check for default content
  273. $default = $this->field->args( 'default' );
  274. // check for saved data
  275. if ( ! empty( $meta_value ) ) {
  276. $meta_value = is_array( $meta_value ) ? array_filter( $meta_value ) : $meta_value;
  277. $meta_value = ! empty( $meta_value ) ? $meta_value : $default;
  278. } else {
  279. $meta_value = $default;
  280. }
  281. // Loop value array and add a row
  282. if ( ! empty( $meta_value ) ) {
  283. $count = count( $meta_value );
  284. foreach ( (array) $meta_value as $val ) {
  285. $this->field->escaped_value = $val;
  286. $this->repeat_row( $count < 2 );
  287. $this->iterator++;
  288. }
  289. } else {
  290. // Otherwise add one row
  291. $this->repeat_row( true );
  292. }
  293. // Then add an empty row
  294. $this->field->escaped_value = '';
  295. $this->iterator = $this->iterator ? $this->iterator : 1;
  296. $this->repeat_row( false, 'empty-row hidden' );
  297. }
  298. /**
  299. * Generates a repeatable row's markup
  300. * @since 1.1.0
  301. * @param bool $disable_remover Whether remove button should be disabled
  302. * @param string $class Repeatable table row's class
  303. */
  304. protected function repeat_row( $disable_remover = false, $class = 'cmb-repeat-row' ) {
  305. $disabled = $disable_remover ? ' button-disabled' : '';
  306. ?>
  307. <div class="cmb-row <?php echo $class; ?>">
  308. <div class="cmb-td">
  309. <?php $this->_render(); ?>
  310. </div>
  311. <div class="cmb-td cmb-remove-row">
  312. <button class="button cmb-remove-row-button<?php echo $disabled; ?>"><?php echo esc_html( $this->_text( 'remove_row_text', __( 'Remove', 'cmb2' ) ) ); ?></button>
  313. </div>
  314. </div>
  315. <?php
  316. }
  317. /**
  318. * Generates description markup
  319. * @since 1.0.0
  320. * @param boolean $paragraph Paragraph tag or span
  321. * @param boolean $echo Whether to echo description or only return it
  322. * @return string Field's description markup
  323. */
  324. public function _desc( $paragraph = false, $echo = false, $repeat_group = false ) {
  325. // Prevent description from printing multiple times for repeatable fields
  326. if ( ! $repeat_group && ( $this->field->args( 'repeatable' ) || $this->iterator > 0 ) ) {
  327. return '';
  328. }
  329. $desc = $this->field->args( 'description' );
  330. if ( ! $desc ) {
  331. return;
  332. }
  333. $tag = $paragraph ? 'p' : 'span';
  334. $desc = sprintf( "\n" . '<%1$s class="cmb2-metabox-description">%2$s</%1$s>' . "\n", $tag, $desc );
  335. if ( $echo ) {
  336. echo $desc;
  337. }
  338. return $desc;
  339. }
  340. /**
  341. * Generate field name attribute
  342. * @since 1.1.0
  343. * @param string $suffix For multi-part fields
  344. * @return string Name attribute
  345. */
  346. public function _name( $suffix = '' ) {
  347. return $this->field->args( '_name' ) . ( $this->field->args( 'repeatable' ) ? '[' . $this->iterator . ']' : '' ) . $suffix;
  348. }
  349. /**
  350. * Generate field id attribute
  351. * @since 1.1.0
  352. * @param string $suffix For multi-part fields
  353. * @return string Id attribute
  354. */
  355. public function _id( $suffix = '' ) {
  356. return $this->field->id() . $suffix . ( $this->field->args( 'repeatable' ) ? '_' . $this->iterator . '" data-iterator="' . $this->iterator : '' );
  357. }
  358. /**
  359. * Handles outputting an 'input' element
  360. * @since 1.1.0
  361. * @param array $args Override arguments
  362. * @return string Form input element
  363. */
  364. public function input( $args = array() ) {
  365. $a = $this->parse_args( $args, 'input', array(
  366. 'type' => 'text',
  367. 'class' => 'regular-text',
  368. 'name' => $this->_name(),
  369. 'id' => $this->_id(),
  370. 'value' => $this->field->escaped_value(),
  371. 'desc' => $this->_desc( true ),
  372. ) );
  373. return sprintf( '<input%s/>%s', $this->concat_attrs( $a, array( 'desc' ) ), $a['desc'] );
  374. }
  375. /**
  376. * Handles outputting an 'textarea' element
  377. * @since 1.1.0
  378. * @param array $args Override arguments
  379. * @return string Form textarea element
  380. */
  381. public function textarea( $args = array() ) {
  382. $a = $this->parse_args( $args, 'textarea', array(
  383. 'class' => 'cmb2_textarea',
  384. 'name' => $this->_name(),
  385. 'id' => $this->_id(),
  386. 'cols' => 60,
  387. 'rows' => 10,
  388. 'value' => $this->field->escaped_value( 'esc_textarea' ),
  389. 'desc' => $this->_desc( true ),
  390. ) );
  391. return sprintf( '<textarea%s>%s</textarea>%s', $this->concat_attrs( $a, array( 'desc', 'value' ) ), $a['value'], $a['desc'] );
  392. }
  393. /**
  394. * Begin Field Types
  395. */
  396. public function text() {
  397. return $this->input();
  398. }
  399. public function hidden() {
  400. return $this->input( array( 'type' => 'hidden', 'desc' => '', 'class' => false ) );
  401. }
  402. public function text_small() {
  403. return $this->input( array( 'class' => 'cmb2-text-small', 'desc' => $this->_desc() ) );
  404. }
  405. public function text_medium() {
  406. return $this->input( array( 'class' => 'cmb2-text-medium', 'desc' => $this->_desc() ) );
  407. }
  408. public function text_email() {
  409. return $this->input( array( 'class' => 'cmb2-text-email cmb2-text-medium', 'type' => 'email' ) );
  410. }
  411. public function text_url() {
  412. return $this->input( array( 'class' => 'cmb2-text-url cmb2-text-medium regular-text', 'value' => $this->field->escaped_value( 'esc_url' ) ) );
  413. }
  414. public function text_money() {
  415. return ( ! $this->field->get_param_callback_result( 'before_field' ) ? '$ ' : ' ' ) . $this->input( array( 'class' => 'cmb2-text-money', 'desc' => $this->_desc() ) );
  416. }
  417. public function textarea_small() {
  418. return $this->textarea( array( 'class' => 'cmb2-textarea-small', 'rows' => 4 ) );
  419. }
  420. public function textarea_code() {
  421. return sprintf( '<pre>%s', $this->textarea( array( 'class' => 'cmb2-textarea-code', 'desc' => '</pre>' . $this->_desc( true ) ) ) );
  422. }
  423. public function wysiwyg( $args = array() ) {
  424. $a = $this->parse_args( $args, 'input', array(
  425. 'id' => $this->_id(),
  426. 'value' => $this->field->escaped_value( 'stripslashes' ),
  427. 'desc' => $this->_desc( true ),
  428. 'options' => $this->field->options(),
  429. ) );
  430. wp_editor( $a['value'], $a['id'], $a['options'] );
  431. echo $a['desc'];
  432. }
  433. public function text_date( $args = array() ) {
  434. $args = wp_parse_args( $args, array(
  435. 'class' => 'cmb2-text-small cmb2-datepicker',
  436. 'value' => $this->field->get_timestamp_format(),
  437. 'desc' => $this->_desc(),
  438. ) );
  439. return $this->input( $args );
  440. }
  441. // Alias for text_date
  442. public function text_date_timestamp( $args = array() ) {
  443. return $this->text_date( $args );
  444. }
  445. public function text_time( $args = array() ) {
  446. $args = wp_parse_args( $args, array(
  447. 'class' => 'cmb2-timepicker text-time',
  448. 'value' => $this->field->get_timestamp_format( 'time_format' ),
  449. 'desc' => $this->_desc(),
  450. ) );
  451. return $this->input( $args );
  452. }
  453. public function text_datetime_timestamp( $args = array() ) {
  454. $args = wp_parse_args( $args, array(
  455. 'value' => $this->field->escaped_value(),
  456. 'desc' => $this->_desc(),
  457. 'datepicker' => array(),
  458. 'timepicker' => array(),
  459. ) );
  460. if ( empty( $args['value'] ) ) {
  461. $args['value'] = $this->field->escaped_value();
  462. // This will be used if there is a select_timezone set for this field
  463. $tz_offset = $this->field->field_timezone_offset();
  464. if ( ! empty( $tz_offset ) ) {
  465. $args['value'] -= $tz_offset;
  466. }
  467. }
  468. $has_good_value = ! empty( $args['value'] ) && ! is_array( $args['value'] );
  469. $date_args = wp_parse_args( $args['datepicker'], array(
  470. 'class' => 'cmb2-text-small cmb2-datepicker',
  471. 'name' => $this->_name( '[date]' ),
  472. 'id' => $this->_id( '_date' ),
  473. 'value' => $has_good_value ? $this->field->get_timestamp_format( 'date_format', $args['value'] ) : '',
  474. 'desc' => '',
  475. ) );
  476. $time_args = wp_parse_args( $args['timepicker'], array(
  477. 'class' => 'cmb2-timepicker text-time',
  478. 'name' => $this->_name( '[time]' ),
  479. 'id' => $this->_id( '_time' ),
  480. 'value' => $has_good_value ? $this->field->get_timestamp_format( 'time_format', $args['value'] ) : '',
  481. 'desc' => $args['desc'],
  482. ) );
  483. return $this->input( $date_args ) . "\n" . $this->input( $time_args );
  484. }
  485. public function text_datetime_timestamp_timezone( $args = array() ) {
  486. $args = wp_parse_args( $args, array(
  487. 'value' => $this->field->escaped_value(),
  488. 'desc' => $this->_desc( true ),
  489. 'text_datetime_timestamp' => array(),
  490. 'select_timezone' => array(),
  491. ) );
  492. $args['value'] = $this->field->escaped_value();
  493. if ( is_array( $args['value'] ) ) {
  494. $args['value'] = '';
  495. }
  496. $datetime = unserialize( $args['value'] );
  497. $args['value'] = $tzstring = '';
  498. if ( $datetime && $datetime instanceof DateTime ) {
  499. $tz = $datetime->getTimezone();
  500. $tzstring = $tz->getName();
  501. $args['value'] = $datetime->getTimestamp() + $tz->getOffset( new DateTime( 'NOW' ) );
  502. }
  503. $timestamp_args = wp_parse_args( $args['text_datetime_timestamp'], array(
  504. 'desc' => '',
  505. 'value' => $args['value'],
  506. ) );
  507. $timezone_args = wp_parse_args( $args['select_timezone'], array(
  508. 'class' => 'cmb2_select cmb2-select-timezone',
  509. 'name' => $this->_name( '[timezone]' ),
  510. 'id' => $this->_id( '_timezone' ),
  511. 'options' => wp_timezone_choice( $tzstring ),
  512. 'desc' => $args['desc'],
  513. ) );
  514. return $this->text_datetime_timestamp( $timestamp_args ) . "\n" . $this->select( $timezone_args );
  515. }
  516. public function select_timezone() {
  517. $this->field->args['default'] = $this->field->args( 'default' )
  518. ? $this->field->args( 'default' )
  519. : cmb2_utils()->timezone_string();
  520. return $this->select( array(
  521. 'class' => 'cmb2_select cmb2-select-timezone',
  522. 'options' => wp_timezone_choice( $this->field->escaped_value() ),
  523. 'desc' => $this->_desc(),
  524. ) );
  525. }
  526. public function colorpicker() {
  527. $meta_value = $this->field->escaped_value();
  528. $hex_color = '(([a-fA-F0-9]){3}){1,2}$';
  529. if ( preg_match( '/^' . $hex_color . '/i', $meta_value ) ) {
  530. // Value is just 123abc, so prepend #
  531. $meta_value = '#' . $meta_value;
  532. } elseif ( ! preg_match( '/^#' . $hex_color . '/i', $meta_value ) ) {
  533. // Value doesn't match #123abc, so sanitize to just #
  534. $meta_value = '#';
  535. }
  536. return $this->input( array( 'class' => 'cmb2-colorpicker cmb2-text-small', 'value' => $meta_value ) );
  537. }
  538. public function title( $args = array() ) {
  539. $a = $this->parse_args( $args, 'title', array(
  540. 'tag' => $this->field->object_type == 'post' ? 'h5' : 'h3',
  541. 'class' => 'cmb2-metabox-title',
  542. 'name' => $this->field->args( 'name' ),
  543. 'desc' => $this->_desc( true ),
  544. ) );
  545. return sprintf( '<%1$s class="%2$s">%3$s</%1$s>%4$s', $a['tag'], $a['class'], $a['name'], $a['desc'] );
  546. }
  547. public function select( $args = array() ) {
  548. $a = $this->parse_args( $args, 'select', array(
  549. 'class' => 'cmb2_select',
  550. 'name' => $this->_name(),
  551. 'id' => $this->_id(),
  552. 'desc' => $this->_desc( true ),
  553. 'options' => $this->concat_items(),
  554. ) );
  555. $attrs = $this->concat_attrs( $a, array( 'desc', 'options' ) );
  556. return sprintf( '<select%s>%s</select>%s', $attrs, $a['options'], $a['desc'] );
  557. }
  558. public function taxonomy_select() {
  559. $names = $this->get_object_terms();
  560. $saved_term = is_wp_error( $names ) || empty( $names ) ? $this->field->args( 'default' ) : $names[key( $names )]->slug;
  561. $terms = get_terms( $this->field->args( 'taxonomy' ), 'hide_empty=0' );
  562. $options = '';
  563. $option_none = $this->field->args( 'show_option_none' );
  564. if ( ! empty( $option_none ) ) {
  565. $option_none_value = apply_filters( 'cmb2_taxonomy_select_default_value', '' );
  566. $option_none_value = apply_filters( "cmb2_taxonomy_select_{$this->_id()}_default_value", $option_none_value );
  567. $options .= $this->select_option( array(
  568. 'label' => $option_none,
  569. 'value' => $option_none_value,
  570. 'checked' => $saved_term == $option_none_value,
  571. ) );
  572. }
  573. foreach ( $terms as $term ) {
  574. $options .= $this->select_option( array(
  575. 'label' => $term->name,
  576. 'value' => $term->slug,
  577. 'checked' => $saved_term == $term->slug,
  578. ) );
  579. }
  580. return $this->select( array( 'options' => $options ) );
  581. }
  582. public function radio( $args = array(), $type = 'radio' ) {
  583. $a = $this->parse_args( $args, $type, array(
  584. 'class' => 'cmb2-radio-list cmb2-list',
  585. 'options' => $this->concat_items( array( 'label' => 'test', 'method' => 'list_input' ) ),
  586. 'desc' => $this->_desc( true ),
  587. ) );
  588. return sprintf( '<ul class="%s">%s</ul>%s', $a['class'], $a['options'], $a['desc'] );
  589. }
  590. public function radio_inline() {
  591. return $this->radio( array(), 'radio_inline' );
  592. }
  593. public function multicheck( $type = 'checkbox' ) {
  594. $classes = false === $this->field->args( 'select_all_button' )
  595. ? 'cmb2-checkbox-list no-select-all cmb2-list'
  596. : 'cmb2-checkbox-list cmb2-list';
  597. return $this->radio( array( 'class' => $classes, 'options' => $this->concat_items( array( 'name' => $this->_name() . '[]', 'method' => 'list_input_checkbox' ) ) ), $type );
  598. }
  599. public function multicheck_inline() {
  600. $this->multicheck( 'multicheck_inline' );
  601. }
  602. public function checkbox() {
  603. $meta_value = $this->field->escaped_value();
  604. $args = array( 'type' => 'checkbox', 'class' => 'cmb2-option cmb2-list', 'value' => 'on', 'desc' => '' );
  605. if ( ! empty( $meta_value ) ) {
  606. $args['checked'] = 'checked';
  607. }
  608. return sprintf( '%s <label for="%s">%s</label>', $this->input( $args ), $this->_id(), $this->_desc() );
  609. }
  610. public function taxonomy_radio() {
  611. $names = $this->get_object_terms();
  612. $saved_term = is_wp_error( $names ) || empty( $names ) ? $this->field->args( 'default' ) : $names[key( $names )]->slug;
  613. $terms = get_terms( $this->field->args( 'taxonomy' ), 'hide_empty=0' );
  614. $options = ''; $i = 1;
  615. if ( ! $terms ) {
  616. $options .= sprintf( '<li><label>%s</label></li>', esc_html( $this->_text( 'no_terms_text', __( 'No terms', 'cmb2' ) ) ) );
  617. } else {
  618. $option_none = $this->field->args( 'show_option_none' );
  619. if ( ! empty( $option_none ) ) {
  620. $option_none_value = apply_filters( "cmb2_taxonomy_radio_{$this->_id()}_default_value", apply_filters( 'cmb2_taxonomy_radio_default_value', '' ) );
  621. $args = array(
  622. 'value' => $option_none_value,
  623. 'label' => $option_none,
  624. );
  625. if ( $saved_term == $option_none_value ) {
  626. $args['checked'] = 'checked';
  627. }
  628. $options .= $this->list_input( $args, $i );
  629. $i++;
  630. }
  631. foreach ( $terms as $term ) {
  632. $args = array(
  633. 'value' => $term->slug,
  634. 'label' => $term->name,
  635. );
  636. if ( $saved_term == $term->slug ) {
  637. $args['checked'] = 'checked';
  638. }
  639. $options .= $this->list_input( $args, $i );
  640. $i++;
  641. }
  642. }
  643. return $this->radio( array( 'options' => $options ), 'taxonomy_radio' );
  644. }
  645. public function taxonomy_radio_inline() {
  646. $this->taxonomy_radio();
  647. }
  648. public function taxonomy_multicheck() {
  649. $names = $this->get_object_terms();
  650. $saved_terms = is_wp_error( $names ) || empty( $names )
  651. ? $this->field->args( 'default' )
  652. : wp_list_pluck( $names, 'slug' );
  653. $terms = get_terms( $this->field->args( 'taxonomy' ), 'hide_empty=0' );
  654. $name = $this->_name() . '[]';
  655. $options = ''; $i = 1;
  656. if ( ! $terms ) {
  657. $options .= sprintf( '<li><label>%s</label></li>', esc_html( $this->_text( 'no_terms_text', __( 'No terms', 'cmb2' ) ) ) );
  658. } else {
  659. foreach ( $terms as $term ) {
  660. $args = array(
  661. 'value' => $term->slug,
  662. 'label' => $term->name,
  663. 'type' => 'checkbox',
  664. 'name' => $name,
  665. );
  666. if ( is_array( $saved_terms ) && in_array( $term->slug, $saved_terms ) ) {
  667. $args['checked'] = 'checked';
  668. }
  669. $options .= $this->list_input( $args, $i );
  670. $i++;
  671. }
  672. }
  673. $classes = false === $this->field->args( 'select_all_button' )
  674. ? 'cmb2-checkbox-list no-select-all cmb2-list'
  675. : 'cmb2-checkbox-list cmb2-list';
  676. return $this->radio( array( 'class' => $classes, 'options' => $options ), 'taxonomy_multicheck' );
  677. }
  678. public function taxonomy_multicheck_inline() {
  679. $this->taxonomy_multicheck();
  680. }
  681. public function oembed() {
  682. $meta_value = trim( $this->field->escaped_value() );
  683. $oembed = ! empty( $meta_value )
  684. ? cmb2_get_oembed( array(
  685. 'url' => $this->field->escaped_value(),
  686. 'object_id' => $this->field->object_id,
  687. 'object_type' => $this->field->object_type,
  688. 'oembed_args' => array( 'width' => '640' ),
  689. 'field_id' => $this->_id(),
  690. ) )
  691. : '';
  692. echo $this->input( array(
  693. 'class' => 'cmb2-oembed regular-text',
  694. 'data-objectid' => $this->field->object_id,
  695. 'data-objecttype' => $this->field->object_type,
  696. ) ),
  697. '<p class="cmb-spinner spinner" style="display:none;"></p>',
  698. '<div id="', $this->_id( '-status' ), '" class="cmb2-media-status ui-helper-clearfix embed_wrap">', $oembed, '</div>';
  699. }
  700. public function file_list() {
  701. $meta_value = $this->field->escaped_value();
  702. $name = $this->_name();
  703. $img_size = $this->field->args( 'preview_size' );
  704. echo $this->input( array(
  705. 'type' => 'hidden',
  706. 'class' => 'cmb2-upload-file cmb2-upload-list',
  707. 'size' => 45, 'desc' => '', 'value' => '',
  708. 'data-previewsize' => is_array( $img_size ) ? sprintf( '[%s]', implode( ',', $img_size ) ) : 50,
  709. ) ),
  710. $this->input( array(
  711. 'type' => 'button',
  712. 'class' => 'cmb2-upload-button button cmb2-upload-list',
  713. 'value' => esc_html( $this->_text( 'add_upload_files_text', __( 'Add or Upload Files', 'cmb2' ) ) ),
  714. 'name' => '', 'id' => '',
  715. ) );
  716. echo '<ul id="', $this->_id( '-status' ), '" class="cmb2-media-status cmb-attach-list">';
  717. if ( $meta_value && is_array( $meta_value ) ) {
  718. foreach ( $meta_value as $id => $fullurl ) {
  719. $id_input = $this->input( array(
  720. 'type' => 'hidden',
  721. 'value' => $fullurl,
  722. 'name' => $name . '[' . $id . ']',
  723. 'id' => 'filelist-' . $id,
  724. 'data-id' => $id,
  725. 'desc' => '',
  726. 'class' => false,
  727. ) );
  728. if ( $this->is_valid_img_ext( $fullurl ) ) {
  729. $this->img_status_output( array(
  730. 'image' => wp_get_attachment_image( $id, $img_size ),
  731. 'tag' => 'li',
  732. 'id_input' => $id_input,
  733. ) );
  734. } else {
  735. $this->file_status_output( array(
  736. 'value' => $fullurl,
  737. 'tag' => 'li',
  738. 'id_input' => $id_input,
  739. ) );
  740. }
  741. }
  742. }
  743. echo '</ul>';
  744. }
  745. public function file() {
  746. $meta_value = $this->field->escaped_value();
  747. $options = (array) $this->field->options();
  748. $img_size = $this->field->args( 'preview_size' );
  749. // if options array and 'url' => false, then hide the url field
  750. $input_type = array_key_exists( 'url', $options ) && false === $options['url'] ? 'hidden' : 'text';
  751. echo $this->input( array(
  752. 'type' => $input_type,
  753. 'class' => 'cmb2-upload-file regular-text',
  754. 'size' => 45,
  755. 'desc' => '',
  756. 'data-previewsize' => is_array( $img_size ) ? '[' . implode( ',', $img_size ) . ']' : 350,
  757. ) );
  758. printf( '<input class="cmb2-upload-button button" type="button" value="%s" />', esc_attr( $this->_text( 'add_upload_file_text', __( 'Add or Upload File', 'cmb2' ) ) ) );
  759. $this->_desc( true, true );
  760. $cached_id = $this->_id();
  761. // Reset field args for attachment ID
  762. $args = $this->field->args();
  763. $args['id'] = $cached_id . '_id';
  764. unset( $args['_id'], $args['_name'] );
  765. // And get new field object
  766. $this->field = new CMB2_Field( array(
  767. 'field_args' => $args,
  768. 'group_field' => $this->field->group,
  769. 'object_type' => $this->field->object_type,
  770. 'object_id' => $this->field->object_id,
  771. ) );
  772. // Get ID value
  773. $_id_value = $this->field->escaped_value( 'absint' );
  774. // If there is no ID saved yet, try to get it from the url
  775. if ( $meta_value && ! $_id_value ) {
  776. $_id_value = cmb2_utils()->image_id_from_url( esc_url_raw( $meta_value ) );
  777. }
  778. echo $this->input( array(
  779. 'type' => 'hidden',
  780. 'class' => 'cmb2-upload-file-id',
  781. 'value' => $_id_value,
  782. 'desc' => '',
  783. ) ),
  784. '<div id="', $this->_id( '-status' ), '" class="cmb2-media-status">';
  785. if ( ! empty( $meta_value ) ) {
  786. if ( $this->is_valid_img_ext( $meta_value ) ) {
  787. if ( $_id_value ) {
  788. $image = wp_get_attachment_image( $_id_value, $img_size, null, array( 'class' => 'cmb-file-field-image' ) );
  789. } else {
  790. $size = is_array( $img_size ) ? $img_size[0] : 350;
  791. $image = '<img style="max-width: ' . absint( $size ) . 'px; width: 100%; height: auto;" src="' . $meta_value . '" alt="" />';
  792. }
  793. $this->img_status_output( array(
  794. 'image' => $image,
  795. 'tag' => 'div',
  796. 'cached_id' => $cached_id,
  797. ) );
  798. } else {
  799. $this->file_status_output( array(
  800. 'value' => $meta_value,
  801. 'tag' => 'div',
  802. 'cached_id' => $cached_id,
  803. ) );
  804. }
  805. }
  806. echo '</div>';
  807. }
  808. /**
  809. * file/file_list image wrap
  810. * @since 2.0.2
  811. * @param array $args Array of arguments for output
  812. * @return string Image wrap output
  813. */
  814. public function img_status_output( $args ) {
  815. printf( '<%1$s class="img-status">%2$s<p class="cmb2-remove-wrapper"><a href="#" class="cmb2-remove-file-button"%3$s>%4$s</a></p>%5$s</%1$s>',
  816. $args['tag'],
  817. $args['image'],
  818. isset( $args['cached_id'] ) ? ' rel="' . $args['cached_id'] . '"' : '',
  819. esc_html( $this->_text( 'remove_image_text', __( 'Remove Image', 'cmb2' ) ) ),
  820. isset( $args['id_input'] ) ? $args['id_input'] : ''
  821. );
  822. }
  823. /**
  824. * file/file_list file wrap
  825. * @since 2.0.2
  826. * @param array $args Array of arguments for output
  827. * @return string File wrap output
  828. */
  829. public function file_status_output( $args ) {
  830. printf( '<%1$s class="file-status"><span>%2$s <strong>%3$s</strong></span>&nbsp;&nbsp; (<a href="%4$s" target="_blank" rel="external">%5$s</a> / <a href="#" class="cmb2-remove-file-button"%6$s>%7$s</a>)%8$s</%1$s>',
  831. $args['tag'],
  832. esc_html( $this->_text( 'file_text', __( 'File:', 'cmb2' ) ) ),
  833. $this->get_file_name_from_path( $args['value'] ),
  834. $args['value'],
  835. esc_html( $this->_text( 'file-download-text', __( 'Download', 'cmb2' ) ) ),
  836. isset( $args['cached_id'] ) ? ' rel="' . $args['cached_id'] . '"' : '',
  837. esc_html( $this->_text( 'remove_text', __( 'Remove', 'cmb2' ) ) ),
  838. isset( $args['id_input'] ) ? $args['id_input'] : ''
  839. );
  840. }
  841. }