I'm building a custom template for WordPress and in a couple places I've used PHP if else statements like the following example within the JS in the footer. It works fine but I'm wondering if this is considered "bad practice" and if so what is a better way to handle it?
<script type="text/javascript">
var $submenu = $('.submenu');
// SUBMENU animation
<?php if ( in_category('Collection') == false ) { ?> // if not a Collection subpage
$('.menu li a').each(function() {
if ( $(this).text() == 'Collection' ) { // If is Collection link show submenu on hover
$(this).mouseenter(function() {
$submenu.slideDown();
});
} else { // else close submenu on hover over other menu links
$(this).mouseenter(function() {
$submenu.slideUp();
});
}
});
$('.nav').mouseleave(function() { // close submenu
$submenu.slideUp();
});
<?php } else { ?> // If a Collection subpage always show subnav
$submenu.show();
<?php } ?>
</script>
Whilst there isn't anything really wrong with mixing PHP and JavaScript, I personally find it quite awkward to read and modify, plus it makes moving that code around tricky. For example if you decided to export that JavaScript to an external file, which has numerous benefits:
<script src="myjs.js.php"></script>
This becomes clunky if your JavaScript needs to know certain values in order to calculate in_category('Collection') as you have to start using GET parameters (unless you are depending on session variables, which can get quite compex and unpredictable, especially through asset requests):
<script src="myjs.js.php?random_vars_required=123"></script>
Another point to be wary of is when having a JavaScript file that changes it's content depending on server-side logic, you have to be careful with what the browser is caching (to avoid these type of problems, it basically means you have to change the request URL for each possible outcome of the js file). i.e.
<script src="myjs.js.php?collection=true"></script>
<script src="myjs.js.php?collection=false"></script>
Another downside is by mixing PHP with JS you are likely to end up duplicating the PHP code in numerous places which goes against the DRY principal. This is why the suggested "export data to a javascript variable" is a much nicer idea. However it's best to avoid variables in the global js namespace if possible. Avoiding the global namespace can prove tricky though if you need to share the logic across multiple JavaScript files and don't wish to export your variables at the top of every file.
another possibility
If the logic you are testing is purely boolean in nature, and it also centres around page classification (or sub-region classification), the following is quite a nice way to handle what you are trying to achieve. It's nice mainly because it keeps your PHP and HTML together, and your JS separate.
The following should be placed in whatever template you use to generate your outer HTML:
<?php
$classes = array();
if ( in_category('Collection') ) {
$classes[] = 'collection';
}
$classes = implode(' ', $classes);
?>
<!--
obviously you'd render the rest of the html markup
I've removed it for simplicity
//-->
<body class="<?php echo $classes; ?>"></body>
Then in your JavaScript / jQuery:
if ( $('body.collection').length ) {
/// if collection sub page
}
else {
/// else do otherwise
}
If you'd rather not add a class to your body element, you could always define your boolean check based on something that already exists on one version of the page and not on the other. Although personally I like to keep things clean and only resort to those kind of checks when I know the HTML markup is not going to change much in the future.
Nearly all browsers that the greater world should be worrying about today support multiple classes on elements. So this means even if you have multiple things you wish to check for, as long as it makes sense, you can place these classes on your html or body tag and use jQuery's Sizzle implementation to find them for you.
Building javascript server-side is probably something we've all done, despite the main arguments for not doing so - namely that the js can't be (easily) validated (with eg. jsLint), and can't (easily) be put into a .js file - there's no point allowing the browser to cache just one of two or more possible versions of the script.
You could consider trading off server-side branching for client-side branching, which arguably makes the code more readable but, more importantly, is an intermediate step to my final suggestion (bear with me) :
var $submenu = $('.submenu');
// SUBMENU animation
var isCollection = <?php echo in_category('Collection') ? 'false' : 'true' ?>;
if ( !isCollection ) { // if not a Collection subpage
$('.menu li a').each(function() {
if ( $(this).text() == 'Collection' ) { // If is Collection link show submenu on hover
$(this).mouseenter(function() {
$submenu.slideDown();
});
} else { // else close submenu on hover over other menu links
$(this).mouseenter(function() {
$submenu.slideUp();
});
}
});
$('.nav').mouseleave(function() { // close submenu
$submenu.slideUp();
});
} else { // If a Collection subpage always show subnav
$submenu.show();
}
However, if the boolean isCollection could be determined by another means (eg. by enquiring some aspect of the DOM such as a data-xxx attribute), then you're cooking with gas. Only one version of the js script would be necessary; it could be easily validated with jsLint; and could be moved into a .js file if desired.
Of course you need to set the data-xxx attribute (or whatever) elsewhere in the server-side code (complete with an explanatory comment), which is a possible downside, but maybe not a big one.
Maybe not all js would be amenable to this approach but I think the example in the question would be.
To my mind, this is a viable way ahead on this occasion.
At least its not a sign of great code. There are alternatives:
Generate a JSON object and parse it in JavaScript
Dynamic inclusion of JS files
Just set conditions:
if(<?= (int)$mybool ?>) {
doSomething();
}
Related
I'm stuck using a theme in WordPress for a client where the header is horrible in responsive view. I can work with desktop widths but anything below 768px needs to have an entirely different markup because of the clients demands -- any attempt to try to do this via CSS has led to even more UI disasters. My hope was to utilize jQuery's .html() functionality to swap out Bootstrap grid elements at < 768px. Here's a snippet example -- say I needed to move the logo from a far right position in desktop to the first element on the left in a header. I'm using the theme's declarations for the dynamic logo correctly:
if($(window).width() < 768) {
$('.top-bar').html('<div class="col-md-3"><?php vg_ebuilder_display_logo_sticky(); ?><div class="logo-inside"><?php vg_ebuilder_display_top_logo(); ?></div></div>');
}
But this returns commented out PHP:
<!--?php vg_ebuilder_display_logo_sticky(); ?-->
and
<!--?php vg_ebuilder_display_top_logo(); ?-->
So, maybe two questions here: is there a way to add dynamic PHP like this in WordPress via a jQuery .html() function on $(document).ready and, assuming it could, would it indeed be dynamic if loaded after the DOM?
No. PHP runs on the server, not the client. The javascript would need to make a call to an endpoint that would perform the php logic, return a response, and that response put on the page. Inserting php on the client will not be invoked.
I can't 'comment' a suggestion to you as my reputation isn't yet 50, so hopefully this is the right answer. I found this worked for me with a similar issue in Joomla (Q48891999).
In the div you want to change, add a unique class, e.g. "builder".
Then, if you need to, write a new css class or classes starting with
#media (max-width: 767px) {
.your_new_class {
}
}
- but not using the name 'builder' for the new class - in your custom css file for the div you want to change.
Then use jquery .addClass to apply the css class to your div in your index.php. Something like this:
<script>
$( ".builder" ).addClass( "the_class_you_want_to_apply another_class" );
</script>
The spaces between the parentheses and the double quotes are deliberate, as used in the examples on the jquery website.
In my case, I added this to the bottom of my index.php just before the closing body tag.
You may need to have more than one of these scripts to apply to different elements.
I know that I can remove an empty div using javascript, but is it possible using php?
I have a div that has several if statements that will fill the content of the div. If those terms aren't met I get up with an empty div, doing nothing. The div has a class, if that makes it any simpler.
Is this possible in php? Is there a .hide() or .remove() equivalent in php?
You can however try out by including div inside if condition and closing it wherever it is appropriate,
this displays div if a particular condition is present
else doesn't include particular div in your code at all
For E,g
if(some condn..)
{
echo "<div>";
your code...
echo "</div>";
}
I have shown you the simple one using one if, but you can fix it up for any number of ifs
with little attention of opening and closing of DIV tags
Secondly Jquery is Equivalent to CSS
Jquery
i.e $("#abc").hide();
css
#abc{
display:none;
}
etc i have given you just a sample but you can explore on...
PHP is a server scripting language,So it is not possible.
As the others have mentioned, this is not possible using a server-side language, unless you choose to not render the div at all in the first place. This is not necessarily a bad choice, but depending on what you are planning on doing (if you wanted to provide more of an explanation, please feel free to).
If you would prefer to do this client-side then you could use either vanilla javascript and remove the node from the DOM. Alternatively (probably a better idea) you could remove it using a one-liner using jQuery:
$(".yourDiv").remove();
Up to you - hope that helps!
No, it's not possible to remove a created div with PHP.
What you can do is not create the div unless one of your if statements pass
No, PHP is a SERVER side language that only runs before the page is loaded the only way to hide a div is to give a hidden div in the html. You ill need javascript to hide it dynamicly.
using php, you can do it like this
<?php if(satisfy both $a and $b): ?>
<div>
<?php
if($a)
{
echo $a;
}
else if($b)
{
echo $b;
}
?>
</div>
<?php endif; ?>
I may be going about this all wrong, but here goes.... Im trying to use JavaScript in a WP theme file to do conditional PHP includes based on CSS media queries and pseudo-elements.
In the CSS I use a media query to check for mobile devices in portrait mode, add a hidden :after element to the body under this query with content="mobile_portrait" attribute.
I then wanted to go on the homepage template and use JavaScript like this:
var size = window.getComputedStyle(document.body,':after').getPropertyValue('content');
if (size == 'mobile_portrait') {
<?php
add_action( 'genesis_after_header', 'do_this' );
function do_this() {
require(CHILD_DIR.'/do_this.php');
}
?>
}
else {
<?php
add_action( 'genesis_after_header', 'do_the_other' );
function do_the_other() {
require(CHILD_DIR.'/do_the_other.php');
}
?>
}
It seems like WP is skipping the JavaScript and parsing the PHP because if I take out the else it just loads do_this.php whether the Java check returns true or false, if I leave the else in, it breaks the site :(
Ideas about what im doing wrong? or a better way to load PHP files based on media queries?
Thanks in advance
PHP and Javascript cannot be used interchangeably like you are trying to do.
PHP is the renderer, it is building the output (building the Javascript)
The PHP will be run, regardless of where they are put inside a Javascript conditional like you have, as the Javascript conditionals have no bearing on them being executed.
==
Now to add a solution:
Maybe use the javascript like you have setup simply redirect to the phpfile you want to run for a given view:
var size = window.getComputedStyle(document.body,':after').getPropertyValue('content');
if (size == 'mobile_portrait') {
window.location = '<?= CHILD_DIR.'/do_this.php'; ?>';
}
else {
window.location = '<?= CHILD_DIR.'/do_the_other.php'; ?>';
}
So have different pages that do the necessary includes based on the media query
Situation:
A PHP Templating system that is responsible for building a pages HTML.
Javascript core functions are all in external files
Each Template has some default Javascript Functions that need to be called on a per/template basis
When A page is rendered, I next need to call a set of Javascript functions: i.e.
<script type="text/javascript">
$(document).ready(function{
API.loadThis(); // all these Javascript functions are in an external JS file
API.loadThat();
API.buildDateSelector("#idForSelector");
// etc
});
</script>
Up until now I have just appended that as text to each of the HTML templates. However, in the case of a Page that consists of multiple smaller Templates (each possibly containing their own initialization Javascript), then I have multiple bits of inline Javascript thrown all over my webpage.
My question is:
how should I properly organize everything so that I can easily "register" or "trigger" some default Javascript to be called upon page load?
Or is appending each block of Javascript to each template (like above) appropriate?
What I would do is quite similar to #Chris. However, I'd suggest a few minor changes:
Add a parameter to the addJS function which indicates the position on the page. By default you should have support for at least head and foot (head would place it in the head, foot would place it right before the closing </body>).
public function addJS($string, $position = 'head') {
if (!is_array($this->js[$position])) {
$this->js[$position] = array($string);
} elseif (!in_array($string, $this->js[$position])) {
$this->js[$position][] = $string;
}
}
Then, include tokens in the template to indicate the positions:
{{js_head}}
</head>
<body>
<!--content here-->
{{js_foot}}
</body>
Then, when rendering, just do something like:
$js = $this->js;
$positions = preg_replace_callback(
'/{{js_(inline_)?([a-zA-Z0-9]+)}}/',
function ($match) use ($js) {
if (isset($js[$match[2]])) {
$js = implode("\n", $js[$match[2]]);
if ($match[1] == 'inline') {
return $js;
} else {
return '<script type="text/javascript">'.$js.'</script>';
}
return '';
},
$templateBody
);
Now, the real benefit is that your templates can cleanly and trivially define their own positions for re-used and commonly used bits:
$this->addJS('return this.form.submit();', 'submit_form');
$html = '
<input type="text" onblur="{{js_inline_submit_form}}" />
<button name="submit" onclick="{{js_inline_submit_form}}" />
';
It can be quite useful since now you're not duplicating the JS calls everywhere in your code. Plus, it'll reduce the overhead of wrapping each output in <script> tags (since it wraps the entire position in the tags, rather than each piece of content)...
This would allow you to then take all of the non-inline JS and compile a series of files at run-time to send to the browser to take care of caching. It adds the benefit of being able to keep your JS close to your views (for maintainability) yet still serve cached JS and not have to re-send it every time...
public function buildJSCache($position) {
if (!isset($this->js[$position]) || empty($this->js[$position])) {
return '';
}
$file = implode($this->js[$position]);
$name = 'js/'.md5($file) .'.js';
if (!file_exists($name)) {
file_put_contents($name, $file);
}
return $name;
}
Then, in your template code, just do:
$replace = $this->buildJSCache('head');
if ($replace) {
$replace = '<script type="text/javascript" src="'.$filename.'"></script>';
}
$template = str_replace('{{js_head}}', $replace, $template);
You get the double-win of maintainability and speed to the user (you could even minify it if you wanted).
Note: all of this code is demonstration only, if you were to use it in production, I'd clean it up and think it out a bit further...
That's my $0.02 at least...
There are a lot of ways to do this. I suggest that you get some open source frameworks, look at how they do things and decide on your preferences. Some techniques are considered "best practice", but a lot of a framework's structure boils down to developer preference.
I have a framework I use for my own projects that is similar to what you describe, each of the smaller templates is termed as a "component". Each component is able to add any amount of javascript to itself using an addJS() method, likewise for css and html. A top-level controller loops through a given page's content (in terms of components). This give me a chance to have all the css, javascript, and html loaded ahead of time. Then, I can output them in whatever order I see fit.
So:
page controller handles request
inits one or more components
component load method populates html, javascript, and css class properties (arrays of file names, string for html)
for itself
components has its own set of templates, js, css
outputs site-wide templates
includes all component css within page header
iterates through components, outputs component html, layout stuff
outputs component JS for page footer
I have a components folder, within it are folders for each component. Within each component folder is a php file (that component's handler), optionally one or more css/js files. This keeps everything organized nicely.
I have page which created dynamically.
Now I want to add ajax function, so I want to add if statement to change the outputs.
if(js is on){
...
...
echo "js is on";
}else{
...
echo "js is off";
}
Is there any way I can detect if js is on with php?
Or is there any way I can remove/hide it by jquery?
Thanks in advance.
PHP is executed before any browser action takes place, so no, PHP cannot directly detect whether the user has Javascript on or off.
You must provide a bit more info on what you're doing for us to find you a workaround. In PHP, it is possible to detect whether the call was made via AJAX or not using the $_SERVER['X_HTTP_REQUESTED_WITH'] global variable which jQuery will set automatically.
If you need to show an element when Javascript is enabled, you can first hide the element with CSS and enable it with Javascript/jQuery. The same goes the other way around also.
You can't do that in PHP because the page is rendered by the time you know. And apart from some crazy redirect scenario, your best bet may be to use CSS + JS to show/hide what you need:
What I normally do (and your mileage may vary depending on what you need to show/hide) is this:
<html>
<head>
... other stuff here, title, meta, etc ...
<script type="text/javascript">document.documentElement.className += " js"</script>
... everything else
</head>
Then you can use CSS to hide/show based on if JavaScript is enabled/disabled:
/* Hide by default, show if JS is enabled */
#needsJS { display: none }
.js #needsJS { display: block }
/* Show by default, hide if JS is enabled */
.js #fallback { display: none }
It can't do it directly, and workarounds for it are usually awkward and wasteful.
Use progressive enhancement technique instead.
Just make the website working without JS. If everything is fine, you can attach JS functionality with e.g. jQuery.
This is also called unobtrusive JavaScript.
So you basically don't distinguish between client with JS and client without JS. You don't provide different output. You set up your HTML code in such a way that you can easily identify the elements that should JS functionality an this functionality in a programmatic way.
This way is even easier for you as you don't have to think about different outputs and it guarantees that the site is also working without JS.