Установка миниатюры записи из таблицы записей в админке
В этой заметке вы найдете код, который позволяет устанавливать миниатюры записи (поста) со страницы редактирования записей в админ-панели. Картинки также можно загружать/удалять и т.д.
Создайте плагин из кода ниже. Или создайте файл из кода ниже и подключите его в файл темы functions.php.
ВАЖНО: Код работает на основе плагина AJAX Simply, без него работать не будет!
<?php // init if( is_admin() ){ add_action( 'admin_init', [ 'Post_List_Table_Thumb', 'init' ] ); } /** * Возможность загружать и изменять миниатюры записей из таблицы записей в админ-панели. * * @author Kama (wp-kama.ru) * * @version 1.2.2 */ class Post_List_Table_Thumb { // для каких постов включить код. По умолчанию для всех публичных static $post_type = array( 'recipe', 'ingredient' ); static $re_set_attach_for_post_types = array(); // типы записей для которых установка миниатюры пере-прикрепляет файл вложения static $meta_key = '_thumbnail_id'; // название мета ключа // URL пустой картинки static $add_img_url = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkAQMAAABKLAcXAAAABlBMVEUAAAC7u7s37rVJAAAAAXRSTlMAQObYZgAAACJJREFUOMtjGAV0BvL/G0YMr/4/CDwY0rzBFJ704o0CWgMAvyaRh+c6m54AAAAASUVORK5CYII='; ## инициализация всего static function init(){ $post_type = self::$post_type ?: 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 ); } // общая проверка прав доступа для всех текущих ajax запросов add_filter( 'ajaxs_allow_process', function( $allow, $action ){ if( false !== strpos($action, 'Post_List_Table_Thumb') && ! current_user_can('edit_others_posts') ) return false; }, 10, 2 ); } ## добавляет колонку картинки в таблицу терминов static function add_image_column( $columns ){ add_action( 'admin_notices', [ __CLASS__, '_add_js_css_html' ] ); // колонка без названия.. return array_slice( $columns, 0, 1 ) + [ 'image'=>'' ] + $columns; } ## заполняет колонку 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, 1 ); $img_src = $attach_id ? wp_get_attachment_image_url( $attach_id, 'thumbnail' ) : self::$add_img_url; echo ' <a class="pthumb thickbox" data-post_id="'. $post_id .'" data-attach_id="'. $attach_id .'" href="/?TB_inline&inlineId=up-set-post-thumb&width=700&height=500" title="Установка миниатюры записи" > <img src="'. $img_src .'" /> </a>'; } } ## html модального окна, css и js static function _add_js_css_html( $taxonomy ){ add_thickbox(); // скрипты модального окна add_action( 'admin_print_footer_scripts', [ __CLASS__, '_script_code' ], 99 ); ?> <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> <!-- модальное окно --> <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">Картинки записи</button> <button class="button button-small / last-images-js">Последнии из библиотеки</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">Установить миниатюру</button> <button class="button / file-btn-js"><span class="dashicons dashicons-format-image" style=""></span> Загрузить картики</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>Снять миниатюру</button> <button class="button / del-attach-js"><span class="dashicons dashicons-trash"></span>Удалить файл</button> </div> </div> </div> <?php } ## script static function _script_code(){ ?> <script> jQuery(document).ready(function($){ var $thickbox = $('.pthumb-thickbox'), $file = $thickbox.find('[type="file"]'), $images = $thickbox.find('.images'), $fullView = $thickbox.find('.full-view'), $filters = $thickbox.find('.filters'), imageboxTpl = $thickbox.find('#imagebox-tpl-js').html() $cur_pthumb = null; var showMessage = function( message, type ){ var $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); } var _fillImagesBox = function( attachs ){ $images.empty(); if( typeof attachs === 'string' ){ $images.html( attachs ); return; } // переберем массив объектов и добавляем елементы for( var id in attachs ){ var attach = attachs[ id ]; $images.append( imageboxTpl.replace( '{attach_url}', attach.thumb_url ) .replace( '{attach_id}', attach.ID ) .replace( '{full_url}', attach.guid ) ) // установим текущую миниатюру 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'); } }; var _loadAttachments = function( filter_name ){ $images.empty(); // clear images $filters.find('button').removeClass('active'); // clear filters var 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 запрос - загружаем все картинки записи showMessage( 'Загружаю...' ); ajaxs( '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 = $('.pthumb[data-post_id="'+ args.post_id +'"]'); else if( args.attach_id ) args.$pthumb = $('.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 ? '<?= self::$add_img_url ?>' : args.src ); }; // клик по "Загрузить любые картинки", когда у записи нет картинок $filters.on( 'click', 'button', function(resp){ var $btn = $(this); if( $btn.hasClass('post-images-js') ){ _loadAttachments(); } if( $btn.hasClass('last-images-js') ){ _loadAttachments( 'last_media' ); } }); // клик по миниатюре в таблице записей $('.wp-list-table').on('click', '.pthumb', function(ev){ $cur_pthumb = $(this); // Установим текущий объект картинки он хранит ID поста... _loadAttachments(); }); // клик по миниатюре в модальном окне - выбор картинки $images.on('click', '.imagebox', function(){ var $box = $(this); $images.find('.imagebox').removeClass('selected') $box.addClass('selected') } ) // клик по кнопке "установить миниатюру" $thickbox.find('.set-thumb-js').click(function(){ var $setbtn = $(this), $selected_imagebox = $images.find('.selected'), data = { attach_id : $selected_imagebox.data('attach_id'), post_id : $cur_pthumb.data('post_id') } // AJAX showMessage( 'Работаю...' ); ajaxs( 'Post_List_Table_Thumb::ajaxs_set_post_thumbnail', data, function(resp){ hideMessage(); // утановлено, закрываем модалку 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' ); }) }); // клик по кнопке "снять миниатюру" $thickbox.find('.del-post-thumb-js').click(function(){ if( ! $cur_pthumb.data('attach_id') ){ showMessage('ОШИБКА: У текущей записи миниатюра не установлена...', 'error'); return; } // AJAX showMessage('Снимаю...') ajaxs( 'Post_List_Table_Thumb::ajaxs_delete_post_thumbnail', { post_id : $cur_pthumb.data('post_id') }, function(resp){ $images.find('.imagebox').removeClass('selected') showMessage('Миниатюра снята!') resetPthumbImage( { clear: 1, $pthumb: $cur_pthumb } ); }) }); // клик по кнопке "загрузить файлы" - тригер input file $thickbox.find('.file-btn-js').click(function(){ $file.trigger('click') }); // загружаем файл $file.change(function(){ // AJAX загружаем файлы showMessage('Загружаю...'); ajaxs( '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(); } ) }); // клик по "Удалить файл" $thickbox.find('.del-attach-js').click(function(){ var $selected = $images.find('.selected'); if( ! $selected.length ) return showMessage('ОШИБКА: Ничего не выбрано...','error'); if( ! confirm('Точно удалить? Фалй будет удален навсегда!') ) return; // AJAX ajaxs( 'Post_List_Table_Thumb::ajaxs_delete_attach', { attach_id: $selected.data('attach_id') }, function( resp ){ if( resp.success ){ $selected.remove(); } else showMessage( resp.data ); }); }); // двойной клик по картинке в модальном окне - просмотр картинки в полном размере $images.on( 'dblclick', '.imagebox', function(){ $fullView.show().find('img').attr('src', $(this).data('full_url') ); $thickbox.find('.images').hide(); }); $fullView.find('.close').click(function(){ $fullView.hide() $images.show() }); }); </script> <?php } // AJAX обработчики --------- ## получает картинки записи static function ajaxs_get_images( $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 ); // добавим текущую миниатюру if( $jx->cur_attach_id && $attach = get_post($jx->cur_attach_id) ){ array_unshift( $attachs, $attach ); } //$jx->log($attachs); // дебаг // добавим ссылку на миниатюру foreach( $attachs as & $attach ){ $attach->thumb_url = wp_get_attachment_image_url( $attach->ID, 'thumbnail' ); } return $attachs; } static function ajaxs_set_post_thumbnail( $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( 'ОШИБКА: не указано вложение или пост...' ); // die $attach_post = $atatch->post_parent ? get_post( $atatch->post_parent ) : 0; set_post_thumbnail( $post->ID, $atatch->ID ); // вложение не прикреплено никуда, прикрепим к текущему посту if( ! $attach_post ){ wp_update_post( [ 'ID'=>$atatch->ID, 'post_parent'=>$post->ID ] ); } // вложение прикреплено к специальному типу записи и текущий тип записи такой же как у записи вложения // открепим вложение и прикрепим к текущему посту elseif( in_array($attach_post->post_type, self::$re_set_attach_for_post_types) && $attach_post->post_type === $post->post_type ){ wp_update_post( [ 'ID'=>$atatch->ID, 'post_parent'=>$post->ID ] ); // удалим миниатюру у прошлого поста, если у него установлена таже самая миниатюра if( $attach_post->ID !== $post->ID && get_post_thumbnail_id($attach_post->ID) == $atatch->ID ){ delete_post_thumbnail( $attach_post->ID ); $jx->call( 'window.resetPthumbImage', ['clear'=>1, 'post_id'=>$attach_post->ID] ); // очистим миниатюру у прошлого поста } } $jx->success(); } static function ajaxs_delete_post_thumbnail( $jx ){ return delete_post_thumbnail( $jx->post_id ); } static function ajaxs_upload_files( $jx ){ if( ! $jx->pthumb_files ) $jx->error('ОШИБКА: Нет файлов...'); if( ! $jx->post_id ) $jx->error('ОШИБКА: Не указан ID поста...'); // фильтр допустимых типов файлов - разрешим только картинки add_filter( 'upload_mimes', function( $mimes ){ return [ 'jpg|jpeg|jpe'=>'image/jpeg', 'gif'=>'image/gif', 'png'=>'image/png', 'webp'=>'image/webp' ]; } ); // загружаем файлы $results = array(); foreach( $jx->pthumb_files['compact'] as $filedata ){ // чтобы если название в кириллице оно и оставалось в кириллице... $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[] = 'ОШИБКА: '. $id->get_error_message() .' Файл: '. esc_html($filedata['name']); } else $results[] = 'OK: '. esc_html($filedata['name']); } $jx->success( implode('<br>', $results) ); } static function ajaxs_delete_attach( $jx ){ if( ! $jx->attach_id ) $jx->error('ОШИБКА: Не указан ID вложения...'); $res = wp_delete_attachment( $jx->attach_id, $force_delete = true ); if( false === $res ) $jx->error('ОШИБКА: Не удалось удалить...'); $jx->call( 'window.resetPthumbImage', ['clear'=>1, 'attach_id'=>$jx->attach_id] ); // очистим миниатюру в таблице постов $jx->success('Удалено!'); } }
После установки кода получим:
Теоретически, можно сделать тоже самое через стандартное окно media загрузчика, но там придется разбираться с кучей всего. Мне нужен был такой функционал и проще (быстрее) было написать код выше. Если есть альтернативные решения такой задачи, пожалуйста поделитесь в комментариях.