[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/widgets/ -> class-wp-widget-media.php (source)

   1  <?php
   2  /**
   3   * Widget API: WP_Media_Widget class
   4   *
   5   * @package WordPress
   6   * @subpackage Widgets
   7   * @since 4.8.0
   8   */
   9  
  10  /**
  11   * Core class that implements a media widget.
  12   *
  13   * @since 4.8.0
  14   *
  15   * @see WP_Widget
  16   */
  17  abstract class WP_Widget_Media extends WP_Widget {
  18  
  19      /**
  20       * Translation labels.
  21       *
  22       * @since 4.8.0
  23       * @var array
  24       */
  25      public $l10n = array(
  26          'add_to_widget'              => '',
  27          'replace_media'              => '',
  28          'edit_media'                 => '',
  29          'media_library_state_multi'  => '',
  30          'media_library_state_single' => '',
  31          'missing_attachment'         => '',
  32          'no_media_selected'          => '',
  33          'add_media'                  => '',
  34      );
  35  
  36      /**
  37       * Whether or not the widget has been registered yet.
  38       *
  39       * @since 4.8.1
  40       * @var bool
  41       */
  42      protected $registered = false;
  43  
  44      /**
  45       * Constructor.
  46       *
  47       * @since 4.8.0
  48       *
  49       * @param string $id_base         Base ID for the widget, lowercase and unique.
  50       * @param string $name            Name for the widget displayed on the configuration page.
  51       * @param array  $widget_options  Optional. Widget options. See wp_register_sidebar_widget() for
  52       *                                information on accepted arguments. Default empty array.
  53       * @param array  $control_options Optional. Widget control options. See wp_register_widget_control()
  54       *                                for information on accepted arguments. Default empty array.
  55       */
  56  	public function __construct( $id_base, $name, $widget_options = array(), $control_options = array() ) {
  57          $widget_opts = wp_parse_args(
  58              $widget_options,
  59              array(
  60                  'description'                 => __( 'A media item.' ),
  61                  'customize_selective_refresh' => true,
  62                  'mime_type'                   => '',
  63              )
  64          );
  65  
  66          $control_opts = wp_parse_args( $control_options, array() );
  67  
  68          $l10n_defaults = array(
  69              'no_media_selected'          => __( 'No media selected' ),
  70              'add_media'                  => _x( 'Add Media', 'label for button in the media widget' ),
  71              'replace_media'              => _x( 'Replace Media', 'label for button in the media widget; should preferably not be longer than ~13 characters long' ),
  72              'edit_media'                 => _x( 'Edit Media', 'label for button in the media widget; should preferably not be longer than ~13 characters long' ),
  73              'add_to_widget'              => __( 'Add to Widget' ),
  74              'missing_attachment'         => sprintf(
  75                  /* translators: %s: URL to media library. */
  76                  __( 'We can&#8217;t find that file. Check your <a href="%s">media library</a> and make sure it wasn&#8217;t deleted.' ),
  77                  esc_url( admin_url( 'upload.php' ) )
  78              ),
  79              /* translators: %d: Widget count. */
  80              'media_library_state_multi'  => _n_noop( 'Media Widget (%d)', 'Media Widget (%d)' ),
  81              'media_library_state_single' => __( 'Media Widget' ),
  82              'unsupported_file_type'      => __( 'Looks like this isn&#8217;t the correct kind of file. Please link to an appropriate file instead.' ),
  83          );
  84          $this->l10n    = array_merge( $l10n_defaults, array_filter( $this->l10n ) );
  85  
  86          parent::__construct(
  87              $id_base,
  88              $name,
  89              $widget_opts,
  90              $control_opts
  91          );
  92      }
  93  
  94      /**
  95       * Add hooks while registering all widget instances of this widget class.
  96       *
  97       * @since 4.8.0
  98       *
  99       * @param int $number Optional. The unique order number of this widget instance
 100       *                    compared to other instances of the same class. Default -1.
 101       */
 102  	public function _register_one( $number = -1 ) {
 103          parent::_register_one( $number );
 104          if ( $this->registered ) {
 105              return;
 106          }
 107          $this->registered = true;
 108  
 109          // Note that the widgets component in the customizer will also do
 110          // the 'admin_print_scripts-widgets.php' action in WP_Customize_Widgets::print_scripts().
 111          add_action( 'admin_print_scripts-widgets.php', array( $this, 'enqueue_admin_scripts' ) );
 112  
 113          if ( $this->is_preview() ) {
 114              add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_preview_scripts' ) );
 115          }
 116  
 117          // Note that the widgets component in the customizer will also do
 118          // the 'admin_footer-widgets.php' action in WP_Customize_Widgets::print_footer_scripts().
 119          add_action( 'admin_footer-widgets.php', array( $this, 'render_control_template_scripts' ) );
 120  
 121          add_filter( 'display_media_states', array( $this, 'display_media_state' ), 10, 2 );
 122      }
 123  
 124      /**
 125       * Get schema for properties of a widget instance (item).
 126       *
 127       * @since 4.8.0
 128       *
 129       * @see WP_REST_Controller::get_item_schema()
 130       * @see WP_REST_Controller::get_additional_fields()
 131       * @link https://core.trac.wordpress.org/ticket/35574
 132       *
 133       * @return array Schema for properties.
 134       */
 135  	public function get_instance_schema() {
 136          $schema = array(
 137              'attachment_id' => array(
 138                  'type'        => 'integer',
 139                  'default'     => 0,
 140                  'minimum'     => 0,
 141                  'description' => __( 'Attachment post ID' ),
 142                  'media_prop'  => 'id',
 143              ),
 144              'url'           => array(
 145                  'type'        => 'string',
 146                  'default'     => '',
 147                  'format'      => 'uri',
 148                  'description' => __( 'URL to the media file' ),
 149              ),
 150              'title'         => array(
 151                  'type'                  => 'string',
 152                  'default'               => '',
 153                  'sanitize_callback'     => 'sanitize_text_field',
 154                  'description'           => __( 'Title for the widget' ),
 155                  'should_preview_update' => false,
 156              ),
 157          );
 158  
 159          /**
 160           * Filters the media widget instance schema to add additional properties.
 161           *
 162           * @since 4.9.0
 163           *
 164           * @param array           $schema Instance schema.
 165           * @param WP_Widget_Media $this   Widget object.
 166           */
 167          $schema = apply_filters( "widget_{$this->id_base}_instance_schema", $schema, $this );
 168  
 169          return $schema;
 170      }
 171  
 172      /**
 173       * Determine if the supplied attachment is for a valid attachment post with the specified MIME type.
 174       *
 175       * @since 4.8.0
 176       *
 177       * @param int|WP_Post $attachment Attachment post ID or object.
 178       * @param string      $mime_type  MIME type.
 179       * @return bool Is matching MIME type.
 180       */
 181  	public function is_attachment_with_mime_type( $attachment, $mime_type ) {
 182          if ( empty( $attachment ) ) {
 183              return false;
 184          }
 185          $attachment = get_post( $attachment );
 186          if ( ! $attachment ) {
 187              return false;
 188          }
 189          if ( 'attachment' !== $attachment->post_type ) {
 190              return false;
 191          }
 192          return wp_attachment_is( $mime_type, $attachment );
 193      }
 194  
 195      /**
 196       * Sanitize a token list string, such as used in HTML rel and class attributes.
 197       *
 198       * @since 4.8.0
 199       *
 200       * @link http://w3c.github.io/html/infrastructure.html#space-separated-tokens
 201       * @link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList
 202       * @param string|array $tokens List of tokens separated by spaces, or an array of tokens.
 203       * @return string Sanitized token string list.
 204       */
 205  	public function sanitize_token_list( $tokens ) {
 206          if ( is_string( $tokens ) ) {
 207              $tokens = preg_split( '/\s+/', trim( $tokens ) );
 208          }
 209          $tokens = array_map( 'sanitize_html_class', $tokens );
 210          $tokens = array_filter( $tokens );
 211          return implode( ' ', $tokens );
 212      }
 213  
 214      /**
 215       * Displays the widget on the front-end.
 216       *
 217       * @since 4.8.0
 218       *
 219       * @see WP_Widget::widget()
 220       *
 221       * @param array $args     Display arguments including before_title, after_title, before_widget, and after_widget.
 222       * @param array $instance Saved setting from the database.
 223       */
 224  	public function widget( $args, $instance ) {
 225          $instance = wp_parse_args( $instance, wp_list_pluck( $this->get_instance_schema(), 'default' ) );
 226  
 227          // Short-circuit if no media is selected.
 228          if ( ! $this->has_content( $instance ) ) {
 229              return;
 230          }
 231  
 232          echo $args['before_widget'];
 233  
 234          /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
 235          $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
 236  
 237          if ( $title ) {
 238              echo $args['before_title'] . $title . $args['after_title'];
 239          }
 240  
 241          /**
 242           * Filters the media widget instance prior to rendering the media.
 243           *
 244           * @since 4.8.0
 245           *
 246           * @param array           $instance Instance data.
 247           * @param array           $args     Widget args.
 248           * @param WP_Widget_Media $this     Widget object.
 249           */
 250          $instance = apply_filters( "widget_{$this->id_base}_instance", $instance, $args, $this );
 251  
 252          $this->render_media( $instance );
 253  
 254          echo $args['after_widget'];
 255      }
 256  
 257      /**
 258       * Sanitizes the widget form values as they are saved.
 259       *
 260       * @since 4.8.0
 261       *
 262       * @see WP_Widget::update()
 263       * @see WP_REST_Request::has_valid_params()
 264       * @see WP_REST_Request::sanitize_params()
 265       *
 266       * @param array $new_instance Values just sent to be saved.
 267       * @param array $instance     Previously saved values from database.
 268       * @return array Updated safe values to be saved.
 269       */
 270  	public function update( $new_instance, $instance ) {
 271  
 272          $schema = $this->get_instance_schema();
 273          foreach ( $schema as $field => $field_schema ) {
 274              if ( ! array_key_exists( $field, $new_instance ) ) {
 275                  continue;
 276              }
 277              $value = $new_instance[ $field ];
 278  
 279              /*
 280               * Workaround for rest_validate_value_from_schema() due to the fact that
 281               * rest_is_boolean( '' ) === false, while rest_is_boolean( '1' ) is true.
 282               */
 283              if ( 'boolean' === $field_schema['type'] && '' === $value ) {
 284                  $value = false;
 285              }
 286  
 287              if ( true !== rest_validate_value_from_schema( $value, $field_schema, $field ) ) {
 288                  continue;
 289              }
 290  
 291              $value = rest_sanitize_value_from_schema( $value, $field_schema );
 292  
 293              // @codeCoverageIgnoreStart
 294              if ( is_wp_error( $value ) ) {
 295                  continue; // Handle case when rest_sanitize_value_from_schema() ever returns WP_Error as its phpdoc @return tag indicates.
 296              }
 297  
 298              // @codeCoverageIgnoreEnd
 299              if ( isset( $field_schema['sanitize_callback'] ) ) {
 300                  $value = call_user_func( $field_schema['sanitize_callback'], $value );
 301              }
 302              if ( is_wp_error( $value ) ) {
 303                  continue;
 304              }
 305              $instance[ $field ] = $value;
 306          }
 307  
 308          return $instance;
 309      }
 310  
 311      /**
 312       * Render the media on the frontend.
 313       *
 314       * @since 4.8.0
 315       *
 316       * @param array $instance Widget instance props.
 317       * @return string
 318       */
 319      abstract public function render_media( $instance );
 320  
 321      /**
 322       * Outputs the settings update form.
 323       *
 324       * Note that the widget UI itself is rendered with JavaScript via `MediaWidgetControl#render()`.
 325       *
 326       * @since 4.8.0
 327       *
 328       * @see \WP_Widget_Media::render_control_template_scripts() Where the JS template is located.
 329       *
 330       * @param array $instance Current settings.
 331       */
 332  	final public function form( $instance ) {
 333          $instance_schema = $this->get_instance_schema();
 334          $instance        = wp_array_slice_assoc(
 335              wp_parse_args( (array) $instance, wp_list_pluck( $instance_schema, 'default' ) ),
 336              array_keys( $instance_schema )
 337          );
 338  
 339          foreach ( $instance as $name => $value ) : ?>
 340              <input
 341                  type="hidden"
 342                  data-property="<?php echo esc_attr( $name ); ?>"
 343                  class="media-widget-instance-property"
 344                  name="<?php echo esc_attr( $this->get_field_name( $name ) ); ?>"
 345                  id="<?php echo esc_attr( $this->get_field_id( $name ) ); // Needed specifically by wpWidgets.appendTitle(). ?>"
 346                  value="<?php echo esc_attr( is_array( $value ) ? implode( ',', $value ) : (string) $value ); ?>"
 347              />
 348              <?php
 349          endforeach;
 350      }
 351  
 352      /**
 353       * Filters the default media display states for items in the Media list table.
 354       *
 355       * @since 4.8.0
 356       *
 357       * @param array   $states An array of media states.
 358       * @param WP_Post $post   The current attachment object.
 359       * @return array
 360       */
 361  	public function display_media_state( $states, $post = null ) {
 362          if ( ! $post ) {
 363              $post = get_post();
 364          }
 365  
 366          // Count how many times this attachment is used in widgets.
 367          $use_count = 0;
 368          foreach ( $this->get_settings() as $instance ) {
 369              if ( isset( $instance['attachment_id'] ) && $instance['attachment_id'] === $post->ID ) {
 370                  $use_count++;
 371              }
 372          }
 373  
 374          if ( 1 === $use_count ) {
 375              $states[] = $this->l10n['media_library_state_single'];
 376          } elseif ( $use_count > 0 ) {
 377              $states[] = sprintf( translate_nooped_plural( $this->l10n['media_library_state_multi'], $use_count ), number_format_i18n( $use_count ) );
 378          }
 379  
 380          return $states;
 381      }
 382  
 383      /**
 384       * Enqueue preview scripts.
 385       *
 386       * These scripts normally are enqueued just-in-time when a widget is rendered.
 387       * In the customizer, however, widgets can be dynamically added and rendered via
 388       * selective refresh, and so it is important to unconditionally enqueue them in
 389       * case a widget does get added.
 390       *
 391       * @since 4.8.0
 392       */
 393  	public function enqueue_preview_scripts() {}
 394  
 395      /**
 396       * Loads the required scripts and styles for the widget control.
 397       *
 398       * @since 4.8.0
 399       */
 400  	public function enqueue_admin_scripts() {
 401          wp_enqueue_media();
 402          wp_enqueue_script( 'media-widgets' );
 403      }
 404  
 405      /**
 406       * Render form template scripts.
 407       *
 408       * @since 4.8.0
 409       */
 410  	public function render_control_template_scripts() {
 411          ?>
 412          <script type="text/html" id="tmpl-widget-media-<?php echo esc_attr( $this->id_base ); ?>-control">
 413              <# var elementIdPrefix = 'el' + String( Math.random() ) + '_' #>
 414              <p>
 415                  <label for="{{ elementIdPrefix }}title"><?php esc_html_e( 'Title:' ); ?></label>
 416                  <input id="{{ elementIdPrefix }}title" type="text" class="widefat title">
 417              </p>
 418              <div class="media-widget-preview <?php echo esc_attr( $this->id_base ); ?>">
 419                  <div class="attachment-media-view">
 420                      <button type="button" class="select-media button-add-media not-selected">
 421                          <?php echo esc_html( $this->l10n['add_media'] ); ?>
 422                      </button>
 423                  </div>
 424              </div>
 425              <p class="media-widget-buttons">
 426                  <button type="button" class="button edit-media selected">
 427                      <?php echo esc_html( $this->l10n['edit_media'] ); ?>
 428                  </button>
 429              <?php if ( ! empty( $this->l10n['replace_media'] ) ) : ?>
 430                  <button type="button" class="button change-media select-media selected">
 431                      <?php echo esc_html( $this->l10n['replace_media'] ); ?>
 432                  </button>
 433              <?php endif; ?>
 434              </p>
 435              <div class="media-widget-fields">
 436              </div>
 437          </script>
 438          <?php
 439      }
 440  
 441      /**
 442       * Whether the widget has content to show.
 443       *
 444       * @since 4.8.0
 445       *
 446       * @param array $instance Widget instance props.
 447       * @return bool Whether widget has content.
 448       */
 449  	protected function has_content( $instance ) {
 450          return ( $instance['attachment_id'] && 'attachment' === get_post_type( $instance['attachment_id'] ) ) || $instance['url'];
 451      }
 452  }


Generated: Tue Dec 1 01:00:04 2020 Cross-referenced by PHPXref 0.7.1