PHP loop in .js file

javascript
wordpress

#1

I have a load-more.js file the entire code is here →

jQuery(function($){
	$('.class1').append( '<span class="load-more"></span>' );
	var button = $('.class1 .load-more');
	var page = 2;
	var loading = false;
	var scrollHandling = {
	    allow: true,
	    reallow: function() {
	        scrollHandling.allow = true;
	    },
	    delay: 400 //(milliseconds) adjust to the highest acceptable value
	};

	$(window).scroll(function(){
		if( ! loading && scrollHandling.allow ) {
			scrollHandling.allow = false;
			setTimeout(scrollHandling.reallow, scrollHandling.delay);
			var offset = $(button).offset().top - $(window).scrollTop();
			if( 2000 > offset ) {
				loading = true;
				var data = {
					action: 'be_ajax_load_more',
					nonce: beloadmore.nonce,
					page: page,
					query: beloadmore.query,
				};
				$.post(beloadmore.url, data, function(res) {
					if( res.success) {
						$('.class1').append( res.data );
						$('.class1').append( button );
						page = page + 1;
						loading = false;
					} else {
						// console.log(res);
					}
				}).fail(function(xhr, textStatus, e) {
					// console.log(xhr.responseText);
				});

			}
		}
	});
});

However →

1 →

$('.class1').append( '<span class="load-more"></span>' );
	var button = $('.class1 .load-more');

2 →

Needs to be run by a PHp condition because different classes are needed based on the template choosen in the theme customizer.

$('.class1').append( res.data );
$('.class1').append( button );

What I have tried in the load-more.js:

<?php if ( get_theme_mod( 'template_setting_condition', '' ) === 'option_horizontal' ) ?> {
$('.class1').append( '<span class="load-more"></span>' );
	var button = $('.class1 .load-more');
<?php }elseif( get_theme_mod( 'template_setting_condition', '' ) === 'option_gridl' )  { ?>

('.class2').append( '<span class="load-more"></span>' );
	var button = $('.class2 .load-more');
<?php } ?>

Everything is in the PHP tag in the .js file.

But this doesn't work. Is it ever possible that php tags can work in the .js file?

Or my entire effort is in the wrong direction.?


#2

Hi there, no this is not possible. To make that work you'll have to make your file end with '.php' i.e. 'myScript.js.php'.
Then you could just include it as a template as part of your HTML.

Hope that helped.

Andres


#3

Thanks, but I think in that case it will work as a php file not as a JS file. Right?


#4

Yes that is correct... I sometimes name them with '.js.php' if it only contains JS and no HTML... although technically it's still HTML and you would require a script tag...


#5

Thanks for saving my time further.

I was trying all this based on these threads →





#6

I've put together a simple code example for you, let me know if there is anything that needs explanation:

<body>
<?php

function template($file, $vars) {
    $rv = '';
    if (is_array($vars)) {
        foreach ($vars as $name => $val) {
            $varName = $name;     
            // I suggest using a function to sanitize name so that it conforms to a variable format i.e no dashes or spaces
            $$varName=$val;
        }
    }
    if (file_exists($file)) {
        ob_start();
        include($file);
        $rv = ob_get_clean();
    } else {
        throw new Exception("Invalid template file given: ". $file);
    }
    return $rv;
}
$myTemplateContent = template(__DIR__.'/script.js.php', array(
    'var1' => 'value1',
    'var2' => 'value2'
));
echo $myTemplateContent;
?>
</body>

and the script file:

<script type="text/javascript">
    var var1 = '<?php echo $var1 ?>';
    alert(var1);
    var var2 = '<?php echo $var2 ?>';
    alert(var2);
</script>

#7

While it is possible to generate JS dynamically with PHP, jumbling languages like this should better be avoided as it makes your code very hard to maintain. A cleaner approach would be to set a class or data-* attribute on the body that indicates the template:

<body data-template="<?php echo get_theme_mod( 'template_setting_condition', '' ); ?>">...</body>

You can then access that setting with regular JS like so:

var template = document.body.dataset.template

if (template === 'option_horizontal') {
  // ...
} else if (template === 'option_gridl') {
  // ...
}

#8

What does that matter? As long as you serve the right headers and the right content, you can create any file type by PHP. How else would a browser understand dynamically created HTML pages?


#9

Not necessarily IMHO it's just another mechanism that can be used and abused. I find bridging the gap between PHP and JS something awesome if done the right way... And not having to couple everything tightly with the dom, I'm not a big fan of that. Many times I just convert php arrays with json encode and dump them in a script tag as server side configuration of a component that needs to get initialised. I don't see anything wrong with that but again everything can be used in the wrong way...


#10

Yes, well the data-* attribute was just an example as it seemed appropriate in this case... if a template setting is not related to the DOM then what else. :-)

Generally speaking though I think it's okay to generate an object in the global namespace that holds the required data, or maybe small isolated things like generating a tracking pixel call with some backend data. .. e.g.

<script>
winow.myConfig = <?= json_encode($myConfig) ?>

fbq('track', 'Purchase', {
  value: <?= $price ?>,
  currency: '<?= $currency ?>'
});
</script>

But PHP certainly shouldn't modify the actual JS logic (like the branching in the OP)... I mean how would you even write unit tests for this? How would you properly lint your code? How would you minify your code, generate source maps, let alone use a module bundler or transpiler?


#11

I absolutely agree... Although the OP should change their approach to the problem I did not want them to think that passing variables directly from PHP to JS is a bad thing, in fact it can be very good if used in the right way. As for myself I almost always use that in the way that you just showed in your last code example.
Cheers


#12

Its best to create a reusable process to handle passing server-side variables client-side. In the past I have added everything to an associative array and printed it out as JavaScript in the head of the document. You could have a function that adds the info to an array printing it out as an object literal in head of the document. Be careful though not to expose any security critical info.

Example interface:
set_js_varaiable(['title'=> 'whatever','id'=>123],'blog.post);

In js you would access something like this:
let post = config.blog.post

I'm oo all the way so I wouldn't do it exactly like that but you that is the basic idea.

I learned that method from Drupal which is a much more sophisticated interface of that basic concept.

https://api.drupal.org/api/drupal/includes%21common.inc/function/drupal_add_js/7.x

Use the variable values in js conditions. No one likes seeing js and php mixed together especially php conditionals that output different js code. That is really hard to debug and read. Keeping the js as js alone will make keep the integrity of debugging tools intact.

If you are using Wordpress I'm certain wp has something similiar to the drupal interface.


#13

BTW @m3g4p0p I think you missed replacing the PHP vars for myConfig.property in your last code sample. Small thing but might confuse the OP if they try it out :wink:
Cheers


#14

What do you mean? All I am guilty of is misspelling window... ^^ anyway this code

<?php
$myConfig = [
  'foo' => 'bar',
  'mol' => 42
];
?>

<script>
window.myConfig = <?= json_encode($myConfig) ?>
</script>

will produce the expected result

<script>
window.myConfig = {"foo":"bar","mol":42}
</script>

PS: Oh or do you mean the PHP short tags? That's just a small convenience shorthand for <?php echo ...; ?>


#15

This I mean

<script>
window.myConfig = <?= json_encode($myConfig) ?>;

fbq('track', 'Purchase', {
  value: window.myConfig.value,
  currency: window.myConfig.currency
});
</script>

Whereas you had:

<script>
winow.myConfig = <?= json_encode($myConfig) ?>

fbq('track', 'Purchase', {
  value: <?= $price ?>,
  currency: '<?= $currency ?>'
});
</script>

actually no I misread, I mean replacing the PHP variables for JS ones like I showed above


#16

Ah I see, no that was just supposed to be another example of what I'd consider a legitimate mix of PHP and JS. :-) Such tracking pixel calls are usually standing for themselves and are not part of the main.js or similar, so I'd say that's okay.


#17

I find a simple solution:

$('.class1').append( res.data );
$('.class1').append( button );

I changed the above to →

$('.theme_infinite_scroll').append( res.data );
$('.theme_infinite_scroll').append( button );

Then used this class in those two templates div in addition to other classes that exist in those div's:
theme_infinite_scroll

This class has no definition in CSS, but javascript uses this class to generate the infinite scroll.

Solved!


closed #18

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.