Возможно ли установить изображение записи через внешний URL изображения
Я знаю, что существуют плагины, которые загружают изображения с удаленного URL и сохраняют их локально. Мне просто хотелось бы узнать, возможно ли использовать изображение в качестве изображения записи, не сохраняя его в Медиатеке?

Да, это возможно и довольно просто.
Вот рабочий процесс, который я предлагаю:
- Добавить интерфейс для ввода URL изображения записи. Лучше всего использовать хук фильтра
'admin_post_thumbnail_html'
- Использовать хук действия
'save_post'
для сохранения URL (после проверки безопасности и валидации) в произвольном метаполе записи - Использовать хук фильтра
'post_thumbnail_html'
для вывода HTML-разметки<img>
, переопределяя стандартный вывод, если для записи задано метаполе с внешним изображением
Для работы этого процесса необходимо, чтобы миниатюра записи выводилась в шаблоне с помощью функций get_the_post_thumnbail()
или the_post_thumbnail()
.
Кроме того, мы должны убедиться, что метазначение '_thumbnail_id'
не пустое, когда мы устанавливаем метаполе для внешнего URL, иначе функция has_post_thumbnail()
будет возвращать false для записей, у которых есть только внешнее изображение записи.
Фактически, запись может иметь как стандартное локальное изображение записи, так и заданное через наш метод, и в этом случае будет использоваться внешнее изображение.
Для реализации нашего процесса нам нужна функция для валидации URL, используемого как внешнее изображение записи, чтобы убедиться, что это корректный URL изображения.
Есть разные способы выполнить эту задачу; здесь я использую очень простой метод, который только проверяет URL, не загружая изображение. Это работает только для статических URL изображений и не проверяет, существует ли изображение на самом деле, но это быстро. Модифицируйте его на что-то более продвинутое, если нужно (здесь есть помощь).
function url_is_image( $url ) {
if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) {
return FALSE;
}
$ext = array( 'jpeg', 'jpg', 'gif', 'png' );
$info = (array) pathinfo( parse_url( $url, PHP_URL_PATH ) );
return isset( $info['extension'] )
&& in_array( strtolower( $info['extension'] ), $ext, TRUE );
}
Довольно просто. Теперь добавим 3 хука, описанных в рабочем процессе выше:
add_filter( 'admin_post_thumbnail_html', 'thumbnail_url_field' );
add_action( 'save_post', 'thumbnail_url_field_save', 10, 2 );
add_filter( 'post_thumbnail_html', 'thumbnail_external_replace', 10, PHP_INT_MAX );
и соответствующие функции. Сначала та, которая выводит поле в админке:
function thumbnail_url_field( $html ) {
global $post;
$value = get_post_meta( $post->ID, '_thumbnail_ext_url', TRUE ) ? : "";
$nonce = wp_create_nonce( 'thumbnail_ext_url_' . $post->ID . get_current_blog_id() );
$html .= '<input type="hidden" name="thumbnail_ext_url_nonce" value="'
. esc_attr( $nonce ) . '">';
$html .= '<div><p>' . __('Или', 'txtdomain') . '</p>';
$html .= '<p>' . __( 'Введите URL внешнего изображения', 'txtdomain' ) . '</p>';
$html .= '<p><input type="url" name="thumbnail_ext_url" value="' . $value . '"></p>';
if ( ! empty($value) && url_is_image( $value ) ) {
$html .= '<p><img style="max-width:150px;height:auto;" src="'
. esc_url($value) . '"></p>';
$html .= '<p>' . __( 'Оставьте URL пустым, чтобы удалить.', 'txtdomain' ) . '</p>';
}
$html .= '</div>';
return $html;
}
Обратите внимание, что я использовал 'txtdomain'
как текстовый домен, но вы должны использовать зарегистрированный текстовый домен.
Вот как выглядит вывод, когда поле пустое:
А так оно выглядит после добавления URL изображения и сохранения/обновления записи:
Теперь, когда наш интерфейс админки готов, напишем функцию сохранения:
function thumbnail_url_field_save( $pid, $post ) {
$cap = $post->post_type === 'page' ? 'edit_page' : 'edit_post';
if (
! current_user_can( $cap, $pid )
|| ! post_type_supports( $post->post_type, 'thumbnail' )
|| defined( 'DOING_AUTOSAVE' )
) {
return;
}
$action = 'thumbnail_ext_url_' . $pid . get_current_blog_id();
$nonce = filter_input( INPUT_POST, 'thumbnail_ext_url_nonce', FILTER_SANITIZE_STRING );
$url = filter_input( INPUT_POST, 'thumbnail_ext_url', FILTER_VALIDATE_URL );
if (
empty( $nonce )
|| ! wp_verify_nonce( $nonce, $action )
|| ( ! empty( $url ) && ! url_is_image( $url ) )
) {
return;
}
if ( ! empty( $url ) ) {
update_post_meta( $pid, '_thumbnail_ext_url', esc_url($url) );
if ( ! get_post_meta( $pid, '_thumbnail_id', TRUE ) ) {
update_post_meta( $pid, '_thumbnail_id', 'by_url' );
}
} elseif ( get_post_meta( $pid, '_thumbnail_ext_url', TRUE ) ) {
delete_post_meta( $pid, '_thumbnail_ext_url' );
if ( get_post_meta( $pid, '_thumbnail_id', TRUE ) === 'by_url' ) {
delete_post_meta( $pid, '_thumbnail_id' );
}
}
}
Функция, после проверок безопасности, проверяет переданный URL и, если он корректен, сохраняет его в метаполе '_thumbnail_ext_url'
. Если URL пустой, а метаполе было сохранено, оно удаляется, что позволяет убрать метаполе просто очистив поле внешнего URL.
Последнее, что нужно сделать — вывести HTML-разметку изображения записи, когда задано наше внешнее изображение:
function thumbnail_external_replace( $html, $post_id ) {
$url = get_post_meta( $post_id, '_thumbnail_ext_url', TRUE );
if ( empty( $url ) || ! url_is_image( $url ) ) {
return $html;
}
$alt = get_post_field( 'post_title', $post_id ) . ' ' . __( 'изображение записи', 'txtdomain' );
$attr = array( 'alt' => $alt );
$attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, NULL );
$attr = array_map( 'esc_attr', $attr );
$html = sprintf( '<img src="%s"', esc_url($url) );
foreach ( $attr as $name => $value ) {
$html .= " $name=" . '"' . $value . '"';
}
$html .= ' />';
return $html;
}
Готово.
Что осталось сделать
В выводе изображения записи я не использовал атрибуты width
или height
, ни классы, которые обычно добавляет WordPress, такие как 'attachment-$size'
. Это потому, что определение размера изображения требует дополнительной работы, которая замедлит загрузку страницы, особенно если у вас несколько изображений записи на странице.
Если вам нужны эти атрибуты, вы можете модифицировать мой код, добавив обработчик к фильтру wp_get_attachment_image_attributes'
(это стандартный хук WordPress) или изменить мой код для определения размера изображения и вывода соответствующих атрибутов и классов.
Плагин Gist
Весь код, приведенный здесь, за исключением инициализации правильного текстового домена, доступен как полностью рабочий плагин в Gist здесь. Там код использует пространство имен, поэтому требует PHP 5.3+.
Примечания
Конечно, вы должны быть уверены, что у вас есть лицензия и разрешение на использование и хотлинкинг изображений на вашем сайте с внешних источников.

можете объяснить, какой именно код и на какую страницу мы должны написать. Я новичок в PHP/Wordpress, поэтому объясните, пожалуйста, пошагово. Спасибо
