16

I'm building a custom theme that has a lot of variables that I wish to use throughout.

Example:

$tv     = $options['tv'];
$movies = $options['movies'];
$print  = $options['print'];
//....and about 50 more.

For this purpose I have been simply placing them all in a file called vars.php and then in header.php of the theme I include it...

require_once('vars.php');

While this does work, it doesn't feel like the best way. I've read on numerous occasions that use global variables (presumably in functions.php) isn't a good idea, but is this true?

But if it's fine to use global variables in functions.php (even lots of them) is this the right way to go about it?:

global $tv;
$tv     = $options['tv'];

global $movies
$movies = $options['movies'];

global $print
$print  = $options['print'];
User_FTW
  • 661
  • 1
  • 15
  • 32

6 Answers6

10

The best way for this is to define all the variables explicitly in functions.php or in main plugin file for plugin. I have verified this is the way most popular plugins including akismet use. Specifically you need to do this.

define( MYVAR_TV, $options['tv'] );
define( MYVAR_MOVIES, $options['movies'] );
define( MYVAR_PRINT, $options['print'] );

After these you can just use them whereever you want like

echo MYVAR_TV;

Hope it helps.

shazyriver
  • 3,103
  • 4
  • 27
  • 50
  • 2
    @user3256143 This is best practice. Taking it a step forward you could create a shortcode to access the variables from a WYSIWYG. – Dedering Sep 26 '17 at 15:43
  • This is good if your data are only scalars, it won't work even with simple arrays before PHP 7.0 – Jesús Franco Sep 28 '17 at 18:37
9

It's fine to use global, but it's not encouraged (you can read more here Are global variables in PHP considered bad practice? If so, why?). You may consider Singleton implementation:

<?php
class GlobalVariable {
    /**
     * @var array
     */
    public static $option = [];
}

// You can set the variable using this way
GlobalVariable::$option['movies'] = 1;

// And get the variables using that array
print_r(GlobalVariable::$option);

Hope this can help you.

Trac Nguyen
  • 474
  • 4
  • 7
  • This keeps some of the disadvantages of the original poster's solution. Namely: there's no way to detect a typo in the array key (`$option['novies']`). Also: In case the contents of the variables don't change, I'd favor the `define()` approach by @shazyriver. – amenthes Sep 28 '17 at 20:03
  • This way allow you to use many type of variables. In term you don't want your values changed, take a look at Singleton implementation https://stackoverflow.com/questions/37138134/php-singleton-design-pattern-inheritance-error. It may be a little bit abstract but it's a better approach. – Trac Nguyen Sep 29 '17 at 04:35
2

What about creating a function in functions.php that returns an array of your variables?

Example: $options = get_my_custom_vars();

2

I'm assuming that you would like global variables, where it makes an array with all your variables. To use it:

$GLOBALS['your-varriable']

Source: PHP Documentation

HoogleyBoogley
  • 320
  • 2
  • 14
2

I personally like using Acf Options Addon. Altering these and having them translatable via the wpml plugin is useful, too.

These Options will be addable/editable within a "Options Page" in the Backend or as programmed as described in the link.

After initializing the addon via the functions.php

if( function_exists('acf_add_options_page') ) {

acf_add_options_page();

}

simply call these in the template via

<?php the_field('header_title', 'option'); ?>
cptnk
  • 2,390
  • 17
  • 29
2

You can implement a custom stream wrapper, too. This way you could access and store data using functions like file_get_contents, file_put_contents, fread, fwrite, etc. Just like reading and writing from a file, or getting info from a remote URL.

Actually there is an example in the PHP manual, using global variables like you ask. But lets pull it from there in order of completeness and adapting it to your use case in WP and examples of use.

<?php
// variable-stream-class.php just this is pulled from the PHP manual

class VariableStream {
    var $position;
    var $varname;

    function stream_open($path, $mode, $options, &$opened_path)
    {
        $url = parse_url($path);
        $this->varname = $url["host"];
        $this->position = 0;

        return true;
    }

    function stream_read($count)
    {
        $ret = substr($GLOBALS[$this->varname], $this->position, $count);
        $this->position += strlen($ret);
        return $ret;
    }

    function stream_write($data)
    {
        $left = substr($GLOBALS[$this->varname], 0, $this->position);
        $right = substr($GLOBALS[$this->varname], $this->position + strlen($data));
        $GLOBALS[$this->varname] = $left . $data . $right;
        $this->position += strlen($data);
        return strlen($data);
    }

    function stream_tell()
    {
        return $this->position;
    }

    function stream_eof()
    {
        return $this->position >= strlen($GLOBALS[$this->varname]);
    }

    function stream_seek($offset, $whence)
    {
        switch ($whence) {
            case SEEK_SET:
                if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) {
                     $this->position = $offset;
                     return true;
                } else {
                     return false;
                }
                break;

            case SEEK_CUR:
                if ($offset >= 0) {
                     $this->position += $offset;
                     return true;
                } else {
                     return false;
                }
                break;

            case SEEK_END:
                if (strlen($GLOBALS[$this->varname]) + $offset >= 0) {
                     $this->position = strlen($GLOBALS[$this->varname]) + $offset;
                     return true;
                } else {
                     return false;
                }
                break;

            default:
                return false;
        }
    }

    function stream_metadata($path, $option, $var) 
    {
        if($option == STREAM_META_TOUCH) {
            $url = parse_url($path);
            $varname = $url["host"];
            if(!isset($GLOBALS[$varname])) {
                $GLOBALS[$varname] = '';
            }
            return true;
        }
        return false;
    }
}

Let's suppose you have a plugin to isolate your functions, being able to deactivate it for debugging and not losing it if you change the active theme. I'd recommend putting something like this in your plugin entrypoint:

<?php
/**
 * Plugin Name: Stream Wrapper for global variables
 * Plugin URI: https://stackoverflow.com/q/46248656/
 * Description: Utility class and functions to enable global data sharing in WordPress
 * Author: Jesús E. Franco Martínez and the PHP Documentation Group
 * Contributors: tzkmx
 * Version: 0.1
 * Author URI: https://tzkmx.wordpress.com
 */
require 'variable-stream-class.php';

stream_wrapper_register("var", "VariableStream")
    or wp_die("Failed to register protocol", null, ['back_link' => true]);

Then, in your templates or other site plugins you can use the above mentioned functions, or use custom aliases. Let's expand on your request:

// functions.php in your theme or better, in the same plugin.php above

// Using a hook just for frontend in order to get populated
// our variables without require calls in the theme.

add_action('wp_head', 'populate_my_awesome_plugin_options');

function populate_my_awesome_plugin_options() {

// Let's say you get your data from a single get_option call
    $options = get_option( 'my_awesome_plugin_options' );

    foreach( $options as $key => $value ) {
        file_put_contents( 'var://' . $key, $value );
    }
}

function pop_get_var( $var_name ) {
    return file_get_contents( 'var://' . $var_name );
}

Finally, in the header.php or whatever template file you are going to consume your data, the call is just like this:

<p>TV favorite show: <strong><?= pop_get_var( 'tv' ) ?></strong></p>

<p>Movies I like: <strong><?= pop_get_var( 'movies' ) ?></strong></p>

<p>Impressum: <em><?= pop_get_var( 'print' ) ?></em></p>

I know it may look like a lot of boilerplate at first, but because of separation of concerns, you are not limited only to scalar values like using constants, also your stream wrapper could be an adapter to whatever data store you like and not only in memory or stored in WordPress options table. And using a custom function eases you the hassle of writing such long calls to a singleton class, or calling global wherever you want to access your custom data.

Actually if you read the examples in the PHP manual, you'll find an example of using the wrapper to store an entire text, that you could call with include. There is nothing stopping you from using even serialized data, in example with json_encode/json_decode, and stored with your wrapper, even directly in the database with little effort. There is another example to write/read data from a database with PDO, but is easily ported to use WordPress $wpdb object.

Jesús Franco
  • 240
  • 3
  • 11