Last active
April 9, 2019 14:51
-
-
Save westonruter/854aba61243ef08a2e3a2a0e721930dc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Widget API: WP_Media_Widget class | |
* | |
* @package WordPress | |
* @subpackage Widgets | |
* @since 4.8.0 | |
*/ | |
/** | |
* Core class that implements a media widget. | |
* | |
* @since 4.8.0 | |
* | |
* @see WP_Widget | |
*/ | |
class WP_Media_Widget extends WP_Widget { | |
/** | |
* Constructor. | |
* | |
* @since 4.8.0 | |
* @access public | |
* | |
* @param string $id_base Optional Base ID for the widget, lowercase and unique. If left empty, | |
* a portion of the widget's class name will be used Has to be unique. | |
* @param string $name Optional. Name for the widget displayed on the configuration page. | |
* Default empty. | |
* @param array $widget_options Optional. Widget options. See wp_register_sidebar_widget() for | |
* information on accepted arguments. Default empty array. | |
* @param array $control_options Optional. Widget control options. See wp_register_widget_control() | |
* for information on accepted arguments. Default empty array. | |
*/ | |
public function __construct( $id_base = '', $name = '', $widget_options = array(), $control_options = array() ) { | |
$widget_opts = wp_parse_args( $widget_options, array( | |
'classname' => 'widget_media', | |
'description' => __( 'Display media such as images, video, or audio in your sidebar.' ), | |
'customize_selective_refresh' => true, | |
) ); | |
$control_opts = wp_parse_args( $control_options, array() ); | |
parent::__construct( | |
$id_base ? $id_base : 'wp-media-widget', | |
$name ? $name : __( 'Media' ), | |
$widget_opts, | |
$control_opts | |
); | |
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) ); | |
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) ); | |
} | |
/** | |
* Displays the widget on the front-end. | |
* | |
* @since 4.8.0 | |
* @access public | |
* | |
* @see WP_Widget::widget() | |
* | |
* @param array $args Display arguments including before_title, after_title, before_widget, and after_widget. | |
* @param array $instance Saved setting from the database. | |
*/ | |
public function widget( $args, $instance ) { | |
echo $args['before_widget']; | |
if ( ! empty( $instance['title'] ) ) { | |
echo $args['before_title'] . $instance['title'] . $args['after_title']; | |
} | |
if ( ! empty( $instance['description'] ) ) { | |
echo '<p class="attachment-description align' . $instance['align'] . '">' . $instance['description'] . '</p>'; | |
} | |
if ( ! empty( $instance['link'] ) ) { | |
if ( 'file' === $instance['link'] ) { | |
$url = wp_get_attachment_url( $instance['id'] ); | |
$selectedLink = $url; | |
} else if ( 'post' === $instance['link'] ) { | |
$url = get_attachment_link( $instance['id'] ); | |
$selectedLink = $url; | |
} else { | |
$selectedLink = ''; | |
} | |
} | |
// Build the media output. | |
$media_output = ''; | |
if ( ! empty( $selectedLink ) ) { | |
$media_output .= '<a href="' . $selectedLink . '">'; | |
} | |
if ( ! empty( $instance['id'] ) ) { | |
if ( $attachment = get_post( $instance['id'] ) ) { | |
$attrs = array(); | |
if ( ! empty( $instance['title'] ) ) { | |
$attrs['title'] = $instance['title']; | |
} | |
// Image. | |
if ( wp_attachment_is_image( $attachment ) ) { | |
$media_output .= $this->get_attachment_image( $instance['id'], $instance['size'], array( | |
'id' => $args['widget_id'], | |
'align' => $instance['align'], | |
'title' => $attachment->post_title, | |
'caption' => $attachment->post_excerpt, | |
) ); | |
// Audio. | |
} elseif ( wp_attachment_is( 'audio', $attachment ) ) { | |
if ( ! empty( $selectedLink ) ) { | |
$media_output .= $attachment->post_title; | |
} else { | |
$media_output .= $this->get_attachment_audio( $attachment->ID, array() ); | |
} | |
// Video. | |
} elseif ( wp_attachment_is( 'video', $attachment ) ) { | |
if ( ! empty( $selectedLink ) ) { | |
$media_output .= $attachment->post_title; | |
} else { | |
$media_output .= $this->get_attachment_video( $attachment->ID, array() ); | |
} | |
} | |
} | |
} | |
if ( ! empty( $selectedLink ) ) { | |
$media_output .= '</a>'; | |
} | |
echo $media_output; | |
echo $args['after_widget']; | |
} | |
/** | |
* Sanitizes the widget form values as they are saved. | |
* | |
* @since 4.8.0 | |
* @access public | |
* | |
* @see WP_Widget::update() | |
* | |
* @param array $new_instance Values just sent to be saved. | |
* @param array $old_instance Previously saved values from database. | |
* @return array Updated safe values to be saved. | |
*/ | |
function update( $new_instance, $old_instance ) { | |
$instance = $old_instance; | |
// ID, title | |
$instance['id'] = (int) $new_instance['id']; | |
$instance['title'] = sanitize_text_field( $new_instance['title'] ); | |
// Everything else. | |
$instance['align'] = sanitize_text_field( $new_instance['align'] ); | |
$instance['size'] = sanitize_text_field( $new_instance['size'] ); | |
$instance['link'] = sanitize_text_field( $new_instance['link'] ); | |
return $instance; | |
} | |
/** | |
* Renders an image attachment preview. | |
* | |
* @since 4.8.0 | |
* @access public | |
* | |
* @param WP_Post $attachment Attachment object. | |
* @param string $widget_id Widget ID. | |
* @param array $instance Current widget instance arguments. | |
*/ | |
public function render_image( $attachment, $widget_id, $instance ) { | |
$attrs = array( | |
'id' => $widget_id, | |
'align' => $instance['align'], | |
'title' => $attachment->post_title, | |
'caption' => $attachment->post_excerpt, | |
); | |
// If an image id is saved for this widget, display the image using `wp_get_attachment_image()`. | |
echo '<div class="media-widget-admin-preview">'; | |
echo $this->get_attachment_image( $attachment->ID, $instance['size'], $attrs ); | |
echo '</div>'; | |
} | |
/** | |
* Get an elmeent reprensenting an image attachment | |
* | |
* @since 4.8.0 | |
* @access private | |
* | |
* @param int $attachment_id Image attachment ID. | |
* @param string $size Image size. Default value: 'medium' | |
* @param array $attrs Attributes for the markup. | |
*/ | |
private function get_attachment_image( $attachment_id, $size = 'medium', $attrs = array() ) { | |
$img_attrs = array( | |
'data-id' => $attrs['id'], | |
'title' => $attrs['title'], | |
'class' => 'image wp-image-' . $attachment_id, | |
); | |
if ( empty( $attrs['caption'] ) ) { | |
$img_attrs['class'] .= ' ' . 'align' . $attrs['align']; | |
} | |
$image = wp_get_attachment_image( $attachment_id, $size, false, $img_attrs); | |
if ( empty( $attrs['caption'] ) ) { | |
return $image; | |
} | |
$attrs['id'] .= '-caption'; | |
$attrs['width'] = get_option( $size . '_size_w' ); | |
return img_caption_shortcode( $attrs, $image ); | |
} | |
/** | |
* Renders an audio attachment preview. | |
* | |
* @since 4.8.0 | |
* @access public | |
* | |
* @param WP_Post $attachment Attachment object. | |
* @param string $widget_id Widget ID. | |
* @param array $instance Current widget instance arguments. | |
*/ | |
public function render_audio( $attachment, $widget_id, $instance ) { | |
echo '<div class="media-widget-admin-preview">'; | |
if ( 'embed' === $instance['link'] ) { | |
echo $this->get_attachment_audio( $attachment->ID ); | |
} else { | |
echo '<a href="#">' . $attachment->post_title .'</a>'; | |
} | |
echo '</div>'; | |
} | |
/** | |
* Get an audio elmeent reprensenting a video attachment | |
* | |
* @since 4.8.0 | |
* @access private | |
* | |
* @param int $attachment_id Audio attachment ID. | |
* @param array Attributes for the audio markup. | |
*/ | |
private function get_attachment_audio( $attachment_id, $attrs = array() ) { | |
$output = wp_audio_shortcode( array( | |
'src' => wp_get_attachment_url( $attachment_id ) | |
) ); | |
return $output; | |
} | |
/** | |
* Renders a video attachment preview. | |
* | |
* @since 4.8.0 | |
* @access public | |
* | |
* @param WP_Post $attachment Attachment object. | |
* @param string $widget_id Widget ID. | |
* @param array $instance Current widget instance arguments. | |
*/ | |
public function render_video( $attachment, $widget_id, $instance ) { | |
echo '<div class="media-widget-admin-preview">'; | |
if ( 'embed' === $instance['link'] ) { | |
echo $this->get_attachment_video( $attachment->ID ); | |
} else { | |
echo '<a href="#">' . $attachment->post_title .'</a>'; | |
} | |
echo '</div>'; | |
} | |
/** | |
* Get a video elmeent reprensenting a video attachment | |
* | |
* @since 4.8.0 | |
* @access private | |
* | |
* @param int $attachment_id Video attachment ID. | |
* @param array Attributes for the video markup. | |
*/ | |
private function get_attachment_video( $attachment_id, $attrs = array() ) { | |
$output = wp_video_shortcode( array( | |
'src' => wp_get_attachment_url( $attachment_id ) | |
) ); | |
return $output; | |
} | |
/** | |
* Outputs the settings update form. | |
* | |
* @since 4.8.0 | |
* @access public | |
* | |
* @param array $saved_instance Current settings. | |
* @return string Default return is 'noform'. | |
*/ | |
public function form( $saved_instance ) { | |
$defaults = array( | |
'title' => '', | |
// Attachment props. | |
'id' => '', | |
'align' => '', | |
'size' => '', | |
'link' => '', | |
); | |
$instance = wp_parse_args( (array) $saved_instance, $defaults ); | |
$attachment = empty( $instance['id'] ) ? null: get_post( $instance['id'] ); | |
$widget_id = $this->id; | |
?> | |
<div class="<?php echo esc_attr( $widget_id ); ?> media-widget-preview"> | |
<p> | |
<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:' ); ?></label> | |
<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'] ); ?>" /> | |
</p> | |
<p> | |
<?php esc_html_e( 'Add an image, video, or audio to your sidebar.' ); ?> | |
</p> | |
<?php | |
if ( $attachment ) { | |
if ( wp_attachment_is_image( $attachment ) ) { | |
$this->render_image( $attachment, $widget_id, $instance ); | |
} elseif ( wp_attachment_is( 'audio', $attachment ) ) { | |
$this->render_audio( $attachment, $widget_id, $instance ); | |
} elseif ( wp_attachment_is( 'video', $attachment ) ) { | |
$this->render_video( $attachment, $widget_id, $instance ); | |
} | |
} | |
?> | |
<p class="extras"> | |
</p> | |
<p> | |
<button data-id="<?php echo esc_attr( $widget_id ); ?>" class="button select-media widefat"> | |
<?php $attachment ? esc_html_e( 'Change Media' ) : esc_html_e( 'Select Media' ); ?> | |
</button> | |
</p> | |
<?php | |
// Use hidden form fields to capture the attachment details from the media manager. | |
unset( $instance['title'] ); | |
?> | |
<?php foreach ( $instance as $name => $value ) : ?> | |
<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 ); ?>" /> | |
<?php endforeach; ?> | |
</div> | |
<?php | |
} | |
/** | |
* Registers the stylesheet for handling the widget in the back-end. | |
* | |
* @since 4.8.0 | |
* @access public | |
*/ | |
public function enqueue_admin_styles() { | |
wp_enqueue_style( 'wp-media-widget-styles' ); | |
} | |
/** | |
* Registers the scripts for handling the widget in the back-end. | |
* | |
* @since 4.8.0 | |
* @access public | |
*/ | |
public function enqueue_admin_scripts() { | |
global $pagenow; | |
// Bail if we are not in the widgets or customize screens. | |
if ( ! ( 'widgets.php' == $pagenow || 'customize.php' == $pagenow ) ) { | |
return; | |
} | |
// Load the required media files for the media manager. | |
wp_enqueue_media(); | |
// Register, localize and enqueue custom JS. | |
wp_enqueue_script( 'wp-media-widget' ); | |
wp_localize_script( 'wp-media-widget', '_mediaWidgetl10n', | |
array( | |
'title' => __( 'Select an Image' ), | |
'button' => __( 'Insert Image' ), | |
'select-media' => __( 'Select Media' ), | |
'change-media' => __( 'Change Media' ), | |
'add-to-widget' => __( 'Add to widget' ), | |
) | |
); | |
add_action( 'admin_print_footer_scripts', array( $this, 'admin_print_footer_scripts' ) ); | |
} | |
/** | |
* Prints footer scripts. | |
* | |
* @since 4.8.0 | |
* @access public | |
*/ | |
public function admin_print_footer_scripts() { | |
?> | |
<script type="text/html" id="tmpl-wp-media-widget-audio"> | |
<?php wp_underscore_audio_template() ?> | |
</script> | |
<script type="text/html" id="tmpl-wp-media-widget-video"> | |
<?php wp_underscore_video_template() ?> | |
</script> | |
<?php | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.media-widget-preview .button { | |
text-align: center | |
} | |
.media-widget-preview .wp-caption { | |
max-width: 100%; | |
margin: 0; | |
} | |
.media-widget-preview .image { | |
height: auto; | |
max-width: 100%; | |
cursor: pointer; | |
} | |
.media-widget-preview .aligncenter { | |
display: block; | |
margin: 0 auto; | |
text-align: center | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @since 4.8.0 | |
* | |
* @package WP_Media_Widget | |
*/ | |
( function ( $ ) { | |
var frame, widgetFrame; | |
function translate( key, defaultText ) { | |
return ( window._mediaWidgetl10n && _mediaWidgetl10n[ key ] ) || defaultText; | |
} | |
frame = { | |
buttonId: '.media-widget-preview .button', | |
defaultProps: { | |
id: '', | |
align: '', | |
size: '', | |
link: '', | |
}, | |
init: function() { | |
$( frame.buttonId ) | |
.off( 'click.mediaWidget' ) | |
.on( 'click.mediaWidget', frame.openMediaManager ); | |
frame.bindImageClick(); | |
wp.mediaelement.initialize(); | |
}, | |
bindImageClick: function() { | |
$( '.media-widget-preview .image' ) | |
.off( 'click.mediaWidget' ) | |
.on( 'click.mediaWidget', frame.openMediaManager ); | |
}, | |
openMediaManager: function( event ) { | |
event.preventDefault(); | |
var widgetId = $( event.target ).data( 'id' ); | |
// Create the media frame. | |
widgetFrame = wp.media( { | |
button: { | |
text: translate( 'add-to-widget', 'Add to widget' ), // Text of the submit button. | |
}, | |
states: new wp.media.controller.Library( { | |
library: wp.media.query(), | |
title: translate( 'select-media', 'Select Media' ), // Media frame title | |
multiple: false, | |
priority: 20, | |
display: true, // attachment display setting | |
filterable: 'all', | |
} ), | |
} ); | |
// Populate previously selected media when the media frame is opened. | |
widgetFrame.on( 'open', function() { | |
var selection = widgetFrame.state().get( 'selection' ), | |
ids = $( '#widget-' + widgetId + '-id' ).val().split(','); | |
if ( ids[0] > 0 ) { | |
ids.forEach( function( id ) { | |
var attachment = wp.media.attachment( id ); | |
attachment.fetch(); | |
selection.add( attachment ? [ attachment ] : [] ); | |
} ); | |
} | |
} ); | |
// Render the attachment details. | |
widgetFrame.on( 'select', function() { | |
var props, attachment; | |
// Only try to render the attachment details if a selection was made. | |
if ( widgetFrame.state().get( 'selection' ).length > 0 ) { | |
props = widgetFrame.content.get( '.attachments-browser' ) | |
.sidebar.get( 'display' ).model.toJSON(); | |
attachment = widgetFrame.state().get( 'selection' ).first().toJSON(); | |
frame.renderFormView( widgetId, props, attachment ); | |
} | |
} ); | |
widgetFrame.open( widgetId ); | |
}, | |
/** | |
* Renders the attachment details from the media modal into the widget. | |
* | |
* @param {String} widgetId | |
* @param {Object} props Attachment Display Settings (align, link, size, etc). | |
* @param {Object} attachment Attachment Details (title, description, caption, url, sizes, etc). | |
*/ | |
renderFormView: function( widgetId, props, attachment ) { | |
// Start with container elements for the widgets page, customizer controls, and customizer preview. | |
var previewEl, | |
extras, | |
formView = $( '.' + widgetId + ', #customize-control-widget_' + widgetId + ', #' + widgetId ); | |
// The widget title bar doesn't update automatically on the Appearance > Widgets page. This fixes that problem. | |
formView.closest( '.widget' ).find( '.in-widget-title' ).html( ': ' + attachment.title ); | |
formView.find( '.attachment-description' ) | |
[ attachment.description ? 'removeClass' : 'addClass' ]('hidden') | |
.html( attachment.description ); | |
extras = formView.find( '.extras' ); | |
// Display a preview of the image in the widgets page and customizer controls. | |
extras.removeClass( 'hidden' ); | |
previewEl = formView.find( '.media-widget-admin-preview' ); | |
if ( ! previewEl ) { | |
previewEl = $( '<div class="media-widget-admin-preview />' ).insertBefore( extras ); | |
} | |
previewEl.html( frame.renderMediaElement( widgetId, props, attachment ) ); | |
if ( -1 < $.inArray( attachment.type, [ 'audio', 'video' ] ) ) { | |
wp.mediaelement.initialize(); | |
} else if ( 'image' === attachment.type ) { | |
frame.bindImageClick(); | |
} | |
// Populate form fields with selection data from the media frame. | |
_.each( _.keys( frame.defaultProps ), function ( key ) { | |
formView.find( '#widget-' + widgetId + '-' + key ).val( attachment[ key ] || props[ key ] ).trigger( 'change' ); | |
} ); | |
// Trigger a sync to update the widget in the customizer preview. | |
formView.find( '#widget-' + widgetId + '-url' ).trigger( 'change' ); | |
// Change button text | |
formView.find( frame.buttonId ).text( translate( 'change-media', 'Change Media' ) ); | |
}, | |
/** | |
* Renders the media attachment in HTML. | |
* | |
* @param {String} widgetId | |
* @param {Object} props Attachment Display Settings (align, link, size, etc). | |
* @param {Object} attachment Attachment Details (title, description, caption, url, sizes, etc). | |
*/ | |
renderMediaElement: function( widgetId, props, attachment ) { | |
var image; | |
if ( 'image' === attachment.type ) { | |
image = $( '<img />' ) | |
.addClass( 'image wp-image' + attachment.id ) | |
.attr( { | |
'data-id': widgetId, | |
src: attachment.sizes[ props.size ].url, | |
title: attachment.title, | |
alt: attachment.alt, | |
width: attachment.sizes[ props.size ].width, | |
height: attachment.sizes[ props.size ].height | |
} ); | |
if ( attachment.caption ) { | |
image = $( '<figure />' ) | |
.width( attachment.sizes[ props.size ].width ) | |
.addClass( 'wp-caption' ) | |
.attr( 'id', widgetId + '-caption' ) | |
.append( image ); | |
$( '<figcaption class="wp-caption-text" />' ).text( attachment.caption ).appendTo( image ); | |
} | |
return image.wrap( '<div />' ).parent().html(); | |
} | |
if ( 'audio' === attachment.type ) { | |
if ( 'embed' === props.link ) { | |
return wp.media.template( 'wp-media-widget-audio' )( { | |
model: { | |
src: attachment.url | |
} | |
} ); | |
} | |
return wp.html.string( { | |
tag: 'a', | |
content: attachment.title, | |
attrs: { | |
href: '#' | |
} | |
} ); | |
} | |
if ( 'video' === attachment.type ) { | |
if ( 'embed' === props.link ) { | |
return wp.media.template( 'wp-media-widget-video' )( { | |
model: { | |
src: attachment.url, | |
width: attachment.width, | |
height: attachment.height | |
} | |
} ); | |
} | |
return wp.html.string( { | |
tag: 'a', | |
content: attachment.title, | |
attrs: { | |
href: '#' | |
} | |
} ); | |
} | |
// Unknown media type | |
return ''; | |
} | |
}; | |
$( document ) | |
.ready( frame.init ) | |
.on( 'widget-added widget-updated', frame.init ); | |
window.wp = window.wp || {}; | |
window.wp.MediaWidget = frame; | |
} )( jQuery ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: WP Media Widget | |
* Version: 0.1.0 | |
* Description: Adding images to your widget areas is a common, yet currently incredibly tedious task -- you need to upload it in your media library, find the url, copy the url, and then manually add an image tag inside of a text widget. That's a lot to ask for a beginner user to do. We should include a default image widget in core to make this task easier. | |
* Author: WordPress.org | |
* Plugin URI: https://core.trac.wordpress.org/ticket/32417 | |
* Domain Path: /languages | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License, version 2 or, at | |
* your discretion, any later version, as published by the Free | |
* Software Foundation. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
*/ | |
/** | |
* Register widget scripts. | |
* | |
* @param WP_Scripts $scripts | |
*/ | |
function wp32417_default_scripts( WP_Scripts $scripts ) { | |
$scripts->add( 'wp-media-widget', plugin_dir_url( __FILE__ ) . 'wp-media-widget.js', array( 'jquery', 'media-models', 'media-views', 'wp-mediaelement' ) ); | |
} | |
add_action( 'wp_default_scripts', 'wp32417_default_scripts' ); | |
/** | |
* Register widget styles. | |
* | |
* @param WP_Styles $styles | |
*/ | |
function wp32417_default_styles( WP_Styles $styles ) { | |
$styles->add( 'wp-media-widget-styles', plugin_dir_url( __FILE__ ) . 'wp-media-widget.css', array( 'media-views' ) ); | |
} | |
add_action( 'wp_default_styles', 'wp32417_default_styles' ); | |
/** | |
* Register widget. | |
*/ | |
function wp32417_widgets_init() { | |
require_once( __DIR__ . '/class-wp-widget-media.php' ); | |
register_widget( 'WP_Media_Widget' ); | |
} | |
add_action( 'widgets_init', 'wp32417_widgets_init' ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I've cloned this over to its own dedicated GitHub project, so please push additional commits to https://github.com/xwp/wp-core-media-widgets