This repository has been archived by the owner. It is now read-only.

Gallery Widget #120

Merged
merged 43 commits into from Sep 19, 2017
Commits
Jump to file or symbol
Failed to load files and symbols.
+323 −0
Diff settings

Always

Just for now

Next

[WIP] Gallery Widget

First pass.

Fixes #62.
  • Loading branch information...
obenland committed May 2, 2017
commit 634f3cdae0015c24983bb61d7cf8f33cb078c17a
View
@@ -41,6 +41,7 @@ function wp32417_default_scripts( WP_Scripts $scripts ) {
$scripts->add_inline_script( 'media-widgets', 'wp.mediaWidgets.init();', 'after' );
$scripts->add( 'media-audio-widget', plugin_dir_url( __FILE__ ) . 'wp-admin/js/widgets/media-audio-widget.js', array( 'media-widgets', 'media-audiovideo' ) );
$scripts->add( 'media-gallery-widget', plugin_dir_url( __FILE__ ) . 'wp-admin/js/widgets/media-gallery-widget.js', array( 'media-widgets' ) );
$scripts->add( 'media-image-widget', plugin_dir_url( __FILE__ ) . 'wp-admin/js/widgets/media-image-widget.js', array( 'media-widgets' ) );
$scripts->add( 'media-video-widget', plugin_dir_url( __FILE__ ) . 'wp-admin/js/widgets/media-video-widget.js', array( 'media-widgets', 'media-audiovideo' ) );
@@ -88,9 +89,11 @@ function wp32417_twentyten_styles() {
function wp32417_widgets_init() {
require_once( dirname( __FILE__ ) . '/wp-includes/widgets/class-wp-widget-media.php' );
require_once( dirname( __FILE__ ) . '/wp-includes/widgets/class-wp-widget-media-audio.php' );
require_once( dirname( __FILE__ ) . '/wp-includes/widgets/class-wp-widget-media-gallery.php' );
require_once( dirname( __FILE__ ) . '/wp-includes/widgets/class-wp-widget-media-image.php' );
require_once( dirname( __FILE__ ) . '/wp-includes/widgets/class-wp-widget-media-video.php' );
register_widget( 'WP_Widget_Media_Gallery' );
register_widget( 'WP_Widget_Media_Image' );
register_widget( 'WP_Widget_Media_Video' );
register_widget( 'WP_Widget_Media_Audio' );
@@ -0,0 +1,154 @@
/* eslint consistent-this: [ "error", "control" ] */
(function( component ) {
'use strict';
var GalleryWidgetModel, GalleryWidgetControl, GalleryDetailsMediaFrame;
/**
* Custom gallery details frame.
*
* @class GalleryDetailsMediaFrame
* @constructor
*/
GalleryDetailsMediaFrame = wp.media.view.MediaFrame.Post.extend( {
/**
* Create the default states.
*
* @returns {void}
*/
createStates: function createStates() {
this.states.add([
new wp.media.controller.Library({
id: 'gallery',
title: wp.media.view.l10n.createGalleryTitle,
priority: 40,
toolbar: 'main-gallery',
filterable: 'uploaded',
multiple: 'add',
editable: false,
library: wp.media.query( _.defaults({
type: 'image'
}, this.options.library ) )
}),
// Gallery states.
new wp.media.controller.GalleryEdit({
library: this.options.selection,
editing: this.options.editing,
menu: 'gallery'
}),
new wp.media.controller.GalleryAdd()
]);
}
} );
/**
* Gallery widget model.
*
* See WP_Widget_Gallery::enqueue_admin_scripts() for amending prototype from PHP exports.
*
* @class GalleryWidgetModel
* @constructor
*/
GalleryWidgetModel = component.MediaWidgetModel.extend( {} );
/**
* Gallery widget control.
*
* See WP_Widget_Gallery::enqueue_admin_scripts() for amending prototype from PHP exports.
*
* @class GalleryWidgetControl
* @constructor
*/
GalleryWidgetControl = component.MediaWidgetControl.extend( {
/**
* Render preview.
*
* @returns {void}
*/
renderPreview: function renderPreview() {
var control = this, previewContainer, previewTemplate;
previewContainer = control.$el.find( '.media-widget-preview' );
previewTemplate = wp.template( 'wp-media-widget-gallery-preview' );
previewContainer.html( previewTemplate( _.extend( control.previewTemplateProps.toJSON() ) ) );
},
/**
* Open the media select frame to chose an item.
*
* @returns {void}
*/
selectMedia: function selectMedia() {
var control = this, selection, mediaFrame, defaultSync, mediaFrameProps;
if ( control.isSelected() && 0 !== control.model.get( 'attachment_id' ) ) {
selection = new wp.media.model.Selection( [ control.selectedAttachment ] );
} else {
selection = null;
}
mediaFrameProps = control.mapModelToMediaFrameProps( control.model.toJSON() );
if ( mediaFrameProps.size ) {
control.displaySettings.set( 'size', mediaFrameProps.size );

This comment has been minimized.

@westonruter

westonruter Sep 16, 2017

Contributor

This doesn't seem to be used?

@westonruter

westonruter Sep 16, 2017

Contributor

This doesn't seem to be used?

}
mediaFrame = new GalleryDetailsMediaFrame({
frame: 'select',
text: control.l10n.add_to_widget,
selection: selection,
mimeType: control.mime_type,
selectedDisplaySettings: control.displaySettings,
showDisplaySettings: control.showDisplaySettings,
metadata: mediaFrameProps,
state: 'gallery'
});
wp.media.frame = mediaFrame; // See wp.media().
// Handle selection of a media item.
mediaFrame.on( 'reset', function onInsert() {
var state = mediaFrame.state();
console.log(wp.media.controller.state().get('selection'));
});
// Disable syncing of attachment changes back to server. See <https://core.trac.wordpress.org/ticket/40403>.
defaultSync = wp.media.model.Attachment.prototype.sync;
wp.media.model.Attachment.prototype.sync = function rejectedSync() {
return $.Deferred().rejectWith( this ).promise();
};
mediaFrame.on( 'close', function onClose() {
wp.media.model.Attachment.prototype.sync = defaultSync;
});
mediaFrame.$el.addClass( 'media-widget' );
mediaFrame.open();
// Clear the selected attachment when it is deleted in the media select frame.

This comment has been minimized.

@timmyc

timmyc Aug 17, 2017

Collaborator

Not sure we need this logic here... but will test to confirm

@timmyc

timmyc Aug 17, 2017

Collaborator

Not sure we need this logic here... but will test to confirm

This comment has been minimized.

@westonruter

westonruter Sep 16, 2017

Contributor

It was needed. I confirmed.

@westonruter

westonruter Sep 16, 2017

Contributor

It was needed. I confirmed.

if ( selection ) {
selection.on( 'destroy', function onDestroy( attachment ) {
if ( control.model.get( 'attachment_id' ) === attachment.get( 'id' ) ) {
control.model.set({
attachment_id: 0,
url: ''
});
}
});
}
/*
* Make sure focus is set inside of modal so that hitting Esc will close
* the modal and not inadvertently cause the widget to collapse in the customizer.
*/
mediaFrame.$el.find( ':focusable:first' ).focus();
}
} );
// Exports.
component.controlConstructors.media_gallery = GalleryWidgetControl;
component.modelConstructors.media_gallery = GalleryWidgetModel;
})( wp.mediaWidgets );
@@ -0,0 +1,166 @@
<?php
/**
* Widget API: WP_Widget_Media_Gallery class
*
* @package WordPress
* @subpackage Widgets
* @since 4.8.0
*/
/**
* Core class that implements a gallery widget.
*
* @since 4.8.0
*
* @see WP_Widget
*/
class WP_Widget_Media_Gallery extends WP_Widget_Media {
/**
* Constructor.
*
* @since 4.8.0
* @access public
*/
public function __construct() {
parent::__construct( 'media_gallery', __( 'Gallery' ), array(
'description' => __( 'Displays an image gallery.' ),
'mime_type' => 'image',
) );
$this->l10n = array_merge( $this->l10n, array(
'no_media_selected' => __( 'No images selected' ),
'select_media' => _x( 'Select Images', 'label for button in the gallery widget; should not be longer than ~13 characters long' ),
'change_media' => _x( 'Add Image', 'label for button in the gallery widget; should not be longer than ~13 characters long' ),
'edit_media' => _x( 'Edit Gallery', 'label for button in the gallery widget; should not be longer than ~13 characters long' ),
'missing_attachment' => sprintf(
/* translators: placeholder is URL to media library */
__( 'We can&#8217;t find that gallery. Check your <a href="%s">media library</a> and make sure it wasn&#8217;t deleted.' ),
esc_url( admin_url( 'upload.php' ) )
),
'media_library_state_multi' => '',
'media_library_state_single' => '',
) );
}
/**
* Get schema for properties of a widget instance (item).
*
* @since 4.8.0
* @access public
*
* @see WP_REST_Controller::get_item_schema()
* @see WP_REST_Controller::get_additional_fields()
* @link https://core.trac.wordpress.org/ticket/35574
* @return array Schema for properties.
*/
public function get_instance_schema() {
return array_merge(
parent::get_instance_schema(),

This comment has been minimized.

@timmyc

timmyc Aug 17, 2017

Collaborator

get_instance_schema() here will return title, attachment_id, and url. We do need the title, but not attachment_id nor url. Should we even call the parent method here, or just simply add in the title bits directly?

@timmyc

timmyc Aug 17, 2017

Collaborator

get_instance_schema() here will return title, attachment_id, and url. We do need the title, but not attachment_id nor url. Should we even call the parent method here, or just simply add in the title bits directly?

array(
'ids' => array(
'type' => 'array',
'default' => array(),
),
'columns' => array(
'type' => 'integer',
'default' => 3,
),
'size' => array(
'type' => 'string',
'enum' => array_merge( get_intermediate_image_sizes(), array( 'full', 'custom' ) ),
'default' => 'thumbnail',
),
'link' => array(
'type' => 'string',
'default' => '',
'format' => 'uri',
'sanitize_callback' => 'esc_url',
'should_preview_update' => false,
),
)
);
}
/**
* Render the media on the frontend.
*
* @since 4.8.0
* @access public
*
* @param array $instance Widget instance props.
* @return void
*/
public function render_media( $instance ) {
$instance = array_merge( wp_list_pluck( $this->get_instance_schema(), 'default' ), $instance );
echo gallery_shortcode( array(
'ids' => $instance['ids'],
) );
}
/**
* Loads the required media files for the media manager and scripts for media widgets.
*
* @since 4.8.0
* @access public
*/
public function enqueue_admin_scripts() {
parent::enqueue_admin_scripts();
$handle = 'media-gallery-widget';
wp_enqueue_script( $handle );
$exported_schema = array();
foreach ( $this->get_instance_schema() as $field => $field_schema ) {
$exported_schema[ $field ] = wp_array_slice_assoc( $field_schema, array( 'type', 'default', 'enum', 'minimum', 'format', 'media_prop', 'should_preview_update' ) );
}
wp_add_inline_script(
$handle,
sprintf(
'wp.mediaWidgets.modelConstructors[ %s ].prototype.schema = %s;',
wp_json_encode( $this->id_base ),
wp_json_encode( $exported_schema )
)
);
wp_add_inline_script(
$handle,
sprintf(
'
wp.mediaWidgets.controlConstructors[ %1$s ].prototype.mime_type = %2$s;
_.extend( wp.mediaWidgets.controlConstructors[ %1$s ].prototype.l10n, %3$s );
',
wp_json_encode( $this->id_base ),
wp_json_encode( $this->widget_options['mime_type'] ),
wp_json_encode( $this->l10n )
)
);
}
/**
* Render form template scripts.
*
* @since 4.8.0
* @access public
*/
public function render_control_template_scripts() {
parent::render_control_template_scripts();
?>
<script type="text/html" id="tmpl-wp-media-widget-gallery-preview">
<# var describedById = 'describedBy-' + String( Math.random() ); #>
<# if ( data.error && 'missing_attachment' === data.error ) { #>

This comment has been minimized.

@timmyc

timmyc Aug 17, 2017

Collaborator

Looks like we never set the missing_attachment error in this widget so we could likely remove this logic.

@timmyc

timmyc Aug 17, 2017

Collaborator

Looks like we never set the missing_attachment error in this widget so we could likely remove this logic.

<div class="notice notice-error notice-alt notice-missing-attachment">
<p><?php echo $this->l10n['missing_attachment']; ?></p>
</div>
<# } else { #>
<div class="attachment-media-view">
<p class="placeholder"><?php echo esc_html( $this->l10n['no_media_selected'] ); ?></p>
</div>
<# } #>
</script>
<?php
}
}
ProTip! Use n and p to navigate between commits in a pull request.