0

I'm a developer who is relatively new to developing in PHP for WordPress, and I am working on a WordPress site that has a considerable amount of custom code in the site's theme. I have been enjoying using the WordPress Coding Standards tool, since it often makes me aware of PHP's gotchas and footguns.

One of the coding standards that seems to come up a lot is related to variable naming, which typically validate against three criteria:

  1. Use $snake_case
  2. Don't override WordPress global variables like $post and $id.
  3. Prefix all global variables with $theme_name_ to have the effect of namespacing these variables to avoid conflicts with globals from WP or other packages.

In other languages I am more experienced with like JavaScript, I tend to code in a functional style, and avoid polluting global scope by using IIFEs.

What I've seen so far with template files and template parts in WordPress themes seems to suggest it is impossible not to pollute global scope, so I'm very curious to know if I'm unaware of a better practice, or otherwise missing something.

For example, again comparing with JavaScript, if I wanted to write a template file, I could do something like this:

export function template_html (args) {
  const title = args['title'];
  const subtitle = args['subtitle'];
  return `
<h1>${title}</h1>
<h2>${subtitle}</h2>
<p>Hello world</p>
`;
}

Whereas in WordPress, I have something like the following:

<?php
/**
 * This is a template file
 *
 * @package my-theme
 */

$my_theme_title = $args['title'];
$my_theme_subtitle = $args['subtitle'];
?>

<h1><?php echo esc_html( $my_theme_title ); ?></h1>
<h2><?php echo esc_html( $my_theme_subtitle ); ?></h2>
<p>Hello world</p>

Is this really as good as it gets? I am still learning PHP require semantics and it seems worrying that if you can't avoid populating the global variable scope, even if the tooling helps you avoid clobbering WP variables, you have no guarantees that you haven't reused your own namespaced global variable names across multiple files and could end up with initial values that you don't expect since they were populated in a different file, earlier in the require chain.

3
  • Have you seen [get_template_part][developer.wordpress.org/reference/functions/get_template_part/]?
    – cjbj
    Apr 11 at 15:45
  • @cjbj Yes, and that's nice for modularity and code reuse, but isn't it true that the .php file you use to implement your template part has exactly the same properties with regard to global variable scope? I don't see how that would address my concerns.
    – NReilingh
    Apr 12 at 12:37
  • It addresses your concerns in the sense that it lets WordPress keep track of your variables. But utlimately, this is a limitation of PHP when you use require while you are already building the template. If you want to go around this, you'll have to skip WP's template system and build something yourself with functions that generate the templates
    – cjbj
    Apr 13 at 11:53

1 Answer 1

2

I feel there is a bit of confusion — let me try and clarify some key concepts.

A WordPress installation can potentially run huge amounts of 3rd party code. Code you can't control. That leads to a high chance of naming collisions. That's why WordPress coding standards suggest to "namespace" functions and variables declared in the global scope. If you're defining a variable inside your functions or templates (so, not in the global scope), there is no need to "namespace" it.

Regarding templates in particular, you probably already know that you can pass data to templates you load through get_template_part() and the likes.

Data passed this way is in no way global: it's only accessible to the template you're passing it to. From the link I shared above:

In the above example, the additional data passed to get_template_part() through the $args variable can be accessed within the foo.php template through the locally scoped $args variable.

In other words, you don't need to namespace your variables in your templates. This is perfectly fine:

<?php
/**
 * This is a template file
 *
 * @package my-theme
 */
?>

<h1><?php echo esc_html( $args['title'] ); ?></h1>
<h2><?php echo esc_html( $args['subtitle'] ); ?></h2>
<p>Hello world</p>
6
  • Right, I know that I can avoid that particular variable assignment just by referencing the array member on $args directly, but I'm trying to imply in my example that there's some other kind of processing I want to do on the args value, for example $my_value = $args['value'] + 1;, and then reference $my_value multiple times in the template without duplicating the expression. Again, this is a toy example so just imagine that the expression is non-trivial and worth deduplicating.
    – NReilingh
    Apr 12 at 12:41
  • I understand that $args is provided to the template by the get_template_part() (or equivalent) function, but I think you are incorrect that defining a variable inside a template is not in the global scope. Everything I can find suggests that in PHP there is no such thing as file/template scope, there is only function scope and global scope, so if you are inside of a template file and not in a function definition, your variables declarations are in the global scope. This would seem to be supported by the WPCS tool which insists that you "namespace" your variables even in a template.
    – NReilingh
    Apr 12 at 12:46
  • Take a look at the PHP documentation for include() (which also applies to require() and require_once()). It clearly states: "If the include occurs inside a function within the calling file, then all of the code contained in the called file will behave as though it had been defined inside that function. So, it will follow the variable scope of that function [...]". This applies to get_template_part() too, by extension. Apr 12 at 13:19
  • Ah, okay -- you're right: replit.com/@NReilingh/UnfinishedDarkgrayBoard#main.php I was thrown by the next line, which says "However, all functions and classes defined in the included file have the global scope." -- so functions defined in the include have global scope, but variables do not. So now I have to wonder why WPCS insists on those naming conventions even for template files, given that WordPress requires all template files within a load_template() function...
    – NReilingh
    Apr 12 at 15:43
  • I'm wondering too — I don't use WPCS myself, but I suspect it's being overly zealous. :) Also, prefixing with theme_name_ or plugin_name_ is now just a relic of the past — true PHP namespaces have been available since 5.3 and are a much better fit. Apr 12 at 16:33

Your Answer

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

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