args = $args; $this->construct(); // The init() action/hook. $init_hook = $this->get_init_hook(); // Continue plugin run after $init_hook has fired. if ( did_action( $init_hook ) > 0 ) { $this->register(); } else { add_action( $init_hook, array( $this, 'register' ) ); } } /** * Empty function typically overridden by child class */ protected function construct() {} /** * This is where the magic begins * * Declare this inside the child and put any custom code inside of it. */ abstract public function init(); /** * Adds a Tribe Plugin to the list of plugins this extension depends upon. * * If this plugin is not present or does not exceed the specified version * init() will not run. * * @param string $main_class The Main class for this Tribe plugin. * @param string|null $minimum_version Minimum acceptable version of plugin. */ final protected function add_required_plugin( $main_class, $minimum_version = null ) { $this->set( array( 'requires', $main_class ), $minimum_version ); } /** * Set the extension's tec.com URL * * @param string $url URL to the extension's page. */ final protected function set_url( $url ) { $this->set( 'url', $url ); // Adds this as a tutorial link to Wp Admin > Plugins page. Tribe__Plugin_Meta_Links::instance()->add_link( $this->get_plugin_file(), __( 'Tutorial', 'tribe-common' ), $url, array( 'class' => 'tribe-meta-link-extension' ) ); } /** * Set the extension's version number * * @param string $version Extensions semantic version number. */ final protected function set_version( $version ) { $this->set( 'version', $version ); } /** * Checks if the extension has permission to run, if so runs init() in child class */ final public function register() { $is_plugin_authorized = tribe_register_plugin( $this->get_plugin_file(), $this->get( 'class' ), $this->get_version(), $this->get( 'requires', array() ) ); if ( $is_plugin_authorized ) { $this->init(); } } /** * Gets the full path to the extension's plugin file * * Sets default if the arg is blank. * * @return string File path */ final public function get_plugin_file() { $file = $this->get( 'file' ); // If this is not set assume the extension's plugin class is the plugin file. if ( empty( $file ) ) { $reflection = new ReflectionClass( $this->get( 'class' ) ); $file = $reflection->getFileName(); $this->set( 'file', $file ); } return $file; } /** * Get the extension's version number * * @return string Semantic version number */ final public function get_version() { return $this->get_arg_or_plugin_data( 'version', 'Version' ); } /** * Get the extension's plugin name * * @return string Plugin name */ final public function get_name() { return $this->get_arg_or_plugin_data( 'name', 'Name' ); } /** * Get the extension's description * * @return string Plugin description */ final public function get_description() { return $this->get_arg_or_plugin_data( 'description', 'Description' ); } /** * Get's the action/hook for the extensions init() * * @return string Action/hook */ final public function get_init_hook() { return $this->get( 'hook', 'tribe_plugins_loaded' ); } /** * Gets the plugin data from the plugin file header * * This is somewhat resource intensive, so data is stored in $args * in case of subsequent calls. * * @see get_plugin_data() for WP Admin only function this is similar to. * * @return array Plugin data; keys match capitalized file header declarations. */ final public function get_plugin_data() { $plugin_data = $this->get( 'plugin_data' ); // Set the plugin data arg/cache to match. if ( empty( $plugin_data ) ) { $plugin_data = $this->set( 'plugin_data', Tribe__Utils__Plugins::get_plugin_data( $this->get_plugin_file() ) ); } return $plugin_data; } /** * Retrieves any args whose default value is stored in the plugin file header * * @param string $arg The key for arg. * @param string $plugin_data_key The key for the arg in the file header. * * @return string|null String if set, otherwise null. */ final public function get_arg_or_plugin_data( $arg, $plugin_data_key ) { $arg_value = $this->get( $arg, null ); // See if the arg is already set, if not get default from plugin data and set it. if ( null === $arg_value ) { $pdata = $this->get_plugin_data(); $arg_value = isset( $pdata[ $plugin_data_key ] ) ? $pdata[ $plugin_data_key ] : null; } return $arg_value; } /** * Sets an arg, including one nested a few levels deep * * @param string|array $key To set an arg nested multiple levels deep pass an array * specifying each key in order as a value. * Example: array( 'lvl1', 'lvl2', 'lvl3' ); * @param mixed $value The value. */ final protected function set( $key, $value ) { $this->args = Tribe__Utils__Array::set( $this->args, $key, $value ); } /** * Retrieves arg, including one nested a few levels deep * * @param string|array $key To select an arg nested multiple levels deep pass an * array specifying each key in order as a value. * Example: array( 'lvl1', 'lvl2', 'lvl3' ); * @param null $default Value to return if nothing is set. * * @return mixed Returns the args value or the default if arg is not found. */ final public function get( $key, $default = null ) { return Tribe__Utils__Array::get( $this->args, $key, $default ); } /** * Gets the name of the class the method is called in; typically will be a child class * * This uses some hackery if the server is on PHP 5.2, and it can fail in rare * circumstances causing a null value to be returned. * * @return string|null Class name */ final protected static function get_called_class() { $class_name = null; if ( function_exists( 'get_called_class' ) ) { // For PHP 5.3+ we can use the late static binding class name. $class_name = get_called_class(); } else { // For PHP 5.2 and under we hack around the lack of late static bindings. try { $backtraces = debug_backtrace(); // Grab each class from the backtrace. foreach ( $backtraces as $i ) { $class = null; if ( array_key_exists( 'class', $i ) ) { // Direct call to a class. $class = $i['class']; } elseif ( array_key_exists( 'function', $i ) && strpos( $i['function'], 'call_user_func' ) === 0 && array_key_exists( 'args', $i ) && is_array( $i['args'] ) && is_array( $i['args'][0] ) && isset( $i['args'][0][0] ) ) { // Found a call from call_user_func... and $i['args'][0][0] is present // indicating a static call to a method. $class = $i['args'][0][0]; } else { // Slight performance boost from skipping ahead. continue; } // Check to see if the parent is the current class. // The first backtrace with a matching parent is our class. if ( get_parent_class( $class ) === __CLASS__ ) { $class_name = $class; break; } } } catch ( Exception $e ) { // Host has disabled or misconfigured debug_backtrace(). $exception = new Tribe__Exception( $e ); $exception->handle(); } } // Class name was not set by debug_backtrace() hackery. if ( null === $class_name ) { tribe_notice( 'tribe_debug_backtrace_disabled', array( __CLASS__, 'notice_debug_backtrace' ) ); } return $class_name; } /** * Echoes error message indicating user is on PHP 5.2 and debug_backtrace is disabled */ final public static function notice_debug_backtrace() { printf( '

%s

', 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' ) ); } /** * Prevent cloning the singleton with 'clone' operator * * @return void */ final private function __clone() { _doing_it_wrong( __FUNCTION__, 'Can not use this method on singletons.', '4.3' ); } /** * Prevent unserializing the singleton instance * * @return void */ final private function __wakeup() { _doing_it_wrong( __FUNCTION__, 'Can not use this method on singletons.', '4.3' ); } }