Completed
Push — develop ( f4a922...18dd12 )
by Zack
18:17 queued 24s
created

Gamajo_Template_Loader::set_template_data()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 2
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Template Loader for Plugins.
4
 *
5
 * @package   Gamajo_Template_Loader
6
 * @author    Gary Jones
7
 * @link      http://github.com/GaryJones/Gamajo-Template-Loader
8
 * @copyright 2013 Gary Jones
9
 * @license   GPL-2.0+
10
 * @version   1.3.0
11
 */
12
13
namespace GV;
14
15
if ( ! class_exists( '\GV\Gamajo_Template_Loader' ) ) {
16
17
	/**
18
	 * Template loader.
19
	 *
20
	 * Originally based on functions in Easy Digital Downloads (thanks Pippin!).
21
	 *
22
	 * When using in a plugin, create a new class that extends this one and just overrides the properties.
23
	 *
24
	 * @package Gamajo_Template_Loader
25
	 * @author  Gary Jones
26
	 */
27
	class Gamajo_Template_Loader {
28
		/**
29
		 * Prefix for filter names.
30
		 *
31
		 * @since 1.0.0
32
		 *
33
		 * @var string
34
		 */
35
		protected $filter_prefix = 'your_plugin';
36
37
		/**
38
		 * Directory name where custom templates for this plugin should be found in the theme.
39
		 *
40
		 * For example: 'your-plugin-templates'.
41
		 *
42
		 * @since 1.0.0
43
		 *
44
		 * @var string
45
		 */
46
		protected $theme_template_directory = 'plugin-templates';
47
48
		/**
49
		 * Reference to the root directory path of this plugin.
50
		 *
51
		 * Can either be a defined constant, or a relative reference from where the subclass lives.
52
		 *
53
		 * e.g. YOUR_PLUGIN_TEMPLATE or plugin_dir_path( dirname( __FILE__ ) ); etc.
54
		 *
55
		 * @since 1.0.0
56
		 *
57
		 * @var string
58
		 */
59
		protected $plugin_directory = 'YOUR_PLUGIN_DIR';
60
61
		/**
62
		 * Directory name where templates are found in this plugin.
63
		 *
64
		 * Can either be a defined constant, or a relative reference from where the subclass lives.
65
		 *
66
		 * e.g. 'templates' or 'includes/templates', etc.
67
		 *
68
		 * @since 1.1.0
69
		 *
70
		 * @var string
71
		 */
72
		protected $plugin_template_directory = 'templates';
73
74
		/**
75
		 * Internal use only: Store located template paths.
76
		 *
77
		 * @var array
78
		 */
79
		private $template_path_cache = array();
80
81
		/**
82
		 * Internal use only: Store variable names used for template data.
83
		 *
84
		 * Means unset_template_data() can remove all custom references from $wp_query.
85
		 *
86
		 * Initialized to contain the default 'data'.
87
		 *
88
		 * @var array
89
		 */
90
		private $template_data_var_names = array('data');
0 ignored issues
show
introduced by
No space after opening parenthesis of array is bad style
Loading history...
introduced by
No space before closing parenthesis of array is bad style
Loading history...
91
92
		/**
93
		 * Clean up template data.
94
		 *
95
		 * @since 1.2.0
96
		 */
97
		public function __destruct() {
98
			$this->unset_template_data();
99
		}
100
101
		/**
102
		 * Retrieve a template part.
103
		 *
104
		 * @since 1.0.0
105
		 *
106
		 * @param string $slug Template slug.
107
		 * @param string $name Optional. Template variation name. Default null.
108
		 * @param bool   $load Optional. Whether to load template. Default true.
109
		 *
110
		 * @return string
111
		 */
112
		public function get_template_part( $slug, $name = null, $load = true ) {
113
			// Execute code for this part.
114
			do_action( 'get_template_part_' . $slug, $slug, $name );
115
			do_action( $this->filter_prefix . '_get_template_part_' . $slug, $slug, $name );
116
117
			// Get files names of templates, for given slug and name.
118
			$templates = $this->get_template_file_names( $slug, $name );
119
120
			// Return the part that is found.
121
			return $this->locate_template( $templates, $load, false );
122
		}
123
124
		/**
125
		 * Make custom data available to template.
126
		 *
127
		 * Data is available to the template as properties under the `$data` variable.
128
		 * i.e. A value provided here under `$data['foo']` is available as `$data->foo`.
129
		 *
130
		 * When an input key has a hyphen, you can use `$data->{foo-bar}` in the template.
131
		 *
132
		 * @since 1.2.0
133
		 *
134
		 * @param mixed  $data     Custom data for the template.
135
		 * @param string $var_name Optional. Variable under which the custom data is available in the template.
136
		 *                         Default is 'data'.
137
		 *
138
		 * @return Gamajo_Template_Loader
139
		 */
140
		public function set_template_data( $data, $var_name = 'data' ) {
141
			global $wp_query;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
142
143
			$wp_query->query_vars[ $var_name ] = (object) $data;
144
145
			// Add $var_name to custom variable store if not default value
146
			if( $var_name !== 'data' ) {
0 ignored issues
show
introduced by
Found "!== '". Use Yoda Condition checks, you must
Loading history...
147
				$this->template_data_var_names[] = $var_name;
148
			}
149
150
			return $this;
151
		}
152
153
		/**
154
		 * Remove access to custom data in template.
155
		 *
156
		 * Good to use once the final template part has been requested.
157
		 *
158
		 * @since 1.2.0
159
		 *
160
		 * @return Gamajo_Template_Loader
161
		 */
162
		public function unset_template_data() {
163
			global $wp_query;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
164
165
			// Remove any duplicates from the custom variable store
166
			$custom_var_names = array_unique( $this->template_data_var_names );
167
168
			// Remove each custom data reference from $wp_query
169
			foreach ( $custom_var_names as $var ) {
170
				if ( isset( $wp_query->query_vars[$var] ) ) {
0 ignored issues
show
introduced by
Array keys should be surrounded by spaces unless they contain a string or an integer.
Loading history...
171
					unset( $wp_query->query_vars[$var] );
0 ignored issues
show
introduced by
Array keys should be surrounded by spaces unless they contain a string or an integer.
Loading history...
172
				}
173
			}
174
175
			return $this;
176
		}
177
178
		/**
179
		 * Given a slug and optional name, create the file names of templates.
180
		 *
181
		 * @since 1.0.0
182
		 *
183
		 * @param string $slug Template slug.
184
		 * @param string $name Template variation name.
185
		 *
186
		 * @return array
187
		 */
188
		protected function get_template_file_names( $slug, $name ) {
189
			$templates = array();
190
			if ( isset( $name ) ) {
191
				$templates[] = $slug . '-' . $name . '.php';
192
			}
193
			$templates[] = $slug . '.php';
194
195
			/**
196
			 * Allow template choices to be filtered.
197
			 *
198
			 * The resulting array should be in the order of most specific first, to least specific last.
199
			 * e.g. 0 => recipe-instructions.php, 1 => recipe.php
200
			 *
201
			 * @since 1.0.0
202
			 *
203
			 * @param array  $templates Names of template files that should be looked for, for given slug and name.
204
			 * @param string $slug      Template slug.
205
			 * @param string $name      Template variation name.
206
			 */
207
			return apply_filters( $this->filter_prefix . '_get_template_part', $templates, $slug, $name );
208
		}
209
210
		/**
211
		 * Retrieve the name of the highest priority template file that exists.
212
		 *
213
		 * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
214
		 * inherit from a parent theme can just overload one file. If the template is
215
		 * not found in either of those, it looks in the theme-compat folder last.
216
		 *
217
		 * @since 1.0.0
218
		 *
219
		 * @param string|array $template_names Template file(s) to search for, in order.
220
		 * @param bool         $load           If true the template file will be loaded if it is found.
221
		 * @param bool         $require_once   Whether to require_once or require. Default true.
222
		 *                                     Has no effect if $load is false.
223
		 *
224
		 * @return string The template filename if one is located.
225
		 */
226
		public function locate_template( $template_names, $load = false, $require_once = true ) {
227
228
			// Use $template_names as a cache key - either first element of array or the variable itself if it's a string
229
			$cache_key = is_array( $template_names ) ? $template_names[0] : $template_names;
230
231
			// If the key is in the cache array, we've already located this file.
232
			if ( isset( $this->template_path_cache[$cache_key] ) ) {
0 ignored issues
show
introduced by
Array keys should be surrounded by spaces unless they contain a string or an integer.
Loading history...
233
				$located = $this->template_path_cache[$cache_key];
0 ignored issues
show
introduced by
Array keys should be surrounded by spaces unless they contain a string or an integer.
Loading history...
234
			} else {
235
236
				// No file found yet.
237
				$located = false;
238
239
				// Remove empty entries.
240
				$template_names = array_filter( (array) $template_names );
241
				$template_paths = $this->get_template_paths();
242
243
				// Try to find a template file.
244
				foreach ( $template_names as $template_name ) {
245
					// Trim off any slashes from the template name.
246
					$template_name = ltrim( $template_name, '/' );
247
248
					// Try locating this template file by looping through the template paths.
249
					foreach ( $template_paths as $template_path ) {
250
						if ( file_exists( $template_path . $template_name ) ) {
251
							$located = $template_path . $template_name;
252
							// Store the template path in the cache
253
							$this->template_path_cache[$cache_key] = $located;
0 ignored issues
show
introduced by
Array keys should be surrounded by spaces unless they contain a string or an integer.
Loading history...
254
							break 2;
255
						}
256
					}
257
				}
258
			}
259
260
			if ( $load && $located ) {
261
				load_template( $located, $require_once );
262
			}
263
264
			return $located;
265
		}
266
267
		/**
268
		 * Return a list of paths to check for template locations.
269
		 *
270
		 * Default is to check in a child theme (if relevant) before a parent theme, so that themes which inherit from a
271
		 * parent theme can just overload one file. If the template is not found in either of those, it looks in the
272
		 * theme-compat folder last.
273
		 *
274
		 * @since 1.0.0
275
		 *
276
		 * @return mixed|void
277
		 */
278
		protected function get_template_paths() {
279
			$theme_directory = trailingslashit( $this->theme_template_directory );
280
281
			$file_paths = array(
282
				10  => trailingslashit( get_template_directory() ) . $theme_directory,
283
				100 => $this->get_templates_dir(),
284
			);
285
286
			// Only add this conditionally, so non-child themes don't redundantly check active theme twice.
287
			if ( get_stylesheet_directory() !== get_template_directory() ) {
288
				$file_paths[1] = trailingslashit( get_stylesheet_directory() ) . $theme_directory;
289
			}
290
291
			/**
292
			 * Allow ordered list of template paths to be amended.
293
			 *
294
			 * @since 1.0.0
295
			 *
296
			 * @param array $var Default is directory in child theme at index 1, parent theme at 10, and plugin at 100.
297
			 */
298
			$file_paths = apply_filters( $this->filter_prefix . '_template_paths', $file_paths );
299
300
			// Sort the file paths based on priority.
301
			ksort( $file_paths, SORT_NUMERIC );
302
303
			return array_map( 'trailingslashit', $file_paths );
304
		}
305
306
		/**
307
		 * Return the path to the templates directory in this plugin.
308
		 *
309
		 * May be overridden in subclass.
310
		 *
311
		 * @since 1.0.0
312
		 *
313
		 * @return string
314
		 */
315
		protected function get_templates_dir() {
316
			return trailingslashit( $this->plugin_directory ) . $this->plugin_template_directory;
317
		}
318
	}
319
}