WordPress.org

Make WordPress Core

Ticket #32417: 32417.13.diff

File 32417.13.diff, 26.5 KB (added by gonom9, 9 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}