cf = WpssoConfig::get_config(); WpssoConfig::set_constants( $plugin_file ); WpssoConfig::require_libs( $plugin_file ); // Includes the register.php class library. $this->reg = new WpssoRegister( $this ); // Activate, deactivate, uninstall hooks. /* * The WordPress 'init' action fires after WordPress has finished loading, but before any headers are sent. * * Most of WordPress is loaded at this stage, and the user is authenticated. WordPress continues to load on * the 'init' hook (e.g. widgets), and many plugins instantiate themselves on it for all sorts of reasons * (e.g. they need a user, a taxonomy, etc.). */ add_action( 'init', array( $this, 'set_config' ), WPSSO_INIT_CONFIG_PRIORITY ); // Runs at init -10. add_action( 'widgets_init', array( $this, 'register_widgets' ), 10 ); // Runs at init 1. add_action( 'init', array( $this, 'set_options' ), WPSSO_INIT_OPTIONS_PRIORITY ); // Runs at init 9. add_action( 'init', array( $this, 'set_objects' ), WPSSO_INIT_OBJECTS_PRIORITY ); // Runs at init 10. add_action( 'init', array( $this, 'init_shortcodes' ), WPSSO_INIT_SHORTCODES_PRIORITY ); // Runs at init 11. add_action( 'init', array( $this, 'init_plugin' ), WPSSO_INIT_PLUGIN_PRIORITY ); // Runs at init 12. /* * The 'wpsso_init_textdomain' action is run after the $check, $avail, and $debug properties have been instantiated. */ add_action( 'wpsso_init_textdomain', array( $this, 'init_textdomain' ), -1000, 0 ); /* * The 'change_locale' action also runs the 'wpsso_init_textdomain' action. */ add_action( 'change_locale', array( $this, 'change_locale' ), -1000, 1 ); /* * If the "Use Plugin MO Translations" option is enabled, returns the file path to the plugin or add-on mo file. */ add_filter( 'load_textdomain_mofile', array( $this, 'textdomain_mofile' ), 10, 3 ); /* * Declare compatibility with WooCommerce features. */ if ( ! empty( $this->cf[ 'plugin' ][ 'wpsso' ][ 'wc_compat' ] ) ) { $wc_compat = $this->cf[ 'plugin' ][ 'wpsso' ][ 'wc_compat' ]; add_action( 'before_woocommerce_init', function () use ( $plugin_file, $wc_compat ) { if ( class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) { foreach ( $wc_compat as $feature ) { \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( $feature, $plugin_file, true ); } } }, 10, 0 ); unset( $wc_compat ); } unset( $plugin_file, $plugin_dir ); } public static function &get_instance() { if ( null === self::$instance ) { self::$instance = new self; } return self::$instance; } /* * Force a refresh of the plugin config. * * Runs at init priority -10 and called by WpssoRegister->activate_plugin() as well. */ public function set_config( $activate = false ) { $this->cf = WpssoConfig::get_config( $read_cache = false ); } /* * Runs at init 1. */ public function register_widgets() { /* * Load lib/widget/* library files. */ $classnames = $this->get_lib_classnames( 'widget' ); // Always returns an array. foreach ( $classnames as $id => $classname ) { register_widget( $classname ); } } /* * Runs at init priority 9. * * Called by WpssoRegister->activate_plugin() as well. */ public function set_options( $activate = false ) { if ( $activate && defined( 'WPSSO_RESET_ON_ACTIVATE' ) && WPSSO_RESET_ON_ACTIVATE ) { delete_option( WPSSO_OPTIONS_NAME ); $this->options = false; } else $this->options = get_option( WPSSO_OPTIONS_NAME ); if ( ! is_array( $this->options ) ) { /* * The set_options() action is run before the set_objects() action, where the WpssoOptions class is * instantiated, so the WpssoOptions->get_defaults() method is not available yet. Load the defaults * directly from the config array and trigget a defaults reload in set_objects(). */ $this->options = $this->cf[ 'opt' ][ 'defaults' ]; $this->options[ '__reload_defaults' ] = true; } if ( is_multisite() ) { $this->site_options = get_site_option( WPSSO_SITE_OPTIONS_NAME ); if ( ! is_array( $this->site_options ) ) { $this->site_options = $this->cf[ 'opt' ][ 'site_defaults' ]; $this->site_options[ '__reload_defaults' ] = true; } if ( is_array( $this->options ) && is_array( $this->site_options ) ) { $blog_id = get_current_blog_id(); $defined_constants = get_defined_constants( $categorize = true ); foreach ( $this->site_options as $key => $val ) { if ( false !== strpos( $key, ':use' ) ) { continue; } elseif ( isset( $this->site_options[ $key . ':use' ] ) ) { switch ( $this->site_options[ $key . ':use' ] ) { case 'force': $this->options[ $key ] = $this->site_options[ $key ]; $this->options[ $key . ':disabled' ] = true; break; case 'empty': // Blank string, null, false, or 0. if ( empty( $this->options[ $key ] ) ) { $this->options[ $key ] = $this->site_options[ $key ]; } break; } } $constant_name = 'WPSSO_ID_' . $blog_id . '_OPT_' . strtoupper( $key ); if ( isset( $defined_constants[ 'user' ][ $constant_name ] ) ) { $this->options[ $key ] = $defined_constants[ 'user' ][ $constant_name ]; $this->options[ $key . ':disabled' ] = true; } } } } } /* * Runs at init priority 10. * * Called by WpssoRegister->activate_plugin() as well. */ public function set_objects( $activate = false ) { $is_doing = array( 'admin' => is_admin(), 'ajax' => SucomUtilWP::doing_ajax(), 'cron' => SucomUtilWP::doing_cron(), 'dev' => SucomUtilWP::doing_dev(), ); /* * Check for defined constants (in order): * * WPSSO_CRON_DEBUG_LOG * WPSSO_CRON_DEBUG_HTML * WPSSO_AJAX_DEBUG_LOG * WPSSO_AJAX_DEBUG_HTML * WPSSO_ADMIN_DEBUG_LOG * WPSSO_ADMIN_DEBUG_HTML * WPSSO_DEBUG_LOG * WPSSO_DEBUG_HTML */ $debug_log = $this->get_const_status( 'DEBUG_LOG', $is_doing ); $debug_html = $this->get_const_status( 'DEBUG_HTML', $is_doing ); $this->check = new WpssoCheck( $this ); $this->avail = $this->check->get_avail(); // Uses $this->options for availability checks. /* * Make sure a debug object variable is always available. */ if ( null === $debug_html ) { // Constant not defined. $debug_html = empty( $this->options[ 'plugin_debug_html' ] ) ? false : true; } if ( $debug_log || $debug_html ) { require_once WPSSO_PLUGINDIR . 'lib/com/debug.php'; // Only load class when needed. $this->debug = new SucomDebug( $this, array( 'log' => $debug_log, 'html' => $debug_html, ) ); if ( $this->debug->enabled ) { global $wp_version; $this->debug->log( __METHOD__ . ' init ' . WPSSO_INIT_OBJECTS_PRIORITY ); $this->debug->log( 'debug enabled on ' . gmdate( 'c' ) ); $this->debug->log( 'PHP version ' . phpversion() ); $this->debug->log( 'WP version ' . $wp_version ); $this->debug->log( 'WP home URL ' . get_home_url() ); $this->debug->log( 'WP site URL ' . get_site_url() ); $this->debug->log_arr( 'generator', $this->check->get_ext_gen_list() ); $this->debug->log_arr( 'avail', $this->avail ); } } else $this->debug = new SucomNoDebug(); // Class always loaded in WpssoConfig::require_libs(). if ( $this->debug->enabled ) { $this->debug->mark_diff( 'debug class loaded' ); } /* * The 'wpsso_init_textdomain' action is run after the $check, $avail, and $debug properties have been instantiated. * * The WordPress 'change_locale' action also runs the 'wpsso_init_textdomain' action. */ do_action( 'wpsso_init_textdomain' ); /* * Make sure a notice object variable is always available. */ if ( $is_doing[ 'admin' ] || $is_doing[ 'cron' ] ) { require_once WPSSO_PLUGINDIR . 'lib/messages.php'; // Only load class when needed. require_once WPSSO_PLUGINDIR . 'lib/com/notice.php'; // Only load class when needed. $this->msgs = new WpssoMessages( $this ); // Admin tooltip messages. $this->notice = new SucomNotice( $this ); } else $this->notice = new SucomNoNotice(); // Class always loaded in WpssoConfig::require_libs(). if ( $this->debug->enabled ) { $this->debug->mark_diff( 'notice class loaded' ); } $this->cache = new SucomCache( $this ); $this->util = new WpssoUtil( $this ); // Extends SucomUtil. $this->opt = new WpssoOptions( $this ); do_action( 'wpsso_init_options' ); $this->script = new WpssoScript( $this ); $this->style = new WpssoStyle( $this ); /* * Note that when running a cron task, admin is false. */ if ( $is_doing[ 'admin' ] ) { require_once WPSSO_PLUGINDIR . 'lib/admin.php'; // Only load class when needed. require_once WPSSO_PLUGINDIR . 'lib/conflict.php'; // Only load class when needed. require_once WPSSO_PLUGINDIR . 'lib/edit.php'; // Only load class when needed. require_once WPSSO_PLUGINDIR . 'lib/com/form.php'; // Only load class when needed. $this->admin = new WpssoAdmin( $this ); // Admin menus and settings pages. $this->conflict = new WpssoConflict( $this ); // Admin plugin conflict checks. $this->edit = new WpssoEdit( $this ); // Admin editing page metabox. } /* * Setup media and module classes: * * $comment * $media * $page * $post * $term * $user */ $this->comment = new WpssoComment( $this ); // Extends WpssoAbstractWpMeta. $this->media = new WpssoMedia( $this ); $this->page = new WpssoPage( $this ); $this->post = new WpssoPost( $this ); // Extends WpssoAbstractWpMeta. $this->term = new WpssoTerm( $this ); // Extends WpssoAbstractWpMeta. $this->user = new WpssoUser( $this ); // Extends WpssoAbstractWpMeta. if ( $this->debug->enabled ) { $this->debug->mark_diff( 'media and module classes loaded' ); } /* * Setup classe for meta tags and Schema markup: * * $head * $link_rel * $meta_name * $og * $pinterest * $schema * $tc * $loader */ $this->head = new WpssoHead( $this ); $this->link_rel = new WpssoLinkRel( $this ); // Link relation tags. $this->meta_name = new WpssoMetaName( $this ); // Meta name tags. $this->oembed = new WpssoOembed( $this ); // Oembed response data. $this->og = new WpssoOpenGraph( $this ); // Open Graph meta tags. $this->pinterest = new WpssoPinterest( $this ); // Pinterest image markup. $this->schema = new WpssoSchema( $this ); // Schema json data. $this->tc = new WpssoTwitterCard( $this ); // X (Twitter) Card meta tags. if ( $this->debug->enabled ) { $this->debug->mark_diff( 'meta tags and schema classes loaded' ); } do_action( 'wpsso_init_objects_preloader' ); $this->loader = new WpssoLoader( $this ); // Modules loader. do_action( 'wpsso_init_objects' ); if ( $this->debug->enabled ) { $this->debug_reminder( $is_doing ); $this->debug->mark_diff( 'objects defined' ); } } /* * Runs at init priority 11. */ public function init_shortcodes() { if ( $this->debug->enabled ) { $this->debug->mark( 'init shortcodes' ); // Begin timer. } /* * Load lib/shortcode/* library files. */ $classnames = $this->get_lib_classnames( 'shortcode' ); // Always returns an array. foreach ( $classnames as $id => $classname ) { /* * Note that Wpsso->sc[ 'schema' ] is used by WpssoSscFilters->filter_json_data_graph_element(). */ if ( ! isset( $this->sc[ $id ] ) ) { // Just in case. $this->sc[ $id ] = new $classname( $this ); if ( $this->debug->enabled ) { $this->debug->mark_diff( 'added ' . $id . ' shortcode' ); } } } if ( $this->debug->enabled ) { $this->debug->mark( 'init shortcodes' ); // Begin timer. } } /* * Runs at init priority 12. */ public function init_plugin() { if ( $this->debug->enabled ) { $this->debug_hooks(); } /* * All WPSSO Core objects are instantiated and configured. * * See SucomAbstractAddOn->init_plugin_notices(). */ do_action( 'wpsso_init_plugin' ); } /* * The 'wpsso_init_textdomain' action is run after the $check, $avail, and $debug properties are instantiated. */ public function init_textdomain() { load_plugin_textdomain( 'wpsso', false, 'wpsso/languages/' ); } /* * The 'change_locale' action also runs the 'wpsso_init_textdomain' action. */ public function change_locale( $locale ) { do_action( 'wpsso_init_textdomain' ); } /* * If the "Use Plugin MO Translations" option is enabled, returns the file path to the plugin or add-on mo file. */ public function textdomain_mofile( $wp_mofile, $domain ) { if ( empty( $this->options[ 'plugin_load_mofiles' ] ) ) { // Nothing to do. return $wp_mofile; } if ( 0 === strpos( $domain, 'wpsso' ) ) { // Optimize. foreach ( $this->cf[ 'plugin' ] as $ext => $info ) { if ( empty( $info[ 'slug' ] ) ) { // Just in case. continue; } elseif ( $domain === $info[ 'slug' ] ) { $languages_mofile = 'languages/' . basename( $wp_mofile ); if ( $plugin_mofile = WpssoConfig::get_ext_file_path( $ext, $languages_mofile ) ) { global $l10n; unset( $l10n[ $domain ] ); // Prevent merging. return $plugin_mofile; } break; // Stop here. } } } return $wp_mofile; } /* * Check for defined constants (in order): * * WPSSO_CRON_DEBUG_LOG * WPSSO_CRON_DEBUG_HTML * WPSSO_AJAX_DEBUG_LOG * WPSSO_AJAX_DEBUG_HTML * WPSSO_ADMIN_DEBUG_LOG * WPSSO_ADMIN_DEBUG_HTML * WPSSO_DEBUG_LOG * WPSSO_DEBUG_HTML * * See Wpsso->get_const_status(). * See Wpsso->get_const_status_transl(). */ public function get_const( $const_suffix, $is_doing = null ) { if ( ! is_array( $is_doing ) ) { $is_doing = array( 'admin' => is_admin(), 'ajax' => SucomUtilWP::doing_ajax(), 'cron' => SucomUtilWP::doing_cron(), 'dev' => SucomUtilWP::doing_dev(), ); } if ( $is_doing[ 'cron' ] && defined( 'WPSSO_CRON_' . $const_suffix ) ) { return 'WPSSO_CRON_' . $const_suffix; } elseif ( $is_doing[ 'ajax' ] && defined( 'WPSSO_AJAX_' . $const_suffix ) ) { return 'WPSSO_AJAX_' . $const_suffix; } elseif ( $is_doing[ 'admin' ] && defined( 'WPSSO_ADMIN_' . $const_suffix ) ) { return 'WPSSO_ADMIN_' . $const_suffix; } elseif ( defined( 'WPSSO_' . $const_suffix ) ) { return 'WPSSO_' . $const_suffix; } return null; // Constant not defined. } /* * See Wpsso->set_objects(). * See WpssoSubmenuAdvanced->get_table_rows(). */ public function get_const_status( $const_suffix, $is_doing = null ) { $const_name = $this->get_const( $const_suffix, $is_doing ); // Returns null if constant not defined. return $const_name ? constant( $const_name ) : null; } /* * See WpssoSubmenuAdvanced->get_table_rows(). */ public function get_const_status_transl( $const_suffix, $is_doing = null ) { $const_name = $this->get_const( $const_suffix, $is_doing ); // Returns null if constant not defined. if ( $const_name ) { if ( constant( $const_name ) ) { return sprintf( _x( '(%s constant is true)', 'option comment', 'wpsso' ), $const_name ); } return sprintf( _x( '(%s constant is false)', 'option comment', 'wpsso' ), $const_name ); } return ''; } public function get_lib_classnames( $type_dir ) { $classnames = array(); foreach ( $this->cf[ 'plugin' ] as $ext => $info ) { if ( ! isset( $info[ 'lib' ][ $type_dir ] ) ) { continue; } elseif ( ! is_array( $info[ 'lib' ][ $type_dir ] ) ) { continue; } foreach ( $info[ 'lib' ][ $type_dir ] as $sub_dir => $libs ) { if ( is_array( $libs ) ) { /* * Skip loading admin library modules if not in admin back-end. */ if ( 'admin' === $sub_dir && ! is_admin() ) { continue; } foreach ( $libs as $id => $label ) { $lib_path = $type_dir . '/' . $sub_dir . '/' . $id; $classname = apply_filters( $ext . '_load_lib', false, $lib_path ); if ( is_string( $classname ) && class_exists( $classname ) ) { $classnames[ $sub_dir . '-' . $id ] = $classname; } } } elseif ( is_string( $libs ) ) { $id = $sub_dir; $label = $libs; $lib_path = $type_dir . '/' . $id; $classname = apply_filters( $ext . '_load_lib', false, $lib_path ); if ( is_string( $classname ) && class_exists( $classname ) ) { $classnames[ $id ] = $classname; } } } } return $classnames; } public function get_options( $opt_key = false, $def_value = null ) { if ( false !== $opt_key ) { if ( isset( $this->options[ $opt_key ] ) ) { return $this->options[ $opt_key ]; } return $def_value; } return $this->options; } public function debug_hooks() { /* * Show debug messages after the head and footer sections. * * Do not include the "shutdown" action as that would create HTML after the html closing tag. */ foreach ( array( 'wp_head', 'wp_footer', 'admin_head', 'admin_footer' ) as $action ) { add_action( $action, array( $this, 'show_debug' ), PHP_INT_MAX ); } /* * Show plugin settings just after the footer section. */ foreach ( array( 'wp_footer', 'admin_footer' ) as $action ) { add_action( $action, array( $this, 'show_config' ), PHP_INT_MAX ); } } /* * Only runs when debug is enabled. */ public function show_debug() { echo "\n\n" . '' . "\n\n"; $this->debug->show_html( null, 'debug log' ); } /* * Only runs when debug is enabled. */ public function show_config() { if ( ! $this->debug->enabled ) { // Just in case. return; } $this->debug->mark(); /* * Show constants. */ $defined_constants = get_defined_constants( $categorize = true ); $defined_constants[ 'user' ][ 'WPSSO_NONCE_NAME' ] = '********'; if ( is_multisite() ) { $this->debug->log_arr( 'multisite constants', SucomUtil::preg_grep_keys( '/^(MULTISITE|^SUBDOMAIN_INSTALL|.*_SITE)$/', $defined_constants[ 'user' ] ) ); } $this->debug->log_arr( 'wpsso constants', SucomUtil::preg_grep_keys( '/^WPSSO_/', $defined_constants[ 'user' ] ) ); /* * Show active plugins. */ $this->debug->log_arr( 'active plugins', SucomPlugin::get_active_plugins() ); /* * Show available modules. */ $this->debug->log_arr( 'available features', $this->avail ); /* * Show all plugin options. */ $opts = $this->options; foreach ( $opts as $key => $val ) { switch ( $key ) { case ( false !== strpos( $key, '_js_' ) ? true : false ): case ( false !== strpos( $key, '_css_' ) ? true : false ): case ( preg_match( '/(_css|_js|_html)$/', $key ) ? true : false ): case ( preg_match( '/_(key|secret|tid|token)$/', $key ) ? true : false ): if ( '' !== $opts[ $key ] ) $opts[ $key ] = '[removed]'; break; } } $this->debug->log_arr( 'wpsso settings', $opts ); $this->debug->mark(); $this->debug->show_html(); } private function debug_reminder( array $is_doing ) { if ( $this->debug->is_enabled( 'log' ) ) { $this->debug->log( 'WP debug log mode is active' ); } if ( $this->debug->is_enabled( 'html' ) ) { $this->debug->log( 'HTML debug mode is active' ); } if ( $is_doing[ 'admin' ] && ! $is_doing[ 'dev' ] ) { $info = $this->cf[ 'plugin' ][ 'wpsso' ]; $notice_msg = ''; $notice_key = 'debug-mode-is-active'; $dismiss_time = 12 * HOUR_IN_SECONDS; if ( $this->debug->is_enabled( 'log' ) ) { $notice_key .= '-with-debug-log'; $notice_msg .= __( 'WP debug logging mode is active - debug messages are being sent to the WordPress debug log.', 'wpsso' ) . ' '; } if ( $this->debug->is_enabled( 'html' ) ) { $notice_key .= '-with-html-comments'; $notice_msg .= __( 'HTML debug mode is active - debug messages are being added to webpages as hidden HTML comments.', 'wpsso' ) . ' '; } /* * WP debug logging and/or HTML debug mode is active. */ if ( $notice_msg ) { $notice_msg .= sprintf( __( 'The %s plugin\'s debug mode generates thousands of messages during page load, which affects website performance.', 'wpsso' ), $info[ 'name' ] ) . ' '; $notice_msg .= __( 'Don\'t forget to disable debug mode when debugging is complete.', 'wpsso' ); $this->notice->warn( $notice_msg, null, $notice_key, $dismiss_time ); } /* * WPSSO_CACHE_DISABLE constant is true or the 'plugin_cache_disable' option is checked. */ if ( $this->util->cache->is_disabled() ) { $notice_msg = sprintf( __( 'The %s plugin\'s cache feature is disabled for debugging, which affects website performance.', 'wpsso' ), $info[ 'name' ] ) . ' '; $notice_msg .= __( 'Don\'t forget to re-enable caching when debugging is complete.', 'wpsso' ); $notice_key = 'plugin-cache-is-disabled'; $this->notice->warn( $notice_msg, null, $notice_key, $dismiss_time ); } } } } global $wpsso; $wpsso =& Wpsso::get_instance(); }