asked on
Use PHP Loop to output values inside a JavaScript
So I have a Java Script I am using to pre-load heavier gif files after the page loads
I have got it working by manually inputting the the data into the JavaScript - however I would like to use a PHP loop, to output the the values dynamically from a custom post type.
This is the post data I use to drill down into the custom post type and custom post type tax I am trying to pull from ..
<?php
$args = array(
'numberposts' => 100,
'post_type' => 'rps-portfolio',
'tax_query' => array(
array(
'taxonomy' => 'portfolio-type',
'field' => 'id',
'terms' => 438
)
)
);
$myposts = get_posts( $args );
//var_dump($myposts);
foreach( $myposts as $post ) : setup_postdata($post);
$animated_gif = get_post_meta($post->ID, 'wpcf-animated-gif', true);
?>
and this is how I have pulled in the animated gif from the custom field in another loop I have used... So this is the name of the custom field to be output as the the URL.
<?= get_post_meta($post->ID, "wpcf-animated-gif", true); ?>
So there are a couple of values in the the JavaScript that need to increment by 1 as the loop processes each piece of data...
Here is a screen shot showing the dynamic parts that need to be output in the loop and this is also the desired output after the loop runs
Here is my base JavaScript
<script type="text/javascript">function preloader() {
if (document.images) {
// PHP Loop Code to recreate this structure Needed
var img1 = new Image();
var img2 = new Image();
var img3 = new Image();
img1.src = "/wp-content/uploads/2022/08/candle-lighters.gif";
img2.src = "/wp-content/uploads/2022/08/mama-gerties.gif";
img3.src = "/wp-content/uploads/2022/08/artemis-website-gif.gif";
}
}
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent(preloader);
</script>
So looking for a way I can possibly query my custom field and dynamically output the data in the JavaScript using a loop that increments the variable name by 1 as the loop is processed in the two spots outlined in red on the screen shot and and then output the url of the gif ( <?= get_post_meta($post->ID, "wpcf-animated-gif", true); ?> ) also outlined in red on the screen shot .
https://jsfiddle.net/mplungjan/Lbp1qtxc/
// this is a simple JS array. You ONLY need the PHP to update this
// $animated_gifs is a PHP array of your images
const sources = <?= json_encode($animated_gifs) ?>;
// here is the rest of the code
let cnt = 0;
const preload = () => {
if (cnt >= sources.length) return; // stop
const img = new Image()
img.addEventListener("load", () => {
cnt++;
preload();
});
img.addEventListener("error", () => {
console.log("Failed to load", sources[cnt])
cnt++;
preload();
});
img.src = sources[cnt];
};
window.addEventListener("DOMContentLoaded", preload);
ASKER
is this what you are referring to?
<?php
$args = array(
'numberposts' => 100,
'post_type' => 'rps-portfolio',
'tax_query' => array(
array(
'taxonomy' => 'portfolio-type',
'field' => 'id',
'terms' => 438
)
)
);
$myposts = get_posts( $args );
//var_dump($myposts);
foreach( $myposts as $post ) : setup_postdata($post);
$animated_gif = get_post_meta($post->ID, 'wpcf-animated-gif', true);
?>
in your example it looks like you have hard coded the image paths - but I need to pull the image paths in dynamically via a loop. from a custom field and then increment the variable name by one .
<? $animated_gifs = array();
foreach($myposts as $post) {
setup_postdata($post);
$animated_gifs[] = get_post_meta($post->ID, 'wpcf-animated-gif', true);
}?>
const sources = <?= json_encode($animated_gifs) ?>;
add_action('wp_enqueue_scripts', function() {
$images = [];
$args = [
'numberposts' => 100,
'post_type' => 'rps-portfolio',
'tax_query' => [
'taxonomy' => 'portfolio-type',
'field' => 'id',
'terms' => 438
]
];
$myposts = get_posts( $args );
foreach( $myposts as $post ):
setup_postdata($post);
$images[] = get_post_meta($post->ID, 'wpcf-animated-gif', true);
endforeach;
$js = "const MY_IMAGES = " . json_encode($images);
// enqueue your main JS file
wp_enqueue_script('myscript_handle', get_template_directory_uri() .'/js/yourscript.js');
// and inject your PHP data
wp_add_inline_script('myscript_handle', $js, 'before');
}
ASKER
if (document.images) {
const preload = [];
MY_IMAGES.forEach(img => {
preload.push( (new Image()).src = img);
});
}
@Michel - this is a Wordpress issue, so personally, I'd advise against echoing out PHP in an inline JS file. For WP, using wp_add_inline_script() is the best-practice approach to it.
ASKER
- so the goal in a nutshell was to load the page as fast as possible and then AFTER the page loaded go ahead and start downloading the large animated mouse gif images to make the mouse over image appear faster without the delay
I was able to get the initial solution to work and do all that.... however I wanted it to be dynamic and pull in the image paths from a custom field... So since I had a working hard coded solution - my challenge was to pull in the pieces and dynamically write out the code.
This was the working Solution I ended up with thanks to every ones help
<script>
<?
$images = [];
$args = array(
'numberposts' => 100,
'post_type' => 'rps-portfolio',
'tax_query' => array(
array(
'taxonomy' => 'portfolio-type',
'field' => 'id',
'terms' => 438
)
)
);
$counter=0;
$myposts = get_posts( $args );
foreach( $myposts as $post ):
setup_postdata($post);
$counter++;
echo "var img".$counter." = new Image();\n";
echo "img".$counter.".src = '". get_post_meta($post->ID, 'wpcf-animated-gif', true) ."';\n";
endforeach;
?>
}
}
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent(preloader);
</script>
ASKER
I would be open to knowing how I might adapt this to work with your more modern suggestion.
The solution I showed would do exactly what you wanted, but it would use the recommended Wordpress way of doing things.
ASKER
<script type="text/javascript">
const sources = [<?
$images = [];
$args = array(
'numberposts' => 12,
'post_type' => 'rps-portfolio',
'tax_query' => array(
array(
'taxonomy' => 'portfolio-type',
'field' => 'id',
'terms' => 438
)
)
);
$myposts = get_posts( $args );
foreach( $myposts as $post ):
setup_postdata($post);
echo "'". get_post_meta($post->ID, 'wpcf-animated-gif', true) ."',\n";
endforeach;
?>
];
let cnt = 0;
const preload = () => {
if (cnt >= sources.length) return; // stop
const img = new Image()
img.addEventListener("load", () => {
cnt++;
preload();
});
img.addEventListener("error", () => {
console.log("Failed to load", sources[cnt])
cnt++;
preload();
});
img.src = sources[cnt];
};
window.addEventListener("DOMContentLoaded", preload);
</script>
It seems to work, just one question- Does this do the pre loading of the animated gifs after the page loads?
or
Does this start preloading the images as soon as the page loads?
- ideally I would like the page to load first - and then begin preloading the images after the page loads - if this doesn't work that way what would we need to update in order to make it work that way?
This is what the current output looks like when I view the page source - Does this look correct?
I was originally using this method shown here https://perishablepress.com/3-ways-preload-images-css-javascript-ajax/ that you said was old (Method 2: Preloading with JavaScript Only - JavaScript Method #2 ) because of this explanation -
We can even improve this method a bit by delaying preloading until after the page loads. To do this, we simply wrap the script in a function and use addLoadEvent() to make it work:
window.addEventListener("D
It is more or less the same as INSTEAD use preload() at the bottom of the page depending on how many external files you load
<script>
preload()
</script>
</body>
const sources = [
....
....
?>
].filter(img => img && img.trim() !== "");
ASKER
window.addEventListener("DOMContentLoaded", preload);
Is that correct?
ASKER
ASKER
https://rpsstage.wpengine.com/our-work/
You do realise that you have jQuery available to you on your site, so the whole notion of DOMContentLoaded event listeners is not necssary. Just wrap your code in the jQuery Dom Ready block - it'll do the same thing
ASKER
This is what should appear in the view source -
<script type="text/javascript">
const sources = ['',
'https://rpsstage.wpengine.com/wp-content/uploads/2022/08/candle-lighters.gif',
'https://rpsstage.wpengine.com/wp-content/uploads/2022/08/artemis-website-gif.gif',
'https://rpsstage.wpengine.com/wp-content/uploads/2022/08/mama-gerties.gif',
].filter(img => img && img.trim() !== "");
let cnt = 0;
const preload = () => {
if (cnt >= sources.length) return; // stop
const img = new Image()
img.addEventListener("load", () => {
cnt++;
preload();
});
img.addEventListener("error", () => {
console.log("Failed to load", sources[cnt])
cnt++;
preload();
});
img.src = sources[cnt];
};
window.addEventListener("DOMContentLoaded", preload);
</script>
$( window ).on( "load", preload)
instead of
window.addEventListener("DOMContentLoaded", preload);
ASKER
<script>
jQuery(document).ready(function($) {
// Code that uses jQuery's $ can follow here.
});
</script>
so would it then look like?
jQuery(document).ready(function($) {
// Code that uses jQuery's $ can follow here.
$( window ).on( "load", preload)
});
jQuery(function($) {
// Code goes here and you can use the $ in here :)
...
});
ASKER
$(function() {
something
something
preload()
})
but
$( window ).on( "load", preload)
or
jQuery( window ).on( "load", preload)
does the same and can be placed anywhere after the jQuery library but NOT in another load/ready function
ASKER
<script type="text/javascript">
jQuery(document).ready(function($) {
// Code that uses jQuery's $ can follow here.
const sources = [<?
$images = [];
$args = array(
'numberposts' => 12,
'post_type' => 'rps-portfolio',
'tax_query' => array(
array(
'taxonomy' => 'portfolio-type',
'field' => 'id',
'terms' => 438
)
)
);
$myposts = get_posts( $args );
foreach( $myposts as $post ):
setup_postdata($post);
echo "'". get_post_meta($post->ID, 'wpcf-animated-gif', true) ."',\n";
endforeach;
?>
].filter(img => img && img.trim() !== "");
let cnt = 0;
const preload = () => {
if (cnt >= sources.length) return; // stop
const img = new Image()
img.addEventListener("load", () => {
cnt++;
preload();
});
img.addEventListener("error", () => {
console.log("Failed to load", sources[cnt])
cnt++;
preload();
});
img.src = sources[cnt];
};
$( window ).on( "load", preload)
});
</script>
EITHER change it to just
preload()
OR move
jQuery( window ).on( "load", preload);
outside the });
ASKER
ASKER
<script type="text/javascript">
jQuery(document).ready(function(){
const sources = [<?
$images = [];
$args = array(
'numberposts' => 12,
'post_type' => 'rps-portfolio',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'portfolio-type',
'field' => 'term_id',
'terms' => 403
),
array(
'relation' => 'AND',
'taxonomy' => 'portfolio-type',
'field' => 'term_id',
'terms' => 438
)
)
);
$myposts = get_posts( $args );
foreach( $myposts as $post ):
setup_postdata($post);
echo "'". get_post_meta($post->ID, 'wpcf-animated-gif', true) ."',\n";
endforeach;
?>
].filter(img => img && img.trim() !== "");
let cnt = 0;
const preload = () => {
if (cnt >= sources.length) return; // stop
const img = new Image()
img.addEventListener("load", () => {
cnt++;
preload();
});
img.addEventListener("error", () => {
console.log("Failed to load", sources[cnt])
cnt++;
preload();
});
img.src = sources[cnt];
};
preload()
});
</script>
Probably the most 'wordpress' way to do it is to call the wp_add_inline_script() function - either from your own custom plugin or from your themes function.php file. Basically, you enqueue your external JS file and then you add the inline JS code. General idea is something along these lines:
Open in new window
You'll need to edit your JS a little because what the above code does is create a variable within Javascript called MY_IMAGES . That will be an array of your images, and because its in JS, you can just loop over it:Open in new window