2

I am creating a website for a composer to include a page in a blog style with YouTube videos of concerts. I am attempting to block all the code for the videos from automatically loading on the page (and to warn of remote cookies) unless someone clicks/taps to watch the video. There is a custom field which contains the YouTube video ID, eg aBC_1deF_gH, and I created a new menu item type called 'Watch' in which I have added the following code to the watch_item.php file:

<div class="ytcover">Click to watch this video</div> (It's not styled, yet)

At the end of the file I have added the following, which was based on this post: video lazy loading skipping first video in list

( function() {

var youtube = document.querySelectorAll( ".ytcover" );

for (var i = 0; i < youtube.length; i++) {

youtube[i].addEventListener( "click", function() {

var iframe = document.createElement( "iframe" );
                iframe.setAttribute( "frameborder", "0" );
                iframe.setAttribute( "allowfullscreen", "" );
                iframe.setAttribute( "src", "https://www.youtube.com/embed/aBC_1deF_gH?rel=0&showinfo=0&autoplay=1" );
this.innerHTML = "";
            this.appendChild( iframe );
        } );    
    };
} )();

As you can see, the video code [not a real one here] is hard-coded into the JavaScript but I did this to test that the JavaScript works, which it does.

What I really want to have here is something like this:

iframe.setAttribute( "src", "https://www.youtube.com/embed/<?php echo $this->item->jcfields[1]->value; ?>?rel=0&showinfo=0&autoplay=1" );

Is this possible and, if so, how?

Edit - further tests:

I have also tried adding this as a shortcut: $ytubeId = $this->item->jcfields[1]->value; which does display correctly when echoed in a plain div.

So I modified the script to this:

( function() {

var youtube = document.querySelectorAll( ".ytcover" );

for (var i = 0; i < youtube.length; i++) {
var ytid = "https://www.youtube.com/embed/<?php echo $ytubeId; ?>?rel=0&showinfo=0&autoplay=1";
youtube[i].addEventListener( "click", function() {


var iframe = document.createElement( "iframe" );
                iframe.setAttribute( "frameborder", "0" );
                iframe.setAttribute( "allowfullscreen", "" );
                iframe.setAttribute( "src", ytid );
this.innerHTML = "";
            this.appendChild( iframe );
        } );    
    };
} )();

But whilst the resulting script in the html is showing the correct URL, i.e. var ytid = "https://www.youtube.com/embed/aBC_1deF_gH?rel=0&showinfo=0&autoplay=1";

The actual URL for the link is missing the video id, i.e: src="https://www.youtube.com/embed/?rel=0&showinfo=0&autoplay=1"

So the iframe.setAttribute function for the src URL is not working correctly. Any idea why, please?

Update 2: I added this shortcut: $ytubeURL = "https://www.youtube.com/embed/$ytubeId?rel=0&showinfo=0&autoplay=1"; and changed the JavaScript to:

( function() {

var youtube = document.querySelectorAll( ".ytcover" );

for (var i = 0; i < youtube.length; i++) {

youtube[i].addEventListener( "click", function() {

var iframe = document.createElement( "iframe" );
                iframe.setAttribute( "frameborder", "0" );
                iframe.setAttribute( "allowfullscreen", "" );
                iframe.setAttribute( "src", "<?php echo $ytubeURL; ?>" );
this.innerHTML = "";
            this.appendChild( iframe );
        } );    
    };
} )();

When the html source code is viewed, the full URL is displayed in the script, but when clicking the link on the front end, and viewing via developer tools, the actual URL is still missing the YouTube ID:

Front-end Screenshot with dev tools

2
  • Is it one video on one page or a list of videos?
    – Zollie
    May 3, 2023 at 7:07
  • A mixture. Each article could have up to three videos, but these each have their own custom field entry. The articles and their video links would be added by the completely non-techie site owner, so I need to make it as simple as possible.
    – Gillian
    May 3, 2023 at 9:11

1 Answer 1

1

I wanted to write that in every web-developer's life there comes a time when he/she meets with the iFrame problem (passing PHP variables to it and it can have complications), since iFrame is a new browsing context (a new document)... But before writing a long boring essay on that, I decided to do a fast test of your code to see whether it is working in my local environment or not. Could I replicate your issue or not. And I have to say it is working on my local Joomla4 without the problem you described above in your question.

I just actually pasted your code in one of my test view/layout with very tiny modification in the code:

<?php

$ytubeURL = "https://www.youtube.com/watch?v=uXCipjbcQfM"; // simply the youtube video watch URL is copied
$video_id = youTubeGetID($ytubeURL);

function youTubeGetID($url) {
    // this function should be worked out for making a bit more sophisticated
    // to check the input url value - if it is OK or not, otherwise could fail
    // if the YT video URL format is not like the given example
    $url = explode("v=", $url);
    return $url[1];
}

?>

<div class="yt-section">
    <p class="strong">here we'll have a youtube video</p>    
    <div class="ytcover">
        <img src=<?php echo "http://img.youtube.com/vi/" . $video_id . "/hqdefault.jpg"?> alt=""> 
    </div>
    <p class="strong">here we'll have another youtube video</p>    
    <div class="ytcover">
        <img src=<?php echo "http://img.youtube.com/vi/" . $video_id . "/hqdefault.jpg"?> alt=""> 
    </div>
</div>

<script>

( function() {

const youtube = document.querySelectorAll( ".ytcover" );

for (let i = 0; i < youtube.length; i++) {

    youtube[i].addEventListener( "click", function() {

        let iframe = document.createElement( "iframe" );
                        iframe.setAttribute( "frameborder", "0" );
                        iframe.setAttribute( "allowfullscreen", "" );
                        iframe.setAttribute( "src", "<?php echo "https://www.youtube.com/embed/" . $video_id; ?>" );
        this.innerHTML = "";
        this.appendChild( iframe );
        } );    
    };
} )();

</script>

I used the normal watch URL of the youtube video (copy and paste from the browser). I stripped the ID of the video that I used to get the video image and also used that ID to create the embed video link in the iFrame. I was not able to duplicate the problem this way.

I link my visual results where you can see that it is working in my layout: https://ibb.co/bzYdbY5

Updated javascript sample:

Here I link for you my codepen example with an updated script that is iterating over youtube video IDs, creating video cover images then on clicks it displays the embedded videos: https://codepen.io/Zollie01/pen/JjmMBYw?editors=1111

——————-

And just to make sure, a helpful additional info for applying the above Javascript in Joomla layout: converting PHP array to javascript array in the same layout:

In PHP you define an array of Ids for example:

$video_ids = json_encode([$vidid1, $vidid2, $vidid3]);

Then in javascript:

const videoIDs = <?php echo $video_ids ?>;

<< LAST UPDATE ON THIS >>

What the hell do we want to do with $this->item->jcfields[1]->value here throughout multiple articles? So let's run this one more time and let's just do the whole thing in javascript. I hope you can follow and use this finally:

1. create few custom Text fields which will be the video ID text fields (you already have this but you have to carefully follow the second point).

2. Important! At Edit Field -> Options -> Display Options -> Value class add a class name for these fields values ytvideoid hidden - this is important since the javascript finds these fields by this value (by this class name)!

3. Insert 2 or 3 of these video ID fields to articles with different video ID values. I know, You already did that, but important now to follow the 2. point above on this with these custom fields regarding the value class names. The fields in html source have to have it ytvideoid.

4. Also important! Do not edit or customize or add anything to the PHP Joomla layouts for this, do not add any HTML, no any value, no any PHP code, other than this javascript script at the end of the layout:

<script>

window.addEventListener('load', ev => {

    // the video ID fields from the page if 
    // it has any video id custom field published by Joomla
    let sourceNodes = document.querySelectorAll(".ytvideoid");

    // const sourceValues = sourceNodes.values(); // if needed

    if (sourceNodes.length) {

        const videoIds = [];

        for (const val of sourceNodes) {
            const id = val.innerText;
            
            if (id !== "") {
                videoIds.push(id);
            }
        }
    
        if (videoIds.length) {

            sourceNodes.forEach((el, index) => {
                el.classList.remove("hidden");
                el.innerHTML = "";
                let coverimage = document.createElement( "img" );
                coverimage.setAttribute("src", "https://img.youtube.com/vi/" + videoIds[index] + "/hqdefault.jpg");
                el.appendChild(coverimage);
            });

            for (let i = 0; i < sourceNodes.length; i++) {

                sourceNodes[i].addEventListener( "click", function() {

                    let iframe = document.createElement( "iframe" );
                        iframe.setAttribute( "frameborder", "0" );
                        iframe.setAttribute( "allowfullscreen", "" );
                        iframe.setAttribute( "src", "https://www.youtube.com/embed/" + videoIds[i]); 
                    this.innerHTML = "";
                    this.appendChild( iframe );
                });    
            }
        }
    }
});

</script>

Before javascript runs, the HTML created by Joomla with these custom text fields should be exactly like in this codepen: https://codepen.io/Zollie01/pen/XWxVLLQ

And everything should work like in this codepen.

As an extra mile, Gillian set up a demo site for this and the script is applied now on Joomla:

https://ytubetest.joomla.com/

1
  • 1
    Comments have been moved to chat; please do not continue the discussion here. Before posting a comment below this one, please review the purposes of comments. Comments that do not request clarification or suggest improvements usually belong as an answer, on Joomla Meta, or in Joomla Chat. Comments continuing discussion may be removed. May 7, 2023 at 4:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.