wp-seo-main.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Main
  6. */
  7. if ( ! function_exists( 'add_filter' ) ) {
  8. header( 'Status: 403 Forbidden' );
  9. header( 'HTTP/1.1 403 Forbidden' );
  10. exit();
  11. }
  12. /**
  13. * {@internal Nobody should be able to overrule the real version number as this can cause
  14. * serious issues with the options, so no if ( ! defined() ).}}
  15. */
  16. define( 'WPSEO_VERSION', '12.7.1' );
  17. if ( ! defined( 'WPSEO_PATH' ) ) {
  18. define( 'WPSEO_PATH', plugin_dir_path( WPSEO_FILE ) );
  19. }
  20. if ( ! defined( 'WPSEO_BASENAME' ) ) {
  21. define( 'WPSEO_BASENAME', plugin_basename( WPSEO_FILE ) );
  22. }
  23. /*
  24. * {@internal The prefix constants are used to build prefixed versions of dependencies.
  25. * These should not be changed on run-time, thus missing the ! defined() check.}}
  26. */
  27. define( 'YOAST_VENDOR_NS_PREFIX', 'YoastSEO_Vendor' );
  28. define( 'YOAST_VENDOR_DEFINE_PREFIX', 'YOASTSEO_VENDOR__' );
  29. define( 'YOAST_VENDOR_PREFIX_DIRECTORY', 'vendor_prefixed' );
  30. if ( ! defined( 'WPSEO_NAMESPACES' ) ) {
  31. define( 'WPSEO_NAMESPACES', true );
  32. }
  33. /* ***************************** CLASS AUTOLOADING *************************** */
  34. /**
  35. * Autoload our class files.
  36. *
  37. * @param string $class Class name.
  38. *
  39. * @return void
  40. */
  41. function wpseo_auto_load( $class ) {
  42. static $classes = null;
  43. if ( $classes === null ) {
  44. $classes = [
  45. 'wp_list_table' => ABSPATH . 'wp-admin/includes/class-wp-list-table.php',
  46. 'walker_category' => ABSPATH . 'wp-includes/category-template.php',
  47. ];
  48. }
  49. $cn = strtolower( $class );
  50. if ( ! class_exists( $class ) && isset( $classes[ $cn ] ) ) {
  51. require_once $classes[ $cn ];
  52. }
  53. }
  54. $yoast_autoload_file = WPSEO_PATH . 'vendor/autoload.php';
  55. if ( is_readable( $yoast_autoload_file ) ) {
  56. require $yoast_autoload_file;
  57. }
  58. elseif ( ! class_exists( 'WPSEO_Options' ) ) { // Still checking since might be site-level autoload R.
  59. add_action( 'admin_init', 'yoast_wpseo_missing_autoload', 1 );
  60. return;
  61. }
  62. if ( function_exists( 'spl_autoload_register' ) ) {
  63. spl_autoload_register( 'wpseo_auto_load' );
  64. }
  65. /* ********************* DEFINES DEPENDING ON AUTOLOADED CODE ********************* */
  66. /**
  67. * Defaults to production, for safety.
  68. */
  69. if ( ! defined( 'YOAST_ENVIRONMENT' ) ) {
  70. define( 'YOAST_ENVIRONMENT', 'production' );
  71. }
  72. /**
  73. * Only use minified assets when we are in a production environment.
  74. */
  75. if ( ! defined( 'WPSEO_CSSJS_SUFFIX' ) ) {
  76. define( 'WPSEO_CSSJS_SUFFIX', ( 'development' !== YOAST_ENVIRONMENT ) ? '.min' : '' );
  77. }
  78. /* ***************************** PLUGIN (DE-)ACTIVATION *************************** */
  79. /**
  80. * Run single site / network-wide activation of the plugin.
  81. *
  82. * @param bool $networkwide Whether the plugin is being activated network-wide.
  83. */
  84. function wpseo_activate( $networkwide = false ) {
  85. if ( ! is_multisite() || ! $networkwide ) {
  86. _wpseo_activate();
  87. }
  88. else {
  89. /* Multi-site network activation - activate the plugin for all blogs. */
  90. wpseo_network_activate_deactivate( true );
  91. }
  92. }
  93. /**
  94. * Run single site / network-wide de-activation of the plugin.
  95. *
  96. * @param bool $networkwide Whether the plugin is being de-activated network-wide.
  97. */
  98. function wpseo_deactivate( $networkwide = false ) {
  99. if ( ! is_multisite() || ! $networkwide ) {
  100. _wpseo_deactivate();
  101. }
  102. else {
  103. /* Multi-site network activation - de-activate the plugin for all blogs. */
  104. wpseo_network_activate_deactivate( false );
  105. }
  106. }
  107. /**
  108. * Run network-wide (de-)activation of the plugin.
  109. *
  110. * @param bool $activate True for plugin activation, false for de-activation.
  111. */
  112. function wpseo_network_activate_deactivate( $activate = true ) {
  113. global $wpdb;
  114. $network_blogs = $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE site_id = %d", $wpdb->siteid ) );
  115. if ( is_array( $network_blogs ) && $network_blogs !== [] ) {
  116. foreach ( $network_blogs as $blog_id ) {
  117. switch_to_blog( $blog_id );
  118. if ( $activate === true ) {
  119. _wpseo_activate();
  120. }
  121. else {
  122. _wpseo_deactivate();
  123. }
  124. restore_current_blog();
  125. }
  126. }
  127. }
  128. /**
  129. * Runs on activation of the plugin.
  130. */
  131. function _wpseo_activate() {
  132. require_once WPSEO_PATH . 'inc/wpseo-functions.php';
  133. require_once WPSEO_PATH . 'inc/class-wpseo-installation.php';
  134. wpseo_load_textdomain(); // Make sure we have our translations available for the defaults.
  135. new WPSEO_Installation();
  136. WPSEO_Options::get_instance();
  137. if ( ! is_multisite() ) {
  138. WPSEO_Options::initialize();
  139. }
  140. else {
  141. WPSEO_Options::maybe_set_multisite_defaults( true );
  142. }
  143. WPSEO_Options::ensure_options_exist();
  144. if ( is_multisite() && ms_is_switched() ) {
  145. delete_option( 'rewrite_rules' );
  146. }
  147. else {
  148. $wpseo_rewrite = new WPSEO_Rewrite();
  149. $wpseo_rewrite->schedule_flush();
  150. }
  151. do_action( 'wpseo_register_roles' );
  152. WPSEO_Role_Manager_Factory::get()->add();
  153. do_action( 'wpseo_register_capabilities' );
  154. WPSEO_Capability_Manager_Factory::get()->add();
  155. // Clear cache so the changes are obvious.
  156. WPSEO_Utils::clear_cache();
  157. // Create the text link storage table.
  158. $link_installer = new WPSEO_Link_Installer();
  159. $link_installer->install();
  160. // Trigger reindex notification.
  161. $notifier = new WPSEO_Link_Notifier();
  162. $notifier->manage_notification();
  163. // Schedule cronjob when it doesn't exists on activation.
  164. $wpseo_onpage = new WPSEO_OnPage();
  165. $wpseo_onpage->activate_hooks();
  166. do_action( 'wpseo_activate' );
  167. }
  168. /**
  169. * On deactivation, flush the rewrite rules so XML sitemaps stop working.
  170. */
  171. function _wpseo_deactivate() {
  172. require_once WPSEO_PATH . 'inc/wpseo-functions.php';
  173. if ( is_multisite() && ms_is_switched() ) {
  174. delete_option( 'rewrite_rules' );
  175. }
  176. else {
  177. add_action( 'shutdown', 'flush_rewrite_rules' );
  178. }
  179. // Register capabilities, to make sure they are cleaned up.
  180. do_action( 'wpseo_register_roles' );
  181. do_action( 'wpseo_register_capabilities' );
  182. // Clean up capabilities.
  183. WPSEO_Role_Manager_Factory::get()->remove();
  184. WPSEO_Capability_Manager_Factory::get()->remove();
  185. // Clear cache so the changes are obvious.
  186. WPSEO_Utils::clear_cache();
  187. do_action( 'wpseo_deactivate' );
  188. }
  189. /**
  190. * Run wpseo activation routine on creation / activation of a multisite blog if WPSEO is activated
  191. * network-wide.
  192. *
  193. * Will only be called by multisite actions.
  194. *
  195. * {@internal Unfortunately will fail if the plugin is in the must-use directory.
  196. * {@link https://core.trac.wordpress.org/ticket/24205} }}
  197. *
  198. * @param int|WP_Site $blog_id Blog ID.
  199. */
  200. function wpseo_on_activate_blog( $blog_id ) {
  201. if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
  202. require_once ABSPATH . 'wp-admin/includes/plugin.php';
  203. }
  204. if ( $blog_id instanceof WP_Site ) {
  205. $blog_id = (int) $blog_id->blog_id;
  206. }
  207. if ( is_plugin_active_for_network( plugin_basename( WPSEO_FILE ) ) ) {
  208. switch_to_blog( $blog_id );
  209. wpseo_activate( false );
  210. restore_current_blog();
  211. }
  212. }
  213. /* ***************************** PLUGIN LOADING *************************** */
  214. /**
  215. * Load translations.
  216. */
  217. function wpseo_load_textdomain() {
  218. $wpseo_path = str_replace( '\\', '/', WPSEO_PATH );
  219. $mu_path = str_replace( '\\', '/', WPMU_PLUGIN_DIR );
  220. if ( false !== stripos( $wpseo_path, $mu_path ) ) {
  221. load_muplugin_textdomain( 'wordpress-seo', dirname( WPSEO_BASENAME ) . '/languages/' );
  222. }
  223. else {
  224. load_plugin_textdomain( 'wordpress-seo', false, dirname( WPSEO_BASENAME ) . '/languages/' );
  225. }
  226. }
  227. add_action( 'plugins_loaded', 'wpseo_load_textdomain' );
  228. /**
  229. * On plugins_loaded: load the minimum amount of essential files for this plugin.
  230. */
  231. function wpseo_init() {
  232. require_once WPSEO_PATH . 'inc/wpseo-functions.php';
  233. require_once WPSEO_PATH . 'inc/wpseo-functions-deprecated.php';
  234. // Make sure our option and meta value validation routines and default values are always registered and available.
  235. WPSEO_Options::get_instance();
  236. WPSEO_Meta::init();
  237. if ( version_compare( WPSEO_Options::get( 'version', 1 ), WPSEO_VERSION, '<' ) ) {
  238. if ( function_exists( 'opcache_reset' ) ) {
  239. @opcache_reset();
  240. }
  241. new WPSEO_Upgrade();
  242. // Get a cleaned up version of the $options.
  243. }
  244. if ( WPSEO_Options::get( 'stripcategorybase' ) === true ) {
  245. $GLOBALS['wpseo_rewrite'] = new WPSEO_Rewrite();
  246. }
  247. if ( WPSEO_Options::get( 'enable_xml_sitemap' ) === true ) {
  248. $GLOBALS['wpseo_sitemaps'] = new WPSEO_Sitemaps();
  249. }
  250. if ( ! wp_doing_ajax() ) {
  251. require_once WPSEO_PATH . 'inc/wpseo-non-ajax-functions.php';
  252. }
  253. // Init it here because the filter must be present on the frontend as well or it won't work in the customizer.
  254. new WPSEO_Customizer();
  255. /*
  256. * Initializes the link watcher for both the frontend and backend.
  257. * Required to process scheduled items properly.
  258. */
  259. $link_watcher = new WPSEO_Link_Watcher_Loader();
  260. $link_watcher->load();
  261. $integrations = [];
  262. $integrations[] = new WPSEO_Slug_Change_Watcher();
  263. $integrations[] = new WPSEO_Structured_Data_Blocks();
  264. foreach ( $integrations as $integration ) {
  265. $integration->register_hooks();
  266. }
  267. // Loading Ryte integration.
  268. $wpseo_onpage = new WPSEO_OnPage();
  269. $wpseo_onpage->register_hooks();
  270. // Feature flag introduced to resolve problems with composer installation in 11.8.
  271. if ( defined( 'YOAST_SEO_EXPERIMENTAL_PHP56' ) && YOAST_SEO_EXPERIMENTAL_PHP56 ) {
  272. // When namespaces are not available, stop further execution.
  273. if ( version_compare( PHP_VERSION, '5.6.0', '>=' ) ) {
  274. require_once WPSEO_PATH . 'src/main.php';
  275. // require_once WPSEO_PATH . 'src/loaders/oauth.php'; Temporarily disabled.
  276. }
  277. }
  278. }
  279. /**
  280. * Loads the rest api endpoints.
  281. */
  282. function wpseo_init_rest_api() {
  283. // We can't do anything when requirements are not met.
  284. if ( ! WPSEO_Utils::is_api_available() ) {
  285. return;
  286. }
  287. // Boot up REST API.
  288. $configuration_service = new WPSEO_Configuration_Service();
  289. $configuration_service->initialize();
  290. $ryte_endpoint_service = new WPSEO_Ryte_Service( new WPSEO_OnPage_Option() );
  291. $statistics_service = new WPSEO_Statistics_Service( new WPSEO_Statistics() );
  292. $endpoints = [];
  293. $endpoints[] = new WPSEO_Link_Reindex_Post_Endpoint( new WPSEO_Link_Reindex_Post_Service() );
  294. $endpoints[] = new WPSEO_Endpoint_Ryte( $ryte_endpoint_service );
  295. $endpoints[] = new WPSEO_Endpoint_Indexable( new WPSEO_Indexable_Service() );
  296. $endpoints[] = new WPSEO_Endpoint_File_Size( new WPSEO_File_Size_Service() );
  297. $endpoints[] = new WPSEO_Endpoint_Statistics( $statistics_service );
  298. $endpoints[] = new WPSEO_Endpoint_MyYoast_Connect();
  299. foreach ( $endpoints as $endpoint ) {
  300. $endpoint->register();
  301. }
  302. }
  303. /**
  304. * Used to load the required files on the plugins_loaded hook, instead of immediately.
  305. */
  306. function wpseo_frontend_init() {
  307. add_action( 'init', 'initialize_wpseo_front' );
  308. if ( WPSEO_Options::get( 'breadcrumbs-enable' ) === true ) {
  309. /**
  310. * If breadcrumbs are active (which they supposedly are if the users has enabled this settings,
  311. * there's no reason to have bbPress breadcrumbs as well.
  312. *
  313. * {@internal The class itself is only loaded when the template tag is encountered
  314. * via the template tag function in the wpseo-functions.php file.}}
  315. */
  316. add_filter( 'bbp_get_breadcrumb', '__return_false' );
  317. }
  318. add_action( 'template_redirect', 'wpseo_frontend_head_init', 999 );
  319. }
  320. /**
  321. * Instantiate the different social classes on the frontend.
  322. */
  323. function wpseo_frontend_head_init() {
  324. if ( WPSEO_Options::get( 'twitter' ) === true ) {
  325. add_action( 'wpseo_head', [ 'WPSEO_Twitter', 'get_instance' ], 40 );
  326. }
  327. if ( WPSEO_Options::get( 'opengraph' ) === true ) {
  328. $GLOBALS['wpseo_og'] = new WPSEO_OpenGraph();
  329. }
  330. }
  331. /**
  332. * Used to load the required files on the plugins_loaded hook, instead of immediately.
  333. */
  334. function wpseo_admin_init() {
  335. new WPSEO_Admin_Init();
  336. }
  337. /**
  338. * Initialize the WP-CLI integration.
  339. *
  340. * The WP-CLI integration needs PHP 5.3 support, which should be automatically
  341. * enforced by the check for the WP_CLI constant. As WP-CLI itself only runs
  342. * on PHP 5.3+, the constant should only be set when requirements are met.
  343. */
  344. function wpseo_cli_init() {
  345. if ( WPSEO_Utils::is_yoast_seo_premium() ) {
  346. WP_CLI::add_command(
  347. 'yoast redirect list',
  348. 'WPSEO_CLI_Redirect_List_Command',
  349. [ 'before_invoke' => 'WPSEO_CLI_Premium_Requirement::enforce' ]
  350. );
  351. WP_CLI::add_command(
  352. 'yoast redirect create',
  353. 'WPSEO_CLI_Redirect_Create_Command',
  354. [ 'before_invoke' => 'WPSEO_CLI_Premium_Requirement::enforce' ]
  355. );
  356. WP_CLI::add_command(
  357. 'yoast redirect update',
  358. 'WPSEO_CLI_Redirect_Update_Command',
  359. [ 'before_invoke' => 'WPSEO_CLI_Premium_Requirement::enforce' ]
  360. );
  361. WP_CLI::add_command(
  362. 'yoast redirect delete',
  363. 'WPSEO_CLI_Redirect_Delete_Command',
  364. [ 'before_invoke' => 'WPSEO_CLI_Premium_Requirement::enforce' ]
  365. );
  366. WP_CLI::add_command(
  367. 'yoast redirect has',
  368. 'WPSEO_CLI_Redirect_Has_Command',
  369. [ 'before_invoke' => 'WPSEO_CLI_Premium_Requirement::enforce' ]
  370. );
  371. WP_CLI::add_command(
  372. 'yoast redirect follow',
  373. 'WPSEO_CLI_Redirect_Follow_Command',
  374. [ 'before_invoke' => 'WPSEO_CLI_Premium_Requirement::enforce' ]
  375. );
  376. }
  377. // Only add the namespace if the required base class exists (WP-CLI 1.5.0+).
  378. // This is optional and only adds the description of the root `yoast`
  379. // command.
  380. if ( class_exists( 'WP_CLI\Dispatcher\CommandNamespace' ) ) {
  381. WP_CLI::add_command( 'yoast', 'WPSEO_CLI_Yoast_Command_Namespace' );
  382. if ( WPSEO_Utils::is_yoast_seo_premium() ) {
  383. WP_CLI::add_command( 'yoast redirect', 'WPSEO_CLI_Redirect_Command_Namespace' );
  384. }
  385. else {
  386. WP_CLI::add_command( 'yoast redirect', 'WPSEO_CLI_Redirect_Upsell_Command_Namespace' );
  387. }
  388. }
  389. }
  390. /* ***************************** BOOTSTRAP / HOOK INTO WP *************************** */
  391. $spl_autoload_exists = function_exists( 'spl_autoload_register' );
  392. $filter_exists = function_exists( 'filter_input' );
  393. if ( ! $spl_autoload_exists ) {
  394. add_action( 'admin_init', 'yoast_wpseo_missing_spl', 1 );
  395. }
  396. if ( ! $filter_exists ) {
  397. add_action( 'admin_init', 'yoast_wpseo_missing_filter', 1 );
  398. }
  399. if ( ! wp_installing() && ( $spl_autoload_exists && $filter_exists ) ) {
  400. add_action( 'plugins_loaded', 'wpseo_init', 14 );
  401. add_action( 'rest_api_init', 'wpseo_init_rest_api' );
  402. if ( is_admin() ) {
  403. new Yoast_Alerts();
  404. $yoast_addon_manager = new WPSEO_Addon_Manager();
  405. $yoast_addon_manager->register_hooks();
  406. if ( wp_doing_ajax() ) {
  407. require_once WPSEO_PATH . 'admin/ajax.php';
  408. // Plugin conflict ajax hooks.
  409. new Yoast_Plugin_Conflict_Ajax();
  410. if ( filter_input( INPUT_POST, 'action' ) === 'inline-save' ) {
  411. add_action( 'plugins_loaded', 'wpseo_admin_init', 15 );
  412. }
  413. }
  414. else {
  415. add_action( 'plugins_loaded', 'wpseo_admin_init', 15 );
  416. }
  417. }
  418. else {
  419. add_action( 'plugins_loaded', 'wpseo_frontend_init', 15 );
  420. }
  421. add_action( 'plugins_loaded', 'load_yoast_notifications' );
  422. if ( defined( 'WP_CLI' ) && WP_CLI ) {
  423. add_action( 'plugins_loaded', 'wpseo_cli_init', 20 );
  424. }
  425. add_filter( 'phpcompat_whitelist', 'yoast_free_phpcompat_whitelist' );
  426. add_action( 'init', [ 'WPSEO_Replace_Vars', 'setup_statics_once' ] );
  427. }
  428. // Activation and deactivation hook.
  429. register_activation_hook( WPSEO_FILE, 'wpseo_activate' );
  430. register_deactivation_hook( WPSEO_FILE, 'wpseo_deactivate' );
  431. // Wpmu_new_blog has been deprecated in 5.1 and replaced by wp_insert_site.
  432. global $wp_version;
  433. if ( version_compare( $wp_version, '5.1', '<' ) ) {
  434. add_action( 'wpmu_new_blog', 'wpseo_on_activate_blog' );
  435. }
  436. else {
  437. add_action( 'wp_initialize_site', 'wpseo_on_activate_blog', 99 );
  438. }
  439. add_action( 'activate_blog', 'wpseo_on_activate_blog' );
  440. // Registers SEO capabilities.
  441. $wpseo_register_capabilities = new WPSEO_Register_Capabilities();
  442. $wpseo_register_capabilities->register_hooks();
  443. // Registers SEO roles.
  444. $wpseo_register_capabilities = new WPSEO_Register_Roles();
  445. $wpseo_register_capabilities->register_hooks();
  446. /**
  447. * Wraps for notifications center class.
  448. */
  449. function load_yoast_notifications() {
  450. // Init Yoast_Notification_Center class.
  451. Yoast_Notification_Center::get();
  452. }
  453. /**
  454. * Throw an error if the PHP SPL extension is disabled (prevent white screens) and self-deactivate plugin.
  455. *
  456. * @since 1.5.4
  457. *
  458. * @return void
  459. */
  460. function yoast_wpseo_missing_spl() {
  461. if ( is_admin() ) {
  462. add_action( 'admin_notices', 'yoast_wpseo_missing_spl_notice' );
  463. yoast_wpseo_self_deactivate();
  464. }
  465. }
  466. /**
  467. * Returns the notice in case of missing spl extension.
  468. */
  469. function yoast_wpseo_missing_spl_notice() {
  470. $message = esc_html__( 'The Standard PHP Library (SPL) extension seem to be unavailable. Please ask your web host to enable it.', 'wordpress-seo' );
  471. yoast_wpseo_activation_failed_notice( $message );
  472. }
  473. /**
  474. * Throw an error if the Composer autoload is missing and self-deactivate plugin.
  475. *
  476. * @return void
  477. */
  478. function yoast_wpseo_missing_autoload() {
  479. if ( is_admin() ) {
  480. add_action( 'admin_notices', 'yoast_wpseo_missing_autoload_notice' );
  481. yoast_wpseo_self_deactivate();
  482. }
  483. }
  484. /**
  485. * Returns the notice in case of missing Composer autoload.
  486. */
  487. function yoast_wpseo_missing_autoload_notice() {
  488. /* translators: %1$s expands to Yoast SEO, %2$s / %3$s: links to the installation manual in the Readme for the Yoast SEO code repository on GitHub */
  489. $message = esc_html__( 'The %1$s plugin installation is incomplete. Please refer to %2$sinstallation instructions%3$s.', 'wordpress-seo' );
  490. $message = sprintf( $message, 'Yoast SEO', '<a href="https://github.com/Yoast/wordpress-seo#installation">', '</a>' );
  491. yoast_wpseo_activation_failed_notice( $message );
  492. }
  493. /**
  494. * Throw an error if the filter extension is disabled (prevent white screens) and self-deactivate plugin.
  495. *
  496. * @since 2.0
  497. *
  498. * @return void
  499. */
  500. function yoast_wpseo_missing_filter() {
  501. if ( is_admin() ) {
  502. add_action( 'admin_notices', 'yoast_wpseo_missing_filter_notice' );
  503. yoast_wpseo_self_deactivate();
  504. }
  505. }
  506. /**
  507. * Returns the notice in case of missing filter extension.
  508. */
  509. function yoast_wpseo_missing_filter_notice() {
  510. $message = esc_html__( 'The filter extension seem to be unavailable. Please ask your web host to enable it.', 'wordpress-seo' );
  511. yoast_wpseo_activation_failed_notice( $message );
  512. }
  513. /**
  514. * Echo's the Activation failed notice with any given message.
  515. *
  516. * @param string $message Message string.
  517. */
  518. function yoast_wpseo_activation_failed_notice( $message ) {
  519. echo '<div class="error"><p>' . esc_html__( 'Activation failed:', 'wordpress-seo' ) . ' ' . strip_tags( $message, '<a>' ) . '</p></div>';
  520. }
  521. /**
  522. * The method will deactivate the plugin, but only once, done by the static $is_deactivated.
  523. */
  524. function yoast_wpseo_self_deactivate() {
  525. static $is_deactivated;
  526. if ( $is_deactivated === null ) {
  527. $is_deactivated = true;
  528. deactivate_plugins( plugin_basename( WPSEO_FILE ) );
  529. if ( isset( $_GET['activate'] ) ) {
  530. unset( $_GET['activate'] );
  531. }
  532. }
  533. }
  534. /**
  535. * Excludes specific files from php-compatibility-checker.
  536. *
  537. * @since 9.4
  538. *
  539. * @param array $ignored Array of ignored directories/files.
  540. *
  541. * @return array Array of ignored directories/files.
  542. */
  543. function yoast_free_phpcompat_whitelist( $ignored ) {
  544. $path = '*/' . basename( WPSEO_PATH ) . '/';
  545. // To prevent: (warning) File has mixed line endings; this may cause incorrect results.
  546. $ignored[] = $path . 'vendor/ruckusing/lib/Ruckusing/FrameworkRunner.php';
  547. $ignored[] = $path . 'vendor_prefixed/ruckusing/lib/Ruckusing/FrameworkRunner.php';
  548. /*
  549. * To prevent: (error) Extension 'sqlite' is removed since PHP 5.4.
  550. * Ignoring because we are not using the sqlite functionality.
  551. */
  552. $ignored[] = $path . 'vendor/ruckusing/lib/Ruckusing/Adapter/Sqlite3/Base.php';
  553. $ignored[] = $path . 'vendor_prefixed/ruckusing/lib/Ruckusing/Adapter/Sqlite3/Base.php';
  554. return $ignored;
  555. }