Skip to content

Instantly share code, notes, and snippets.

@andrewinsidelazarev
Last active February 2, 2026 16:09
Show Gist options
  • Select an option

  • Save andrewinsidelazarev/70f581460419813773aeb848f4ad8c62 to your computer and use it in GitHub Desktop.

Select an option

Save andrewinsidelazarev/70f581460419813773aeb848f4ad8c62 to your computer and use it in GitHub Desktop.
Shortcode for Youtube video
function youtube_embed_shortcode($atts) {
$atts = shortcode_atts(array(
'id' => '',
'sd' => 'false' // поддержка sd="true"
), $atts);
if (empty($atts['id'])) return '';
$videoId = esc_attr($atts['id']);
$containerId = 'yt-container-' . $videoId;
$playerId = 'yt-player-' . $videoId;
$fsBtnId = 'yt-fs-btn-' . $videoId;
// Выбор миниатюры: WebP (как в оригинале)
$thumbFile = ($atts['sd'] === 'true') ? 'sddefault.webp' : 'maxresdefault.webp';
$thumbUrl = 'https://i.ytimg.com/vi_webp/' . $videoId . '/' . $thumbFile;
ob_start();
?>
<div id="<?= $containerId ?>"
class="yt-custom-wrapper"
tabindex="0"
onclick="this.focus()">
<img src="<?= esc_url($thumbUrl) ?>"
class="yt-thumb"
alt="Video Thumbnail"
onclick="ytInitPlayer('<?= $videoId ?>')">
<div class="yt-play-btn" onclick="ytInitPlayer('<?= $videoId ?>')">
<svg width="68" height="48" viewBox="0 0 68 48">
<path d="M66.52 7.68C65.76 5.23 63.97 3.44 61.52 2.68C57.68 1.48 34 1.48 34 1.48S10.32 1.48 6.48 2.68C4.03 3.44 2.24 5.23 1.48 7.68 0.28 11.52 0.28 24 0.28 24s0.28 12.48 1.48 16.32c.76 2.45 2.55 4.24 5 5 3.84 1.2 27.52 1.2 27.52 1.2s23.68 0 27.52-1.2c2.45-.76 4.24-2.55 5-5 1.2-3.84 1.2-16.32 1.2-16.32s0-12.48-1.2-16.32z" fill="red"/>
<path d="M45 24L27 14V34L45 24Z" fill="white"/>
</svg>
</div>
<div id="<?= $playerId ?>" class="yt-player-placeholder"></div>
<button id="<?= $fsBtnId ?>"
type="button"
class="yt-fs-btn"
tabindex="-1"
onmousedown="event.preventDefault()"
onclick="ytToggleFS('<?= $containerId ?>')">
<svg class="icon-enter" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M15 3h6v6M9 21H3v-6M21 15v6h-6M3 9V3h6"/>
</svg>
<svg class="icon-exit" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="display:none;">
<path d="M8 3v5H3M16 3v5h5M8 21v-5H3M16 21v-5h5"/>
</svg>
</button>
</div>
<?php
static $js_added = false;
if (!$js_added) :
$js_added = true;
?>
<style>
.yt-custom-wrapper {
position: relative;
width: 100%;
padding-top: 56.25%;
background: #000;
overflow: hidden;
outline: none;
}
.yt-custom-wrapper img.yt-thumb {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
bottom: 0; /* Страховка */
object-fit: cover;
display: block;
cursor: pointer;
z-index: 10;
margin: 0; /* Убираем возможные отступы темы */
}
.yt-play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
cursor: pointer;
z-index: 11;
}
.yt-player-placeholder {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
display: none;
z-index: 5;
}
.yt-fs-btn {
position: absolute;
bottom: 10px;
right: 15px;
width: 35px;
height: 35px;
display: none;
align-items: center;
justify-content: center;
padding: 0;
border: none;
border-radius: 0;
background: rgba(0,0,0,0.6);
cursor: pointer;
z-index: 20;
transition: opacity 0.3s;
}
</style>
<script>
var ytApiReady = false;
var ytPlayers = {};
var ytQueue = [];
var ytFsTimer = null;
if (!window.YT_API_LOADING) {
window.YT_API_LOADING = true;
var tag = document.createElement('script');
tag.src = 'https://www.youtube.com/iframe_api';
document.head.appendChild(tag);
}
function onYouTubeIframeAPIReady() {
ytApiReady = true;
ytQueue.forEach(id => ytCreatePlayer(id));
ytQueue = [];
}
function ytInitPlayer(videoId) {
if (!ytApiReady) {
ytQueue.push(videoId);
return;
}
ytCreatePlayer(videoId);
}
function ytCreatePlayer(videoId) {
if (ytPlayers[videoId]) return;
var wrapper = document.getElementById('yt-container-' + videoId);
var holder = document.getElementById('yt-player-' + videoId);
var fsBtn = document.getElementById('yt-fs-btn-' + videoId);
// Безопасное удаление (вместо ?.)
var thumb = wrapper.querySelector('.yt-thumb');
if (thumb) thumb.remove();
var playBtn = wrapper.querySelector('.yt-play-btn');
if (playBtn) playBtn.remove();
holder.style.display = 'block';
fsBtn.style.display = 'flex';
ytPlayers[videoId] = new YT.Player(holder, {
videoId: videoId,
playerVars: { autoplay: 1, rel: 0 }
});
wrapper.focus();
if (!wrapper.dataset.fsListener) {
wrapper.dataset.fsListener = "1";
wrapper.addEventListener("mousemove", function() {
fsBtn.style.opacity = "1";
fsBtn.style.cursor = "pointer";
if (ytFsTimer) clearTimeout(ytFsTimer);
if (document.fullscreenElement) {
ytFsTimer = setTimeout(function() {
fsBtn.style.opacity = "0";
fsBtn.style.cursor = "none";
}, 3000);
}
});
}
}
function ytToggleFS(containerId) {
var el = document.getElementById(containerId);
if (!document.fullscreenElement) {
if(el.requestFullscreen) el.requestFullscreen();
else if(el.webkitRequestFullscreen) el.webkitRequestFullscreen();
} else {
if(document.exitFullscreen) document.exitFullscreen();
else if(document.webkitExitFullscreen) document.webkitExitFullscreen();
}
setTimeout(() => el.focus(), 50);
}
document.addEventListener("fullscreenchange", function() {
var fsEl = document.fullscreenElement;
document.querySelectorAll(".yt-custom-wrapper .icon-exit").forEach(el => el.style.display = 'none');
document.querySelectorAll(".yt-custom-wrapper .icon-enter").forEach(el => el.style.display = 'block');
if (fsEl && fsEl.classList.contains("yt-custom-wrapper")) {
var btn = fsEl.querySelector(".yt-fs-btn");
if (btn) {
btn.querySelector(".icon-enter").style.display = 'none';
btn.querySelector(".icon-exit").style.display = 'block';
}
fsEl.focus();
}
});
document.addEventListener('keydown', function(e) {
if (e.code !== 'Space' && e.keyCode !== 32) return;
var el = document.activeElement;
if (!el || !el.classList.contains('yt-custom-wrapper')) return;
e.preventDefault();
var videoId = el.id.replace('yt-container-', '');
var player = ytPlayers[videoId];
if (!player || typeof player.getPlayerState !== 'function') return;
var state = player.getPlayerState();
(state === YT.PlayerState.PLAYING) ? player.pauseVideo() : player.playVideo();
});
</script>
<?php
endif;
return ob_get_clean();
}
add_shortcode('youtube_embed', 'youtube_embed_shortcode');
@andrewinsidelazarev
Copy link
Author

Теперь вы можете использовать шорткод так:

[youtube_embed id="VIDEO_ID"] для загрузки maxresdefault.webp.
[youtube_embed id="VIDEO_ID" sd="true"] для загрузки sddefault.webp.
Этот подход позволит гибко переключаться между вариантами миниатюр.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment