Created
January 15, 2024 21:05
-
-
Save doiftrue/3b2f31c422fb0c16bbc2ce6799d4d453 to your computer and use it in GitHub Desktop.
[wpkama embed] https://wp-kama.ru/9227 Ability to upload and modify post thumbnails from the posts list table in the admin panel.
This file contains 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 | |
if( ! is_admin() ){ | |
return; | |
} | |
add_action( 'admin_init', [ Kama_Post_List_Table_Thumb::class, 'init' ] ); | |
/** | |
* Ability to upload and modify post thumbnails from the posts list table in the admin panel. | |
* | |
* @author Kama (wp-kama.ru) | |
* | |
* @require PHP 7.4 | |
* | |
* @version 1.2.3 | |
*/ | |
class Kama_Post_List_Table_Thumb { | |
use Kama_Post_List_Table_Thumb__ajax_handlers; | |
/** @var array For which posts to include the code. By default, for all public ones. */ | |
private static array $post_types = [ 'post', 'handbook', 'article' ]; | |
/** @var array Post types for which setting a thumbnail re-attaches the attachment file. */ | |
private static array $re_set_attach_for_post_types = []; | |
/** @var string Meta key name. */ | |
private static string $meta_key = '_thumbnail_id'; | |
/** @var string Empty image Url. */ | |
private static string $add_img_url = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkAQM' . | |
'AAABKLAcXAAAABlBMVEUAAAC7u7s37rVJAAAAAXRSTlMAQObYZgAAACJJREFUOMtjGA' . | |
'V0BvL/G0YMr/4/CDwY0rzBFJ704o0CWgMAvyaRh+c6m54AAAAASUVORK5CYII='; | |
public static function init( $args = [] ) { | |
$post_type = self::$post_types ?: get_post_types( [ 'public' => true ], 'names' ); | |
foreach( $post_type as $ptype ){ | |
add_filter( "manage_{$ptype}_posts_columns", [ __CLASS__, 'add_image_column' ] ); | |
add_filter( "manage_{$ptype}_posts_custom_column", [ __CLASS__, 'fill_image_column' ], 10, 2 ); | |
} | |
// general access cap check for all ajax requests | |
add_filter( 'ajaxs_allow_process', static function( $allow, $action ) { | |
if( | |
str_contains( $action, Kama_Post_List_Table_Thumb::class ) | |
&& ! current_user_can( 'edit_others_posts' ) | |
){ | |
return false; | |
} | |
return $allow; | |
}, 10, 2 ); | |
} | |
public static function add_image_column( $columns ) { | |
add_action( 'admin_notices', [ __CLASS__, '_js_css_html' ] ); | |
// untitled column. | |
return array_slice( $columns, 0, 1 ) + [ 'image' => '' ] + $columns; | |
} | |
public static function fill_image_column( $colname, $post_id ){ | |
if( $colname === 'image' && current_user_can( 'edit_post', $post_id ) ){ | |
$attach_id = get_post_meta( $post_id, self::$meta_key, true ); | |
$img_src = $attach_id ? wp_get_attachment_image_url( $attach_id, 'thumbnail' ) : self::$add_img_url; | |
?> | |
<a class="pthumb thickbox" data-post_id="<?= (int) $post_id ?>" data-attach_id="<?= (int) $attach_id ?>" | |
href="/?TB_inline&inlineId=up-set-post-thumb&width=700&height=500" | |
title="Setting post thumbnail" | |
> | |
<img src="<?= esc_attr( $img_src ) ?>" alt=""/> | |
</a> | |
<?php | |
} | |
} | |
# modal window html, css and js | |
public static function _js_css_html(){ | |
// modal window scripts | |
add_thickbox(); | |
add_action( 'admin_print_footer_scripts', [ __CLASS__, '_js' ], 99 ); | |
self::_css(); | |
?> | |
<!-- modal window --> | |
<div id="up-set-post-thumb" style="display:none;"> | |
<div class="pthumb-thickbox"> | |
<script type="text/template" id="imagebox-tpl-js"> | |
<div class="imagebox" data-attach_id="{attach_id}" data-full_url="{full_url}"> | |
<img src="{attach_url}" alt="" /> | |
</div> | |
</script> | |
<div class="filters"> | |
<button class="button button-small active / post-images-js">Post Images</button> | |
<button class="button button-small / last-images-js">Last from Library</button> | |
</div> | |
<div class="full-view" style="display:none;"> | |
<div class="close"><span class="dashicons dashicons-no-alt"></span></div> | |
<img src="" alt=""> | |
</div> | |
<div class="images"></div> | |
<div class="ajax-res" style="display:none;"></div> | |
<div class="footer"> | |
<button class="button-primary / set-thumb-js">Set Thumbnail</button> | |
<button class="button / file-btn-js"><span class="dashicons dashicons-format-image" style=""></span> Upload Images</button> | |
<input type="file" name="pthumb_files[]" multiple accept="image/*" style="display:none;" /> | |
<button class="button / del-post-thumb-js"><span class="dashicons dashicons-no-alt"></span>Unset Thumbnail</button> | |
<button class="button / del-attach-js"><span class="dashicons dashicons-trash"></span>Delete File</button> | |
</div> | |
</div> | |
</div> | |
<?php | |
} | |
public static function _css(){ | |
?> | |
<style> | |
.column-image{ width:50px; text-align:center; } | |
.pthumb{ display:block; } | |
.pthumb img{ width:35px; background:#eee; border-radius:3px; cursor:pointer; } | |
.pthumb:hover img{ opacity:.7; } | |
.pthumb-thickbox{ box-sizing:border-box; } | |
.pthumb-thickbox *{ box-sizing:inherit; } | |
.pthumb-thickbox{ display:flex; flex-direction:column; height:calc(100% + 17px); margin:-2px -15px -15px; } | |
.pthumb-thickbox > *{ padding:15px; } | |
.pthumb-thickbox .images{ flex-grow:1; height:1px; overflow-y:scroll; } | |
.pthumb-thickbox .filters{ background:#eee; padding-top:5px;padding-bottom:5px; } | |
.pthumb-thickbox .filters .active{ font-weight:700; } | |
.pthumb-thickbox .imagebox{ float:left; padding:10px; margin:0 1em 1em 0; background:#eee; border:1px solid #ddd; cursor:pointer; } | |
/*.pthumb-thickbox .imagebox:nth-child(5n){ margin-right:0; }*/ | |
.pthumb-thickbox .imagebox:hover{ outline:5px solid #9ca4ac; } | |
.pthumb-thickbox .imagebox.selected{ outline:5px solid #2d3238; } | |
.pthumb-thickbox .imagebox img{ width:100px; height:100px; display:block; } | |
.pthumb-thickbox .footer{ display:flex; justify-content:space-between; height:60px; border-top:1px solid #ddd; background:#eee; box-shadow:0 0 1em #b5b9bb; z-index:1; } | |
.pthumb-thickbox .footer .dashicons{ margin-top:6px; font-size:15px; } | |
.pthumb-thickbox .ajax-res{ position:absolute; width:100%; bottom:60px; padding-right:60px; } | |
.pthumb-thickbox .ajax-res{ background:#ddeacb; color:#3d6703; } | |
.pthumb-thickbox .ajax-res.err{ background:#ffebeb; color:#951212; } | |
.pthumb-thickbox .full-view{ position:relative; flex-grow:1; max-height:100%; text-align:center; background:#7d7d7d; } | |
.pthumb-thickbox .full-view img{ max-width:100%; max-height:380px; } | |
.pthumb-thickbox .close{ position:absolute; top:0; right:0; padding:15px; background:rgba(0,0,0,.2); color:#fff; cursor:pointer; } | |
</style> | |
<?php | |
} | |
public static function _js(){ | |
?> | |
<script> | |
document.addEventListener( 'DOMContentLoaded', function(){ | |
let $thickbox = jQuery( '.pthumb-thickbox' ) | |
let $file = $thickbox.find( '[type="file"]' ) | |
let $images = $thickbox.find( '.images' ) | |
let $fullView = $thickbox.find( '.full-view' ) | |
let $filters = $thickbox.find( '.filters' ) | |
let imageboxTpl = $thickbox.find( '#imagebox-tpl-js' ).html() | |
let $cur_pthumb = null | |
const addImgSrc = '<?= self::$add_img_url ?>' | |
let showMessage = function( message, type ){ | |
let $res = $thickbox.find( '.ajax-res' ).removeClass( 'err' ) | |
$res.html( message + '<div class="close" onclick="jQuery(this).parent().slideUp(100)"><span class="dashicons dashicons-no-alt"></span></div>' ) | |
.addClass( type === 'error' ? 'err' : '' ).slideDown( 100 ) | |
setTimeout( function(){ | |
$res.slideUp( 100 ) | |
}, 25000 ) | |
}, | |
hideMessage = function(){ | |
$thickbox.find( '.ajax-res' ).slideUp( 100 ) | |
} | |
let _fillImagesBox = function( attachs ){ | |
$images.empty() | |
if( typeof attachs === 'string' ){ | |
$images.html( attachs ) | |
return | |
} | |
// go through the array of objects and add elements. | |
for( let id in attachs ){ | |
let attach = attachs[id] | |
$images.append( | |
imageboxTpl.replace( '{attach_url}', attach.thumb_url ) | |
.replace( '{attach_id}', attach.ID ) | |
.replace( '{full_url}', attach.guid ) | |
) | |
// set the current thumbnail | |
if( $cur_pthumb.data( 'attach_id' ) ){ | |
$images.find( '[data-attach_id="' + $cur_pthumb.data( 'attach_id' ) + '"]' ).addClass( 'selected' ) | |
} | |
else{ | |
$images.find( '.imagebox:first' ).addClass( 'selected' ) | |
} | |
} | |
} | |
let _loadAttachments = function( filter_name ){ | |
$images.empty() // clear images | |
$filters.find( 'button' ).removeClass( 'active' ) // clear filters | |
let data = { | |
post_id : $cur_pthumb.data( 'post_id' ), | |
cur_attach_id: $cur_pthumb.data( 'attach_id' ) | |
} | |
if( filter_name === 'last_media' ){ | |
delete data.post_id | |
$filters.find( '.last-images-js' ).addClass( 'active' ) | |
} | |
else { | |
$filters.find( '.post-images-js' ).addClass( 'active' ) | |
} | |
// AJAX request - load all images of the post | |
showMessage( 'Loading...' ) | |
ajaxs( 'Kama_Post_List_Table_Thumb::ajaxs_get_images', data, function( resp ){ | |
hideMessage() | |
if( resp.toString() === '' ) | |
_loadAttachments( 'last_media' ) | |
else | |
_fillImagesBox( resp ) | |
} ) | |
} | |
window.resetPthumbImage = function( args ){ | |
// args: post_id, attach_id, src, clear, $pthumb | |
if( ! args.$pthumb ){ | |
if( args.post_id ) args.$pthumb = jQuery( '.pthumb[data-post_id="' + args.post_id + '"]' ) | |
else if( args.attach_id ) args.$pthumb = jQuery( '.pthumb[data-attach_id="' + args.attach_id + '"]' ) | |
} | |
var new_attach_id = args.clear ? '' : args.attach_id | |
args.$pthumb.data( 'attach_id', new_attach_id ).attr( 'data-attach_id', new_attach_id ) | |
args.$pthumb.find( 'img' ).attr( 'src', args.clear ? addImgSrc : args.src ) | |
} | |
// Click on "Upload any images" when the post has no images | |
$filters.on( 'click', 'button', function( resp ){ | |
var $btn = jQuery( this ) | |
if( $btn.hasClass( 'post-images-js' ) ){ | |
_loadAttachments() | |
} | |
if( $btn.hasClass( 'last-images-js' ) ){ | |
_loadAttachments( 'last_media' ) | |
} | |
} ) | |
// Click on the thumbnail in the post table | |
jQuery( '.wp-list-table' ).on( 'click', '.pthumb', function( ev ){ | |
$cur_pthumb = jQuery( this ) | |
_loadAttachments() | |
} ) | |
// Click on the thumbnail in the modal window - image selection | |
$images.on( 'click', '.imagebox', function(){ | |
let $box = jQuery( this ) | |
$images.find( '.imagebox' ).removeClass( 'selected' ) | |
$box.addClass( 'selected' ) | |
} ) | |
// Click on the "Set Thumbnail" button | |
$thickbox.find( '.set-thumb-js' ).on( 'click', function(){ | |
let $setbtn = jQuery( this ) | |
let $selected_imagebox = $images.find( '.selected' ) | |
let data = { | |
attach_id: $selected_imagebox.data( 'attach_id' ), | |
post_id : $cur_pthumb.data( 'post_id' ) | |
} | |
// AJAX | |
showMessage( 'Wait...' ) | |
ajaxs( 'Kama_Post_List_Table_Thumb::ajaxs_set_post_thumbnail', data, function( resp ){ | |
hideMessage() | |
// Set, close the modal | |
if( resp.success ){ | |
jQuery( '#TB_closeWindowButton' ).trigger( 'click' ) | |
resetPthumbImage( { | |
$pthumb : $cur_pthumb, | |
attach_id: data.attach_id, | |
src : $selected_imagebox.find( 'img' ).attr( 'src' ) | |
} ) | |
} | |
else | |
showMessage( resp.data, 'error' ) | |
} ) | |
} ) | |
// Click on the "Remove Thumbnail" button | |
$thickbox.find( '.del-post-thumb-js' ).on( 'click', function(){ | |
if( ! $cur_pthumb.data( 'attach_id' ) ){ | |
showMessage( 'ОШИБКА: У текущей записи миниатюра не установлена...', 'error' ) | |
return | |
} | |
// AJAX | |
showMessage( 'Unsetting...' ) | |
ajaxs( 'Kama_Post_List_Table_Thumb::ajaxs_delete_post_thumbnail', | |
{ post_id: $cur_pthumb.data( 'post_id' ) }, | |
function( resp ){ | |
$images.find( '.imagebox' ).removeClass( 'selected' ) | |
showMessage( 'Thumbnail cancelled!' ) | |
resetPthumbImage( { clear: 1, $pthumb: $cur_pthumb } ) | |
} | |
) | |
} ) | |
// Click on the "Upload Files" button - trigger input file | |
$thickbox.find( '.file-btn-js' ).on( 'click', function(){ | |
$file.trigger( 'click' ) | |
} ) | |
// Upload file | |
$file.change( function(){ | |
// AJAX upload files | |
showMessage( 'Loading...' ) | |
ajaxs( 'Kama_Post_List_Table_Thumb::ajaxs_upload_files', | |
{ | |
post_id: $cur_pthumb.data( 'post_id' ), | |
foo : $thickbox | |
}, | |
function( resp ){ | |
showMessage( resp.data, (resp.success ? 'success' : 'error') ) | |
if( resp.success ){ | |
_loadAttachments() | |
} | |
} | |
) | |
} ) | |
// Click on "Delete File" | |
$thickbox.find( '.del-attach-js' ).on( 'click', function(){ | |
let $selected = $images.find( '.selected' ) | |
if( ! $selected.length ){ | |
return showMessage( 'ERROR: Nothing has been selected....', 'error' ) | |
} | |
if( !confirm( 'Are you sure to delete? The file will be permanently deleted!' ) ){ | |
return | |
} | |
// AJAX | |
ajaxs( 'Kama_Post_List_Table_Thumb::ajaxs_delete_attach', | |
{ attach_id: $selected.data( 'attach_id' ) }, | |
function( resp ){ | |
if( resp.success ){ | |
$selected.remove() | |
} | |
else{ | |
showMessage( resp.data ) | |
} | |
} | |
) | |
} ) | |
// Double click on the image in the modal window - view the image in full size | |
$images.on( 'dblclick', '.imagebox', function(){ | |
$fullView.show().find( 'img' ).attr( 'src', this.dataset['full_url'] ) | |
$thickbox.find( '.images' ).hide() | |
} ) | |
$fullView.find( '.close' ).on( 'click', function(){ | |
$fullView.hide() | |
$images.show() | |
} ) | |
} ) | |
</script> | |
<?php | |
} | |
} | |
trait Kama_Post_List_Table_Thumb__ajax_handlers { | |
public static function ajaxs_get_images( AJAX_Simply_Core $jx ) { | |
$args = [ | |
'post_type' => 'attachment', | |
'post_mime_type' => 'image', | |
'order_by' => 'post_date', | |
'order' => 'DESC', | |
'numberposts' => $jx->limit ?: 100, | |
]; | |
if( $jx->post_id ){ | |
$args['post_parent'] = $jx->post_id; | |
} | |
if( $jx->cur_attach_id ){ | |
$args['exclude'] = $jx->cur_attach_id; | |
} | |
$attachs = get_posts( $args ); | |
// add the current thumbnail | |
if( $jx->cur_attach_id && $attach = get_post( $jx->cur_attach_id ) ){ | |
array_unshift( $attachs, $attach ); | |
} | |
// add a link to the thumbnail | |
foreach( $attachs as $attach ){ | |
$attach->thumb_url = wp_get_attachment_image_url( $attach->ID, 'thumbnail' ); | |
} | |
return $attachs; | |
} | |
public static function ajaxs_set_post_thumbnail( AJAX_Simply_Core $jx ) { | |
$atatch = $jx->attach_id ? get_post( $jx->attach_id ) : 0; | |
$post = $jx->post_id ? get_post( $jx->post_id ) : 0; | |
if( ! $atatch || ! $post ){ | |
$jx->error( 'ERROR: no attachment or post...' ); // die | |
} | |
$attach_post = $atatch->post_parent ? get_post( $atatch->post_parent ) : 0; | |
set_post_thumbnail( $post->ID, $atatch->ID ); | |
// the attachment is not attached anywhere, let's attach it to the current post | |
if( ! $attach_post ){ | |
wp_update_post( [ 'ID' => $atatch->ID, 'post_parent' => $post->ID ] ); | |
} | |
// the attachment is attached to a special post type and the current post type is the same as the attachment post type | |
// detach the attachment and attach it to the current post | |
elseif( | |
in_array( $attach_post->post_type, self::$re_set_attach_for_post_types, true ) | |
&& $attach_post->post_type === $post->post_type | |
){ | |
wp_update_post( [ 'ID' => $atatch->ID, 'post_parent' => $post->ID ] ); | |
// remove the thumbnail from the previous post if the same thumbnail is set for it | |
if( $attach_post->ID !== $post->ID && (int) get_post_thumbnail_id( $attach_post->ID ) === (int) $atatch->ID ){ | |
delete_post_thumbnail( $attach_post->ID ); | |
$jx->call( 'window.resetPthumbImage', [ 'clear' => 1, | |
'post_id' => $attach_post->ID, | |
] ); // clear the thumbnail of the previous post | |
} | |
} | |
$jx->success(); | |
} | |
public static function ajaxs_delete_post_thumbnail( AJAX_Simply_Core $jx ) { | |
return delete_post_thumbnail( $jx->post_id ); | |
} | |
public static function ajaxs_upload_files( AJAX_Simply_Core $jx ) { | |
if( ! $jx->pthumb_files ){ | |
$jx->error( 'ERROR: No files...' ); | |
} | |
if( ! $jx->post_id ){ | |
$jx->error( 'ERROR: Post ID is not specified...' ); | |
} | |
// filter for allowed file types - allow only images | |
add_filter( 'upload_mimes', static function( $mimes ) { | |
return [ | |
'jpg|jpeg|jpe' => 'image/jpeg', | |
'gif' => 'image/gif', | |
'png' => 'image/png', | |
'webp' => 'image/webp', | |
]; | |
} ); | |
// uploading files | |
$results = []; | |
foreach( $jx->pthumb_files['compact'] as $filedata ){ | |
// so that if the name is in Cyrillic, it remains in Cyrillic... | |
$name = sanitize_text_field( preg_replace( '/\.(?:jpg|jpeg|png|gif|webp)$/', '', $filedata['name'] ) ); | |
$id = media_handle_sideload( $filedata, $jx->post_id, $name ); | |
if( is_wp_error( $id ) ){ | |
@ unlink( $filedata['tmp_name'] ); | |
$results[] = 'ERROR: ' . $id->get_error_message() . ' File: ' . esc_html( $filedata['name'] ); | |
} | |
else{ | |
$results[] = 'OK: ' . esc_html( $filedata['name'] ); | |
} | |
} | |
$jx->success( implode( '<br>', $results ) ); | |
} | |
public static function ajaxs_delete_attach( AJAX_Simply_Core $jx ) { | |
if( ! $jx->attach_id ){ | |
$jx->error( 'ERROR: Attachment ID not specified...' ); | |
} | |
$res = wp_delete_attachment( $jx->attach_id, $force_delete = true ); | |
if( false === $res ){ | |
$jx->error( 'ERROR: Failed to delete...' ); | |
} | |
// clean the thumbnail in the posts table | |
$jx->call( 'window.resetPthumbImage', [ 'clear' => 1, 'attach_id' => $jx->attach_id ] ); | |
$jx->success( 'Deleted!' ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment