WordPress.org

Make WordPress Core

Ticket #32417: 32417.13.diff

File 32417.13.diff, 26.5 KB (added by gonom9, 15 months ago)
  • src/wp-includes/class-wp-customize-manager.php

    diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php
    index 229a248..6468b49 100644
    a b final class WP_Customize_Manager { 
    18071807                                'stylesheet' => $this->get_stylesheet(),
    18081808                                'active'     => $this->is_theme_active(),
    18091809                        ),
     1810                        'media' => array(
     1811                                'audioLibrary' => apply_filters( 'wp_audio_shortcode_library', 'mediaelement' ),
     1812                                'videoLibrary' => apply_filters( 'wp_video_shortcode_library', 'mediaelement' ),
     1813                        ),
    18101814                        'url' => array(
    18111815                                'self' => $self_url,
    18121816                                'allowed' => array_map( 'esc_url_raw', $this->get_allowed_urls() ),
  • src/wp-includes/css/wp-media-widget.css

    diff --git a/src/wp-includes/css/wp-media-widget.css b/src/wp-includes/css/wp-media-widget.css
    index e69de29..d36ec25 100644
    a b  
     1.media-widget-preview .button {
     2        text-align: center
     3}
     4
     5.media-widget-preview .wp-caption {
     6        max-width: 100%;
     7        margin: 0;
     8}
     9
     10.media-widget-preview .image {
     11        height: auto;
     12        max-width: 100%;
     13        cursor: pointer;
     14}
     15
     16.media-widget-preview .aligncenter {
     17        display: block;
     18        margin: 0 auto;
     19        text-align: center
     20}
  • src/wp-includes/default-widgets.php

    diff --git a/src/wp-includes/default-widgets.php b/src/wp-includes/default-widgets.php
    index 0cf5fc3..e803135 100644
    a b require_once( ABSPATH . WPINC . '/widgets/class-wp-widget-tag-cloud.php' ); 
    4545
    4646/** WP_Nav_Menu_Widget class */
    4747require_once( ABSPATH . WPINC . '/widgets/class-wp-nav-menu-widget.php' );
     48
     49/** WP_Widget_Media class */
     50require_once( ABSPATH . WPINC . '/widgets/class-wp-widget-media.php' );
  • src/wp-includes/js/customize-selective-refresh.js

    diff --git a/src/wp-includes/js/customize-selective-refresh.js b/src/wp-includes/js/customize-selective-refresh.js
    index d3b81db..bb21079 100644
    a b wp.customize.selectiveRefresh = ( function( $, api ) { 
    398398                 * @returns {boolean} Whether the rendering was successful and the fallback was not invoked.
    399399                 */
    400400                renderContent: function( placement ) {
    401                         var partial = this, content, newContainerElement;
     401                        var partial = this, content, mediaSettings = api.settings.media, newContainerElement;
    402402                        if ( ! placement.container ) {
    403403                                partial.fallback( new Error( 'no_container' ), [ placement ] );
    404404                                return false;
    wp.customize.selectiveRefresh = ( function( $, api ) { 
    452452                                        placement.container.html( content );
    453453                                }
    454454
     455                                // Auto-initialize media elements when they are contained in the placement
     456                                if ( $( 'audio, video', placement.container ).length > 0 ) {
     457                                        if ( wp.mediaelement && wp.mediaelement.initialize && _.contains( [ mediaSettings.audioLibrary, mediaSettings.videoLibrary ], 'mediaelement' ) ) {
     458                                                wp.mediaelement.initialize();
     459                                        }
     460                                }
     461
    455462                                placement.container.removeClass( 'customize-render-content-error' );
    456463                        } catch ( error ) {
    457464                                if ( 'undefined' !== typeof console && console.error ) {
  • src/wp-includes/js/wp-media-widget.js

    diff --git a/src/wp-includes/js/wp-media-widget.js b/src/wp-includes/js/wp-media-widget.js
    index e69de29..19e6e99 100644
    a b  
     1/**
     2 * @since 4.8.0
     3 *
     4 * @package WP_Media_Widget
     5 */
     6( function ( $, l10n ) {
     7        var frame = {
     8                defaultProps: {
     9                        id:    '',
     10                        align: '',
     11                        size:  '',
     12                        link:  ''
     13                },
     14
     15                init: function() {
     16                        frame.bindEvent();
     17                        wp.mediaelement.initialize();
     18                },
     19
     20                bindEvent: function( context ) {
     21                        $( '.button.select-media, .image', context || '.media-widget-preview' )
     22                                .off( 'click.mediaWidget' )
     23                                .on( 'click.mediaWidget', frame.openMediaManager );
     24                },
     25
     26                /**
     27                 * Get current selection of media
     28                 *
     29                 * @param {String} widgetId
     30                 * @return {wp.media.models.Selection|null}
     31                 */
     32                getSelection: function( widgetId ) {
     33                        var ids = $( '#widget-' + widgetId + '-id' ).val();
     34
     35                        if ( ! ids ) {
     36                                return null;
     37                        }
     38
     39                        var selection = ids.split(',').reduce( function( list, id ) {
     40                                var attachment = wp.media.attachment( id );
     41                                if ( id && attachment ) {
     42                                        list.push( attachment );
     43                                }
     44                                return list;
     45                        }, [] );
     46
     47                        return new wp.media.model.Selection( selection );
     48                },
     49
     50                openMediaManager: function( event ) {
     51                        var widgetId = $( event.target ).data( 'id' );
     52
     53                        // Create the media frame.
     54                        var widgetFrame = wp.media( {
     55                                button: {
     56                                        text: translate( 'addToWidget', 'Add to widget' ) // Text of the submit button.
     57                                },
     58
     59                                states: new wp.media.controller.Library( {
     60                                        library:    wp.media.query( { type: [ 'image', 'audio', 'video' ] } ),
     61                                        title:      translate( 'selectMedia', 'Select Media' ), // Media frame title
     62                                        selection:  frame.getSelection( widgetId ),
     63                                        multiple:   false,
     64                                        priority:   20,
     65                                        display:    true, // attachment display setting
     66                                        filterable: 'all'
     67                                } )
     68                        } );
     69
     70                        // Render the attachment details.
     71                        widgetFrame.on( 'select', function() {
     72                                var props, attachment;
     73
     74                                // Only try to render the attachment details if a selection was made.
     75                                if ( widgetFrame.state().get( 'selection' ).length > 0 ) {
     76                                        props = widgetFrame.content.get( '.attachments-browser' )
     77                                                .sidebar.get( 'display' ).model.toJSON();
     78
     79                                        attachment = widgetFrame.state().get( 'selection' ).first().toJSON();
     80
     81                                        frame.renderFormView( widgetId, props, attachment );
     82                                }
     83                        } );
     84
     85                        widgetFrame.open( widgetId );
     86                },
     87
     88                /**
     89                 * Renders the attachment details from the media modal into the widget.
     90                 *
     91                 * @param {String} widgetId
     92                 * @param {Object} props Attachment Display Settings (align, link, size, etc).
     93                 * @param {Object} attachment Attachment Details (title, description, caption, url, sizes, etc).
     94                 */
     95                renderFormView: function( widgetId, props, attachment ) {
     96                        // Start with container elements for the widgets page, customizer controls, and customizer preview.
     97                        var previewEl,
     98                                extras,
     99                                formView = $( '.' + widgetId + ', #customize-control-widget_' + widgetId + ', #' + widgetId ),
     100                                scale = $( '#widget-' + widgetId + '-scale' );
     101
     102                        // Bail if there is no target form
     103                        if ( ! formView.length || ! scale.length ) {
     104                                return;
     105                        }
     106
     107                        _.extend( attachment, _.pick( props, 'link', 'size' ) );
     108
     109                        // Show/hide the widget description
     110                        formView.find( '.attachment-description' )
     111                                .toggleClass( 'hidden', ! attachment.description )
     112                                .html( attachment.description );
     113
     114                        // Display a preview of the image in the widgets page and customizer controls.
     115                        extras = formView.find( '.extras' ).removeClass( 'hidden' );
     116
     117                        // Set the preview content
     118                        previewEl = formView.find( '.media-widget-admin-preview' );
     119                        previewEl.html( frame.renderMediaElement( widgetId, props, attachment ) );
     120
     121                        // Apply responsive styles to the media if the scale option is checked
     122                        if ( scale.prop( 'checked' ) ) {
     123                                previewEl
     124                                        .find( '.wp-video, .wp-caption' ).css( 'width', '100%' ).end()
     125                                        .find( 'img.image' ).css( { width: '100%', height: 'auto' } );
     126                        }
     127
     128                        if ( _.contains( [ 'audio', 'video' ], attachment.type ) ) {
     129                                wp.mediaelement.initialize();
     130                        }
     131
     132                        frame.bindEvent( formView );
     133
     134                        // Populate form fields with selection data from the media frame.
     135                        _.each( _.keys( frame.defaultProps ), function ( key ) {
     136                                formView.find( '#widget-' + widgetId + '-' + key ).val( attachment[ key ] || props[ key ] ).trigger( 'change' );
     137                        } );
     138
     139                        // Trigger a sync to update the widget in the customizer preview.
     140                        formView.find( '#widget-' + widgetId + '-url' ).trigger( 'change' );
     141
     142                        // Change button text
     143                        formView.find( frame.buttonId ).text( translate( 'changeMedia', 'Change Media' ) );
     144                },
     145
     146                /**
     147                 * Renders the media attachment in HTML.
     148                 *
     149                 * @param {String} widgetId
     150                 * @param {Object} props Attachment Display Settings (align, link, size, etc).
     151                 * @param {Object} attachment Attachment Details (title, description, caption, url, sizes, etc).
     152                 *
     153                 * @return {String}
     154                 */
     155                renderMediaElement: function( widgetId, props, attachment ) {
     156                        var type = attachment.type || '';
     157                        var renderer = 'render' + type.charAt(0).toUpperCase() + type.slice(1);
     158
     159                        if ( 'function' === typeof frame[renderer] ) {
     160                                return frame[renderer]( widgetId, props, attachment );
     161                        }
     162
     163                        // In case no renderer found
     164                        return '';
     165                },
     166
     167                /**
     168                 * Renders the image attachment
     169                 *
     170                 * @param {String} widgetId
     171                 * @param {Object} props Attachment Display Settings (align, link, size, etc).
     172                 * @param {Object} attachment Attachment Details (title, description, caption, url, sizes, etc).
     173                 *
     174                 * @return {String}
     175                 */
     176                renderImage: function( widgetId, props, attachment ) {
     177                        var image = $( '<img />' )
     178                                .addClass( 'image wp-image' + attachment.id )
     179                                .attr( {
     180                                        'data-id': widgetId,
     181                                        src:       attachment.sizes[ props.size ].url,
     182                                        title:     attachment.title,
     183                                        alt:       attachment.alt,
     184                                        width:     attachment.sizes[ props.size ].width,
     185                                        height:    attachment.sizes[ props.size ].height
     186                                } );
     187
     188                        if ( attachment.caption ) {
     189                                image = $( '<figure />' )
     190                                        .width( attachment.sizes[ props.size ].width )
     191                                        .addClass( 'wp-caption' )
     192                                        .attr( 'id', widgetId + '-caption' )
     193                                        .append( image );
     194
     195                                $( '<figcaption class="wp-caption-text" />' ).text( attachment.caption ).appendTo( image );
     196                        }
     197
     198                        return image.wrap( '<div />' ).parent().html();
     199                },
     200
     201                /**
     202                 * Renders the audio attachment
     203                 *
     204                 * @param {String} widgetId
     205                 * @param {Object} props Attachment Display Settings (align, link, size, etc).
     206                 * @param {Object} attachment Attachment Details (title, description, caption, url, sizes, etc).
     207                 *
     208                 * @return {String}
     209                 */
     210                renderAudio: function( widgetId, props, attachment ) {
     211                        if ( 'embed' === props.link ) {
     212                                return wp.media.template( 'wp-media-widget-audio' )( {
     213                                        model: {
     214                                                src:    attachment.url
     215                                        }
     216                                } );
     217                        }
     218
     219                        return wp.html.string( {
     220                                tag: 'a',
     221                                content: attachment.title,
     222                                attrs: {
     223                                        href: '#'
     224                                }
     225                        } );
     226                },
     227
     228                /**
     229                 * Renders the video attachment
     230                 *
     231                 * @param {String} widgetId
     232                 * @param {Object} props Attachment Display Settings (align, link, size, etc).
     233                 * @param {Object} attachment Attachment Details (title, description, caption, url, sizes, etc).
     234                 *
     235                 * @return {String}
     236                 */
     237                renderVideo: function( widgetId, props, attachment ) {
     238                        if ( 'embed' === props.link ) {
     239                                return wp.media.template( 'wp-media-widget-video' )( {
     240                                        model: {
     241                                                src:    attachment.url,
     242                                                width:  attachment.width,
     243                                                height: attachment.height
     244                                        }
     245                                } );
     246                        }
     247
     248                        return wp.html.string( {
     249                                tag: 'a',
     250                                content: attachment.title,
     251                                attrs: {
     252                                        href: '#'
     253                                }
     254                        } );
     255                }
     256        };
     257
     258        function translate( key, defaultText ) {
     259                return l10n[ key ] || defaultText;
     260        }
     261
     262        $( document )
     263                .ready( frame.init )
     264                .on( 'widget-added widget-updated', frame.init );
     265
     266        window.wp = window.wp || {};
     267        window.wp.MediaWidget = frame;
     268} )( jQuery, window._mediaWidgetL10n || {} );
  • src/wp-includes/script-loader.php

    diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php
    index b2e24d6..3609373 100644
    a b function wp_default_scripts( &$scripts ) { 
    761761                $scripts->add( 'media-gallery', "/wp-admin/js/media-gallery$suffix.js", array('jquery'), false, 1 );
    762762
    763763                $scripts->add( 'svg-painter', '/wp-admin/js/svg-painter.js', array( 'jquery' ), false, 1 );
     764
     765                // Media Widget
     766                $scripts->add( 'wp-media-widget', '/wp-includes/js/wp-media-widget.js', array( 'jquery', 'media-models', 'media-views' ), false, 1 );
     767                did_action( 'init' ) && $scripts->localize( 'wp-media-widget', '_mediaWidgetL10n', array(
     768                        'selectMedia' => __( 'Select Media' ),
     769                        'changeMedia' => __( 'Change Media' ),
     770                        'addToWidget' => __( 'Add to widget' )
     771                ) );
    764772        }
    765773}
    766774
    function wp_default_styles( &$styles ) { 
    865873        $styles->add( 'media-views',          "/wp-includes/css/media-views$suffix.css", array( 'buttons', 'dashicons', 'wp-mediaelement' ) );
    866874        $styles->add( 'wp-pointer',           "/wp-includes/css/wp-pointer$suffix.css", array( 'dashicons' ) );
    867875        $styles->add( 'customize-preview',    "/wp-includes/css/customize-preview$suffix.css", array( 'dashicons' ) );
     876        $styles->add( 'wp-media-widget',      "/wp-includes/css/wp-media-widget.css", array( 'media-views' ) );
    868877        $styles->add( 'wp-embed-template-ie', "/wp-includes/css/wp-embed-template-ie$suffix.css" );
    869878        $styles->add_data( 'wp-embed-template-ie', 'conditional', 'lte IE 8' );
    870879
  • src/wp-includes/widgets.php

    diff --git a/src/wp-includes/widgets.php b/src/wp-includes/widgets.php
    index 1abadfb..f046f2d 100644
    a b function wp_widgets_init() { 
    14661466
    14671467        register_widget('WP_Nav_Menu_Widget');
    14681468
     1469        register_widget('WP_Media_Widget');
     1470
    14691471        /**
    14701472         * Fires after all default WordPress widgets have been registered.
    14711473         *
  • src/wp-includes/widgets/class-wp-widget-media.php

    diff --git a/src/wp-includes/widgets/class-wp-widget-media.php b/src/wp-includes/widgets/class-wp-widget-media.php
    index e69de29..8e18c31 100644
    a b  
     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 */
     17class WP_Media_Widget extends WP_Widget {
     18        private $default_instance = array(
     19                'id'          => '',
     20                'title'       => '',
     21                'description' => '',
     22                'link'        => '',
     23                'align'       => 'none',
     24        );
     25
     26        /**
     27         * Constructor.
     28         *
     29         * @since 4.8.0
     30         * @access public
     31         *
     32         * @param string $id_base         Optional Base ID for the widget, lowercase and unique. If left empty,
     33         *                                a portion of the widget's class name will be used Has to be unique.
     34         * @param string $name            Optional. Name for the widget displayed on the configuration page.
     35         *                                Default empty.
     36         * @param array  $widget_options  Optional. Widget options. See wp_register_sidebar_widget() for
     37         *                                information on accepted arguments. Default empty array.
     38         * @param array  $control_options Optional. Widget control options. See wp_register_widget_control()
     39         *                                for information on accepted arguments. Default empty array.
     40         */
     41        public function __construct( $id_base = '', $name = '', $widget_options = array(), $control_options = array() ) {
     42                $widget_opts = wp_parse_args( $widget_options, array(
     43                        'classname' => 'widget_media',
     44                        'description' => __( 'Display media such as images, video, or audio in your sidebar.' ),
     45                        'customize_selective_refresh' => true,
     46                ) );
     47
     48                $control_opts = wp_parse_args( $control_options, array() );
     49
     50                parent::__construct(
     51                        $id_base ? $id_base : 'wp-media-widget',
     52                        $name ? $name : __( 'Media' ),
     53                        $widget_opts,
     54                        $control_opts
     55                );
     56
     57                if ( is_customize_preview() ) {
     58                        $this->enqueue_mediaelement_script();
     59                }
     60
     61                add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) );
     62                add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
     63        }
     64
     65        /**
     66         * Displays the widget on the front-end.
     67         *
     68         * @since 4.8.0
     69         * @access public
     70         *
     71         * @see WP_Widget::widget()
     72         *
     73         * @param array $args     Display arguments including before_title, after_title, before_widget, and after_widget.
     74         * @param array $instance Saved setting from the database.
     75         */
     76        public function widget( $args, $instance ) {
     77                $output = $args['before_widget'];
     78
     79                $instance = array_merge( $this->default_instance, $instance );
     80
     81                if ( $instance['title'] ) {
     82                        $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
     83                        $output .= $args['before_title'] . $title . $args['after_title'];
     84                }
     85                if ( $instance['description'] ) {
     86                        $output .= '<p class="attachment-description align' . $instance['align'] . '">' . $instance['description'] . '</p>';
     87                }
     88
     89                // Render the media.
     90                $attachment = $instance['id'] ? get_post( $instance['id'] ) : null;
     91                if ( $attachment ) {
     92                        $output .= $this->render_media( $attachment, $args['widget_id'], $instance );
     93                        $output .= $this->get_responsive_style( $attachment, $args['widget_id'], $instance );
     94                }
     95
     96                $output .= $args['after_widget'];
     97
     98                echo $output;
     99        }
     100
     101        /**
     102         * Sanitizes the widget form values as they are saved.
     103         *
     104         * @since 4.8.0
     105         * @access public
     106         *
     107         * @see WP_Widget::update()
     108         *
     109         * @param array $new_instance Values just sent to be saved.
     110         * @param array $old_instance Previously saved values from database.
     111         * @return array Updated safe values to be saved.
     112         */
     113        public function update( $new_instance, $old_instance ) {
     114                $instance = $old_instance;
     115
     116                // ID, title, scale
     117                $instance['id']    = (int) $new_instance['id'];
     118                $instance['title'] = sanitize_text_field( $new_instance['title'] );
     119                $instance['scale'] = isset( $new_instance['scale'] ) ? sanitize_text_field( $new_instance['scale'] ) : '';
     120
     121                // Everything else.
     122                $instance['align'] = sanitize_text_field( $new_instance['align'] );
     123                $instance['size']  = sanitize_text_field( $new_instance['size'] );
     124                $instance['link']  = sanitize_text_field( $new_instance['link'] );
     125
     126                return $instance;
     127        }
     128
     129        /**
     130         * Get type of a media attachment
     131         *
     132         * @since 4.8.0
     133         * @access private
     134         *
     135         * @param WP_Post $attachment Attachment object.
     136         *
     137         * @return String type string such as image, audio and video. Returns empty string for unknown type
     138         */
     139        private function get_typeof_media( $attachment ) {
     140                if ( wp_attachment_is_image( $attachment ) ) {
     141                        return 'image';
     142                }
     143
     144                if ( wp_attachment_is( 'audio', $attachment ) ) {
     145                        return 'audio';
     146                }
     147
     148                if ( wp_attachment_is( 'video', $attachment ) ) {
     149                        return 'video';
     150                }
     151
     152                // unknown media type
     153                return '';
     154        }
     155
     156        /**
     157         * Renders a single media attachment
     158         *
     159         * @since 4.8.0
     160         * @access public
     161         *
     162         * @param WP_Post $attachment Attachment object.
     163         * @param string  $widget_id  Widget ID.
     164         * @param array   $instance   Current widget instance arguments.
     165         * @return string
     166         */
     167        public function render_media( $attachment, $widget_id, $instance ) {
     168                $output = '';
     169                $renderer = 'render_' . $this->get_typeof_media( $attachment );
     170
     171                if ( method_exists( $this, $renderer ) ) {
     172                        $output .= call_user_func( array( $this, $renderer ), $attachment, $widget_id, $instance );
     173                }
     174
     175                return $output;
     176        }
     177
     178        /**
     179         * Renders an image attachment preview.
     180         *
     181         * @since 4.8.0
     182         * @access private
     183         *
     184         * @param WP_Post $attachment Attachment object.
     185         * @param string  $widget_id  Widget ID.
     186         * @param array   $instance   Current widget instance arguments.
     187         * @return string
     188         */
     189        private function render_image( $attachment, $widget_id, $instance ) {
     190                $has_caption   = ( ! empty( $attachment->post_excerpt ) );
     191                $is_responsive = ( ! empty( $instance['scale'] ) );
     192
     193                $img_attrs = array(
     194                        'data-id' => $widget_id,
     195                        'title'   => $attachment->post_title,
     196                        'class'   => 'image wp-image-' . $attachment->ID,
     197                );
     198
     199                if ( ! $has_caption ) {
     200                        $img_attrs['class'] .= ' align' . $instance['align'];
     201                }
     202
     203                if ( $is_responsive ) {
     204                        $img_attrs['style'] = 'width: 100%; height: auto;';
     205                }
     206
     207                $image = wp_get_attachment_image( $attachment->ID, $instance['size'], false, $img_attrs );
     208
     209                if ( ! $has_caption ) {
     210                        return $image;
     211                }
     212
     213                $fig_attrs = array(
     214                        'id'      => $widget_id . '-caption',
     215                        'width'   => get_option( $instance['size'] . '_size_w'),
     216                        'align'   => $instance['align'],
     217                        'caption' => $attachment->post_excerpt
     218                );
     219
     220                $figure = img_caption_shortcode( $fig_attrs, $image );
     221
     222                return $figure;
     223        }
     224
     225        /**
     226         * Renders an audio attachment preview.
     227         *
     228         * @since 4.8.0
     229         * @access private
     230         *
     231         * @param WP_Post $attachment Attachment object.
     232         * @param string  $widget_id  Widget ID.
     233         * @param array   $instance   Current widget instance arguments.
     234         * @return string
     235         */
     236        private function render_audio( $attachment, $widget_id, $instance ) {
     237                if ( in_array( $instance['link'], array( 'file', 'post' ) ) ) {
     238                        return $this->create_link_for( $attachment, $instance['link'] );
     239                }
     240
     241                return wp_audio_shortcode( array(
     242                        'src' => wp_get_attachment_url( $attachment->ID )
     243                ) );
     244        }
     245
     246        /**
     247         * Renders a video attachment preview.
     248         *
     249         * @since 4.8.0
     250         * @access private
     251         *
     252         * @param WP_Post $attachment Attachment object.
     253         * @param string  $widget_id  Widget ID.
     254         * @param array   $instance   Current widget instance arguments.
     255         * @return string
     256         */
     257        private function render_video( $attachment, $widget_id, $instance ) {
     258                if ( in_array( $instance['link'], array( 'file', 'post' ) ) ) {
     259                        return $this->create_link_for( $attachment, $instance['link'] );
     260                }
     261
     262                return wp_video_shortcode( array(
     263                        'src' => wp_get_attachment_url( $attachment->ID )
     264                ) );
     265        }
     266
     267        /**
     268         * Get styles for responsifying the widget
     269         *
     270         * @since 4.8.0
     271         * @access private
     272         *
     273         * @param WP_Post $attachment Attachment object.
     274         * @param string  $widget_id  Widget ID.
     275         * @param array   $instance   Current widget instance arguments.
     276         * @return string styles for responsive media
     277         */
     278        private function get_responsive_style( $attachment, $widget_id, $instance ) {
     279                if ( empty( $instance['scale'] ) || wp_attachment_is( 'audio', $attachment ) ) {
     280                        return;
     281                }
     282
     283                $output = '<style type="text/css">';
     284
     285                if ( wp_attachment_is_image( $attachment ) ) {
     286                        $output .= "#{$widget_id}-caption{ width: 100% !important; }";
     287                }
     288
     289                if ( wp_attachment_is( 'video', $attachment ) ) {
     290                        $output .= "#{$widget_id} .wp-video{ width: 100% !important; }";
     291                }
     292
     293                $output .= '</style>';
     294
     295                return $output;
     296        }
     297
     298
     299        /**
     300         * Creates and returns a link for an attachment
     301         *
     302         * @param WP_Post $attachment Attachment object.
     303         * @param string  $type       link type.
     304         * @return string
     305         */
     306        private function create_link_for( $attachment, $type = '' ) {
     307                $url = '#';
     308                if ( 'file' === $type ) {
     309                        $url = wp_get_attachment_url( $attachment->ID );
     310                } elseif ( 'post' === $type ) {
     311                        $url = get_attachment_link( $attachment->ID );
     312                }
     313
     314                return '<a href="' . $url  . '">' . $attachment->post_title . '</a>';
     315        }
     316
     317        /**
     318         * Outputs the settings update form.
     319         *
     320         * @since 4.8.0
     321         * @access public
     322         *
     323         * @param array $saved_instance Current settings.
     324         * @return string Default return is 'noform'.
     325         */
     326        public function form( $saved_instance ) {
     327                $defaults = array(
     328                        'title'  => '',
     329                        // Attachment props.
     330                        'id'     => '',
     331                        'align'  => '',
     332                        'size'   => '',
     333                        'link'   => '',
     334                        'scale'  => '',
     335                );
     336
     337                $instance   = wp_parse_args( (array) $saved_instance, $defaults );
     338                $attachment = empty( $instance['id'] ) ? null : get_post( $instance['id'] );
     339                $widget_id  = $this->id;
     340                ?>
     341                <div class="<?php echo esc_attr( $widget_id ); ?> media-widget-preview">
     342                        <p>
     343                                <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:' ); ?></label>
     344                                <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $instance['title'] ); ?>" />
     345                        </p>
     346
     347                        <p>
     348                                <?php esc_html_e( 'Add an image, video, or audio to your sidebar.' ); ?>
     349                        </p>
     350
     351                        <div class="media-widget-admin-preview" id="<?php echo $widget_id; ?>">
     352                        <?php
     353                                if ( $attachment ) {
     354                                        echo $this->render_media( $attachment, $widget_id, $instance );
     355                                        echo $this->get_responsive_style( $attachment, $widget_id, $instance );
     356                                }
     357                        ?>
     358                        </div>
     359
     360                        <p class="extras">
     361                                <input
     362                                        type="checkbox"
     363                                        name="<?php echo $this->get_field_name( 'scale' ) ?>"
     364                                        id="<?php echo $this->get_field_id( 'scale' )?>"
     365                                        value="on"
     366                                        <?php checked( 'on', $instance[ 'scale' ]  ); ?>
     367                                />
     368                                <label for="<?php echo $this->get_field_id( 'scale' )?>">
     369                                        <?php esc_html_e( 'Scale to fit width' ); ?>
     370                                </label>
     371                        </p>
     372
     373                        <p>
     374                                <button type="button" data-id="<?php echo esc_attr( $widget_id ); ?>" class="button select-media widefat">
     375                                        <?php $attachment ? esc_html_e( 'Change Media' ) : esc_html_e( 'Select Media' ); ?>
     376                                </button>
     377                        </p>
     378
     379                        <?php
     380                        // Use hidden form fields to capture the attachment details from the media manager.
     381                        unset( $instance['title'], $instance['scale'] );
     382                        ?>
     383
     384                        <?php foreach ( $instance as $name => $value ) : ?>
     385                                <input type="hidden" id="<?php echo esc_attr( $this->get_field_id( $name ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $name ) ); ?>" value="<?php echo esc_attr( $value ); ?>" />
     386                        <?php endforeach; ?>
     387                </div>
     388                <?php
     389        }
     390
     391        /**
     392         * Registers the stylesheet for handling the widget in the back-end.
     393         *
     394         * @since 4.8.0
     395         * @access public
     396         */
     397        public function enqueue_admin_styles() {
     398                wp_enqueue_style( 'wp-media-widget' );
     399        }
     400
     401        /**
     402         * Registers the scripts for handling the widget in the back-end.
     403         *
     404         * @since 4.8.0
     405         * @access public
     406         */
     407        public function enqueue_admin_scripts() {
     408                global $pagenow;
     409
     410                // Bail if we are not in the widgets or customize screens.
     411                if ( 'widgets.php' !== $pagenow && ! is_customize_preview() ) {
     412                        return;
     413                }
     414
     415                // Load the required media files for the media manager.
     416                wp_enqueue_media();
     417
     418                wp_enqueue_script( 'wp-media-widget' );
     419
     420                add_action( 'admin_print_footer_scripts', array( $this, 'admin_print_footer_scripts' ) );
     421        }
     422
     423        /**
     424         * Prints footer scripts.
     425         *
     426         * @since 4.8.0
     427         * @access public
     428         */
     429        public function admin_print_footer_scripts() {
     430                ?>
     431                <script type="text/html" id="tmpl-wp-media-widget-audio">
     432                <?php wp_underscore_audio_template() ?>
     433                </script>
     434
     435                <script type="text/html" id="tmpl-wp-media-widget-video">
     436                <?php wp_underscore_video_template() ?>
     437                </script>
     438
     439                <?php
     440        }
     441
     442        /**
     443         * Enqueue mediaelement script and style if in need,
     444         * so the first instance of the media widget can properly handle media elements.
     445         *
     446         * @since 4.8.0
     447         * @access private
     448         */
     449        private function enqueue_mediaelement_script() {
     450                $audio_library = apply_filters( 'wp_audio_shortcode_library', 'mediaelement' );
     451                $video_library = apply_filters( 'wp_video_shortcode_library', 'mediaelement' );
     452
     453                if ( ! in_array( 'mediaelement', array( $audio_library, $video_library ) ) ) {
     454                        return;
     455                }
     456
     457                wp_enqueue_style( 'wp-mediaelement' );
     458                wp_enqueue_script( 'wp-mediaelement' );
     459        }
     460}