PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 2.9.19.4
Pods – Custom Content Types and Fields v2.9.19.4
2.7.31.4 2.8.23.5 2.9.19.5 3.0.10.5 3.1.4.3 3.2.8.4 3.3.9.2 2.8.23.4 2.9.19.4 3.0.10.4 3.1.4.2 3.2.8.3 3.3.9.1 trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / tribe-common / src / Tribe / Extension.php
pods / tribe-common / src / Tribe Last commit date
Admin 2 weeks ago Ajax 2 weeks ago Asset 2 weeks ago Context 2 weeks ago Customizer 2 weeks ago Debug_Bar 2 weeks ago Dialog 2 weeks ago Documentation 2 weeks ago Duplicate 2 weeks ago Editor 2 weeks ago Image 2 weeks ago JSON_LD 2 weeks ago Languages 2 weeks ago Log 2 weeks ago Meta 2 weeks ago Models 2 weeks ago PUE 2 weeks ago Process 2 weeks ago Promoter 2 weeks ago REST 2 weeks ago Repository 2 weeks ago Service_Providers 2 weeks ago Shortcode 2 weeks ago Support 2 weeks ago Tabbed_View 2 weeks ago Tooltip 2 weeks ago Traits 2 weeks ago Utils 2 weeks ago Validator 2 weeks ago Widget 2 weeks ago Abstract_Deactivation.php 2 weeks ago Abstract_Plugin_Register.php 2 weeks ago App_Shop.php 2 weeks ago Assets.php 2 weeks ago Assets_Pipeline.php 2 weeks ago Autoloader.php 2 weeks ago Cache.php 2 weeks ago Cache_Listener.php 2 weeks ago Changelog_Reader.php 2 weeks ago Container.php 2 weeks ago Context.php 2 weeks ago Cost_Utils.php 2 weeks ago Credits.php 2 weeks ago Customizer.php 2 weeks ago DB_Lock.php 2 weeks ago Data.php 2 weeks ago Date_Utils.php 2 weeks ago Db.php 2 weeks ago Debug.php 2 weeks ago Dependency.php 2 weeks ago Deprecation.php 2 weeks ago Editor.php 2 weeks ago Error.php 2 weeks ago Exception.php 2 weeks ago Extension.php 2 weeks ago Extension_Loader.php 2 weeks ago Feature_Detection.php 2 weeks ago Field.php 2 weeks ago Field_Conditional.php 2 weeks ago Freemius.php 2 weeks ago Log.php 2 weeks ago Main.php 2 weeks ago Notices.php 2 weeks ago Plugin_Meta_Links.php 2 weeks ago Plugins.php 2 weeks ago Plugins_API.php 2 weeks ago Post_History.php 2 weeks ago Post_Transient.php 2 weeks ago Promise.php 2 weeks ago Repository.php 2 weeks ago Rewrite.php 2 weeks ago Settings.php 2 weeks ago Settings_Manager.php 2 weeks ago Settings_Tab.php 2 weeks ago Simple_Table.php 2 weeks ago Support.php 2 weeks ago Tabbed_View.php 2 weeks ago Template.php 2 weeks ago Template_Factory.php 2 weeks ago Template_Part_Cache.php 2 weeks ago Templates.php 2 weeks ago Terms.php 2 weeks ago Timezones.php 2 weeks ago Tracker.php 2 weeks ago Updater.php 2 weeks ago Validate.php 2 weeks ago View_Helpers.php 2 weeks ago
Extension.php
455 lines
1 <?php
2 defined( 'WPINC' ) || die; // Do not load directly.
3
4 /**
5 * Base Extension class
6 *
7 * Avoid using static states within this class unless it's global for all extensions.
8 * Some extension authors may lack a thorough understanding of OOP and inheritance.
9 * This is built with such ones in mind.
10 *
11 * @package Tribe
12 * @subpackage Extension
13 * @since 4.3.1
14 */
15 abstract class Tribe__Extension {
16
17 /**
18 * Extension arguments
19 *
20 * @var array {
21 * Each argument for this extension instance
22 *
23 * @type string $version Extension's semantic version number.
24 * Can be manually set in child to boost performance.
25 *
26 * @type string $url Extension's tec.com page.
27 *
28 * @type string $hook Action/hook to fire init() on.
29 *
30 * @type string $file File path containing plugin header.
31 * Can be manually set in child to boost performance.
32 *
33 * @type string $class Extension's main class name.
34 *
35 * @type array $requires {
36 * Each plugin this extension requires
37 *
38 * @type string $main_class Minimum version number
39 * }
40 *
41 * @type array $plugin_data If the plugin file header is parsed, the
42 * resulting data is stored in this.
43 * }
44 */
45 protected $args = [];
46
47 /**
48 * The various extension instances
49 *
50 * @var array {
51 * Each instance of an extension that extends this class
52 *
53 * @type object $child_class_name instance
54 * }
55 */
56 private static $instances = [];
57
58 /**
59 * Get singleton instance of child class
60 *
61 * @param string $child_class (optional) Name of child class.
62 * @param array $args (optional) Any args that should be set on construct.
63 * Only used the first time the extension is instantiated.
64 *
65 * @return object|null The extension's instance, or null if it can't be instantiated
66 */
67 public static function instance( $child_class = null, $args = null ) {
68 // Defaults to the name of the class that called this instance.
69 $child_class = empty( $child_class ) ? self::get_called_class() : $child_class;
70
71 // @see self::get_called_class() for the reason why this could be empty
72 if ( empty( $child_class ) ) {
73 return null;
74 }
75
76 if ( ! isset( self::$instances[ $child_class ] ) ) {
77 $args = (array) $args;
78 $args['class'] = $child_class;
79
80 self::$instances[ $child_class ] = new $child_class( $args );
81 }
82
83 return self::$instances[ $child_class ];
84 }
85
86 /**
87 * Initializes the extension.
88 *
89 * Waits until after the init hook has fired.
90 *
91 * @param array $args The full path to the plugin file.
92 */
93 final private function __construct( array $args ) {
94 $this->args = $args;
95 $this->construct();
96
97 // The init() action/hook.
98 $init_hook = $this->get_init_hook();
99
100 // Continue plugin run after $init_hook has fired.
101 if ( did_action( $init_hook ) > 0 ) {
102 $this->register();
103 } else {
104 add_action( $init_hook, [ $this, 'register' ] );
105 }
106 }
107
108 /**
109 * Empty function typically overridden by child class
110 */
111 protected function construct() {}
112
113 /**
114 * This is where the magic begins
115 *
116 * Declare this inside the child and put any custom code inside of it.
117 */
118 abstract public function init();
119
120 /**
121 * Adds a Tribe Plugin to the list of plugins this extension depends upon.
122 *
123 * If this plugin is not present or does not exceed the specified version
124 * init() will not run.
125 *
126 * @param string $main_class The Main class for this Tribe plugin.
127 * @param string|null $minimum_version Minimum acceptable version of plugin.
128 */
129 final protected function add_required_plugin( $main_class, $minimum_version = null ) {
130 $this->set( [ 'requires', $main_class ], $minimum_version );
131 }
132
133 /**
134 * Set the extension's tec.com URL
135 *
136 * @param string $url URL to the extension's page.
137 */
138 final protected function set_url( $url ) {
139 $this->set( 'url', $url );
140
141 // Adds this as a tutorial <a> link to Wp Admin > Plugins page.
142 Tribe__Plugin_Meta_Links::instance()->add_link(
143 $this->get_plugin_file(),
144 __( 'Tutorial', 'tribe-common' ),
145 $url,
146 [ 'class' => 'tribe-meta-link-extension' ]
147 );
148 }
149
150 /**
151 * Set the extension's version number
152 *
153 * @param string $version Extensions semantic version number.
154 */
155 final protected function set_version( $version ) {
156 $this->set( 'version', $version );
157 }
158
159 /**
160 * Checks if the extension has permission to run, if so runs init() in child class
161 */
162 final public function register() {
163 $extension_file = $this->get_plugin_file();
164 $extension_class_name = $this->get( 'class' );
165 $extension_version = $this->get_version();
166 $plugins_required = $this->get( 'requires', [] );
167
168 tribe_register_plugin(
169 $extension_file,
170 $extension_class_name,
171 $extension_version,
172 $plugins_required
173 );
174
175 $dependency = Tribe__Dependency::instance();
176
177 // check requisite plugins are active for this extension
178 $is_plugin_authorized = $dependency->has_requisite_plugins( $plugins_required );
179
180 /**
181 * Explicitly disallow an extension, such as a core plugin having absorbed/replaced its functionality.
182 *
183 * @since 4.12.2
184 *
185 * @param bool $is_disallowed    False by default.
186 * @param string $extension_class_name This extension's class name string
187 * (without initial forward slash for namespaced classes).
188 * @param Tribe__Extension $this_instance This extension class' instance.
189 */
190 $is_disallowed = (bool) apply_filters( 'tribe_extension_is_disallowed', false, $extension_class_name, $this );
191
192 if ( $is_disallowed ) {
193 if (
194 is_admin()
195 && current_user_can( 'activate_plugins' )
196 ) {
197 tribe_notice( 'tribe_extension_is_disallowed', [ $this, 'notice_disallowed' ], [ 'type' => 'error' ] );
198 }
199
200 deactivate_plugins( $extension_file, true );
201
202 return;
203 }
204
205 if ( $is_plugin_authorized ) {
206 $this->init();
207
208 // Add extension as active to dependency checker.
209 $dependency->add_active_plugin( $extension_class_name, $extension_version, $extension_file );
210 }
211 }
212
213 /**
214 * Gets the full path to the extension's plugin file
215 *
216 * Sets default if the arg is blank.
217 *
218 * @return string File path
219 */
220 final public function get_plugin_file() {
221 $file = $this->get( 'file' );
222
223 // If this is not set assume the extension's plugin class is the plugin file.
224 if ( empty( $file ) ) {
225 $reflection = new ReflectionClass( $this->get( 'class' ) );
226 $file = $reflection->getFileName();
227 $this->set( 'file', $file );
228 }
229
230 return $file;
231 }
232
233 /**
234 * Get the extension's version number
235 *
236 * @return string Semantic version number
237 */
238 final public function get_version() {
239 return $this->get_arg_or_plugin_data( 'version', 'Version' );
240 }
241
242 /**
243 * Get the extension's plugin name
244 *
245 * @return string Plugin name
246 */
247 final public function get_name() {
248 return $this->get_arg_or_plugin_data( 'name', 'Name' );
249 }
250
251 /**
252 * Get the extension's description
253 *
254 * @return string Plugin description
255 */
256 final public function get_description() {
257 return $this->get_arg_or_plugin_data( 'description', 'Description' );
258 }
259
260 /**
261 * Gets the action/hook for the extensions' init().
262 *
263 * @return string Action/hook
264 */
265 final public function get_init_hook() {
266 return $this->get( 'hook', 'tribe_plugins_loaded' );
267 }
268
269 /**
270 * Gets the plugin data from the plugin file header
271 *
272 * This is somewhat resource intensive, so data is stored in $args
273 * in case of subsequent calls.
274 *
275 * @see get_plugin_data() for WP Admin only function this is similar to.
276 *
277 * @return array Plugin data; keys match capitalized file header declarations.
278 */
279 final public function get_plugin_data() {
280 $plugin_data = $this->get( 'plugin_data' );
281
282 // Set the plugin data arg/cache to match.
283 if ( empty( $plugin_data ) ) {
284 $plugin_data = $this->set( 'plugin_data', Tribe__Utils__Plugins::get_plugin_data( $this->get_plugin_file() ) );
285 }
286
287 return $plugin_data;
288 }
289
290 /**
291 * Retrieves any args whose default value is stored in the plugin file header
292 *
293 * @param string $arg The key for arg.
294 * @param string $plugin_data_key The key for the arg in the file header.
295 *
296 * @return string|null String if set, otherwise null.
297 */
298 final public function get_arg_or_plugin_data( $arg, $plugin_data_key ) {
299 $arg_value = $this->get( $arg, null );
300
301 // See if the arg is already set, if not get default from plugin data and set it.
302 if ( null === $arg_value ) {
303 $pdata = $this->get_plugin_data();
304 $arg_value = isset( $pdata[ $plugin_data_key ] ) ? $pdata[ $plugin_data_key ] : null;
305 }
306
307 return $arg_value;
308 }
309
310 /**
311 * Sets an arg, including one nested a few levels deep
312 *
313 * @param string|array $key To set an arg nested multiple levels deep pass an array
314 * specifying each key in order as a value.
315 * Example: array( 'lvl1', 'lvl2', 'lvl3' );
316 * @param mixed $value The value.
317 */
318 final protected function set( $key, $value ) {
319 $this->args = Tribe__Utils__Array::set( $this->args, $key, $value );
320 }
321
322 /**
323 * Retrieves arg, including one nested a few levels deep
324 *
325 * @param string|array $key To select an arg nested multiple levels deep pass an
326 * array specifying each key in order as a value.
327 * Example: array( 'lvl1', 'lvl2', 'lvl3' );
328 * @param null $default Value to return if nothing is set.
329 *
330 * @return mixed Returns the args value or the default if arg is not found.
331 */
332 final public function get( $key, $default = null ) {
333 return Tribe__Utils__Array::get( $this->args, $key, $default );
334 }
335
336 /**
337 * Gets the name of the class the method is called in; typically will be a child class
338 *
339 * This uses some hackery if the server is on PHP 5.2, and it can fail in rare
340 * circumstances causing a null value to be returned.
341 *
342 * @return string|null Class name
343 */
344 final protected static function get_called_class() {
345 $class_name = null;
346
347 if ( function_exists( 'get_called_class' ) ) {
348 // For PHP 5.3+ we can use the late static binding class name.
349 $class_name = get_called_class();
350 } else {
351 // For PHP 5.2 and under we hack around the lack of late static bindings.
352 try {
353 $backtraces = debug_backtrace();
354
355 // Grab each class from the backtrace.
356 foreach ( $backtraces as $i ) {
357 $class = null;
358
359 if ( array_key_exists( 'class', $i ) ) {
360 // Direct call to a class.
361 $class = $i['class'];
362 } elseif (
363 array_key_exists( 'function', $i ) &&
364 strpos( $i['function'], 'call_user_func' ) === 0 &&
365 array_key_exists( 'args', $i ) &&
366 is_array( $i['args'] ) &&
367 is_array( $i['args'][0] ) &&
368 isset( $i['args'][0][0] )
369 ) {
370 // Found a call from call_user_func... and $i['args'][0][0] is present
371 // indicating a static call to a method.
372 $class = $i['args'][0][0];
373 } else {
374 // Slight performance boost from skipping ahead.
375 continue;
376 }
377
378 // Check to see if the parent is the current class.
379 // The first backtrace with a matching parent is our class.
380 if ( get_parent_class( $class ) === __CLASS__ ) {
381 $class_name = $class;
382 break;
383 }
384 }
385 } catch ( Exception $e ) {
386 // Host has disabled or misconfigured debug_backtrace().
387 $exception = new Tribe__Exception( $e );
388 $exception->handle();
389 }
390 }
391
392 // Class name was not set by debug_backtrace() hackery.
393 if ( null === $class_name ) {
394 tribe_notice( 'tribe_debug_backtrace_disabled', [ __CLASS__, 'notice_debug_backtrace' ] );
395 }
396
397 return $class_name;
398 }
399
400 /**
401 * Echoes error message indicating user is on PHP 5.2 and debug_backtrace is disabled
402 */
403 final public static function notice_debug_backtrace() {
404 printf(
405 '<p>%s</p>',
406 esc_html__( 'Unable to run Tribe Extensions. Your website host is running PHP 5.2 or older, and has likely disabled or misconfigured debug_backtrace(). You, or your website host, will need to upgrade PHP or properly configure debug_backtrace() for Tribe Extensions to work.', 'tribe-common' )
407 );
408 }
409
410 /**
411 * Gets the error message about being explicitly disallowed.
412 *
413 * @since 4.12.2
414 *
415 * @return string Notice text.
416 */
417 public function notice_disallowed() {
418 return sprintf(
419 '<p><strong>%1$s:</strong> %2$s</p>',
420 $this->get_name(),
421 esc_html_x(
422 "This extension has been programmatically disallowed. The most common reason is due to another The Events Calendar plugin having absorbed or replaced this extension's functionality. This extension plugin has been deactivated, and you should likely delete it.",
423 'extension disallowed',
424 'tribe-common'
425 )
426 );
427 }
428
429 /**
430 * Prevent cloning the singleton with 'clone' operator
431 *
432 * @return void
433 */
434 final public function __clone() {
435 _doing_it_wrong(
436 __FUNCTION__,
437 'Can not use this method on singletons.',
438 '4.3'
439 );
440 }
441
442 /**
443 * Prevent unserializing the singleton instance
444 *
445 * @return void
446 */
447 final public function __wakeup() {
448 _doing_it_wrong(
449 __FUNCTION__,
450 'Can not use this method on singletons.',
451 '4.3'
452 );
453 }
454 }
455