Skip to content

Instantly share code, notes, and snippets.

@igorbenic
Last active April 2, 2020 03:49
Show Gist options
  • Save igorbenic/6f950d98aa037d3923939213d8803d79 to your computer and use it in GitHub Desktop.
Save igorbenic/6f950d98aa037d3923939213d8803d79 to your computer and use it in GitHub Desktop.
How to Create a Sortable WordPress Gallery | http://www.ibenic.com/create-sortable-wordpress-gallery/
.sortable_wordpress_gallery li.attachment {
width: 141px;
height: 141px;
}
.sortable_wordpress_gallery {
display: block;
}
.sortable_wordpress_gallery:after {
display: table;
content: '';
clear: both;
}
function sortable_image_gallery_media( $imageContainer, $imageInput ) {
'use strict';
var file_frame;
/**
* If an instance of file_frame already exists, then we can open it
* rather than creating a new instance.
*/
if ( undefined !== file_frame ) {
file_frame.open();
return;
}
/**
* If we're this far, then an instance does not exist, so we need to
* create our own.
*
* Here, use the wp.media library to define the settings of the Media
* Uploader. We're opting to use the 'post' frame which is a template
* defined in WordPress core and are initializing the file frame
* with the 'insert' state.
*
* We're also not allowing the user to select more than one image.
*/
file_frame = wp.media({
multiple: true,
});
file_frame.on('open',function() {
var selection = file_frame.state().get('selection');
var ids = $imageInput.val().split(',');
ids.forEach(function(id) {
var attachment = wp.media.attachment(id);
attachment.fetch();
selection.add( attachment ? [ attachment ] : [] );
});
});
// When an image is selected in the media frame...
file_frame.on( 'select', function() {
// Get media attachment details from the frame state
var attachments = file_frame.state().get('selection').toJSON();
var attachmentIDs = [];
$imageContainer.empty();
var $galleryID = $imageContainer.attr("id");
for( var i = 0; i < attachments.length; i++ ) {
if( attachments[ i ].type == "image" ) {
attachmentIDs.push( attachments[ i ].id );
$imageContainer.append( sortable_gallery_image_create( attachments[ i ], $galleryID ) );
}
}
$imageInput.val( attachmentIDs.join() );
sortable_gallery_image_remove();
});
// Now display the actual file_frame
file_frame.open();
}
function sortable_gallery_image_create( $attachment, $galleryID ) {
var $output = '<li tabindex="0" role="checkbox" aria-label="' + $attachment.title + '" aria-checked="true" data-id="' + $attachment.id + '" class="attachment save-ready selected details">';
$output += '<div class="attachment-preview js--select-attachment type-image subtype-jpeg portrait">';
$output += '<div class="thumbnail">'
$output += '<div class="centered">'
$output += '<img src="' + $attachment.sizes.thumbnail.url + '" draggable="false" alt="">'
$output += '</div>'
$output += '</div>'
$output += '</div>'
$output += '<button type="button" data-gallery="#' + $galleryID + '" class="button-link check asap-image-remove" tabindex="0"><span class="media-modal-icon"></span><span class="screen-reader-text">Deselect</span></button>'
$output += '</li>';
return $output;
}
function sortable_gallery_image_remove( ) {
jQuery(".remove-sortable-wordpress-gallery-image").on( 'click', function(){
$id = jQuery(this).parent().attr("data-id");
$gallery = jQuery(this).attr("data-gallery");
$imageInput = jQuery( $gallery + "_input" );
jQuery(this).parent().remove();
var ids = $imageInput.val().split(',');
$idIndex = ids.indexOf( $id );
if( $idIndex >= 0 ) {
ids.splice( $idIndex, 1 );
$imageInput.val( ids.join() );
}
});
}
(function($){
$(document).ready(function(){
var imageButton = $(".add-sortable-wordpress-gallery");
sortable_gallery_image_remove();
imageButton.each( function(){
var galleryID = $(this).attr("data-gallery");
var imageContainer = $( galleryID );
var imageInput = $( galleryID + "_input" );
imageContainer.sortable();
imageContainer.on( "sortupdate", function( event, ui ) {
$ids = [];
$images = imageContainer.children("li");
$images.each( function(){
$ids.push( $(this).attr("data-id") );
});
imageInput.val($ids.join());
} );
$(this).on('click', function(){
sortable_image_gallery_media( imageContainer, imageInput );
});
});
});
})(jQuery)
<?php
add_filter( 'sortable_wordpress_galleries', 'add_sortable_gallery' );
function add_sortable_gallery( $galleries ) {
$galleries[] = array(
'class' => 'Sortable_WordPress_Gallery',
'id' => 'post-metabox',
'title' => 'Sortable Gallery'
);
return $galleries;
}
<?php
add_filter( 'sortable_wordpress_galleries', 'add_sortable_gallery' );
function add_sortable_gallery( $galleries ) {
$galleries[] = array(
'class' => 'Sortable_WordPress_Gallery',
'id' => 'post-metabox',
'title' => 'Sortable Gallery'
);
$galleries[] = array(
'class' => 'Sortable_WordPress_Gallery',
'id' => 'post-metabox-2',
'title' => 'Sortable Gallery-2'
);
return $galleries;
}
<?php
add_filter( 'sortable_wordpress_gallery_post-metabox-2_post_types', 'second_gallery_only_on_page' );
function second_gallery_only_on_page( $post_types ) {
return array( 'page' );
}
<?php
/**
* Sortable WordPress Gallery class to create gallery metabox and save it
*/
class Sortable_WordPress_Gallery {
// ...
/**
* Hook into the appropriate actions when the class is constructed.
*/
public function __construct( $id, $title = '', $context = 'advanced', $priority = 'high' ) {
// ID is required
if( $id == '' ) {
return;
}
$this->id = $id;
// Create title from ID if not provided
if( $title == '' ) {
$this->title = ucfirst( $id );
} else {
$this->title = $title;
}
// Only valid context can be changed
$available_context = array(
'advanced',
'side',
'normal');
if( in_array( $context, $available_context ) ) {
$this->context = $context;
}
// Only valid priorty can be changed
$available_priority = array(
'default',
'high',
'low');
if( in_array( $priority, $available_priority ) ) {
$this->priority = $priority;
}
add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
add_action( 'save_post', array( $this, 'save' ) );
add_filter( 'the_content', array( $this, 'render' ) );
}
// ...
}
<?php
/**
* Sortable WordPress Gallery class to create gallery metabox and save it
*/
class Sortable_WordPress_Gallery {
// ...
/**
* Adds the meta box container.
*/
public function add_meta_box( $post_type ) {
// Limit meta box to certain post types.
// Can be extended using filter 'sortable_wordpress_gallery_post_types' or
// using a dynamic filter 'sortable_wordpress_gallery_METABOX-ID_post_types'
$post_types = apply_filters( 'sortable_wordpress_gallery_post_types', array( 'post' ) );
$post_types = apply_filters( 'sortable_wordpress_gallery_' . $this->id . '_post_types', $post_types );
if ( in_array( $post_type, $post_types ) ) {
add_meta_box(
$this->id,
$this->title,
array( $this, 'render_meta_box_content' ),
$post_type,
$this->context,
$this->priority
);
}
}
// ...
}
<?php
/**
* Sortable WordPress Gallery class to create gallery metabox and save it
*/
class Sortable_WordPress_Gallery {
// ...
/**
* Render Meta Box content.
*
* @param WP_Post $post The post object.
*/
public function render_meta_box_content( $post ) {
// Add an nonce field so we can check when saving
wp_nonce_field( $this->id . '_metabox', $this->id . '_metabox_nonce' );
// Get the gallery saved data
$sortable_gallery = get_post_meta( $post->ID, '_' . $this->id . '_sortable_wordpress_gallery', true );
?>
<table class="table">
<tr>
<th style="vertical-align: top;">
<?php _e( 'Slider Images', 'your_text_domain' ); ?>
</th>
<td>
<!-- Creating a dynamic ID using the metabox ID for JavaScript-->
<ul id="<?php echo $this->id; ?>_sortable_wordpress_gallery" class="sortable_wordpress_gallery">
<?php
// Getting all the image IDs by creating an array from string ( 1,3,5 => array( 1, 3, 5) )
$gallery = explode(",", $sortable_gallery );
// If there is any ID, create the image for it
if( count( $gallery ) > 0 && $gallery[0] != '' ) {
foreach ( $gallery as $attachment_id ) {
// Create a LI elememnt
$output = '<li tabindex="0" role="checkbox" aria-label="' . get_the_title( $attachment_id ) . '" aria-checked="true" data-id="' . $attachment_id . '" class="attachment save-ready selected details">';
// Create a container for the image. (Copied from the WP Media Library Modal to use the same styling)
$output .= '<div class="attachment-preview js--select-attachment type-image subtype-jpeg portrait">';
$output .= '<div class="thumbnail">';
$output .= '<div class="centered">';
// Get the URL to that image thumbnail
$output .= '<img src="' . wp_get_attachment_thumb_url( $attachment_id ) . '" draggable="false" alt="">';
$output .= '</div>';
$output .= '</div>';
$output .= '</div>';
// Add the button to remove this image if wanted (we set the data-gallery to target the correct gallery if there are more than one)
$output .= '<button type="button" data-gallery="#' . $this->id . '_sortable_wordpress_gallery" class="button-link check remove-sortable-wordpress-gallery-image" tabindex="0"><span class="media-modal-icon"></span><span class="screen-reader-text">Deselect</span></button>';
$output .= '</li>';
echo $output;
}
}
?>
</ul>
<!-- Hidden input used to save the gallery image IDs into the database -->
<!-- We are also creating dynamic IDs here so that we can easily target them in JavaScript -->
<input type="hidden" id="<?php echo $this->id; ?>_sortable_wordpress_gallery_input" name="_<?php echo $this->id; ?>_sortable_wordpress_gallery" value="<?php echo $sortable_gallery; ?>" />
<!-- Button used to open the WordPress Media Library Modal -->
<button type="button" class="button button-primary add-sortable-wordpress-gallery" data-gallery="#<?php echo $this->id; ?>_sortable_wordpress_gallery"><?php _e( 'Add Images', 'your_text_domain' ); ?></button>
</td>
</tr>
</table>
<?php
}
// ...
}
<?php
/**
* Sortable WordPress Gallery class to create gallery metabox and save it
*/
class Sortable_WordPress_Gallery {
// ...
/**
* Save the meta when the post is saved.
*
* @param int $post_id The ID of the post being saved.
*/
public function save( $post_id ) {
/*
* We need to verify this came from the our screen and with proper authorization,
* because save_post can be triggered at other times.
*/
// Check if our nonce is set.
if ( ! isset( $_POST[ $this->id . '_metabox_nonce'] ) ) {
return $post_id;
}
$nonce = $_POST[ $this->id . '_metabox_nonce'];
// Verify that the nonce is valid.
if ( ! wp_verify_nonce( $nonce, $this->id . '_metabox' ) ) {
return $post_id;
}
/*
* If this is an autosave, our form has not been submitted,
* so we don't want to do anything.
*/
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
// Check the user's permissions.
if ( 'page' == $_POST['post_type'] ) {
if ( ! current_user_can( 'edit_page', $post_id ) ) {
return $post_id;
}
} else {
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return $post_id;
}
}
/* OK, it's safe for us to save the data now. */
$gallery = sanitize_text_field( $_POST[ '_' . $this->id . '_sortable_wordpress_gallery' ] );
// Update the meta field.
update_post_meta( $post_id, '_' . $this->id . '_sortable_wordpress_gallery', $gallery );
}
// ...
}
<?php
/**
* Sortable WordPress Gallery class to create gallery metabox and save it
*/
class Sortable_WordPress_Gallery {
// ...
/**
* Rendering the gallery
*/
public function render( $content ) {
global $post;
// Get our registered post types
$post_types = apply_filters( 'sortable_wordpress_gallery_post_types', array( 'post' ) );
$post_types = apply_filters( 'sortable_wordpress_gallery_' . $this->id . '_post_types', $post_types );
// Get current post type
$this_post_type = get_post_type( $post );
// If the current post type is also a registered post type, create the gallery
if( in_array( $this_post_type, $post_types ) ) {
// Get all the image IDs
$gallery_images = get_post_meta( $post->ID, '_' . $this->id . '_sortable_wordpress_gallery', true );
if( $gallery_images != '' ) {
// If the data retrieved is not empty, create an array
$gallery_images_array = explode( ',', $gallery_images );
//Create a gallery container with the 3 column layout
$content .= '<div class="gallery gallery-columns-3">';
// For each image ID, create the gallery image
foreach ( $gallery_images_array as $image_id ) {
$html = wp_get_attachment_image( $image_id );
if( $html == '' ) {
continue;
}
$content .= '<figure class="gallery-item">';
$content .= '<a href="' . get_permalink( $image_id ) . '" target="_blank">';
$content .= $html;
$content .= '</a>';
$content .= '</figure>';
}
$content .= '</div>';
}
}
return $content;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment