fix: elementor-youtube-widget (per JS gebaut) zuverlaessig erkennen

Nach dem script-blocking blieb ein per YouTube-iframe_api gebautes
Elementor-video leer: die API wird blockiert, also baut Elementor kein
iframe -> mein iframe-basierter platzhalter griff nicht, und das
data-settings enthielt nur {"video_type":"youtube"} (keine URL).

videoUrlForWidget() findet die video-URL jetzt aus mehreren quellen:
- explizite keys (youtube_url/vimeo_url/...) im data-settings
- beliebige youtube/vimeo-URL im data-settings (regex, escaped slashes)
- bereits server-gerendertes iframe im widget
- YouTube-thumbnail (i.ytimg.com/vi/ID/) bei lazyload/overlay-modus
Greift auch fuer .elementor-widget[data-widget_type^="video"] und ueberspringt
widgets, die der server-autodetect schon zum platzhalter gemacht hat.

Extraktions-logik isoliert getestet (thumbnail, escaped-json, vimeo).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
s4luorth
2026-06-08 11:36:31 +02:00
parent ca945d2d80
commit 1b7d3434bf

View File

@@ -261,17 +261,61 @@
}
}
/** Elementor video widgets store the URL in data-settings and build the
* player via JS — handle them before that happens. */
/** Reconstruct a YouTube watch URL from a thumbnail (i.ytimg.com/vi/ID/…). */
function ytIdFromThumb( s ) {
const m = String( s || '' ).match( /(?:i\.ytimg\.com|img\.youtube\.com)\/vi\/([\w-]{6,})\// );
return m ? m[ 1 ] : '';
}
/**
* Find the embedded video URL of an Elementor video widget. Elementor often
* does NOT put the URL in data-settings (only {"video_type":"youtube"}) and
* builds the player via the JS API — so we look in several places.
*/
function videoUrlForWidget( widget ) {
const ds = widget.getAttribute( 'data-settings' ) || '';
// 1) Explicit URL keys in data-settings (older/other Elementor versions).
try {
const s = JSON.parse( ds || '{}' );
const u = s.youtube_url || s.vimeo_url || s.video_url || s.external_url
|| s.hosted_url || ( s.link && s.link.url ) || '';
if ( u ) return u;
} catch ( e ) { /* not JSON / no keys */ }
// 2) Any youtube/vimeo URL anywhere in the data-settings string (JSON values
// are quoted, so stop at a quote/space; tolerate escaped slashes \/).
const m = ds.match( /https?:[^"\s]*?(?:youtube\.com|youtu\.be|vimeo\.com)[^"\s]*/i );
if ( m ) return m[ 0 ].replace( /\\\//g, '/' ).replace( /\\/g, '' );
// 3) A server-rendered iframe already inside the widget.
const ifr = widget.querySelector( 'iframe[src]' );
if ( ifr ) return ifr.getAttribute( 'src' );
// 4) A YouTube thumbnail (lazyload / image-overlay mode) → rebuild the URL.
const thumb = widget.querySelector(
'img[src*="ytimg.com/vi/"], img[src*="img.youtube.com/vi/"], [style*="ytimg.com/vi/"]'
);
if ( thumb ) {
const id = ytIdFromThumb( thumb.getAttribute( 'src' ) || thumb.getAttribute( 'style' ) || '' );
if ( id ) return 'https://www.youtube.com/watch?v=' + id;
}
return '';
}
/** Elementor video widgets build the player via JS — replace them with our
* consent placeholder before that happens. */
function handleElementorVideos() {
document.querySelectorAll( '.elementor-widget-video[data-settings]' ).forEach( function ( widget ) {
let settings;
try {
settings = JSON.parse( widget.dataset.settings );
} catch ( e ) {
return;
}
const raw = settings.youtube_url || settings.vimeo_url || settings.external_url || '';
const widgets = document.querySelectorAll(
'.elementor-widget-video, .elementor-widget[data-widget_type^="video"]'
);
widgets.forEach( function ( widget ) {
const container = widget.querySelector( '.elementor-widget-container' ) || widget;
// Already turned into a placeholder (e.g. by the server-side autodetect
// catching a rendered iframe) → leave it.
if ( container.querySelector( '.cb-blocker' ) ) return;
const raw = videoUrlForWidget( widget );
if ( ! raw ) return;
const embed = toEmbedUrl( raw );
@@ -282,7 +326,6 @@
// Neutralise Elementor so it won't build the player / load the overlay.
widget.removeAttribute( 'data-settings' );
const container = widget.querySelector( '.elementor-widget-container' ) || widget;
container.innerHTML = '';
container.appendChild( buildPlaceholder( svc, embed, {} ) );
} );