' . sprintf( __( 'The title & metas settings for %1$s are made up of variables that are replaced by specific values from the page when the page is displayed. The tabs on the left explain the available variables.', 'wordpress-seo' ), 'Yoast SEO' ) . '
' . '
' . __( 'Note that not all variables can be used in every template.', 'wordpress-seo' ) . '
';
+
+ foreach ( $option_tabs->get_tabs() as $tab ) {
+ // Prepare the help center for each tab.
+ $help_center = new WPSEO_Help_Center( $option_tabs->get_base(), $tab );
+
+ $identifier = $tab->get_name();
+ printf( '
', $identifier );
+
+ // Output the help center.
+ $help_center->output_help_center();
+
+ // Output the settings view for all tabs.
+ $tab_view = $this->get_tab_view( $option_tabs, $tab );
+ if ( is_file( $tab_view ) ) {
+ require_once $tab_view;
+ }
+
+ echo '
';
+ }
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/class-option-tabs.php b/wp-content/plugins/wordpress-seo/admin/class-option-tabs.php
new file mode 100644
index 0000000..2d5bd54
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-option-tabs.php
@@ -0,0 +1,106 @@
+base = sanitize_title( $base );
+
+ $tab = filter_input( INPUT_GET, 'tab' );
+ $this->active_tab = empty( $tab ) ? $active_tab : $tab;
+ }
+
+ /**
+ * Get the base
+ *
+ * @return string
+ */
+ public function get_base() {
+ return $this->base;
+ }
+
+ /**
+ * Add a tab
+ *
+ * @param WPSEO_Option_Tab $tab Tab to add.
+ *
+ * @return $this
+ */
+ public function add_tab( WPSEO_Option_Tab $tab ) {
+ $this->tabs[] = $tab;
+
+ return $this;
+ }
+
+ /**
+ * Get active tab
+ *
+ * @return null|WPSEO_Option_Tab Get the active tab.
+ */
+ public function get_active_tab() {
+ if ( empty( $this->active_tab ) ) {
+ return null;
+ }
+
+ $active_tabs = array_filter( $this->tabs, array( $this, 'is_active_tab' ) );
+ if ( ! empty( $active_tabs ) ) {
+ $active_tabs = array_values( $active_tabs );
+ if ( count( $active_tabs ) === 1 ) {
+ return $active_tabs[0];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Is the tab the active tab
+ *
+ * @param WPSEO_Option_Tab $tab Tab to check for active tab.
+ *
+ * @return bool
+ */
+ public function is_active_tab( WPSEO_Option_Tab $tab ) {
+ return ( $tab->get_name() === $this->active_tab );
+ }
+
+ /**
+ * Get all tabs
+ *
+ * @return WPSEO_Option_Tab[]
+ */
+ public function get_tabs() {
+ return $this->tabs;
+ }
+
+ /**
+ * Display the tabs
+ *
+ * @param Yoast_Form $yform Yoast Form needed in the views.
+ * @param array $options Options needed in the views.
+ */
+ public function display( Yoast_Form $yform, $options = array() ) {
+ $formatter = new WPSEO_Option_Tabs_Formatter();
+ $formatter->run( $this, $yform, $options );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/class-plugin-availability.php b/wp-content/plugins/wordpress-seo/admin/class-plugin-availability.php
new file mode 100644
index 0000000..7a04b59
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-plugin-availability.php
@@ -0,0 +1,241 @@
+register_yoast_plugins();
+ $this->register_yoast_plugins_status();
+ }
+
+ /**
+ * Registers all the available Yoast SEO plugins.
+ */
+ protected function register_yoast_plugins() {
+ $this->plugins = array(
+ 'yoast-seo-premium' => array(
+ 'url' => 'https://yoast.com/wordpress/plugins/seo-premium/',
+ 'title' => 'Yoast SEO Premium',
+ /* translators: %1$s expands to Yoast SEO */
+ 'description' => sprintf( __( 'The premium version of %1$s with more features & support.', 'wordpress-seo' ), 'Yoast SEO' ),
+ 'installed' => false,
+ 'slug' => 'wordpress-seo-premium/wp-seo-premium.php',
+ ),
+
+ 'video-seo-for-wordpress-seo-by-yoast' => array(
+ 'url' => 'https://yoast.com/wordpress/plugins/video-seo/',
+ 'title' => 'Video SEO',
+ 'description' => __( 'Optimize your videos to show them off in search results and get more clicks!', 'wordpress-seo' ),
+ 'installed' => false,
+ 'slug' => 'wpseo-video/video-seo.php',
+ ),
+
+ 'yoast-news-seo' => array(
+ 'url' => 'https://yoast.com/wordpress/plugins/news-seo/',
+ 'title' => 'News SEO',
+ 'description' => __( 'Are you in Google News? Increase your traffic from Google News by optimizing for it!', 'wordpress-seo' ),
+ 'installed' => false,
+ 'slug' => 'wpseo-news/wpseo-news.php',
+ ),
+
+ 'local-seo-for-yoast-seo' => array(
+ 'url' => 'https://yoast.com/wordpress/plugins/local-seo/',
+ 'title' => 'Local SEO',
+ 'description' => __( 'Rank better locally and in Google Maps, without breaking a sweat!', 'wordpress-seo' ),
+ 'installed' => false,
+ 'slug' => 'wordpress-seo-local/local-seo.php',
+ ),
+
+ 'yoast-woocommerce-seo' => array(
+ 'url' => 'https://yoast.com/wordpress/plugins/yoast-woocommerce-seo/',
+ 'title' => 'Yoast WooCommerce SEO',
+ /* translators: %1$s expands to Yoast SEO */
+ 'description' => sprintf( __( 'Seamlessly integrate WooCommerce with %1$s and get extra features!', 'wordpress-seo' ), 'Yoast SEO' ),
+ 'installed' => false,
+ 'slug' => 'wpseo-woocommerce/wpseo-woocommerce.php',
+ ),
+ );
+ }
+
+ /**
+ * Sets certain plugin properties based on WordPress' status.
+ */
+ protected function register_yoast_plugins_status() {
+
+ foreach ( $this->plugins as $name => $plugin ) {
+
+ $plugin_slug = $plugin['slug'];
+ $plugin_path = WP_PLUGIN_DIR . '/' . $plugin_slug;
+
+ if ( file_exists( $plugin_path ) ) {
+ $plugin_data = get_plugin_data( $plugin_path, false, false );
+ $this->plugins[ $name ]['installed'] = true;
+ $this->plugins[ $name ]['version'] = $plugin_data['Version'];
+ $this->plugins[ $name ]['active'] = is_plugin_active( $plugin_slug );
+ }
+ }
+ }
+
+ /**
+ * Checks whether or not a plugin is known within the Yoast SEO collection.
+ *
+ * @param {string} $plugin The plugin to search for.
+ *
+ * @return bool Whether or not the plugin is exists.
+ */
+ protected function plugin_exists( $plugin ) {
+ return isset( $this->plugins[ $plugin ] );
+ }
+
+ /**
+ * Gets all the possibly available plugins.
+ *
+ * @return array Array containing the information about the plugins.
+ */
+ public function get_plugins() {
+ return $this->plugins;
+ }
+
+ /**
+ * Gets a specific plugin. Returns an empty array if it cannot be found.
+ *
+ * @param {string} $plugin The plugin to search for.
+ *
+ * @return array The plugin properties.
+ */
+ public function get_plugin( $plugin ) {
+ if ( ! $this->plugin_exists( $plugin ) ) {
+ return array();
+ }
+
+ return $this->plugins[ $plugin ];
+ }
+
+ /**
+ * Gets the version of the plugin.
+ *
+ * @param {string} $plugin The plugin to search for.
+ *
+ * @return string The version associated with the plugin.
+ */
+ public function get_version( $plugin ) {
+ if ( ! isset( $plugin['version'] ) ) {
+ return '';
+ }
+
+ return $plugin['version'];
+ }
+
+ /**
+ * Checks if there are dependencies available for the plugin.
+ *
+ * @param {string} $plugin The plugin to search for.
+ *
+ * @return bool Whether or not there is a dependency present.
+ */
+ public function has_dependencies( $plugin ) {
+ return ( isset( $plugin['_dependencies'] ) && ! empty( $plugin['_dependencies'] ) );
+ }
+
+ /**
+ * Gets the dependencies for the plugin.
+ *
+ * @param {string} $plugin The plugin to search for.
+ *
+ * @return array Array containing all the dependencies associated with the plugin.
+ */
+ public function get_dependencies( $plugin ) {
+ if ( ! $this->has_dependencies( $plugin ) ) {
+ return array();
+ }
+
+ return $plugin['_dependencies'];
+ }
+
+ /**
+ * Checks if all dependencies are satisfied.
+ *
+ * @param {string} $plugin The plugin to search for.
+ *
+ * @return bool Whether or not the dependencies are satisfied.
+ */
+ public function dependencies_are_satisfied( $plugin ) {
+ if ( ! $this->has_dependencies( $plugin ) ) {
+ return true;
+ }
+
+ $dependencies = $this->get_dependencies( $plugin );
+ $installed_dependencies = array_filter( $dependencies, array( $this, 'is_dependency_available' ) );
+
+ return count( $installed_dependencies ) === count( $dependencies );
+ }
+
+ /**
+ * Checks whether or not one of the plugins is properly installed and usable.
+ *
+ * @param {string} $plugin The plugin to search for.
+ *
+ * @return bool Whether or not the plugin is properly installed.
+ */
+ public function is_installed( $plugin ) {
+ if ( empty( $plugin ) ) {
+ return false;
+ }
+
+ $dependencies_are_satisfied = $this->dependencies_are_satisfied( $plugin );
+
+ return $dependencies_are_satisfied && $this->is_available( $plugin );
+ }
+
+ /**
+ * Gets all installed plugins.
+ *
+ * @return array
+ */
+ public function get_installed_plugins() {
+ $installed = array();
+
+ foreach ( $this->plugins as $pluginKey => $plugin ) {
+ if ( $this->is_installed( $plugin ) ) {
+ $installed[ $pluginKey ] = $plugin;
+ }
+ }
+
+ return $installed;
+ }
+
+ /**
+ * Checks for the availability of the plugin.
+ *
+ * @param {string} $plugin The plugin to search for.
+ *
+ * @return bool Whether or not the plugin is available.
+ */
+ public function is_available( $plugin ) {
+ return isset( $plugin['installed'] ) && $plugin['installed'] === true;
+ }
+
+ /**
+ * Checks whether a dependency is available.
+ *
+ * @param {string} $dependency The dependency to look for.
+ *
+ * @return bool Whether or not the dependency is available.
+ */
+ public function is_dependency_available( $dependency ) {
+ return class_exists( $dependency );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/class-plugin-compatibility.php b/wp-content/plugins/wordpress-seo/admin/class-plugin-compatibility.php
new file mode 100644
index 0000000..9b0ee88
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-plugin-compatibility.php
@@ -0,0 +1,101 @@
+current_wpseo_version = $this->get_major_minor_version( $version );
+ $this->availability_checker = $this->retrieve_availability_checker( $availability_checker );
+ $this->installed_plugins = $this->availability_checker->get_installed_plugins();
+ }
+
+ /**
+ * Retrieves the availability checker.
+ *
+ * @param null|object $checker The checker to set.
+ *
+ * @return WPSEO_Plugin_Availability The checker to use.
+ */
+ private function retrieve_availability_checker( $checker ) {
+ if ( is_null( $checker ) || ! is_object( $checker ) ) {
+ return new WPSEO_Plugin_Availability();
+ }
+
+ return $checker;
+ }
+
+ /**
+ * Wraps the availability checker's get_installed_plugins method.
+ *
+ * @return array Array containing all the installed plugins.
+ */
+ public function get_installed_plugins() {
+ return $this->installed_plugins;
+ }
+
+ /**
+ * Creates a list of installed plugins and whether or not they are compatible.
+ *
+ * @return array Array containing the installed plugins and compatibility.
+ */
+ public function get_installed_plugins_compatibility() {
+ foreach ( $this->installed_plugins as $key => $plugin ) {
+
+ $this->installed_plugins[ $key ]['compatible'] = $this->is_compatible( $key );
+ }
+
+ return $this->installed_plugins;
+ }
+
+ /**
+ * Checks whether or not a plugin is compatible.
+ *
+ * @param string $plugin The plugin to look for and match.
+ *
+ * @return bool Whether or not the plugin is compatible.
+ */
+ public function is_compatible( $plugin ) {
+ $plugin = $this->availability_checker->get_plugin( $plugin );
+ $plugin_version = $this->availability_checker->get_version( $plugin );
+
+ return $this->get_major_minor_version( $plugin_version ) === $this->current_wpseo_version;
+ }
+
+ /**
+ * Gets the major/minor version of the plugin for easier comparing.
+ *
+ * @param string $version The version to trim.
+ *
+ * @return string The major/minor version of the plugin.
+ */
+ protected function get_major_minor_version( $version ) {
+ return substr( $version, 0, 3 );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/class-plugin-conflict.php b/wp-content/plugins/wordpress-seo/admin/class-plugin-conflict.php
new file mode 100644
index 0000000..bb0b751
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-plugin-conflict.php
@@ -0,0 +1,155 @@
+ array(
+ '2-click-socialmedia-buttons/2-click-socialmedia-buttons.php',
+ // 2 Click Social Media Buttons.
+ 'add-link-to-facebook/add-link-to-facebook.php', // Add Link to Facebook.
+ 'add-meta-tags/add-meta-tags.php', // Add Meta Tags.
+ 'easy-facebook-share-thumbnails/esft.php', // Easy Facebook Share Thumbnail.
+ 'facebook/facebook.php', // Facebook (official plugin).
+ 'facebook-awd/AWD_facebook.php', // Facebook AWD All in one.
+ 'facebook-featured-image-and-open-graph-meta-tags/fb-featured-image.php',
+ // Facebook Featured Image & OG Meta Tags.
+ 'facebook-meta-tags/facebook-metatags.php', // Facebook Meta Tags.
+ 'wonderm00ns-simple-facebook-open-graph-tags/wonderm00n-open-graph.php',
+ // Facebook Open Graph Meta Tags for WordPress.
+ 'facebook-revised-open-graph-meta-tag/index.php', // Facebook Revised Open Graph Meta Tag.
+ 'facebook-thumb-fixer/_facebook-thumb-fixer.php', // Facebook Thumb Fixer.
+ 'facebook-and-digg-thumbnail-generator/facebook-and-digg-thumbnail-generator.php',
+ // Fedmich's Facebook Open Graph Meta.
+ 'header-footer/plugin.php', // Header and Footer.
+ 'network-publisher/networkpub.php', // Network Publisher.
+ 'nextgen-facebook/nextgen-facebook.php', // NextGEN Facebook OG.
+ 'opengraph/opengraph.php', // Open Graph.
+ 'open-graph-protocol-framework/open-graph-protocol-framework.php',
+ // Open Graph Protocol Framework.
+ 'seo-facebook-comments/seofacebook.php', // SEO Facebook Comments.
+ 'seo-ultimate/seo-ultimate.php', // SEO Ultimate.
+ 'sexybookmarks/sexy-bookmarks.php', // Shareaholic.
+ 'shareaholic/sexy-bookmarks.php', // Shareaholic.
+ 'sharepress/sharepress.php', // SharePress.
+ 'simple-facebook-connect/sfc.php', // Simple Facebook Connect.
+ 'social-discussions/social-discussions.php', // Social Discussions.
+ 'social-sharing-toolkit/social_sharing_toolkit.php', // Social Sharing Toolkit.
+ 'socialize/socialize.php', // Socialize.
+ 'only-tweet-like-share-and-google-1/tweet-like-plusone.php',
+ // Tweet, Like, Google +1 and Share.
+ 'wordbooker/wordbooker.php', // Wordbooker.
+ 'wpsso/wpsso.php', // WordPress Social Sharing Optimization.
+ 'wp-caregiver/wp-caregiver.php', // WP Caregiver.
+ 'wp-facebook-like-send-open-graph-meta/wp-facebook-like-send-open-graph-meta.php',
+ // WP Facebook Like Send & Open Graph Meta.
+ 'wp-facebook-open-graph-protocol/wp-facebook-ogp.php', // WP Facebook Open Graph protocol.
+ 'wp-ogp/wp-ogp.php', // WP-OGP.
+ 'zoltonorg-social-plugin/zosp.php', // Zolton.org Social Plugin.
+ ),
+ 'xml_sitemaps' => array(
+ 'google-sitemap-plugin/google-sitemap-plugin.php',
+ // Google Sitemap (BestWebSoft).
+ 'xml-sitemaps/xml-sitemaps.php',
+ // XML Sitemaps (Denis de Bernardy and Mike Koepke).
+ 'bwp-google-xml-sitemaps/bwp-simple-gxs.php',
+ // Better WordPress Google XML Sitemaps (Khang Minh).
+ 'google-sitemap-generator/sitemap.php',
+ // Google XML Sitemaps (Arne Brachhold).
+ 'xml-sitemap-feed/xml-sitemap.php',
+ // XML Sitemap & Google News feeds (RavanH).
+ 'google-monthly-xml-sitemap/monthly-xml-sitemap.php',
+ // Google Monthly XML Sitemap (Andrea Pernici).
+ 'simple-google-sitemap-xml/simple-google-sitemap-xml.php',
+ // Simple Google Sitemap XML (iTx Technologies).
+ 'another-simple-xml-sitemap/another-simple-xml-sitemap.php',
+ // Another Simple XML Sitemap.
+ 'xml-maps/google-sitemap.php',
+ // Xml Sitemap (Jason Martens).
+ 'google-xml-sitemap-generator-by-anton-dachauer/adachauer-google-xml-sitemap.php',
+ // Google XML Sitemap Generator by Anton Dachauer (Anton Dachauer).
+ 'wp-xml-sitemap/wp-xml-sitemap.php',
+ // WP XML Sitemap (Team Vivacity).
+ 'sitemap-generator-for-webmasters/sitemap.php',
+ // Sitemap Generator for Webmasters (iwebslogtech).
+ 'xml-sitemap-xml-sitemapcouk/xmls.php',
+ // XML Sitemap - XML-Sitemap.co.uk (Simon Hancox).
+ 'sewn-in-xml-sitemap/sewn-xml-sitemap.php',
+ // Sewn In XML Sitemap (jcow).
+ 'rps-sitemap-generator/rps-sitemap-generator.php',
+ // RPS Sitemap Generator (redpixelstudios).
+ ),
+ );
+
+ /**
+ * Overrides instance to set with this class as class
+ *
+ * @param string $class_name Optional class name.
+ *
+ * @return Yoast_Plugin_Conflict
+ */
+ public static function get_instance( $class_name = __CLASS__ ) {
+ return parent::get_instance( $class_name );
+ }
+
+ /**
+ * After activating any plugin, this method will be executed by a hook.
+ *
+ * If the activated plugin is conflicting with ours a notice will be shown.
+ *
+ * @param string|bool $plugin Optional plugin basename to check.
+ */
+ public static function hook_check_for_plugin_conflicts( $plugin = false ) {
+
+ // The instance of itself.
+ $instance = self::get_instance();
+
+ // Only add plugin as active plugin if $plugin isn't false.
+ if ( $plugin && is_string( $plugin ) ) {
+ // Because it's just activated.
+ $instance->add_active_plugin( $instance->find_plugin_category( $plugin ), $plugin );
+ }
+
+ $plugin_sections = array();
+
+ // Only check for open graph problems when they are enabled.
+ $social_options = WPSEO_Options::get_option( 'wpseo_social' );
+ if ( $social_options['opengraph'] ) {
+ /* translators: %1$s expands to Yoast SEO, %2%s: 'Facebook' plugin name of possibly conflicting plugin with regard to creating OpenGraph output*/
+ $plugin_sections['open_graph'] = __( 'Both %1$s and %2$s create OpenGraph output, which might make Facebook, Twitter, LinkedIn and other social networks use the wrong texts and images when your pages are being shared.', 'wordpress-seo' )
+ . '
'
+ . ''
+ /* translators: %1$s expands to Yoast SEO */
+ . sprintf( __( 'Configure %1$s\'s OpenGraph settings', 'wordpress-seo' ), 'Yoast SEO' )
+ . '';
+ }
+
+ // Only check for XML conflicts if sitemaps are enabled.
+ $xml_sitemap_options = WPSEO_Options::get_option( 'wpseo_xml' );
+ if ( $xml_sitemap_options['enablexmlsitemap'] ) {
+ /* translators: %1$s expands to Yoast SEO, %2$s: 'Google XML Sitemaps' plugin name of possibly conflicting plugin with regard to the creation of sitemaps*/
+ $plugin_sections['xml_sitemaps'] = __( 'Both %1$s and %2$s can create XML sitemaps. Having two XML sitemaps is not beneficial for search engines, yet might slow down your site.', 'wordpress-seo' )
+ . '
'
+ . ''
+ /* translators: %1$s expands to Yoast SEO */
+ . sprintf( __( 'Configure %1$s\'s XML Sitemap settings', 'wordpress-seo' ), 'Yoast SEO' )
+ . '';
+ }
+
+ $instance->check_plugin_conflicts( $plugin_sections );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/class-premium-popup.php b/wp-content/plugins/wordpress-seo/admin/class-premium-popup.php
new file mode 100644
index 0000000..302e39e
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-premium-popup.php
@@ -0,0 +1,87 @@
+identifier = $identifier;
+ $this->heading_level = $heading_level;
+ $this->title = $title;
+ $this->content = $content;
+ }
+
+ /**
+ * Returns the premium popup as an HTML string.
+ *
+ * @param bool $popup Show this message as a popup show it straight away.
+ *
+ * @return string
+ */
+ public function get_premium_message( $popup = true ) {
+ // Don't show in Premium.
+ if ( defined( 'WPSEO_PREMIUM_FILE' ) ) {
+ return '';
+ }
+
+ $assets_uri = trailingslashit( plugin_dir_url( WPSEO_FILE ) );
+ $premium_uri = 'https://yoast.com/wordpress/plugins/seo-premium/#utm_source=wordpress-seo-metabox&utm_medium=popup&utm_campaign=help-center-contact-support';
+
+ /* translators: %s expands to Yoast SEO Premium */
+ $cta_text = sprintf( __( 'Buy %s', 'wordpress-seo' ), 'Yoast SEO Premium' );
+ $classes = '';
+ if ( $popup ) {
+ $classes = ' hidden';
+ }
+
+ $popup = <<
+
+ <{$this->heading_level} id="wpseo-contact-support-popup-title" class="wpseo-premium-popup-title">{$this->title}{$this->heading_level}>
+
{$this->content}
+ {$cta_text}
+
+EO_POPUP;
+
+ return $popup;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/class-primary-term-admin.php b/wp-content/plugins/wordpress-seo/admin/class-primary-term-admin.php
new file mode 100644
index 0000000..2d21231
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-primary-term-admin.php
@@ -0,0 +1,226 @@
+register_hooks();
+ }
+
+ /**
+ * Get the current post ID.
+ *
+ * @return integer The post ID.
+ */
+ protected function get_current_id() {
+ return filter_input( INPUT_GET, 'post', FILTER_SANITIZE_NUMBER_INT );
+ }
+
+ /**
+ * Add primary term templates
+ */
+ public function wp_footer() {
+ $taxonomies = $this->get_primary_term_taxonomies();
+
+ if ( ! empty( $taxonomies ) ) {
+ $this->include_js_templates();
+ }
+ }
+
+ /**
+ * Enqueues all the assets needed for the primary term interface
+ *
+ * @return void
+ */
+ public function enqueue_assets() {
+ global $pagenow;
+
+ if ( ! WPSEO_Metabox::is_post_edit( $pagenow ) ) {
+ return;
+ }
+
+ $taxonomies = $this->get_primary_term_taxonomies();
+
+ // Only enqueue if there are taxonomies that need a primary term.
+ if ( empty( $taxonomies ) ) {
+ return;
+ }
+
+ $asset_manager = new WPSEO_Admin_Asset_Manager();
+ $asset_manager->enqueue_style( 'primary-category' );
+ $asset_manager->enqueue_script( 'primary-category' );
+
+ $taxonomies = array_map( array( $this, 'map_taxonomies_for_js' ), $taxonomies );
+
+ $data = array(
+ 'taxonomies' => $taxonomies,
+ );
+ wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'primary-category', 'wpseoPrimaryCategoryL10n', $data );
+ }
+
+ /**
+ * Saves all selected primary terms
+ *
+ * @param int $post_ID Post ID to save primary terms for.
+ */
+ public function save_primary_terms( $post_ID ) {
+ // Bail if this is a multisite installation and the site has been switched.
+ if ( is_multisite() && ms_is_switched() ) {
+ return;
+ }
+
+ $taxonomies = $this->get_primary_term_taxonomies( $post_ID );
+
+ foreach ( $taxonomies as $taxonomy ) {
+ $this->save_primary_term( $post_ID, $taxonomy );
+ }
+ }
+
+ /**
+ * /**
+ * Get the id of the primary term
+ *
+ * @param string $taxonomy_name Taxonomy name for the term.
+ *
+ * @return int primary term id
+ */
+ protected function get_primary_term( $taxonomy_name ) {
+ $primary_term = new WPSEO_Primary_Term( $taxonomy_name, $this->get_current_id() );
+
+ return $primary_term->get_primary_term();
+ }
+
+ /**
+ * Returns all the taxonomies for which the primary term selection is enabled
+ *
+ * @param int $post_ID Default current post ID.
+ * @return array
+ */
+ protected function get_primary_term_taxonomies( $post_ID = null ) {
+
+ if ( null === $post_ID ) {
+ $post_ID = $this->get_current_id();
+ }
+
+ if ( false !== ( $taxonomies = wp_cache_get( 'primary_term_taxonomies_' . $post_ID, 'wpseo' ) ) ) {
+ return $taxonomies;
+ }
+
+ $taxonomies = $this->generate_primary_term_taxonomies( $post_ID );
+
+ wp_cache_set( 'primary_term_taxonomies_' . $post_ID, $taxonomies, 'wpseo' );
+
+ return $taxonomies;
+ }
+
+ /**
+ * Include templates file
+ */
+ protected function include_js_templates() {
+ include_once WPSEO_PATH . '/admin/views/js-templates-primary-term.php';
+ }
+
+ /**
+ * Save the primary term for a specific taxonomy
+ *
+ * @param int $post_ID Post ID to save primary term for.
+ * @param WP_Term $taxonomy Taxonomy to save primary term for.
+ */
+ protected function save_primary_term( $post_ID, $taxonomy ) {
+ $primary_term = filter_input( INPUT_POST, WPSEO_Meta::$form_prefix . 'primary_' . $taxonomy->name . '_term', FILTER_SANITIZE_NUMBER_INT );
+
+ // We accept an empty string here because we need to save that if no terms are selected.
+ if ( null !== $primary_term && check_admin_referer( 'save-primary-term', WPSEO_Meta::$form_prefix . 'primary_' . $taxonomy->name . '_nonce' ) ) {
+ $primary_term_object = new WPSEO_Primary_Term( $taxonomy->name, $post_ID );
+ $primary_term_object->set_primary_term( $primary_term );
+ }
+ }
+
+ /**
+ * Generate the primary term taxonomies.
+ *
+ * @param int $post_ID ID of the post.
+ *
+ * @return array
+ */
+ protected function generate_primary_term_taxonomies( $post_ID ) {
+ $post_type = get_post_type( $post_ID );
+ $all_taxonomies = get_object_taxonomies( $post_type, 'objects' );
+ $all_taxonomies = array_filter( $all_taxonomies, array( $this, 'filter_hierarchical_taxonomies' ) );
+
+ /**
+ * Filters which taxonomies for which the user can choose the primary term.
+ *
+ * @api array $taxonomies An array of taxonomy objects that are primary_term enabled.
+ *
+ * @param string $post_type The post type for which to filter the taxonomies.
+ * @param array $all_taxonomies All taxonomies for this post types, even ones that don't have primary term
+ * enabled.
+ */
+ $taxonomies = (array) apply_filters( 'wpseo_primary_term_taxonomies', $all_taxonomies, $post_type, $all_taxonomies );
+
+ return $taxonomies;
+ }
+
+ /**
+ * Returns an array suitable for use in the javascript
+ *
+ * @param stdClass $taxonomy The taxonomy to map.
+ *
+ * @return array
+ */
+ private function map_taxonomies_for_js( $taxonomy ) {
+ $primary_term = $this->get_primary_term( $taxonomy->name );
+
+ if ( empty( $primary_term ) ) {
+ $primary_term = '';
+ }
+
+ return array(
+ 'title' => $taxonomy->labels->singular_name,
+ 'name' => $taxonomy->name,
+ 'primary' => $primary_term,
+ 'terms' => array_map( array( $this, 'map_terms_for_js' ), get_terms( $taxonomy->name ) ),
+ );
+ }
+
+ /**
+ * Returns an array suitable for use in the javascript
+ *
+ * @param stdClass $term The term to map.
+ *
+ * @return array
+ */
+ private function map_terms_for_js( $term ) {
+ return array(
+ 'id' => $term->term_id,
+ 'name' => $term->name,
+ );
+ }
+
+ /**
+ * Returns whether or not a taxonomy is hierarchical
+ *
+ * @param stdClass $taxonomy Taxonomy object.
+ *
+ * @return bool
+ */
+ private function filter_hierarchical_taxonomies( $taxonomy ) {
+ return (bool) $taxonomy->hierarchical;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/class-product-upsell-notice.php b/wp-content/plugins/wordpress-seo/admin/class-product-upsell-notice.php
new file mode 100644
index 0000000..fe00692
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-product-upsell-notice.php
@@ -0,0 +1,201 @@
+options = $this->get_options();
+ }
+
+ /**
+ * Checks if the notice should be added or removed.
+ */
+ public function initialize() {
+ if ( $this->is_notice_dismissed() ) {
+ $this->remove_notification();
+
+ return;
+ }
+
+ if ( $this->should_add_notification() ) {
+ $this->add_notification();
+ }
+ }
+
+ /**
+ * Sets the upgrade notice.
+ */
+ public function set_upgrade_notice() {
+
+ if ( $this->has_first_activated_on() ) {
+ return;
+ }
+
+ $this->set_first_activated_on();
+ $this->add_notification();
+ }
+
+ /**
+ * Listener for the upsell notice.
+ */
+ public function dismiss_notice_listener() {
+ if ( filter_input( INPUT_GET, 'yoast_dismiss' ) !== 'upsell' ) {
+ return;
+ }
+
+ $this->dismiss_notice();
+
+ wp_redirect( admin_url( 'admin.php?page=wpseo_dashboard' ) );
+ exit;
+ }
+
+ /**
+ * When the notice should be shown.
+ *
+ * @return bool
+ */
+ protected function should_add_notification() {
+ return ( $this->options['first_activated_on'] < strtotime( '-2weeks' ) );
+ }
+
+ /**
+ * Checks if the options has a first activated on date value.
+ */
+ protected function has_first_activated_on() {
+ return $this->options['first_activated_on'] !== false;
+ }
+
+ /**
+ * Sets the first activated on.
+ */
+ protected function set_first_activated_on() {
+ $this->options['first_activated_on'] = strtotime( '-2weeks' );
+
+ $this->save_options();
+ }
+
+ /**
+ * Adds a notification to the notification center.
+ */
+ protected function add_notification() {
+ $notification_center = Yoast_Notification_Center::get();
+ $notification_center->add_notification( $this->get_notification() );
+ }
+
+ /**
+ * Adds a notification to the notification center.
+ */
+ protected function remove_notification() {
+ $notification_center = Yoast_Notification_Center::get();
+ $notification_center->remove_notification( $this->get_notification() );
+ }
+
+ /**
+ * Returns a premium upsell section if using the free plugin.
+ *
+ * @return string
+ */
+ protected function get_premium_upsell_section() {
+ $features = new WPSEO_Features();
+ if ( $features->is_free() ) {
+ /* translators: %1$s expands anchor to premium plugin page, %2$s expands to */
+ return sprintf(
+ __( 'By the way, did you know we also have a %1$sPremium plugin%2$s? It offers advanced features, like a redirect manager and support for multiple keywords. It also comes with 24/7 personal support.' , 'wordpress-seo' ),
+ "",
+ ''
+ );
+ }
+
+ return '';
+ }
+
+ /**
+ * Gets the notification value.
+ *
+ * @return Yoast_Notification
+ */
+ protected function get_notification() {
+ /* translators: %1$s expands to Yoast SEO, %2$s is a link start tag to the plugin page on WordPress.org, %3$s is the link closing tag. */
+ $message = sprintf(
+ __( 'We\'ve noticed you\'ve been using %1$s for some time now; we hope you love it! We\'d be thrilled if you could %2$sgive us a 5 stars rating on WordPress.org%3$s!', 'wordpress-seo' ),
+ 'Yoast SEO',
+ '',
+ ''
+ ) . "\n\n";
+
+ $message .= sprintf(
+ /* translators: %1$s is a link start tag to the bugreport guidelines on the Yoast knowledge base, %2$s is the link closing tag. */
+ __( 'If you are experiencing issues, %1$splease file a bug report%2$s and we\'ll do our best to help you out.', 'wordpress-seo' ),
+ '',
+ ''
+ ) . "\n\n";
+
+ $message .= $this->get_premium_upsell_section() . "\n\n";
+
+ $message .= sprintf(
+ /* translators: %1$s is the notification dismissal link start tag, %2$s is the link closing tag. */
+ __( '%1$sPlease don\'t show me this notification anymore%2$s', 'wordpress-seo' ),
+ '',
+ ''
+ );
+
+ $notification = new Yoast_Notification(
+ $message,
+ array(
+ 'type' => Yoast_Notification::WARNING,
+ 'id' => 'wpseo-upsell-notice',
+ 'capabilities' => 'manage_options',
+ 'priority' => 0.8,
+ )
+ );
+
+ return $notification;
+ }
+
+ /**
+ * Dismisses the notice.
+ *
+ * @return string
+ */
+ protected function is_notice_dismissed() {
+ return get_user_meta( get_current_user_id(), self::USER_META_DISMISSED, true ) === '1';
+ }
+
+ /**
+ * Dismisses the notice.
+ */
+ protected function dismiss_notice() {
+ update_user_meta( get_current_user_id(), self::USER_META_DISMISSED, true );
+ }
+
+ /**
+ * Returns the set options
+ *
+ * @return mixed|void
+ */
+ protected function get_options() {
+ return get_option( self::OPTION_NAME );
+ }
+
+ /**
+ * Saves the options to the database.
+ */
+ protected function save_options() {
+ update_option( self::OPTION_NAME, $this->options );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/class-recalculate-scores.php b/wp-content/plugins/wordpress-seo/admin/class-recalculate-scores.php
new file mode 100644
index 0000000..4e1a72f
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-recalculate-scores.php
@@ -0,0 +1,52 @@
+enqueue_script( 'recalculate' );
+ }
+
+ /**
+ * Initialize the modal box to be displayed when needed.
+ */
+ public function modal_box() {
+ // Adding the thickbox.
+ add_thickbox();
+
+ $progress = sprintf(
+ /* translators: 1: expands to a containing the number of posts recalculated. 2: expands to a containing the total number of posts. */
+ __( '%1$s of %2$s done.', 'wordpress-seo' ),
+ '0',
+ '0'
+ );
+
+ ?>
+
+
+
+
+
+
+ options = WPSEO_Options::get_option( 'wpseo_social' );
+ self::translate_meta_boxes();
+ add_filter( 'wpseo_save_metaboxes', array( $this, 'save_meta_boxes' ), 10, 1 );
+ add_action( 'wpseo_save_compare_data', array( $this, 'og_data_compare' ), 10, 1 );
+ }
+
+ /**
+ * Translate text strings for use in the meta box
+ *
+ * IMPORTANT: if you want to add a new string (option) somewhere, make sure you add that array key to
+ * the main meta box definition array in the class WPSEO_Meta() as well!!!!
+ */
+ public static function translate_meta_boxes() {
+ /* translators: %s expands to the social network's name */
+ $title_text = __( 'If you don\'t want to use the post title for sharing the post on %s but instead want another title there, write it here.', 'wordpress-seo' );
+ /* translators: %s expands to the social network's name */
+ $description_text = __( 'If you don\'t want to use the meta description for sharing the post on %s but want another description there, write it here.', 'wordpress-seo' );
+ /* translators: %s expands to the social network's name */
+ $image_text = __( 'If you want to override the image used on %s for this post, upload / choose an image or add the URL here.', 'wordpress-seo' );
+ /* translators: %1$s expands to the social network, %2$s to the recommended image size */
+ $image_size_text = __( 'The recommended image size for %1$s is %2$s pixels.', 'wordpress-seo' );
+
+ $options = WPSEO_Options::get_option( 'wpseo_social' );
+
+ $social_networks = array(
+ 'opengraph' => __( 'Facebook', 'wordpress-seo' ),
+ 'twitter' => __( 'Twitter', 'wordpress-seo' ),
+ );
+
+ // Source: https://blog.bufferapp.com/ideal-image-sizes-social-media-posts.
+ $recommended_image_sizes = array(
+ /* translators: %1$s expands to the image recommended width, %2$s to its height. */
+ 'opengraph' => sprintf( __( '%1$s by %2$s', 'wordpress-seo' ), '1200', '630' ), // Source: https://developers.facebook.com/docs/sharing/best-practices#images.
+ /* translators: %1$s expands to the image recommended width, %2$s to its height. */
+ 'twitter' => sprintf( __( '%1$s by %2$s', 'wordpress-seo' ), '1024', '512' ),
+ );
+
+ foreach ( $social_networks as $network => $label ) {
+ if ( true === $options[ $network ] ) {
+
+ self::$meta_fields['social'][ $network . '-title' ]['title'] = sprintf( __( '%s Title', 'wordpress-seo' ), $label );
+ self::$meta_fields['social'][ $network . '-title' ]['description'] = sprintf( $title_text, $label );
+
+ self::$meta_fields['social'][ $network . '-description' ]['title'] = sprintf( __( '%s Description', 'wordpress-seo' ), $label );
+ self::$meta_fields['social'][ $network . '-description' ]['description'] = sprintf( $description_text, $label );
+
+ self::$meta_fields['social'][ $network . '-image' ]['title'] = sprintf( __( '%s Image', 'wordpress-seo' ), $label );
+ self::$meta_fields['social'][ $network . '-image' ]['description'] = sprintf( $image_text, $label ) . ' ' . sprintf( $image_size_text, $label, $recommended_image_sizes[ $network ] );
+ }
+ }
+ }
+
+ /**
+ * Returns the metabox section for the social settings.
+ *
+ * @return WPSEO_Metabox_Tab_Section
+ */
+ public function get_meta_section() {
+ $tabs = array();
+ $social_meta_fields = $this->get_meta_field_defs( 'social' );
+ $single = true;
+
+ if ( $this->options['opengraph'] === true && $this->options['twitter'] === true ) {
+ $single = null;
+ }
+
+ if ( $this->options['opengraph'] === true ) {
+ $tabs[] = new WPSEO_Metabox_Form_Tab(
+ 'facebook',
+ $this->get_social_tab_content( 'opengraph', $social_meta_fields ),
+ '' . __( 'Facebook / Open Graph metadata', 'wordpress-seo' ) . '',
+ array(
+ 'link_aria_label' => __( 'Facebook / Open Graph metadata', 'wordpress-seo' ),
+ 'link_class' => 'yoast-tooltip yoast-tooltip-se',
+ 'single' => $single,
+ )
+ );
+ }
+
+ if ( $this->options['twitter'] === true ) {
+ $tabs[] = new WPSEO_Metabox_Form_Tab(
+ 'twitter',
+ $this->get_social_tab_content( 'twitter', $social_meta_fields ),
+ '' . __( 'Twitter metadata', 'wordpress-seo' ) . '',
+ array(
+ 'link_aria_label' => __( 'Twitter metadata', 'wordpress-seo' ),
+ 'link_class' => 'yoast-tooltip yoast-tooltip-se',
+ 'single' => $single,
+ )
+ );
+ }
+
+ return new WPSEO_Metabox_Tab_Section(
+ 'social',
+ '' . __( 'Social', 'wordpress-seo' ) . '',
+ $tabs,
+ array(
+ 'link_aria_label' => __( 'Social', 'wordpress-seo' ),
+ 'link_class' => 'yoast-tooltip yoast-tooltip-e',
+ )
+ );
+ }
+
+ /**
+ * Generates the html for a social settings tab for one of the supported social media.
+ *
+ * @param string $medium can be 'opengraph' or 'twitter'.
+ * @param array $meta_field_defs The social meta field definitions.
+ *
+ * @return string
+ */
+ private function get_social_tab_content( $medium, $meta_field_defs ) {
+ $field_names = array(
+ $medium . '-title',
+ $medium . '-description',
+ $medium . '-image',
+ );
+
+ $tab_content = '';
+
+ foreach ( $field_names as $field_name ) {
+ $tab_content .= $this->do_meta_box( $meta_field_defs[ $field_name ], $field_name );
+ }
+
+ return $tab_content;
+ }
+
+ /**
+ * Filter over the meta boxes to save, this function adds the Social meta boxes.
+ *
+ * @param array $field_defs Array of metaboxes to save.
+ *
+ * @return array
+ */
+ public function save_meta_boxes( $field_defs ) {
+ return array_merge( $field_defs, $this->get_meta_field_defs( 'social' ) );
+ }
+
+ /**
+ * This method will compare opengraph fields with the posted values.
+ *
+ * When fields are changed, the facebook cache will be purge.
+ *
+ * @param WP_Post $post Post instance.
+ */
+ public function og_data_compare( $post ) {
+
+ // Check if post data is available, if post_id is set and if original post_status is publish.
+ if (
+ ! empty( $_POST ) && ! empty( $post->ID ) && $post->post_status == 'publish' &&
+ isset( $_POST['original_post_status'] ) && $_POST['original_post_status'] === 'publish'
+ ) {
+
+ $fields_to_compare = array(
+ 'opengraph-title',
+ 'opengraph-description',
+ 'opengraph-image',
+ );
+
+ $reset_facebook_cache = false;
+
+ foreach ( $fields_to_compare as $field_to_compare ) {
+ $old_value = self::get_value( $field_to_compare, $post->ID );
+ $new_value = self::get_post_value( self::$form_prefix . $field_to_compare );
+
+ if ( $old_value !== $new_value ) {
+ $reset_facebook_cache = true;
+ break;
+ }
+ }
+ unset( $field_to_compare, $old_value, $new_value );
+
+ if ( $reset_facebook_cache ) {
+ wp_remote_get(
+ 'https://graph.facebook.com/?id=' . get_permalink( $post->ID ) . '&scrape=true&method=post'
+ );
+ }
+ }
+ }
+
+
+ /********************** DEPRECATED METHODS **********************/
+
+ /**
+ * Define the meta boxes for the Social tab
+ *
+ * @deprecated 1.5.0
+ * @deprecated use WPSEO_Meta::get_meta_field_defs()
+ * @see WPSEO_Meta::get_meta_field_defs()
+ *
+ * @param string $post_type Optional post type string.
+ *
+ * @return array Array containing the meta boxes
+ */
+ public function get_meta_boxes( $post_type = 'post' ) {
+ _deprecated_function( __METHOD__, 'WPSEO 1.5.0', 'WPSEO_Meta::get_meta_field_defs()' );
+
+ return $this->get_meta_field_defs( 'social' );
+ }
+
+ /**
+ * @deprecated 3.0 Removed.
+ *
+ * @return string
+ */
+ public function tab_header() {
+ _deprecated_function( 'WPSEO_Social_Admin::tab_header', 'WPSEO 3.0' );
+
+ return '';
+ }
+
+ /**
+ * @deprecated 3.0 Removed.
+ *
+ * @return string
+ */
+ public function tab_content() {
+ _deprecated_function( 'WPSEO_Social_Admin::tab_content', 'WPSEO 3.0' );
+
+ return '';
+ }
+} /* End of class */
diff --git a/wp-content/plugins/wordpress-seo/admin/class-social-facebook.php b/wp-content/plugins/wordpress-seo/admin/class-social-facebook.php
new file mode 100644
index 0000000..84748a4
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-social-facebook.php
@@ -0,0 +1,480 @@
+options = get_option( 'wpseo_social' );
+
+ $this->get_listener();
+
+ $this->form = new Yoast_Social_Facebook_Form();
+ }
+
+ /**
+ * Returns the output from the form class
+ */
+ public function show_form() {
+ $this->form->show_form();
+ }
+
+ /**
+ * Adding a new admin
+ *
+ * @param string $admin_name Name string.
+ * @param string $admin_id ID string.
+ *
+ * @return string
+ */
+ public function add_admin( $admin_name, $admin_id ) {
+ $success = 0;
+
+ // If one of the fields is empty.
+ if ( empty( $admin_name ) || empty( $admin_id ) ) {
+ $response_body = $this->get_response_body( 'not_present' );
+ }
+ else {
+ $admin_id = $this->parse_admin_id( $admin_id );
+
+ if ( ! isset( $this->options['fb_admins'][ $admin_id ] ) ) {
+ $name = sanitize_text_field( urldecode( $admin_name ) );
+ $admin_id = sanitize_text_field( $admin_id );
+
+ if ( preg_match( '/[0-9]+?/', $admin_id ) && preg_match( '/[\w\s]+?/', $name ) ) {
+ $this->options['fb_admins'][ $admin_id ]['name'] = $name;
+ $this->options['fb_admins'][ $admin_id ]['link'] = urldecode( 'http://www.facebook.com/' . $admin_id );
+
+ $this->save_options();
+
+ $success = 1;
+ $response_body = $this->form->get_admin_link( $admin_id, $this->options['fb_admins'][ $admin_id ] );
+ }
+ else {
+ $response_body = $this->get_response_body( 'invalid_format' );
+ }
+ }
+ else {
+ $response_body = $this->get_response_body( 'already_exists' );
+ }
+ }
+
+ return wp_json_encode(
+ array(
+ 'success' => $success,
+ 'html' => $response_body,
+ )
+ );
+ }
+
+ /**
+ * Fetches the id if the full meta tag or a full url was given
+ *
+ * @param string $admin_id Admin ID input string to process.
+ *
+ * @return string
+ */
+ private function parse_admin_id( $admin_id ) {
+ if ( preg_match( '/^\" . __( 'Please make sure both fields are filled.', 'wordpress-seo' ) . '';
+ break;
+ case 'invalid_format':
+ $return = "
" . __( 'Your input contains invalid characters. Please make sure both fields are filled in correctly.', 'wordpress-seo' ) . '
';
+ break;
+ case 'already_exists':
+ $return = "
" . __( 'This Facebook user has already been added as an admin.', 'wordpress-seo' ) . '
';
+ break;
+ default:
+ $return = '';
+ break;
+ }
+
+ return $return;
+ }
+
+ /**
+ * This method will hook into the defined get params
+ */
+ private function get_listener() {
+ if ( $delfbadmin = filter_input( INPUT_GET, 'delfbadmin' ) ) {
+ $this->delete_admin( $delfbadmin );
+ }
+ elseif ( filter_input( INPUT_GET, 'fbclearall' ) ) {
+ $this->clear_all();
+ }
+ }
+
+ /**
+ * Deletes the admin from the options
+ *
+ * @param string $delfbadmin Facebook admin ID.
+ */
+ private function delete_admin( $delfbadmin ) {
+ $this->verify_nonce( 'delfbadmin' );
+
+ $admin_id = sanitize_text_field( $delfbadmin );
+ if ( isset( $this->options['fb_admins'][ $admin_id ] ) ) {
+ $fbadmin = $this->options['fb_admins'][ $admin_id ]['name'];
+ unset( $this->options['fb_admins'][ $admin_id ] );
+
+ $this->save_options();
+ $this->success_notice( sprintf( __( 'Successfully removed admin %s', 'wordpress-seo' ), $fbadmin ) );
+
+ unset( $fbadmin );
+ }
+
+ unset( $admin_id );
+
+ // Clean up the referrer url for later use.
+ if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
+ $this->cleanup_referrer_url( 'nonce', 'delfbadmin' );
+ }
+ }
+
+ /**
+ * Clear all the facebook that has been set already
+ */
+ private function clear_all() {
+ $this->verify_nonce( 'fbclearall' );
+
+ // Reset to defaults, don't unset as otherwise the old values will be retained.
+ $this->options['fb_admins'] = WPSEO_Options::get_default( 'wpseo_social', 'fb_admins' );
+
+ $this->save_options();
+ $this->success_notice( __( 'Successfully cleared all Facebook Data', 'wordpress-seo' ) );
+
+ // Clean up the referrer url for later use.
+ if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
+ $this->cleanup_referrer_url( 'nonce', 'fbclearall' );
+ }
+ }
+
+ /**
+ * Clean up the request_uri. The given params are the params that will be removed from the URL
+ */
+ private function cleanup_referrer_url() {
+ $_SERVER['REQUEST_URI'] = remove_query_arg(
+ func_get_args(),
+ sanitize_text_field( $_SERVER['REQUEST_URI'] )
+ );
+ }
+
+ /**
+ * When something is going well, show a success notice
+ *
+ * @param string $notice_text Message string.
+ */
+ private function success_notice( $notice_text ) {
+ add_settings_error( 'yoast_wpseo_social_options', 'success', $notice_text, 'updated' );
+ }
+
+ /**
+ * Verify the nonce from the URL with the saved nonce
+ *
+ * @param string $nonce_name Nonce name string.
+ */
+ private function verify_nonce( $nonce_name ) {
+ if ( wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ), $nonce_name ) != 1 ) {
+ die( "I don't think that's really nice of you!." );
+ }
+ }
+
+ /**
+ * Saving the options
+ */
+ private function save_options() {
+ update_option( 'wpseo_social', $this->options );
+ }
+}
+
+/**
+ * This will display the HTML for the facebook insights part
+ */
+class Yoast_Social_Facebook_Form {
+
+ /**
+ * @var array - The options for social
+ */
+ private $options;
+
+ /**
+ * @var array - The repository for the buttons that will be shown
+ */
+ private $buttons = array();
+
+ /**
+ * @var string - The URL to link to
+ */
+ private $admin_url = 'admin.php?page=wpseo_social';
+
+ /**
+ * Setting the options and call the methods to display everything
+ */
+ public function __construct() {
+ $this->options = get_option( 'wpseo_social' );
+ }
+
+ /**
+ * Returns the output-property
+ */
+ public function show_form() {
+ $this
+ ->form_head()
+ ->manage_user_admin()
+ ->form_thickbox()
+ ->show_buttons()
+ ->manage_app_as_admin();
+ }
+
+ /**
+ * Parses the admin_link
+ *
+ * @param string $admin_id Facebook admin ID string.
+ * @param array $admin Admin data array.
+ * @param string|bool $nonce Optional nonce string.
+ *
+ * @return string
+ */
+ public function get_admin_link( $admin_id, $admin, $nonce = false ) {
+ if ( $nonce === false ) {
+ $nonce = $this->get_delete_nonce();
+ }
+
+ $return = '
';
+
+ return $return;
+ }
+
+ /**
+ * SHow the top of the social insights part of the page
+ *
+ * @return $this
+ */
+ private function form_head() {
+ echo '
', sprintf(
+ /* translators: %1$s and %2$s expand to a link to Facebook Insights */
+ esc_html__( 'To be able to access %1$sFacebook Insights%2$s for your site, you need to specify a Facebook Admin. This can be a user. If you have an app for your site, you could use that as well.', 'wordpress-seo' ),
+ '',
+ ''
+ );
+ echo ' ';
+ /* translators: %1$s and %2$s expand to a link to the Yoast Knowledge Base */
+ printf( __( 'More info can be found %1$son our knowledge base%2$s.', 'wordpress-seo' ), '', '' );
+ echo '
';
+
+ return $this;
+ }
+
+ /**
+ * Show the form inside the thickbox
+ */
+ private function form_thickbox() {
+ // Adding the thickbox.
+ add_thickbox();
+
+ echo '
';
+ echo "
";
+ echo '
';
+ /* translators: %1$s and %2$s expand to a link to Facebook Insights */
+ printf( __( 'To be able to access %1$sFacebook Insights%2$s, you need to add a user here. The name is used for reference only, the ID is used for verification.', 'wordpress-seo' ), '', '' );
+ echo '
';
+ echo '
';
+ /* translators: %1$s and %2$s expand to a link to the Yoast Knowledge Base */
+ printf( __( 'If you don\'t know where to find the needed ID, see %1$sthis knowledge base article%2$s.', 'wordpress-seo' ), '', '' );
+ echo '
';
+ echo '
';
+ echo '';
+ echo '';
+ echo '
';
+ echo '
';
+ echo '';
+ echo '';
+ echo '
';
+ echo "
";
+ echo '';
+ echo '';
+ echo '
';
+ echo '
';
+ echo '
';
+
+ return $this;
+ }
+
+ /**
+ * Display the buttons to add an admin or add another admin from Facebook and display the admin that has been added already.
+ *
+ * @return $this
+ */
+ private function manage_user_admin() {
+ $button_text = __( 'Add Facebook admin', 'wordpress-seo' );
+ $nonce = false;
+ $class_attr = ' class="hidden"';
+
+ if ( is_array( $this->options['fb_admins'] ) && $this->options['fb_admins'] !== array() ) {
+ $nonce = $this->get_delete_nonce();
+ $button_text = __( 'Add Another Facebook Admin', 'wordpress-seo' );
+ $class_attr = '';
+ }
+
+ echo "
';
+ }
+
+ /**
+ * Generates the sidebar for admin pages.
+ */
+ public function admin_sidebar() {
+
+ // No banners in Premium.
+ if ( class_exists( 'WPSEO_Product_Premium' ) ) {
+ $license_manager = new Yoast_Plugin_License_Manager( new WPSEO_Product_Premium() );
+ if ( $license_manager->license_is_valid() ) {
+ return;
+ }
+ }
+
+ $sidebar_renderer = new WPSEO_Admin_Banner_Sidebar_Renderer( new WPSEO_Admin_Banner_Spot_Renderer() );
+
+ $banner_renderer = new WPSEO_Admin_Banner_Renderer;
+ $banner_renderer->set_base_path( plugins_url( 'images/banner/', WPSEO_FILE ) );
+
+ $sidebar = new WPSEO_Admin_Banner_Sidebar( sprintf( '%1s recommendations', 'Yoast' ), $banner_renderer );
+ $sidebar->initialize( new WPSEO_Features() );
+
+ echo $sidebar_renderer->render( $sidebar );
+
+ }
+
+ /**
+ * Output a label element
+ *
+ * @param string $text Label text string.
+ * @param array $attr HTML attributes set.
+ */
+ public function label( $text, $attr ) {
+ $attr = wp_parse_args( $attr, array(
+ 'class' => 'checkbox',
+ 'close' => true,
+ 'for' => '',
+ )
+ );
+ echo "';
+ }
+ }
+
+ /**
+ * Output a legend element.
+ *
+ * @param string $text Legend text string.
+ * @param array $attr HTML attributes set.
+ */
+ public function legend( $text, $attr ) {
+ $attr = wp_parse_args( $attr, array(
+ 'id' => '',
+ 'class' => '',
+ )
+ );
+ $id = ( '' === $attr['id'] ) ? '' : ' id="' . esc_attr( $attr['id'] ) . '"';
+ echo '';
+ }
+
+ /**
+ * Create a Checkbox input field.
+ *
+ * @param string $var The variable within the option to create the checkbox for.
+ * @param string $label The label to show for the variable.
+ * @param bool $label_left Whether the label should be left (true) or right (false).
+ */
+ public function checkbox( $var, $label, $label_left = false ) {
+ if ( ! isset( $this->options[ $var ] ) ) {
+ $this->options[ $var ] = false;
+ }
+
+ if ( $this->options[ $var ] === true ) {
+ $this->options[ $var ] = 'on';
+ }
+
+ $class = '';
+ if ( $label_left !== false ) {
+ if ( ! empty( $label_left ) ) {
+ $label_left .= ':';
+ }
+ $this->label( $label_left, array( 'for' => $var ) );
+ }
+ else {
+ $class = 'double';
+ }
+
+ echo 'options[ $var ], 'on', false ), '/>';
+
+ if ( ! empty( $label ) ) {
+ $this->label( $label, array( 'for' => $var ) );
+ }
+
+ echo ' ';
+ }
+
+ /**
+ * Create a light switch input field.
+ *
+ * @param string $var The variable within the option to create the checkbox for.
+ * @param string $label The label to show for the variable.
+ * @param array $buttons Array of two labels for the buttons (defaults Off/On).
+ * @param boolean $reverse Reverse order of buttons (default true).
+ */
+ public function light_switch( $var, $label, $buttons = array(), $reverse = true ) {
+
+ if ( ! isset( $this->options[ $var ] ) ) {
+ $this->options[ $var ] = false;
+ }
+
+ if ( $this->options[ $var ] === true ) {
+ $this->options[ $var ] = 'on';
+ }
+
+ $class = 'switch-light switch-candy switch-yoast-seo';
+ $aria_labelledby = esc_attr( $var ) . '-label';
+
+ if ( $reverse ) {
+ $class .= ' switch-yoast-seo-reverse';
+ }
+
+ if ( empty( $buttons ) ) {
+ $buttons = array( __( 'Disabled', 'wordpress-seo' ), __( 'Enabled', 'wordpress-seo' ) );
+ }
+
+ list( $off_button, $on_button ) = $buttons;
+
+ echo '
',
+ '
';
+ }
+
+ /**
+ * Create a Text input field.
+ *
+ * @param string $var The variable within the option to create the text input field for.
+ * @param string $label The label to show for the variable.
+ * @param array|string $attr Extra class to add to the input field.
+ */
+ public function textinput( $var, $label, $attr = array() ) {
+ if ( ! is_array( $attr ) ) {
+ $attr = array(
+ 'class' => $attr,
+ );
+ }
+ $attr = wp_parse_args( $attr, array(
+ 'placeholder' => '',
+ 'class' => '',
+ ) );
+ $val = ( isset( $this->options[ $var ] ) ) ? $this->options[ $var ] : '';
+
+ $this->label( $label . ':', array( 'for' => $var ) );
+ echo '', ' ';
+ }
+
+ /**
+ * Create a textarea.
+ *
+ * @param string $var The variable within the option to create the textarea for.
+ * @param string $label The label to show for the variable.
+ * @param array $attr The CSS class to assign to the textarea.
+ */
+ public function textarea( $var, $label, $attr = array() ) {
+ if ( ! is_array( $attr ) ) {
+ $attr = array(
+ 'class' => $attr,
+ );
+ }
+ $attr = wp_parse_args( $attr, array(
+ 'cols' => '',
+ 'rows' => '',
+ 'class' => '',
+ ) );
+ $val = ( isset( $this->options[ $var ] ) ) ? $this->options[ $var ] : '';
+
+ $this->label( $label . ':', array( 'for' => $var, 'class' => 'textinput' ) );
+ echo '' . ' ';
+ }
+
+ /**
+ * Create a hidden input field.
+ *
+ * @param string $var The variable within the option to create the hidden input for.
+ * @param string $id The ID of the element.
+ */
+ public function hidden( $var, $id = '' ) {
+ $val = ( isset( $this->options[ $var ] ) ) ? $this->options[ $var ] : '';
+ if ( is_bool( $val ) ) {
+ $val = ( $val === true ) ? 'true' : 'false';
+ }
+
+ if ( '' === $id ) {
+ $id = 'hidden_' . $var;
+ }
+
+ echo '';
+ }
+
+ /**
+ * Create a Select Box.
+ *
+ * @param string $field_name The variable within the option to create the select for.
+ * @param string $label The label to show for the variable.
+ * @param array $select_options The select options to choose from.
+ */
+ public function select( $field_name, $label, array $select_options ) {
+
+ if ( empty( $select_options ) ) {
+ return;
+ }
+
+ $this->label( $label . ':', array( 'for' => $field_name, 'class' => 'select' ) );
+
+ $select_name = esc_attr( $this->option_name ) . '[' . esc_attr( $field_name ) . ']';
+ $active_option = ( isset( $this->options[ $field_name ] ) ) ? $this->options[ $field_name ] : '';
+
+ $select = new Yoast_Input_Select( $field_name, $select_name, $select_options, $active_option );
+ $select->add_attribute( 'class', 'select' );
+ $select->output_html();
+
+ echo ' ';
+ }
+
+ /**
+ * Create a File upload field.
+ *
+ * @param string $var The variable within the option to create the file upload field for.
+ * @param string $label The label to show for the variable.
+ */
+ public function file_upload( $var, $label ) {
+ $val = '';
+ if ( isset( $this->options[ $var ] ) && is_array( $this->options[ $var ] ) ) {
+ $val = $this->options[ $var ]['url'];
+ }
+
+ $var_esc = esc_attr( $var );
+ $this->label( $label . ':', array( 'for' => $var, 'class' => 'select' ) );
+ echo '';
+
+ // Need to save separate array items in hidden inputs, because empty file inputs type will be deleted by settings API.
+ if ( ! empty( $this->options[ $var ] ) ) {
+ $this->hidden( 'file', $this->option_name . '_file' );
+ $this->hidden( 'url', $this->option_name . '_url' );
+ $this->hidden( 'type', $this->option_name . '_type' );
+ }
+ echo ' ';
+ }
+
+ /**
+ * Media input
+ *
+ * @param string $var Option name.
+ * @param string $label Label message.
+ */
+ public function media_input( $var, $label ) {
+ $val = '';
+ if ( isset( $this->options[ $var ] ) ) {
+ $val = $this->options[ $var ];
+ }
+
+ $var_esc = esc_attr( $var );
+
+ $this->label( $label . ':', array( 'for' => 'wpseo_' . $var, 'class' => 'select' ) );
+ echo '';
+ echo '';
+ echo ' ';
+ }
+
+ /**
+ * Create a Radio input field.
+ *
+ * @param string $var The variable within the option to create the radio button for.
+ * @param array $values The radio options to choose from.
+ * @param string $legend Optional. The legend to show for the field set, if any.
+ * @param array $legend_attr Optional. The attributes for the legend, if any.
+ */
+ public function radio( $var, $values, $legend = '', $legend_attr = array() ) {
+ if ( ! is_array( $values ) || $values === array() ) {
+ return;
+ }
+ if ( ! isset( $this->options[ $var ] ) ) {
+ $this->options[ $var ] = false;
+ }
+
+ $var_esc = esc_attr( $var );
+
+ echo '';
+ }
+
+
+ /**
+ * Create a toggle switch input field.
+ *
+ * @param string $var The variable within the option to create the file upload field for.
+ * @param array $values The radio options to choose from.
+ * @param string $label The label to show for the variable.
+ */
+ public function toggle_switch( $var, $values, $label ) {
+ if ( ! is_array( $values ) || $values === array() ) {
+ return;
+ }
+ if ( ! isset( $this->options[ $var ] ) ) {
+ $this->options[ $var ] = false;
+ }
+ if ( $this->options[ $var ] === true ) {
+ $this->options[ $var ] = 'on';
+ }
+ if ( $this->options[ $var ] === false ) {
+ $this->options[ $var ] = 'off';
+ }
+
+ $var_esc = esc_attr( $var );
+
+ echo '
';
+ echo '
' . "\n\n";
+ }
+
+ /**
+ * Returns two random selected service banners.
+ *
+ * @return WPSEO_Admin_Banner_Spot
+ */
+ private function get_service_banners() {
+
+ $service_banner_spot = new WPSEO_Admin_Banner_Spot(
+ __( 'Services', 'wordpress-seo' ),
+ sprintf(
+ /* translators: %1$s expands to a link start tag to the Yoast Services page, %2$s to Yoast, %3$s is the link closing tag. */
+ __( 'Don\'t want to dive into SEO yourself? %1$sLet team %2$s help you!%3$s', 'wordpress-seo' ),
+ '',
+ 'Yoast',
+ ''
+ )
+ );
+
+ $service_banner_spot->add_banner(
+ new WPSEO_Admin_Banner(
+ 'https://yoast.com/hire-us/website-review/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=website-review-banner',
+ 'banner-website-review.png',
+ 261,
+ 190,
+ __( 'Order a Website Review and we will tell you what to improve to attract more visitors!', 'wordpress-seo' )
+ )
+ );
+
+ $service_banner_spot->add_banner(
+ new WPSEO_Admin_Banner(
+ 'https://yoast.com/hire-us/yoast-seo-configuration/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=configuration-service-banner',
+ 'banner-configuration-service.png',
+ 261,
+ 190,
+ sprintf(
+ /* translators: %1$s expands to Yoast SEO Premium. */
+ __( 'Let our experts set up your %1$s plugin!', 'wordpress-seo' ),
+ 'Yoast SEO Premium'
+ )
+ )
+ );
+
+ $service_banner_spot->add_banner(
+ new WPSEO_Admin_Banner(
+ 'https://yoast.com/academy/course/seo-copywriting-training/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=seo-copywriting-training-banner',
+ 'banner-seo-copywriting-training.png',
+ 261,
+ 190,
+ __( 'Take the online SEO Copywriting Training course and learn how to write awesome copy that ranks!', 'wordpress-seo' )
+ )
+ );
+
+ $service_banner_spot->add_banner(
+ new WPSEO_Admin_Banner(
+ 'https://yoast.com/academy/course/basic-seo-training/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=basic-seo-training-banner',
+ 'banner-basic-seo-training.png',
+ 261,
+ 190,
+ __( 'Take the online Basic SEO Training course and learn the fundamentals of SEO!', 'wordpress-seo' )
+ )
+ );
+
+ $service_banner_spot->add_banner(
+ new WPSEO_Admin_Banner(
+ 'https://yoast.com/academy/course/yoast-seo-wordpress-training/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=yoast-seo-plugin-training-banner',
+ 'banner-yoast-seo-for-wordpress-training.png',
+ 261,
+ 190,
+ /* translators: %1$s expands to Yoast SEO for WordPress Training, %2$s to Yoast SEO for WordPress. */
+ sprintf(
+ __( 'Take the %s course and become a certified %2$s expert!', 'wordpress-seo' ),
+ 'Yoast SEO for WordPress Training',
+ 'Yoast SEO for WordPress'
+ )
+ )
+ );
+
+ return $service_banner_spot;
+ }
+
+ /**
+ * Returns two random selected plugin banners.
+ *
+ * @return WPSEO_Admin_Banner_Spot
+ */
+ private function get_plugin_banners() {
+
+ $plugin_banners = new WPSEO_Admin_Banner_Spot(
+ __( 'Extensions', 'wordpress-seo' ),
+ sprintf(
+ /* translators: %1$s expands to Yoast SEO, %2$s to a link start tag to the Yoast plugin page, %3$s is the link closing tag. */
+ __( 'Extend your %1$s plugin with our %2$sSEO plugins%3$s.', 'wordpress-seo' ),
+ 'Yoast SEO',
+ '',
+ ''
+ )
+ );
+
+
+ $plugin_banners->add_banner(
+ new WPSEO_Admin_Banner(
+ 'https://yoast.com/wordpress/plugins/seo-premium/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=premium-seo-banner',
+ 'banner-premium-seo.png',
+ 261,
+ 152,
+ sprintf(
+ /* translators: %1$s expands to Yoast SEO Premium. */
+ __( 'Buy the %1$s plugin now and get access to extra features and 24/7 support!', 'wordpress-seo' ),
+ 'Yoast SEO Premium'
+ )
+ )
+ );
+
+ if ( ! class_exists( 'wpseo_Video_Sitemap' ) ) {
+ $plugin_banners->add_banner(
+ new WPSEO_Admin_Banner(
+ 'https://yoast.com/wordpress/plugins/video-seo/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=video-seo-banner',
+ 'banner-video-seo.png',
+ 261,
+ 152,
+ sprintf(
+ /* translators: %1$s expands to Yoast Video SEO. */
+ __( 'Buy the %1$s plugin now and optimize your videos for video search results and social media!', 'wordpress-seo' ),
+ 'Yoast Video SEO'
+ )
+ )
+ );
+ }
+
+ if ( class_exists( 'Woocommerce' ) && ! class_exists( 'Yoast_WooCommerce_SEO' ) ) {
+ $plugin_banners->add_banner(
+ new WPSEO_Admin_Banner(
+ 'https://yoast.com/wordpress/plugins/yoast-woocommerce-seo/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=woocommerce-seo-banner',
+ 'banner-woocommerce-seo.png',
+ 261,
+ 152,
+ sprintf(
+ /* translators: %1$s expands to Yoast WooCommerce SEO. */
+ __( 'Buy the %1$s plugin now and optimize your shop today to improve your product promotion!', 'wordpress-seo' ),
+ 'Yoast WooCommerce SEO'
+ )
+ )
+ );
+ }
+
+ if ( ! defined( 'WPSEO_LOCAL_VERSION' ) ) {
+ $plugin_banners->add_banner(
+ new WPSEO_Admin_Banner(
+ 'https://yoast.com/wordpress/plugins/local-seo/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=local-seo-banner',
+ 'banner-local-seo.png',
+ 261,
+ 152,
+ sprintf(
+ /* translators: %1$s expands to Yoast Local SEO. */
+ __( 'Buy the %1$s plugin now to improve your site’s Local SEO and ranking in Google Maps!', 'wordpress-seo' ),
+ 'Yoast Local SEO'
+ )
+ )
+ );
+ }
+
+ if ( ! class_exists( 'WPSEO_News' ) ) {
+ $plugin_banners->add_banner(
+ new WPSEO_Admin_Banner(
+ 'https://yoast.com/wordpress/plugins/news-seo/#utm_source=wordpress-seo-config&utm_medium=banner&utm_campaign=news-seo-banner',
+ 'banner-news-seo.png',
+ 261,
+ 152,
+ sprintf(
+ /* translators: %1$s expands to Yoast News SEO. */
+ __( 'Buy the %1$s plugin now and start optimizing to get your site featured in Google News!', 'wordpress-seo' ),
+ 'Yoast News SEO'
+ )
+ )
+ );
+ }
+
+ return $plugin_banners;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/class-yoast-notification-center.php b/wp-content/plugins/wordpress-seo/admin/class-yoast-notification-center.php
new file mode 100644
index 0000000..7d59899
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-yoast-notification-center.php
@@ -0,0 +1,568 @@
+retrieve_notifications_from_storage();
+
+ add_action( 'all_admin_notices', array( $this, 'display_notifications' ) );
+
+ add_action( 'wp_ajax_yoast_get_notifications', array( $this, 'ajax_get_notifications' ) );
+
+ add_action( 'wpseo_deactivate', array( $this, 'deactivate_hook' ) );
+ add_action( 'shutdown', array( $this, 'update_storage' ) );
+ }
+
+ /**
+ * Singleton getter
+ *
+ * @return Yoast_Notification_Center
+ */
+ public static function get() {
+
+ if ( null === self::$instance ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Dismiss a notification
+ */
+ public static function ajax_dismiss_notification() {
+
+ $notification_center = self::get();
+
+ $notification_id = filter_input( INPUT_POST, 'notification' );
+ if ( empty( $notification_id ) ) {
+ die( '-1' );
+ }
+
+ $notification = $notification_center->get_notification_by_id( $notification_id );
+ if ( false === ( $notification instanceof Yoast_Notification ) ) {
+
+ // Permit legacy.
+ $notification = new Yoast_Notification( '', array(
+ 'id' => $notification_id,
+ 'dismissal_key' => $notification_id,
+ ) );
+ }
+
+ if ( $notification_center->maybe_dismiss_notification( $notification ) ) {
+ die( '1' );
+ }
+
+ die( '-1' );
+ }
+
+ /**
+ * Check if the user has dismissed a notification
+ *
+ * @param Yoast_Notification $notification The notification to check for dismissal.
+ * @param null|int $user_id User ID to check on.
+ *
+ * @return bool
+ */
+ public static function is_notification_dismissed( Yoast_Notification $notification, $user_id = null ) {
+
+ $user_id = ( ! is_null( $user_id ) ? $user_id : get_current_user_id() );
+ $dismissal_key = $notification->get_dismissal_key();
+
+ $current_value = get_user_meta( $user_id, $dismissal_key, $single = true );
+
+ return ! empty( $current_value );
+ }
+
+ /**
+ * Check if the nofitication is being dismissed
+ *
+ * @param string|Yoast_Notification $notification Notification to check dismissal of.
+ * @param string $meta_value Value to set the meta value to if dismissed.
+ *
+ * @return bool True if dismissed.
+ */
+ public static function maybe_dismiss_notification( Yoast_Notification $notification, $meta_value = 'seen' ) {
+
+ // Only persistent notifications are dismissible.
+ if ( ! $notification->is_persistent() ) {
+ return false;
+ }
+
+ // If notification is already dismissed, we're done.
+ if ( self::is_notification_dismissed( $notification ) ) {
+ return true;
+ }
+
+ $dismissal_key = $notification->get_dismissal_key();
+ $notification_id = $notification->get_id();
+
+ $is_dismissing = ( $dismissal_key === self::get_user_input( 'notification' ) );
+ if ( ! $is_dismissing ) {
+ $is_dismissing = ( $notification_id === self::get_user_input( 'notification' ) );
+ }
+
+ // Fallback to ?dismissal_key=1&nonce=bla when JavaScript fails.
+ if ( ! $is_dismissing ) {
+ $is_dismissing = ( '1' === self::get_user_input( $dismissal_key ) );
+ }
+
+ if ( ! $is_dismissing ) {
+ return false;
+ }
+
+ $user_nonce = self::get_user_input( 'nonce' );
+ if ( false === wp_verify_nonce( $user_nonce, $notification_id ) ) {
+ return false;
+ }
+
+ return self::dismiss_notification( $notification, $meta_value );
+ }
+
+ /**
+ * Clear dismissal information for the specified Notification
+ *
+ * When a cause is resolved, the next time it is present we want to show
+ * the message again.
+ *
+ * @param string|Yoast_Notification $notification Notification to clear the dismissal of.
+ *
+ * @return bool
+ */
+ public function clear_dismissal( $notification ) {
+
+ if ( $notification instanceof Yoast_Notification ) {
+ $dismissal_key = $notification->get_dismissal_key();
+ }
+
+ if ( is_string( $notification ) ) {
+ $dismissal_key = $notification;
+ }
+
+ if ( empty( $dismissal_key ) ) {
+ return false;
+ }
+
+ // Remove notification dismissal for all users.
+ $deleted = delete_metadata( 'user', $user_id = 0, $dismissal_key, $meta_value = '', $delete_all = true );
+
+ return $deleted;
+ }
+
+ /**
+ * Add notification to the cookie
+ *
+ * @param Yoast_Notification $notification Notification object instance.
+ */
+ public function add_notification( Yoast_Notification $notification ) {
+
+ // Don't add if the user can't see it.
+ if ( ! $notification->display_for_current_user() ) {
+ return;
+ }
+
+ $notification_id = $notification->get_id();
+
+ // Empty notifications are always added.
+ if ( $notification_id !== '' ) {
+
+ // If notification ID exists in notifications, don't add again.
+ $present_notification = $this->get_notification_by_id( $notification_id );
+ if ( ! is_null( $present_notification ) ) {
+ $this->remove_notification( $present_notification, false );
+ }
+
+ if ( is_null( $present_notification ) ) {
+ $this->new[] = $notification_id;
+ }
+ }
+
+ // Add to list.
+ $this->notifications[] = $notification;
+ }
+
+ /**
+ * Get the notification by ID
+ *
+ * @param string $notification_id The ID of the notification to search for.
+ *
+ * @return null|Yoast_Notification
+ */
+ public function get_notification_by_id( $notification_id ) {
+
+ foreach ( $this->notifications as & $notification ) {
+ if ( $notification_id === $notification->get_id() ) {
+ return $notification;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Display the notifications
+ */
+ public function display_notifications() {
+
+ // Never display notifications for network admin.
+ if ( function_exists( 'is_network_admin' ) && is_network_admin() ) {
+ return;
+ }
+
+ $sorted_notifications = $this->get_sorted_notifications();
+ foreach ( $sorted_notifications as $notification ) {
+ if ( ! $notification->is_persistent() ) {
+ echo $notification;
+ $this->remove_notification( $notification );
+ }
+ }
+ }
+
+ /**
+ * Remove notification after it has been displayed
+ *
+ * @param Yoast_Notification $notification Notification to remove.
+ * @param bool $resolve Resolve as fixed.
+ */
+ public function remove_notification( Yoast_Notification $notification, $resolve = true ) {
+
+ $index = false;
+
+ // Match persistent Notifications by ID, non persistent by item in the array.
+ if ( $notification->is_persistent() ) {
+ foreach ( $this->notifications as $current_index => $present_notification ) {
+ if ( $present_notification->get_id() === $notification->get_id() ) {
+ $index = $current_index;
+ break;
+ }
+ }
+ }
+ else {
+ $index = array_search( $notification, $this->notifications, true );
+ }
+
+ if ( false === $index ) {
+ return;
+ }
+
+ if ( $notification->is_persistent() && $resolve ) {
+ $this->resolved++;
+ $this->clear_dismissal( $notification );
+ }
+
+ unset( $this->notifications[ $index ] );
+ $this->notifications = array_values( $this->notifications );
+ }
+
+ /**
+ * Get the notification count
+ *
+ * @param bool $dismissed Count dismissed notifications.
+ *
+ * @return int Number of notifications
+ */
+ public function get_notification_count( $dismissed = false ) {
+
+ $notifications = $this->get_notifications();
+ $notifications = array_filter( $notifications, array( $this, 'filter_persistent_notifications' ) );
+
+ if ( ! $dismissed ) {
+ $notifications = array_filter( $notifications, array( $this, 'filter_dismissed_notifications' ) );
+ }
+
+ return count( $notifications );
+ }
+
+ /**
+ * Get the number of notifications resolved this execution
+ *
+ * These notifications have been resolved and should be counted when active again.
+ *
+ * @return int
+ */
+ public function get_resolved_notification_count() {
+
+ return $this->resolved;
+ }
+
+ /**
+ * Return the notifications sorted on type and priority
+ *
+ * @return array|Yoast_Notification[] Sorted Notifications
+ */
+ public function get_sorted_notifications() {
+
+ $notifications = $this->get_notifications();
+ if ( empty( $notifications ) ) {
+ return array();
+ }
+
+ // Sort by severity, error first.
+ usort( $notifications, array( $this, 'sort_notifications' ) );
+
+ return $notifications;
+ }
+
+ /**
+ * AJAX display notifications
+ */
+ public function ajax_get_notifications() {
+
+ // Display the notices.
+ $this->display_notifications();
+
+ // AJAX die.
+ exit;
+ }
+
+ /**
+ * Remove storage when the plugin is deactivated
+ */
+ public function deactivate_hook() {
+
+ $this->clear_notifications();
+ }
+
+ /**
+ * Save persistent notifications to storage
+ *
+ * We need to be able to retrieve these so they can be dismissed at any time during the execution.
+ *
+ * @since 3.2
+ *
+ * @return void
+ */
+ public function update_storage() {
+
+ $notifications = $this->get_notifications();
+
+ // No notifications to store, clear storage.
+ if ( empty( $notifications ) ) {
+ $this->remove_storage();
+
+ return;
+ }
+
+ $notifications = array_map( array( $this, 'notification_to_array' ), $notifications );
+
+ // Save the notifications to the storage.
+ update_user_option( get_current_user_id(), self::STORAGE_KEY, $notifications );
+ }
+
+ /**
+ * Provide a way to verify present notifications
+ *
+ * @return array|Yoast_Notification[] Registered notifications.
+ */
+ public function get_notifications() {
+
+ return $this->notifications;
+ }
+
+ /**
+ * Get newly added notifications
+ *
+ * @return array
+ */
+ public function get_new_notifications() {
+
+ return array_map( array( $this, 'get_notification_by_id' ), $this->new );
+ }
+
+ /**
+ * Get information from the User input
+ *
+ * @param string $key Key to retrieve.
+ *
+ * @return mixed value of key if set.
+ */
+ private static function get_user_input( $key ) {
+
+ $filter_input_type = INPUT_GET;
+ if ( 'POST' === strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
+ $filter_input_type = INPUT_POST;
+ }
+
+ return filter_input( $filter_input_type, $key );
+ }
+
+ /**
+ * Retrieve the notifications from storage
+ *
+ * @return array Yoast_Notification[] Notifications
+ */
+ private function retrieve_notifications_from_storage() {
+
+ $stored_notifications = get_user_option( self::STORAGE_KEY, get_current_user_id() );
+
+ // Check if notifications are stored.
+ if ( empty( $stored_notifications ) ) {
+ return;
+ }
+
+ if ( is_array( $stored_notifications ) ) {
+ $notifications = array_map( array( $this, 'array_to_notification' ), $stored_notifications );
+ $notifications = array_filter( $notifications, array( $this, 'filter_notification_current_user' ) );
+
+ $this->notifications = $notifications;
+ }
+ }
+
+ /**
+ * Sort on type then priority
+ *
+ * @param Yoast_Notification $a Compare with B.
+ * @param Yoast_Notification $b Compare with A.
+ *
+ * @return int 1, 0 or -1 for sorting offset.
+ */
+ private function sort_notifications( Yoast_Notification $a, Yoast_Notification $b ) {
+
+ $a_type = $a->get_type();
+ $b_type = $b->get_type();
+
+ if ( $a_type === $b_type ) {
+ return WPSEO_Utils::calc( $b->get_priority(), 'compare', $a->get_priority() );
+ }
+
+ if ( 'error' === $a_type ) {
+ return -1;
+ }
+
+ if ( 'error' === $b_type ) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Dismiss the notification
+ *
+ * @param Yoast_Notification $notification Notification to dismiss.
+ * @param string $meta_value Value to save in the dismissal.
+ *
+ * @return bool
+ */
+ private static function dismiss_notification( Yoast_Notification $notification, $meta_value = 'seen' ) {
+ // Dismiss notification.
+ return ( false !== update_user_meta( get_current_user_id(), $notification->get_dismissal_key(), $meta_value ) );
+ }
+
+ /**
+ * Remove all notifications from storage
+ */
+ private function remove_storage() {
+
+ delete_user_option( get_current_user_id(), self::STORAGE_KEY );
+ }
+
+ /**
+ * Clear local stored notifications
+ */
+ private function clear_notifications() {
+
+ $this->notifications = array();
+ }
+
+ /**
+ * Filter out non-persistent notifications.
+ *
+ * @param Yoast_Notification $notification Notification to test for persistent.
+ *
+ * @since 3.2
+ *
+ * @return bool
+ */
+ private function filter_persistent_notifications( Yoast_Notification $notification ) {
+
+ return $notification->is_persistent();
+ }
+
+ /**
+ * Filter out dismissed notifications
+ *
+ * @param Yoast_Notification $notification Notification to check.
+ *
+ * @return bool
+ */
+ private function filter_dismissed_notifications( Yoast_Notification $notification ) {
+
+ return ! $this->maybe_dismiss_notification( $notification );
+ }
+
+ /**
+ * Convert Notification to array representation
+ *
+ * @param Yoast_Notification $notification Notification to convert.
+ *
+ * @since 3.2
+ *
+ * @return array
+ */
+ private function notification_to_array( Yoast_Notification $notification ) {
+
+ return $notification->to_array();
+ }
+
+ /**
+ * Convert stored array to Notification.
+ *
+ * @param array $notification_data Array to convert to Notification.
+ *
+ * @return Yoast_Notification
+ */
+ private function array_to_notification( $notification_data ) {
+
+ return new Yoast_Notification(
+ $notification_data['message'],
+ $notification_data['options']
+ );
+ }
+
+ /**
+ * Filter notifications that should not be displayed for the current user
+ *
+ * @param Yoast_Notification $notification Notification to test.
+ *
+ * @return bool
+ */
+ private function filter_notification_current_user( Yoast_Notification $notification ) {
+ return $notification->display_for_current_user();
+ }
+
+ /**
+ * Write the notifications to a cookie (hooked on shutdown)
+ *
+ * Function renamed to 'update_storage'.
+ *
+ * @deprecated 3.2 remove in 3.5
+ */
+ public function set_transient() {
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/class-yoast-notification.php b/wp-content/plugins/wordpress-seo/admin/class-yoast-notification.php
new file mode 100644
index 0000000..ef1f7a8
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-yoast-notification.php
@@ -0,0 +1,303 @@
+ self::UPDATED,
+ 'id' => '',
+ 'nonce' => null,
+ 'priority' => 0.5,
+ 'data_json' => array(),
+ 'dismissal_key' => null,
+ 'capabilities' => array(),
+ 'capability_check' => self::MATCH_ALL,
+ );
+
+ /**
+ * Notification class constructor.
+ *
+ * @param string $message Message string.
+ * @param array $options Set of options.
+ */
+ public function __construct( $message, $options = array() ) {
+ $this->message = $message;
+ $this->options = $this->normalize_options( $options );
+ }
+
+ /**
+ * Retrieve notification ID string.
+ *
+ * @return string
+ */
+ public function get_id() {
+ return $this->options['id'];
+ }
+
+ /**
+ * Retrieve nonce identifier.
+ *
+ * @return null|string Nonce for this Notification.
+ */
+ public function get_nonce() {
+ if ( $this->options['id'] && empty( $this->options['nonce'] ) ) {
+ $this->options['nonce'] = wp_create_nonce( $this->options['id'] );
+ }
+
+ return $this->options['nonce'];
+ }
+
+ /**
+ * Make sure the nonce is up to date
+ */
+ public function refresh_nonce() {
+ if ( $this->options['id'] ) {
+ $this->options['nonce'] = wp_create_nonce( $this->options['id'] );
+ }
+ }
+
+ /**
+ * Get the type of the notification
+ *
+ * @return string
+ */
+ public function get_type() {
+ return $this->options['type'];
+ }
+
+ /**
+ * Priority of the notification
+ *
+ * Relative to the type.
+ *
+ * @return float Returns the priority between 0 and 1.
+ */
+ public function get_priority() {
+ return $this->options['priority'];
+ }
+
+ /**
+ * Get the User Meta key to check for dismissal of notification
+ *
+ * @return string User Meta Option key that registers dismissal.
+ */
+ public function get_dismissal_key() {
+ if ( empty( $this->options['dismissal_key'] ) ) {
+ return $this->options['id'];
+ }
+
+ return $this->options['dismissal_key'];
+ }
+
+ /**
+ * Is this Notification persistent
+ *
+ * @return bool True if persistent, False if fire and forget.
+ */
+ public function is_persistent() {
+ $id = $this->get_id();
+
+ return ! empty( $id );
+ }
+
+ /**
+ * Check if the notification is relevant for the current user
+ *
+ * @return bool True if a user needs to see this Notification, False if not.
+ */
+ public function display_for_current_user() {
+ // If the notification is for the current page only, always show.
+ if ( ! $this->is_persistent() ) {
+ return true;
+ }
+
+ // If the current user doesn't match capabilities.
+ return $this->match_capabilities();
+ }
+
+ /**
+ * Does the current user match required capabilities
+ *
+ * @return bool
+ */
+ public function match_capabilities() {
+ // Super Admin can do anything.
+ if ( is_multisite() && is_super_admin() ) {
+ return true;
+ }
+
+ /**
+ * Filter capabilities that enable the displaying of this notification.
+ *
+ * @since 3.2
+ *
+ * @param array $capabilities The capabilities that must be present for this Notification.
+ * @param Yoast_Notification $notification The notification object.
+ *
+ * @return array of capabilities or empty for no restrictions.
+ */
+ $capabilities = apply_filters( 'wpseo_notification_capabilities', $this->options['capabilities'], $this );
+
+ // Should be an array.
+ if ( ! is_array( $capabilities ) ) {
+ $capabilities = (array) $capabilities;
+ }
+
+ /**
+ * Filter capability check to enable all or any capabilities.
+ *
+ * @since 3.2
+ *
+ * @param string $capability_check The type of check that will be used to determine if an capability is present.
+ * @param Yoast_Notification $notification The notification object.
+ *
+ * @return string self::MATCH_ALL or self::MATCH_ANY.
+ */
+ $capability_check = apply_filters( 'wpseo_notification_capability_check', $this->options['capability_check'], $this );
+
+ if ( ! in_array( $capability_check, array( self::MATCH_ALL, self::MATCH_ANY ), true ) ) {
+ $capability_check = self::MATCH_ALL;
+ }
+
+ if ( ! empty( $capabilities ) ) {
+
+ $has_capabilities = array_filter( $capabilities, array( $this, 'has_capability' ) );
+
+ switch ( $capability_check ) {
+ case self::MATCH_ALL:
+ return $has_capabilities === $capabilities;
+ case self::MATCH_ANY:
+ return ! empty( $has_capabilities );
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Array filter function to find matched capabilities
+ *
+ * @param string $capability Capability to test.
+ *
+ * @return bool
+ */
+ private function has_capability( $capability ) {
+ return current_user_can( $capability );
+ }
+
+ /**
+ * Return the object properties as an array
+ *
+ * @return array
+ */
+ public function to_array() {
+ return array(
+ 'message' => $this->message,
+ 'options' => $this->options,
+ );
+ }
+
+ /**
+ * Adds string (view) behaviour to the Notification
+ *
+ * @return string
+ */
+ public function __toString() {
+ $attributes = array();
+
+ // Default notification classes.
+ $classes = array(
+ 'yoast-alert',
+ );
+
+ // Maintain WordPress visualisation of alerts when they are not persistent.
+ if ( ! $this->is_persistent() ) {
+ $classes[] = 'notice';
+ $classes[] = $this->get_type();
+ }
+
+ if ( ! empty( $classes ) ) {
+ $attributes['class'] = implode( ' ', $classes );
+ }
+
+ // Combined attribute key and value into a string.
+ array_walk( $attributes, array( $this, 'parse_attributes' ) );
+
+ // Build the output DIV.
+ return '
' . wpautop( $this->message ) . '
' . PHP_EOL;
+ }
+
+ /**
+ * Get the JSON if provided
+ *
+ * @return false|string
+ */
+ public function get_json() {
+ if ( empty( $this->options['data_json'] ) ) {
+ return '';
+ }
+
+ return wp_json_encode( $this->options['data_json'] );
+ }
+
+ /**
+ * Make sure we only have values that we can work with
+ *
+ * @param array $options Options to normalize.
+ *
+ * @return array
+ */
+ private function normalize_options( $options ) {
+ $options = wp_parse_args( $options, $this->defaults );
+
+ // Should not exceed 0 or 1.
+ $options['priority'] = min( 1, max( 0, $options['priority'] ) );
+
+ // Set default capabilities when not supplied.
+ if ( empty( $options['capabilities'] ) || array() === $options['capabilities'] ) {
+ $options['capabilities'] = array( 'manage_options' );
+ }
+
+ return $options;
+ }
+
+ /**
+ * Format HTML element attributes
+ *
+ * @param string $value Attribute value.
+ * @param string $key Attribute name.
+ */
+ private function parse_attributes( & $value, $key ) {
+ $value = sprintf( '%s="%s"', $key, esc_attr( $value ) );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/class-yoast-plugin-conflict.php b/wp-content/plugins/wordpress-seo/admin/class-yoast-plugin-conflict.php
new file mode 100644
index 0000000..5dde1d2
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/class-yoast-plugin-conflict.php
@@ -0,0 +1,333 @@
+plugins the active plugins will be stored in this
+ * property
+ *
+ * @var array
+ */
+ protected $active_plugins = array();
+
+ /**
+ * Property for holding instance of itself
+ *
+ * @var Yoast_Plugin_Conflict
+ */
+ protected static $instance;
+
+ /**
+ * For the use of singleton pattern. Create instance of itself and return his instance
+ *
+ * @param string $class_name Give the classname to initialize. If classname is false (empty) it will use it's own __CLASS__.
+ *
+ * @return Yoast_Plugin_Conflict
+ */
+ public static function get_instance( $class_name = '' ) {
+
+ if ( is_null( self::$instance ) ) {
+ if ( ! is_string( $class_name ) || $class_name === '' ) {
+ $class_name = __CLASS__;
+ }
+
+ self::$instance = new $class_name();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Setting instance, all active plugins and search for active plugins
+ *
+ * Protected constructor to prevent creating a new instance of the
+ * *Singleton* via the `new` operator from outside of this class.
+ */
+ protected function __construct() {
+ // Set active plugins.
+ $this->all_active_plugins = get_option( 'active_plugins' );
+
+ if ( filter_input( INPUT_GET, 'action' ) === 'deactivate' ) {
+ $this->remove_deactivated_plugin();
+ }
+
+ // Search for active plugins.
+ $this->search_active_plugins();
+ }
+
+ /**
+ * Check if there are conflicting plugins for given $plugin_section
+ *
+ * @param string $plugin_section Type of plugin conflict (such as Open Graph or sitemap).
+ *
+ * @return bool
+ */
+ public function check_for_conflicts( $plugin_section ) {
+
+ static $sections_checked;
+
+ if ( $sections_checked === null ) {
+ $sections_checked = array();
+ }
+
+ if ( ! in_array( $plugin_section, $sections_checked ) ) {
+ $sections_checked[] = $plugin_section;
+ $has_conflicts = ( ! empty( $this->active_plugins[ $plugin_section ] ) );
+
+ return $has_conflicts;
+ }
+
+ return false;
+ }
+
+ /**
+ * Getting all the conflicting plugins and return them as a string.
+ *
+ * This method will loop through all conflicting plugins to get the details of each plugin. The plugin name
+ * will be taken from the details to parse a comma separated string, which can be use for by example a notice
+ *
+ * @param string $plugin_section Plugin conflict type (such as Open Graph or sitemap).
+ *
+ * @return string
+ */
+ public function get_conflicting_plugins_as_string( $plugin_section ) {
+ if ( ! function_exists( 'get_plugin_data' ) ) {
+ require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
+ }
+
+ // Getting the active plugins by given section.
+ $plugins = $this->active_plugins[ $plugin_section ];
+
+ $plugin_names = array();
+ foreach ( $plugins as $plugin ) {
+ if ( $name = WPSEO_Utils::get_plugin_name( $plugin ) ) {
+ $plugin_names[] = '' . $name . '';
+ }
+ }
+ unset( $plugins, $plugin );
+
+ if ( ! empty( $plugin_names ) ) {
+ return implode( ' & ', $plugin_names );
+ }
+ }
+
+ /**
+ * Checks for given $plugin_sections for conflicts
+ *
+ * @param array $plugin_sections Set of sections.
+ */
+ public function check_plugin_conflicts( $plugin_sections ) {
+ foreach ( $plugin_sections as $plugin_section => $readable_plugin_section ) {
+ // Check for conflicting plugins and show error if there are conflicts.
+ if ( $this->check_for_conflicts( $plugin_section ) ) {
+ $this->set_error( $plugin_section, $readable_plugin_section );
+ }
+ }
+
+ // List of all active sections.
+ $sections = array_keys( $plugin_sections );
+ // List of all sections.
+ $all_plugin_sections = array_keys( $this->plugins );
+
+ /*
+ * Get all sections that are inactive.
+ * These plugins need to be cleared.
+ *
+ * This happens when Sitemaps or OpenGraph implementations toggle active/disabled.
+ */
+ $inactive_sections = array_diff( $all_plugin_sections, $sections );
+ if ( ! empty( $inactive_sections ) ) {
+ foreach ( $inactive_sections as $section ) {
+ array_walk( $this->plugins[ $section ], array( $this, 'clear_error' ) );
+ }
+ }
+
+ // For active sections clear errors for inactive plugins.
+ foreach ( $sections as $section ) {
+ // By default clear errors for all plugins of the section.
+ $inactive_plugins = $this->plugins[ $section ];
+
+ // If there are active plugins, filter them from being cleared.
+ if ( isset( $this->active_plugins[ $section ] ) ) {
+ $inactive_plugins = array_diff( $this->plugins[ $section ], $this->active_plugins[ $section ] );
+ }
+
+ array_walk( $inactive_plugins, array( $this, 'clear_error' ) );
+ }
+ }
+
+ /**
+ * Setting an error on the screen
+ *
+ * @param string $plugin_section Type of conflict group (such as Open Graph or sitemap).
+ * @param string $readable_plugin_section This is the value for the translation.
+ */
+ protected function set_error( $plugin_section, $readable_plugin_section ) {
+
+ $notification_center = Yoast_Notification_Center::get();
+
+ foreach ( $this->active_plugins[ $plugin_section ] as $plugin_file ) {
+
+ $plugin_name = WPSEO_Utils::get_plugin_name( $plugin_file );
+
+ $error_message = '';
+ /* translators: %1$s: 'Facebook & Open Graph' plugin name(s) of possibly conflicting plugin(s), %2$s to Yoast SEO */
+ $error_message .= '
' . sprintf( __( 'The %1$s plugin might cause issues when used in conjunction with %2$s.', 'wordpress-seo' ), '' . $plugin_name . '', 'Yoast SEO' ) . '
';
+
+ $this->set_property( 'html', $html );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/config-ui/fields/class-field.php b/wp-content/plugins/wordpress-seo/admin/config-ui/fields/class-field.php
new file mode 100644
index 0000000..f4b3c2e
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/config-ui/fields/class-field.php
@@ -0,0 +1,134 @@
+field = $field;
+ $this->component = $component;
+ }
+
+ /**
+ * Get the identifier
+ *
+ * @return string
+ */
+ public function get_identifier() {
+ return $this->field;
+ }
+
+ /**
+ * Get the component
+ *
+ * @return string
+ */
+ public function get_component() {
+ return $this->component;
+ }
+
+ /**
+ * Set a property value
+ *
+ * @param string $name Property to set.
+ * @param mixed $value Value to apply.
+ */
+ public function set_property( $name, $value ) {
+ $this->properties[ $name ] = $value;
+ }
+
+ /**
+ * Get all the properties
+ *
+ * @return array
+ */
+ public function get_properties() {
+ return $this->properties;
+ }
+
+ /**
+ * Get the data
+ *
+ * @return mixed
+ */
+ public function get_data() {
+ return $this->data;
+ }
+
+ /**
+ * Array representation of this object.
+ *
+ * @return array
+ */
+ public function to_array() {
+ $output = array(
+ 'componentName' => $this->get_component(),
+ );
+
+ $properties = $this->get_properties();
+ if ( $properties ) {
+ $output['properties'] = $properties;
+ }
+
+ $requires = $this->get_requires();
+ if ( ! empty( $requires ) ) {
+ $output['requires'] = $requires;
+ }
+
+ return $output;
+ }
+
+ /**
+ * Set the adapter to use
+ *
+ * @param WPSEO_Configuration_Options_Adapter $adapter Adapter to register lookup on.
+ */
+ public function set_adapter( WPSEO_Configuration_Options_Adapter $adapter ) {
+ }
+
+ /**
+ * Requires another field to have a certain value.
+ *
+ * @param string $field Field to check for a certain value.
+ * @param mixed $value Value of the field.
+ */
+ public function set_requires( $field, $value ) {
+ $this->requires = array(
+ 'field' => $field,
+ 'value' => $value,
+ );
+ }
+
+ /**
+ * Get the required field settings (if present)
+ *
+ * @return array
+ */
+ public function get_requires() {
+ return $this->requires;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/formatter/class-metabox-formatter.php b/wp-content/plugins/wordpress-seo/admin/formatter/class-metabox-formatter.php
new file mode 100644
index 0000000..ed7a477
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/formatter/class-metabox-formatter.php
@@ -0,0 +1,99 @@
+formatter = $formatter;
+ }
+
+ /**
+ * Returns the values
+ *
+ * @return array
+ */
+ public function get_values() {
+ $defaults = $this->get_defaults();
+ $values = $this->formatter->get_values();
+
+ return ( $values + $defaults );
+ }
+
+ /**
+ * Returns array with all the values always needed by a scraper object
+ *
+ * @return array
+ */
+ private function get_defaults() {
+ $analysis_seo = new WPSEO_Metabox_Analysis_SEO();
+ $analysis_readability = new WPSEO_Metabox_Analysis_Readability();
+
+ return array(
+ 'search_url' => '',
+ 'post_edit_url' => '',
+ 'base_url' => '',
+ 'contentTab' => __( 'Readability', 'wordpress-seo' ),
+ 'keywordTab' => __( 'Keyword:', 'wordpress-seo' ),
+ 'enterFocusKeyword' => __( 'Enter your focus keyword', 'wordpress-seo' ),
+ 'removeKeyword' => __( 'Remove keyword', 'wordpress-seo' ),
+ 'locale' => WPSEO_Utils::get_user_locale(),
+ 'translations' => $this->get_translations(),
+ 'keyword_usage' => array(),
+ 'title_template' => '',
+ 'metadesc_template' => '',
+ 'contentAnalysisActive' => $analysis_readability->is_enabled() ? 1 : 0,
+ 'keywordAnalysisActive' => $analysis_seo->is_enabled() ? 1 : 0,
+
+ /**
+ * Filter to determine if the markers should be enabled or not.
+ *
+ * @param bool $showMarkers Should the markers being enabled. Default = true.
+ */
+ 'show_markers' => apply_filters( 'wpseo_enable_assessment_markers', true ),
+ 'publish_box' => array(
+ 'labels' => array(
+ 'content' => __( 'Readability', 'wordpress-seo' ),
+ 'keyword' => __( 'SEO', 'wordpress-seo' ),
+ ),
+ 'statuses' => array(
+ 'na' => __( 'Not available', 'wordpress-seo' ),
+ 'bad' => __( 'Needs improvement', 'wordpress-seo' ),
+ 'ok' => __( 'OK', 'wordpress-seo' ),
+ 'good' => __( 'Good', 'wordpress-seo' ),
+ ),
+ ),
+ );
+
+ }
+
+ /**
+ * Returns Jed compatible YoastSEO.js translations.
+ *
+ * @return array
+ */
+ private function get_translations() {
+ $locale = WPSEO_Utils::get_user_locale();
+
+ $file = plugin_dir_path( WPSEO_FILE ) . 'languages/wordpress-seo-' . $locale . '.json';
+ if ( file_exists( $file ) && $file = file_get_contents( $file ) ) {
+ return json_decode( $file, true );
+ }
+
+ return array();
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/formatter/class-post-metabox-formatter.php b/wp-content/plugins/wordpress-seo/admin/formatter/class-post-metabox-formatter.php
new file mode 100644
index 0000000..697d09c
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/formatter/class-post-metabox-formatter.php
@@ -0,0 +1,181 @@
+post = $post;
+ $this->options = $options;
+ $this->permalink = $structure;
+ }
+
+ /**
+ * Returns the translated values.
+ *
+ * @return array
+ */
+ public function get_values() {
+ $values = array(
+ 'search_url' => $this->search_url(),
+ 'post_edit_url' => $this->edit_url(),
+ 'base_url' => $this->base_url_for_js(),
+ 'metaDescriptionDate' => '',
+ );
+
+ if ( $this->post instanceof WP_Post ) {
+ $values_to_set = array(
+ 'keyword_usage' => $this->get_focus_keyword_usage(),
+ 'title_template' => $this->get_title_template(),
+ 'metadesc_template' => $this->get_metadesc_template(),
+ 'metaDescriptionDate' => $this->get_metadesc_date(),
+ );
+
+ $values = ( $values_to_set + $values );
+ }
+
+ return $values;
+ }
+
+ /**
+ * Returns the url to search for keyword for the post
+ *
+ * @return string
+ */
+ private function search_url() {
+ return admin_url( 'edit.php?seo_kw_filter={keyword}' );
+ }
+
+ /**
+ * Returns the url to edit the taxonomy
+ *
+ * @return string
+ */
+ private function edit_url() {
+ return admin_url( 'post.php?post={id}&action=edit' );
+ }
+
+ /**
+ * Returns a base URL for use in the JS, takes permalink structure into account
+ *
+ * @return string
+ */
+ private function base_url_for_js() {
+ global $pagenow;
+
+ // The default base is the home_url.
+ $base_url = home_url( '/', null );
+
+ if ( 'post-new.php' === $pagenow ) {
+ return $base_url;
+ }
+
+ // If %postname% is the last tag, just strip it and use that as a base.
+ if ( 1 === preg_match( '#%postname%/?$#', $this->permalink ) ) {
+ $base_url = preg_replace( '#%postname%/?$#', '', $this->permalink );
+ }
+
+ return $base_url;
+ }
+
+ /**
+ * Counting the number of given keyword used for other posts than given post_id
+ *
+ * @return array
+ */
+ private function get_focus_keyword_usage() {
+ $keyword = WPSEO_Meta::get_value( 'focuskw', $this->post->ID );
+
+ return array(
+ $keyword => WPSEO_Meta::keyword_usage( $keyword, $this->post->ID ),
+ );
+ }
+
+ /**
+ * Retrieves the title template.
+ *
+ * @return string
+ */
+ private function get_title_template() {
+ return $this->get_template( 'title' );
+ }
+
+ /**
+ * Retrieves the metadesc template.
+ *
+ * @return string
+ */
+ private function get_metadesc_template() {
+ return $this->get_template( 'metadesc' );
+ }
+
+ /**
+ * Retrieves a template.
+ *
+ * @param String $template_option_name The name of the option in which the template you want to get is saved.
+ *
+ * @return string
+ */
+ private function get_template( $template_option_name ) {
+ $needed_option = $template_option_name . '-' . $this->post->post_type;
+
+ if ( isset( $this->options[ $needed_option ] ) && $this->options[ $needed_option ] !== '' ) {
+ return $this->options[ $needed_option ];
+ }
+
+ return '';
+ }
+
+ /**
+ * Determines the date to be displayed in the snippet preview
+ *
+ * @return string
+ */
+ private function get_metadesc_date() {
+ $date = '';
+
+ if ( $this->is_show_date_enabled() ) {
+ $date = date_i18n( 'M j, Y', mysql2date( 'U', $this->post->post_date ) );
+ }
+
+ return $date;
+ }
+
+ /**
+ * Returns whether or not showing the date in the snippet preview is enabled.
+ *
+ * @return bool
+ */
+ private function is_show_date_enabled() {
+ $post_type = $this->post->post_type;
+ $key = sprintf( 'showdate-%s', $post_type );
+
+ return isset( $this->options[ $key ] ) && true === $this->options[ $key ];
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/formatter/class-term-metabox-formatter.php b/wp-content/plugins/wordpress-seo/admin/formatter/class-term-metabox-formatter.php
new file mode 100644
index 0000000..a99839f
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/formatter/class-term-metabox-formatter.php
@@ -0,0 +1,143 @@
+term = $term;
+ $this->taxonomy = $taxonomy;
+ $this->options = $options;
+ }
+
+ /**
+ * Returns the translated values.
+ *
+ * @return array
+ */
+ public function get_values() {
+ $values = array();
+
+ // Todo: a column needs to be added on the termpages to add a filter for the keyword, so this can be used in the focus kw doubles.
+ if ( is_object( $this->term ) && property_exists( $this->term, 'taxonomy' ) ) {
+ $values = array(
+ 'search_url' => $this->search_url(),
+ 'post_edit_url' => $this->edit_url(),
+ 'base_url' => $this->base_url_for_js(),
+ 'taxonomy' => $this->term->taxonomy,
+ 'keyword_usage' => $this->get_focus_keyword_usage(),
+ 'title_template' => $this->get_title_template(),
+ 'metadesc_template' => $this->get_metadesc_template(),
+ );
+ }
+
+ return $values;
+ }
+
+ /**
+ * Returns the url to search for keyword for the taxonomy
+ *
+ * @return string
+ */
+ private function search_url() {
+ return admin_url( 'edit-tags.php?taxonomy=' . $this->term->taxonomy . '&seo_kw_filter={keyword}' );
+ }
+
+ /**
+ * Returns the url to edit the taxonomy
+ *
+ * @return string
+ */
+ private function edit_url() {
+ global $wp_version;
+ $script_filename = version_compare( $wp_version, '4.5', '<' ) ? 'edit-tags' : 'term';
+ return admin_url( $script_filename . '.php?action=edit&taxonomy=' . $this->term->taxonomy . '&tag_ID={id}' );
+ }
+
+ /**
+ * Returns a base URL for use in the JS, takes permalink structure into account
+ *
+ * @return string
+ */
+ private function base_url_for_js() {
+
+ $base_url = home_url( '/', null );
+ $options = WPSEO_Options::get_option( 'wpseo_permalinks' );
+ if ( ! $options['stripcategorybase'] ) {
+ $base_url = trailingslashit( $base_url . $this->taxonomy->rewrite['slug'] );
+ }
+
+ return $base_url;
+ }
+
+ /**
+ * Counting the number of given keyword used for other term than given term_id
+ *
+ * @return array
+ */
+ private function get_focus_keyword_usage() {
+ $focuskw = WPSEO_Taxonomy_Meta::get_term_meta( $this->term, $this->term->taxonomy, 'focuskw' );
+
+ return WPSEO_Taxonomy_Meta::get_keyword_usage( $focuskw, $this->term->term_id, $this->term->taxonomy );
+ }
+
+ /**
+ * Retrieves the title template.
+ *
+ * @return string
+ */
+ private function get_title_template() {
+ return $this->get_template( 'title' );
+ }
+
+ /**
+ * Retrieves the metadesc template.
+ *
+ * @return string
+ */
+ private function get_metadesc_template() {
+ return $this->get_template( 'metadesc' );
+ }
+
+ /**
+ * Retrieves a template.
+ *
+ * @param String $template_option_name The name of the option in which the template you want to get is saved.
+ *
+ * @return string
+ */
+ private function get_template( $template_option_name ) {
+ $needed_option = $template_option_name . '-tax-' . $this->term->taxonomy;
+ if ( isset( $this->options[ $needed_option ] ) && $this->options[ $needed_option ] !== '' ) {
+ return $this->options[ $needed_option ];
+ }
+
+ return '';
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/formatter/interface-metabox-formatter.php b/wp-content/plugins/wordpress-seo/admin/formatter/interface-metabox-formatter.php
new file mode 100644
index 0000000..f3be154
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/formatter/interface-metabox-formatter.php
@@ -0,0 +1,18 @@
+valid_nonce() ) {
+ $marker = new WPSEO_GSC_Marker( filter_input( INPUT_POST, 'url' ) );
+
+ wp_die( $marker->get_response() );
+ }
+
+ wp_die( 'false' );
+ }
+
+ /**
+ * Handling the request to create a new redirect from the issued URL
+ */
+ public function ajax_create_redirect() {
+ if ( $this->valid_nonce() && class_exists( 'WPSEO_Redirect_Manager' ) && defined( 'WPSEO_PREMIUM_PATH' ) ) {
+ $redirect_manager = new WPSEO_Redirect_Manager();
+
+ $old_url = filter_input( INPUT_POST, 'old_url' );
+
+ // Creates the redirect.
+ $redirect = new WPSEO_Redirect( $old_url, filter_input( INPUT_POST, 'new_url' ), filter_input( INPUT_POST, 'type' ) );
+
+ if ( $redirect_manager->create_redirect( $redirect ) ) {
+ if ( filter_input( INPUT_POST, 'mark_as_fixed' ) === 'true' ) {
+ new WPSEO_GSC_Marker( $old_url );
+ }
+
+ wp_die( 'true' );
+ }
+ }
+
+ wp_die( 'false' );
+ }
+
+ /**
+ * Handle the AJAX request and dismiss the GSC notice
+ */
+ public function dismiss_notice() {
+ check_ajax_referer( 'dismiss-gsc-notice' );
+
+ update_user_meta( get_current_user_id(), 'wpseo_dismissed_gsc_notice', true );
+
+ wp_die( 'true' );
+ }
+
+ /**
+ * Saves the authorization code.
+ */
+ public function save_auth_code() {
+ if ( ! $this->valid_nonce() ) {
+ wp_die( '0' );
+ }
+
+ // Validate the authorization.
+ $service = $this->get_service();
+ $authorization_code = filter_input( INPUT_POST, 'authorization' );
+ $is_authorization_valid = WPSEO_GSC_Settings::validate_authorization( $authorization_code, $service->get_client() );
+ if ( ! $is_authorization_valid ) {
+ wp_die( '0' );
+ }
+
+ $this->get_profiles();
+ }
+
+ /**
+ * Clears all authorization data.
+ */
+ public function clear_auth_code() {
+ if ( ! $this->valid_nonce() ) {
+ wp_die( '0' );
+ }
+
+ $service = $this->get_service();
+
+ WPSEO_GSC_Settings::clear_data( $service );
+
+ $this->get_profiles();
+ }
+
+ /**
+ * Check if posted nonce is valid and return true if it is
+ *
+ * @return mixed
+ */
+ private function valid_nonce() {
+ return wp_verify_nonce( filter_input( INPUT_POST, 'ajax_nonce' ), 'wpseo-gsc-ajax-security' );
+ }
+
+ /**
+ * Returns an instance of the Google Search Console service.
+ *
+ * @return WPSEO_GSC_Service
+ */
+ private function get_service() {
+ return new WPSEO_GSC_Service();
+ }
+
+ /**
+ * Prints a JSON encoded string with the current profile config.
+ */
+ private function get_profiles() {
+ $component = new WPSEO_Config_Component_Connect_Google_Search_Console();
+
+ wp_die( wp_json_encode( $component->get_data() ) );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-bulk-action.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-bulk-action.php
new file mode 100644
index 0000000..02a5c16
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-bulk-action.php
@@ -0,0 +1,92 @@
+handle_bulk_action();
+ }
+ }
+
+ /**
+ * Handles the bulk action when there is an action posted
+ */
+ private function handle_bulk_action() {
+ if ( $bulk_action = $this->determine_bulk_action() ) {
+ $this->run_bulk_action( $bulk_action, $this->posted_issues() );
+
+ wp_redirect( filter_input( INPUT_POST, '_wp_http_referer' ) );
+ exit;
+ }
+ }
+
+ /**
+ * Determine which bulk action is selected and return that value
+ *
+ * @return string|bool
+ */
+ private function determine_bulk_action() {
+ // If posted action is the selected one above the table, return that value.
+ if ( ( $action = filter_input( INPUT_POST, 'action' ) ) && $action !== '-1' ) {
+ return $action;
+ }
+
+ // If posted action is the selected one below the table, return that value.
+ if ( ( $action = filter_input( INPUT_POST, 'action2' ) ) && $action !== '-1' ) {
+ return $action;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the posted issues and return them
+ *
+ * @return array
+ */
+ private function posted_issues() {
+ if ( $issues = filter_input( INPUT_POST, 'wpseo_crawl_issues', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ) ) {
+ return $issues;
+ }
+
+ // Fallback if issues are empty.
+ return array();
+ }
+
+ /**
+ * Runs the bulk action
+ *
+ * @param string $bulk_action Action type.
+ * @param array $issues Set of issues to apply to.
+ */
+ private function run_bulk_action( $bulk_action, $issues ) {
+ switch ( $bulk_action ) {
+ case 'mark_as_fixed' :
+ array_map( array( $this, 'action_mark_as_fixed' ), $issues );
+
+ break;
+ }
+ }
+
+ /**
+ * Marks the issue as fixed
+ *
+ * @param string $issue Issue URL.
+ *
+ * @return string
+ */
+ private function action_mark_as_fixed( $issue ) {
+ new WPSEO_GSC_Marker( $issue );
+
+ return $issue;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-category-filters.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-category-filters.php
new file mode 100644
index 0000000..f172a81
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-category-filters.php
@@ -0,0 +1,192 @@
+set_counts( $platform_counts );
+ }
+
+ // Setting the filter values.
+ $this->set_filter_values();
+
+ $this->category = $this->get_current_category();
+ }
+
+ /**
+ * Returns the value of the current category
+ *
+ * @return mixed|string
+ */
+ public function get_category() {
+ return $this->category;
+ }
+
+ /**
+ * Returns the current filters as an array
+ *
+ * Only return categories with more than 0 issues
+ *
+ * @return array
+ */
+ public function as_array() {
+ $new_views = array();
+
+ foreach ( $this->category_counts as $category_name => $category ) {
+ $new_views[] = $this->create_view_link( $category_name, $category['count'] );
+ }
+
+ return $new_views;
+ }
+
+ /**
+ * Getting the current view
+ */
+ private function get_current_category() {
+ if ( $current_category = filter_input( INPUT_GET, 'category' ) ) {
+ return $current_category;
+ }
+
+ // Just prevent redirect loops.
+ if ( ! empty( $this->category_counts ) ) {
+ $current_category = 'not_found';
+ if ( empty( $this->category_counts[ $current_category ] ) ) {
+ $current_category = key( $this->category_counts );
+ }
+
+ // Just redirect to set the category.
+ wp_redirect( add_query_arg( 'category', $current_category ) );
+ exit;
+ }
+ }
+
+ /**
+ * Setting the view counts based on the saved data. The info will be used to display the category filters
+ *
+ * @param array $platform_counts Set of counts by platform.
+ */
+ private function set_counts( array $platform_counts ) {
+ $this->category_counts = $this->parse_counts( $platform_counts );
+ }
+
+ /**
+ * Setting the values for the filter
+ */
+ private function set_filter_values() {
+ $this->set_filter_value( 'access_denied', __( 'Access denied', 'wordpress-seo' ), __( 'Server requires authentication or is blocking Googlebot from accessing the site.', 'wordpress-seo' ), __( 'Show information about errors in category \'Access Denied\'', 'wordpress-seo' ) );
+ $this->set_filter_value( 'faulty_redirects', __( 'Faulty redirects', 'wordpress-seo' ) );
+ $this->set_filter_value( 'not_followed',__( 'Not followed', 'wordpress-seo' ) );
+ $this->set_filter_value( 'not_found', __( 'Not found', 'wordpress-seo' ), __( 'URL points to a non-existent page.', 'wordpress-seo' ), __( 'Show information about errors in category \'Not Found\'', 'wordpress-seo' ) );
+ $this->set_filter_value( 'other', __( 'Other', 'wordpress-seo' ), __( 'Google was unable to crawl this URL due to an undetermined issue.', 'wordpress-seo' ), __( 'Show information about errors in category \'Other\'', 'wordpress-seo' ) );
+ /* Translators: %1$s: expands to 'robots.txt'. */
+ $this->set_filter_value( 'roboted', __( 'Blocked', 'wordpress-seo' ), sprintf( __( 'Googlebot could access your site, but certain URLs are blocked for Googlebot in your %1$s file. This block could either be for all Googlebots or even specifically for Googlebot-mobile.', 'wordpress-seo' ), 'robots.txt' ), __( 'Show information about errors in category \'Blocked\'', 'wordpress-seo' ) );
+ $this->set_filter_value( 'server_error', __( 'Server Error', 'wordpress-seo' ), __( 'Request timed out or site is blocking Google.', 'wordpress-seo' ), __( 'Show information about errors in category \'Server\'', 'wordpress-seo' ) );
+ $this->set_filter_value( 'soft_404', __( 'Soft 404', 'wordpress-seo' ), __( "The target URL doesn't exist, but your server is not returning a 404 (file not found) error.", 'wordpress-seo' ), __( 'Show information about errors in category \'Soft 404\'', 'wordpress-seo' ) );
+ }
+
+ /**
+ * Add new filter value to the filter_values
+ *
+ * @param string $key Filter key.
+ * @param string $value Filter value.
+ * @param string $description Optional description string.
+ * @param string $help_button_text Optional help button text.
+ */
+ private function set_filter_value( $key, $value, $description = '', $help_button_text = '' ) {
+ $this->filter_values[ $key ] = array(
+ 'value' => $value,
+ 'description' => $description,
+ 'help-button' => $help_button_text,
+ );
+ }
+
+ /**
+ * Creates a filter link
+ *
+ * @param string $category Issue type.
+ * @param integer $count Count for the type.
+ *
+ * @return string
+ */
+ private function create_view_link( $category, $count ) {
+ $href = add_query_arg( array( 'category' => $category, 'paged' => 1 ) );
+
+ $class = 'gsc_category';
+
+ if ( $this->category === $category ) {
+ $class .= ' current';
+ }
+
+ $help_button = $help_panel = '';
+ if ( $this->filter_values[ $category ]['description'] !== '' ) {
+ $help = new WPSEO_Admin_Help_Panel( $category, $this->filter_values[ $category ]['help-button'], $this->filter_values[ $category ]['description'], 'has-wrapper' );
+ $help_button = $help->get_button_html();
+ $help_panel = $help->get_panel_html();
+ }
+
+ return sprintf(
+ '%3$s (%5$s) %6$s %7$s',
+ esc_attr( $href ),
+ $class,
+ $this->filter_values[ $category ]['value'],
+ $category,
+ $count,
+ $help_button,
+ $help_panel
+ );
+ }
+
+ /**
+ * Parsing the category counts. When there are 0 issues for a specific category, just remove that one from the array
+ *
+ * @param array $category_counts Set of counts for categories.
+ *
+ * @return mixed
+ */
+ private function parse_counts( $category_counts ) {
+ foreach ( $category_counts as $category_name => $category ) {
+ if ( $category['count'] === '0' ) {
+ unset( $category_counts[ $category_name ] );
+ }
+ }
+
+ return $category_counts;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-config.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-config.php
new file mode 100644
index 0000000..9b39644
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-config.php
@@ -0,0 +1,22 @@
+ 'Yoast SEO',
+ 'client_id' => '395430892738-ushj8aced0cji2j4bkq6bda6felaigb9.apps.googleusercontent.com',
+ 'client_secret' => 'c2kYgOwMhk1emWxQ3NaA8wOi',
+ 'redirect_uri' => 'urn:ietf:wg:oauth:2.0:oob',
+ 'scopes' => array( 'https://www.googleapis.com/auth/webmasters' ),
+ );
+
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-count.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-count.php
new file mode 100644
index 0000000..653433d
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-count.php
@@ -0,0 +1,221 @@
+service = $service;
+ }
+
+ /**
+ * Getting the counts for given platform and return them as an array
+ *
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ *
+ * @return array
+ */
+ public function get_platform_counts( $platform ) {
+ $counts = $this->get_counts();
+ if ( array_key_exists( $platform, $counts ) ) {
+ return $counts[ $platform ];
+ }
+
+ return array();
+ }
+
+ /**
+ * Return the fetched issues
+ *
+ * @return array
+ */
+ public function get_issues() {
+ return $this->issues;
+ }
+
+ /**
+ * Listing the issues an gives them back as fetched issues
+ *
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ * @param string $category Issue category.
+ */
+ public function list_issues( $platform, $category ) {
+ $counts = $this->get_counts();
+
+ if ( array_key_exists( $platform, $counts ) ) {
+ $counts[ $platform ] = $this->list_category_issues( $counts[ $platform ], $platform, $category );
+
+ // Write the new counts value.
+ $this->set_counts( $counts );
+ }
+ }
+
+ /**
+ * Getting the counts for given platform and category.
+ *
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ * @param string $category Issue type.
+ *
+ * @return integer
+ */
+ public function get_issue_count( $platform, $category ) {
+ $counts = $this->get_counts();
+
+ if ( ! empty( $counts[ $platform ][ $category ]['count'] ) ) {
+ return $counts[ $platform ][ $category ]['count'];
+ }
+
+ return 0;
+ }
+
+ /**
+ * Update the count of the issues
+ *
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ * @param string $category Issue type.
+ * @param integer $new_count Updated count.
+ */
+ public function update_issue_count( $platform, $category, $new_count ) {
+ $counts = $this->get_counts();
+
+ if ( ! empty( $counts[ $platform ][ $category ] ) && is_array( $counts[ $platform ][ $category ] ) ) {
+ $counts[ $platform ][ $category ]['count'] = $new_count;
+ }
+
+ $this->set_counts( $counts );
+ }
+
+ /**
+ * Fetching the counts from the GSC API
+ */
+ public function fetch_counts() {
+ if ( WPSEO_GSC_Settings::get_profile() && $this->get_last_fetch() <= strtotime( '-12 hours' ) ) {
+ // Remove the timestamp.
+ $this->remove_last_fetch();
+
+ // Getting the counts and parse them.
+ $counts = $this->parse_counts( $this->service->get_crawl_issue_counts() );
+
+ // Fetching the counts by setting an option.
+ $this->set_counts( $counts );
+
+ // Saving the current timestamp.
+ $this->save_last_fetch();
+ }
+ }
+
+ /**
+ * Parsing the received counts from the API and map the keys to plugin friendly values
+ *
+ * @param array $fetched_counts Set of retrieved counts.
+ *
+ * @return array
+ */
+ private function parse_counts( array $fetched_counts ) {
+ $counts = array();
+ foreach ( $fetched_counts as $platform_name => $categories ) {
+ $new_platform = WPSEO_GSC_Mapper::platform_from_api( $platform_name );
+
+ foreach ( $categories as $category_name => $category ) {
+ $new_category = WPSEO_GSC_Mapper::category_from_api( $category_name );
+ $counts[ $new_platform ][ $new_category ] = $category;
+ }
+ }
+
+ return $counts;
+ }
+
+ /**
+ * Listing the issues for current category.
+ *
+ * @param array $counts Set of counts.
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ * @param string $category Issue type.
+ *
+ * @return array
+ */
+ private function list_category_issues( array $counts, $platform, $category ) {
+ // When the issues have to be fetched.
+ if ( array_key_exists( $category, $counts ) && $counts[ $category ]['count'] > 0 && $counts[ $category ]['last_fetch'] <= strtotime( '-12 hours' ) ) {
+ if ( $issues = $this->service->fetch_category_issues( WPSEO_GSC_Mapper::platform_to_api( $platform ), WPSEO_GSC_Mapper::category_to_api( $category ) ) ) {
+ $this->issues = $issues;
+ }
+
+ // Be sure the total count is correct.
+ $counts[ $category ]['count'] = count( $this->issues );
+
+ // Set last fetch.
+ $counts[ $category ]['last_fetch'] = time();
+ }
+
+ return $counts;
+ }
+
+ /**
+ * Getting the counts from the options
+ *
+ * @return array
+ */
+ private function get_counts() {
+ return get_option( self::OPTION_CI_COUNTS, array() );
+ }
+
+ /**
+ * Fetching the counts from the service and store them in an option
+ *
+ * @param array $counts Set of counts.
+ */
+ private function set_counts( array $counts ) {
+ update_option( self::OPTION_CI_COUNTS, $counts );
+ }
+
+ /**
+ * Store the timestamp of when crawl errors were saved the last time.
+ */
+ private function save_last_fetch() {
+ add_option( self::OPTION_CI_LAST_FETCH, time(), '', 'no' );
+ }
+
+ /**
+ * Remove the last checked option
+ */
+ private function remove_last_fetch() {
+ delete_option( self::OPTION_CI_LAST_FETCH );
+ }
+
+ /**
+ * Get the timestamp of when the crawl errors were last saved
+ *
+ * @return int
+ */
+ private function get_last_fetch() {
+ return get_option( self::OPTION_CI_LAST_FETCH, 0 );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-issue.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-issue.php
new file mode 100644
index 0000000..b6ea06d
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-issue.php
@@ -0,0 +1,89 @@
+url = $url;
+ $this->first_detected = $first_detected;
+ $this->last_crawled = $last_crawled;
+ $this->response_code = $response_code;
+ }
+
+ /**
+ * Put the class properties in array
+ *
+ * @return array
+ */
+ public function to_array() {
+ return array(
+ 'url' => $this->url,
+ 'first_detected' => $this->to_date_format( $this->first_detected ),
+ 'first_detected_raw' => $this->to_timestamp( $this->first_detected ),
+ 'last_crawled' => $this->to_date_format( $this->last_crawled ),
+ 'last_crawled_raw' => $this->to_timestamp( $this->last_crawled ),
+ 'response_code' => $this->response_code,
+ );
+ }
+
+ /**
+ * Converting the date to a date format
+ *
+ * @param DateTime $date_to_convert Date instance.
+ * @param string $format Format string.
+ *
+ * @return string
+ */
+ private function to_date_format( DateTime $date_to_convert, $format = '' ) {
+
+ if ( empty( $format ) ) {
+ $format = get_option( 'date_format' );
+ }
+
+ return date_i18n( $format, $date_to_convert->format( 'U' ) );
+ }
+
+ /**
+ * Converting the date to a timestamp
+ *
+ * @param DateTime $date_to_convert Date object instance.
+ *
+ * @return string
+ */
+ private function to_timestamp( DateTime $date_to_convert ) {
+ return $date_to_convert->format( 'U' );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-issues.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-issues.php
new file mode 100644
index 0000000..40a3d4e
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-issues.php
@@ -0,0 +1,175 @@
+option_name = strtolower( 'wpseo-gsc-issues-' . $platform . '-' . $category );
+ $this->issues = $this->get_issues();
+
+ if ( ! empty( $fetched_issues ) && is_array( $fetched_issues ) ) {
+ $this->save_fetched_issues( $fetched_issues );
+ }
+ }
+ /**
+ * Getting the issues from the options.
+ *
+ * @return array
+ */
+ public function get_issues() {
+ return get_option( $this->option_name, array() );
+ }
+
+ /**
+ * Deleting the issue from the issues
+ *
+ * @param string $url URL to delete issues for.
+ *
+ * @return bool
+ */
+ public function delete_issue( $url ) {
+ $target_issue = $this->get_issue_by_url( $url );
+ if ( $target_issue !== false ) {
+ unset( $this->issues[ $target_issue ] );
+
+ $this->save_issues( $this->issues );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Fetching the issues for current category and compare them with the already existing issues.
+ *
+ * @param array $fetched_issues Set of retrieved issues.
+ */
+ private function save_fetched_issues( array $fetched_issues ) {
+ $this->set_current_issues();
+
+ $crawl_issues = $this->get_issues();
+
+ // Walk through the issues to do the comparison.
+ foreach ( $fetched_issues as $issue ) {
+ $this->issue_compare( $crawl_issues, $issue );
+ }
+
+ $this->save_issues( $crawl_issues );
+
+ // Refresh the value of $this->issues.
+ $this->issues = $this->get_issues();
+ }
+
+ /**
+ * Comparing the issue with the list of current existing issues
+ *
+ * @param array $crawl_issues Set of issues by reference.
+ * @param stdClass $issue Issue object to check against the list.
+ */
+ private function issue_compare( &$crawl_issues, $issue ) {
+ $issue->pageUrl = WPSEO_Utils::format_url( (string) $issue->pageUrl );
+
+ if ( ! in_array( $issue->pageUrl, $this->current_issues ) ) {
+ array_push(
+ $crawl_issues,
+ $this->get_issue( $this->create_issue( $issue ) )
+ );
+ }
+ }
+
+ /**
+ * The fetched issue from the API will be parsed as an WPSEO_Crawl_Issue object. After initializing the issue as an
+ * object, the object will be returned
+ *
+ * @param stdClass $issue Issue data object.
+ *
+ * @return WPSEO_GSC_Issue
+ */
+ private function create_issue( $issue ) {
+ return new WPSEO_GSC_Issue(
+ $issue->pageUrl,
+ new DateTime( (string) $issue->first_detected ),
+ new DateTime( (string) $issue->last_crawled ),
+ (string) ( ! empty( $issue->responseCode ) ) ? $issue->responseCode : null
+ );
+ }
+
+ /**
+ * Returns the crawl issue as an array.
+ *
+ * @param WPSEO_GSC_Issue $crawl_issue Issue object instance.
+ *
+ * @return array()
+ */
+ private function get_issue( WPSEO_GSC_Issue $crawl_issue ) {
+ return $crawl_issue->to_array();
+ }
+
+ /**
+ * Saving the issues to the options. The target option is base on current platform and category.
+ *
+ * @param array $issues Set of issues.
+ */
+ private function save_issues( array $issues ) {
+ update_option( $this->option_name, $issues, false );
+ }
+
+ /**
+ * Getting the issues from the options and get only the URL out of it. This is because there will be a comparison
+ * with the issues from the API.
+ */
+ private function set_current_issues() {
+ if ( ! empty( $this->issues ) ) {
+ $this->current_issues = wp_list_pluck( $this->issues, 'url' );
+ }
+ }
+
+ /**
+ * Search in the issues for the given $url
+ *
+ * @param string $url Issue URL to search for.
+ *
+ * @return int|string
+ */
+ private function get_issue_by_url( $url ) {
+ foreach ( $this->issues as $key => $issue ) {
+ if ( $url === $issue['url'] ) {
+ return $key;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-mapper.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-mapper.php
new file mode 100644
index 0000000..afaa104
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-mapper.php
@@ -0,0 +1,112 @@
+ 'web',
+ 'mobile' => 'mobile',
+ 'smartphone_only' => 'smartphoneOnly',
+ 'settings' => 'settings', // This one is basicly not a platform, but a tab.
+ );
+
+ /**
+ * The categories which can be mapped
+ *
+ * @var array
+ */
+ private static $categories = array(
+ 'access_denied' => 'authPermissions',
+ 'faulty_redirects' => 'manyToOneRedirect',
+ 'not_followed' => 'notFollowed',
+ 'not_found' => 'notFound',
+ 'other' => 'other',
+ 'roboted' => 'roboted',
+ 'server_error' => 'serverError',
+ 'soft_404' => 'soft404',
+ );
+
+ /**
+ * If there is no platform, just get the first key out of the array and redirect to it.
+ *
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ *
+ * @return mixed
+ */
+ public static function get_current_platform( $platform ) {
+ if ( $current_platform = filter_input( INPUT_GET, $platform ) ) {
+ return $current_platform;
+ }
+
+ wp_redirect( add_query_arg( $platform, key( self::$platforms ) ) );
+ exit;
+ }
+
+ /**
+ * Mapping the platform
+ *
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ *
+ * @return mixed
+ */
+ public static function platform_to_api( $platform ) {
+ if ( ! empty( $platform ) && array_key_exists( $platform, self::$platforms ) ) {
+ return self::$platforms[ $platform ];
+ }
+ }
+
+ /**
+ * Mapping the given platform by value and return its key
+ *
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ *
+ * @return string
+ */
+ public static function platform_from_api( $platform ) {
+ if ( ! empty( $platform ) && $platform = array_search( $platform, self::$platforms ) ) {
+ return $platform;
+ }
+
+ return $platform;
+ }
+
+ /**
+ * Mapping the given category by searching for its key.
+ *
+ * @param string $category Issue type.
+ *
+ * @return mixed
+ */
+ public static function category_to_api( $category ) {
+ if ( ! empty( $category ) && array_key_exists( $category, self::$categories ) ) {
+ return self::$categories[ $category ];
+ }
+
+ return $category;
+ }
+
+ /**
+ * Mapping the given category by value and return its key
+ *
+ * @param string $category Issue type.
+ *
+ * @return string
+ */
+ public static function category_from_api( $category ) {
+ if ( ! empty( $category ) && $category = array_search( $category, self::$categories ) ) {
+ return $category;
+ }
+
+ return $category;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-marker.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-marker.php
new file mode 100644
index 0000000..f8ae147
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-marker.php
@@ -0,0 +1,143 @@
+url = $url;
+ $this->result = $this->get_result();
+ }
+
+ /**
+ * Getting the response for the AJAX request
+ *
+ * @return string
+ */
+ public function get_response() {
+ return $this->result;
+ }
+
+ /**
+ * Setting the result, this method will check if current
+ *
+ * @return string
+ */
+ private function get_result() {
+ if ( $this->can_be_marked_as_fixed() ) {
+ $service = new WPSEO_GSC_Service( WPSEO_GSC_Settings::get_profile() );
+
+ if ( $this->set_crawl_issues() && $this->send_mark_as_fixed( $service ) && $this->delete_crawl_issue() ) {
+ $this->update_issue_count( $service );
+
+ return 'true';
+ }
+ }
+
+ return 'false';
+ }
+
+ /**
+ * Check if request is valid by verifying the posted nonce and return the URL if this one is set
+ *
+ * @return bool|string
+ */
+ private function can_be_marked_as_fixed() {
+ if ( $this->url !== '' ) {
+ return $this->url;
+ }
+
+ return false;
+ }
+
+ /**
+ * Storing the data belonging to the current issue, this data is needed in the 'mark as fixed' flow
+ *
+ * @return bool
+ */
+ private function set_crawl_issues() {
+ $this->platform = filter_input( INPUT_POST, 'platform' );
+ $this->category = filter_input( INPUT_POST, 'category' );
+ if ( $this->platform && $this->category ) {
+ $this->crawl_issues = new WPSEO_GSC_Issues( $this->platform, $this->category );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Sending a request to the Google Search Console API to let them know we marked an issue as fixed.
+ *
+ * @param WPSEO_GSC_Service $service Service object instance.
+ *
+ * @return bool
+ */
+ private function send_mark_as_fixed( WPSEO_GSC_Service $service ) {
+ return $service->mark_as_fixed( $this->url, $this->platform, $this->category );
+ }
+
+ /**
+ * Delete the crawl issue from the database
+ *
+ * @return bool
+ */
+ private function delete_crawl_issue() {
+ return $this->crawl_issues->delete_issue( $this->url );
+ }
+
+ /**
+ * Getting the counts for current platform - category combination and update the score of it.
+ *
+ * @param WPSEO_GSC_Service $service Service object instance.
+ */
+ private function update_issue_count( WPSEO_GSC_Service $service ) {
+ $counts = new WPSEO_GSC_Count( $service );
+
+ // Get the issues.
+ $total_issues = $counts->get_issue_count( $this->platform, $this->category );
+
+ // Lower the current count with 1.
+ $total_issues = ( $total_issues - 1 );
+
+ // And update the count.
+ $counts->update_issue_count( $this->platform, $this->category, $total_issues );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-platform-tabs.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-platform-tabs.php
new file mode 100644
index 0000000..30a988e
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-platform-tabs.php
@@ -0,0 +1,94 @@
+platform_tabs();
+ }
+
+ /**
+ * Getting the current_tab
+ *
+ * @return string
+ */
+ public function current_tab() {
+ return $this->current_tab;
+ }
+
+ /**
+ * Loops through the array with all the platforms and convert it into an array
+ *
+ * @return string
+ */
+ private function platform_tabs() {
+ $tabs = array( 'settings' => __( 'Settings', 'wordpress-seo' ) );
+
+ $platforms = array(
+ 'web' => __( 'Desktop', 'wordpress-seo' ),
+ 'smartphone_only' => __( 'Smartphone', 'wordpress-seo' ),
+ 'mobile' => __( 'Feature phone', 'wordpress-seo' ),
+ );
+
+ if ( WPSEO_GSC_Settings::get_profile() !== '' ) {
+ $tabs = array_merge( $platforms, $tabs );
+ }
+
+ $admin_link = admin_url( 'admin.php?page=wpseo_search_console&tab=' );
+
+ $this->set_current_tab( $tabs );
+
+ $return = '';
+
+ foreach ( $tabs as $platform_target => $platform_value ) {
+ $return .= $this->platform_tab( $platform_target, $platform_value, $admin_link );
+ }
+
+ return $return;
+ }
+
+ /**
+ * Setting the current tab
+ *
+ * @param array $platforms Set of platforms (desktop, mobile, feature phone).
+ */
+ private function set_current_tab( array $platforms ) {
+ $this->current_tab = key( $platforms );
+ if ( $current_platform = filter_input( INPUT_GET, 'tab' ) ) {
+ $this->current_tab = $current_platform;
+ }
+ }
+
+ /**
+ * Parses the tab
+ *
+ * @param string $platform_target Platform (desktop, mobile, feature phone).
+ * @param string $platform_value Link anchor.
+ * @param string $admin_link Link URL admin base.
+ *
+ * @return string
+ */
+ private function platform_tab( $platform_target, $platform_value, $admin_link ) {
+ $active = '';
+ if ( $this->current_tab === $platform_target ) {
+ $active = ' nav-tab-active';
+ }
+
+ return '' . $platform_value . '';
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-service.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-service.php
new file mode 100644
index 0000000..57e3897
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-service.php
@@ -0,0 +1,192 @@
+profile = $profile;
+
+ $this->set_client();
+ }
+
+ /**
+ * Returns the client
+ *
+ * @return Yoast_Api_Google_Client
+ */
+ public function get_client() {
+ return $this->client;
+ }
+
+ /**
+ * Removes the option and calls the clients clear_data method to clear that one as well
+ */
+ public function clear_data() {
+ // Clear client data.
+ $this->client->clear_data();
+ }
+
+ /**
+ * Get all sites that are registered in the GSC panel
+ *
+ * @return array
+ */
+ public function get_sites() {
+ $sites = array();
+
+ $response_json = $this->client->do_request( 'sites', true );
+
+ // Do list sites request.
+ if ( ! empty( $response_json->siteEntry ) ) {
+ foreach ( $response_json->siteEntry as $entry ) {
+ $sites[ str_ireplace( 'sites/', '', (string) $entry->siteUrl ) ] = (string) $entry->siteUrl;
+ }
+
+ // Sorting the retrieved sites.
+ asort( $sites );
+ }
+
+ return $sites;
+ }
+
+ /**
+ * Get crawl issues
+ *
+ * @return array
+ */
+ public function get_crawl_issue_counts() {
+ // Setup crawl error list.
+ $crawl_error_counts = $this->get_crawl_error_counts( $this->profile );
+
+ $return = array();
+ if ( ! empty( $crawl_error_counts->countPerTypes ) ) {
+ foreach ( $crawl_error_counts->countPerTypes as $category ) {
+ $return[ $category->platform ][ $category->category ] = array(
+ 'count' => $category->entries[0]->count,
+ 'last_fetch' => null,
+ );
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * Sending request to mark issue as fixed
+ *
+ * @param string $url Issue URL.
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ * @param string $category Issue type.
+ *
+ * @return bool
+ */
+ public function mark_as_fixed( $url, $platform, $category ) {
+ $response = $this->client->do_request( 'sites/' . urlencode( $this->profile ) . '/urlCrawlErrorsSamples/' . urlencode( ltrim( $url, '/' ) ) . '?category=' . WPSEO_GSC_Mapper::category_to_api( $category ) . '&platform=' . WPSEO_GSC_Mapper::platform_to_api( $platform ) . '', false, 'DELETE' );
+ return ( $response->getResponseHttpCode() === 204 );
+ }
+
+ /**
+ * Fetching the issues from the GSC API
+ *
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ * @param string $category Issue type.
+ *
+ * @return mixed
+ */
+ public function fetch_category_issues( $platform, $category ) {
+ $issues = $this->client->do_request(
+ 'sites/' . urlencode( $this->profile ) . '/urlCrawlErrorsSamples?category=' . $category . '&platform=' . $platform,
+ true
+ );
+
+ if ( ! empty( $issues->urlCrawlErrorSample ) ) {
+ return $issues->urlCrawlErrorSample;
+ }
+ }
+
+ /**
+ * Setting the GSC client
+ */
+ private function set_client() {
+ try {
+ new Yoast_Api_Libs( '2.0' );
+ }
+ catch ( Exception $exception ) {
+ if ( $exception->getMessage() === 'required_version' ) {
+ $this->incompatible_api_libs(
+ __( 'Yoast plugins share some code between them to make your site faster. As a result of that, we need all Yoast plugins to be up to date. We\'ve detected this isn\'t the case, so please update the Yoast plugins that aren\'t up to date yet.', 'wordpress-seo' )
+ );
+ }
+ }
+
+ if ( class_exists( 'Yoast_Api_Google_Client' ) === false ) {
+ $this->incompatible_api_libs(
+ /* translators: %1$s expands to Yoast SEO, %2$s expands to Google Analytics by Yoast */
+ sprintf(
+ __(
+ '%1$s detected you’re using a version of %2$s which is not compatible with %1$s. Please update %2$s to the latest version to use this feature.',
+ 'wordpress-seo'
+ ),
+ 'Yoast SEO',
+ 'Google Analytics by Yoast'
+ )
+ );
+
+ wp_redirect( admin_url( 'admin.php?page=' . WPSEO_Admin::PAGE_IDENTIFIER ) );
+ exit;
+ }
+
+ $this->client = new Yoast_Api_Google_Client( WPSEO_GSC_Config::$gsc, 'wpseo-gsc', 'https://www.googleapis.com/webmasters/v3/' );
+ }
+
+ /**
+ * Adding notice that the api libs has the wrong version
+ *
+ * @param string $notice Message string.
+ */
+ private function incompatible_api_libs( $notice ) {
+ Yoast_Notification_Center::get()->add_notification(
+ new Yoast_Notification( $notice, array( 'type' => Yoast_Notification::ERROR ) )
+ );
+ }
+
+ /**
+ * Getting the crawl error counts
+ *
+ * @param string $profile Profile name string.
+ *
+ * @return object|bool
+ */
+ private function get_crawl_error_counts( $profile ) {
+ $crawl_error_counts = $this->client->do_request(
+ 'sites/' . urlencode( $profile ) . '/urlCrawlErrorsCounts/query',
+ true
+ );
+
+ if ( ! empty( $crawl_error_counts ) ) {
+ return $crawl_error_counts;
+ }
+
+ return false;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-settings.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-settings.php
new file mode 100644
index 0000000..1a3f343
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-settings.php
@@ -0,0 +1,102 @@
+clear_data();
+ }
+
+ /**
+ * Reloading all the issues
+ */
+ public static function reload_issues() {
+ // Remove issue and issue counts.
+ self::remove();
+ }
+
+ /**
+ * When authorization is successful return true, otherwise false
+ *
+ * @param string $authorization_code Code to validate.
+ * @param Yoast_Api_Google_Client $client Client object instance.
+ *
+ * @return bool
+ */
+ public static function validate_authorization( $authorization_code, Yoast_Api_Google_Client $client ) {
+ return ( $authorization_code !== '' && $client->authenticate_client( $authorization_code ) );
+ }
+
+ /**
+ * Get the GSC profile
+ *
+ * @return string
+ */
+ public static function get_profile() {
+ // Get option.
+ $option = get_option( WPSEO_GSC::OPTION_WPSEO_GSC, array( 'profile' => '' ) );
+
+ // Set the profile.
+ $profile = '';
+ if ( ! empty( $option['profile'] ) ) {
+ $profile = $option['profile'];
+ }
+
+ // Return the profile.
+ return trim( $profile, '/' );
+ }
+
+ /**
+ * Removes the issue counts and all the issues from the options
+ */
+ private static function remove() {
+ // Remove the issue counts from the options.
+ self::remove_issue_counts();
+
+ // Removing all issues from the database.
+ self::remove_issues();
+ }
+
+ /**
+ * Remove the issue counts
+ */
+ private static function remove_issue_counts() {
+ // Remove the options which are holding the counts.
+ delete_option( WPSEO_GSC_Count::OPTION_CI_COUNTS );
+ delete_option( WPSEO_GSC_Count::OPTION_CI_LAST_FETCH );
+ }
+
+ /**
+ * Delete the issues and their meta data from the database
+ */
+ private static function remove_issues() {
+ global $wpdb;
+
+ // Remove local crawl issues by running a delete query.
+ $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE 'wpseo-gsc-issues-%'" );
+ }
+
+ /**
+ * Removes the options for GSC
+ */
+ private static function remove_gsc_option() {
+ delete_option( WPSEO_GSC::OPTION_WPSEO_GSC );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-table.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-table.php
new file mode 100644
index 0000000..01ae5c2
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc-table.php
@@ -0,0 +1,385 @@
+ 300,
+ 'no_premium' => 140,
+ 'already_exists' => 160,
+ );
+
+ /**
+ * Search Console table class constructor (subclasses list table).
+ *
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ * @param string $category Type of the issues.
+ * @param array $items Set of the issues to display.
+ */
+ public function __construct( $platform, $category, array $items ) {
+ parent::__construct();
+
+ // Adding the thickbox.
+ add_thickbox();
+
+ // Set search string.
+ if ( ( $search_string = filter_input( INPUT_GET, 's' ) ) != '' ) {
+ $this->search_string = $search_string;
+ }
+
+ $this->current_view = $category;
+
+ // Set the crawl issue source.
+ $this->show_fields( $platform );
+
+ $this->items = $items;
+ }
+
+ /**
+ * Getting the screen id from this table
+ *
+ * @return string
+ */
+ public function get_screen_id() {
+ return $this->screen->id;
+ }
+
+ /**
+ * Setup the table variables, fetch the items from the database, search, sort and format the items.
+ */
+ public function prepare_items() {
+ // Get variables needed for pagination.
+ $this->per_page = $this->get_items_per_page( 'errors_per_page', $this->per_page );
+ $this->current_page = intval( ( $paged = filter_input( INPUT_GET, 'paged' ) ) ? $paged : 1 );
+
+ $this->setup_columns();
+ $this->views();
+ $this->parse_items();
+ }
+
+ /**
+ * Set the table columns
+ *
+ * @return array
+ */
+ public function get_columns() {
+ $columns = array(
+ 'cb' => '',
+ 'url' => __( 'URL', 'wordpress-seo' ),
+ 'last_crawled' => __( 'Last crawled', 'wordpress-seo' ),
+ 'first_detected' => __( 'First detected', 'wordpress-seo' ),
+ 'response_code' => __( 'Response code', 'wordpress-seo' ),
+ );
+
+ return $columns;
+ }
+
+ /**
+ * Return the columns that are sortable
+ *
+ * @return array
+ */
+ protected function get_sortable_columns() {
+ $sortable_columns = array(
+ 'url' => array( 'url', false ),
+ 'last_crawled' => array( 'last_crawled', false ),
+ 'first_detected' => array( 'first_detected', false ),
+ 'response_code' => array( 'response_code', false ),
+ );
+
+ return $sortable_columns;
+ }
+
+ /**
+ * Return available bulk actions
+ *
+ * @return array
+ */
+ protected function get_bulk_actions() {
+ return array(
+ 'mark_as_fixed' => __( 'Mark as fixed', 'wordpress-seo' ),
+ );
+ }
+
+ /**
+ * Default method to display a column
+ *
+ * @param array $item Data array.
+ * @param string $column_name Column name key.
+ *
+ * @return mixed
+ */
+ protected function column_default( $item, $column_name ) {
+ return $item[ $column_name ];
+ }
+
+ /**
+ * Checkbox column
+ *
+ * @param array $item Item data array.
+ *
+ * @return string
+ */
+ protected function column_cb( $item ) {
+ return sprintf(
+ '', $item['url']
+ );
+ }
+
+ /**
+ * Formatting the output of the column last crawled into a dateformat
+ *
+ * @param array $item Item data array.
+ *
+ * @return string
+ */
+ protected function column_last_crawled( $item ) {
+ return date_i18n( get_option( 'date_format' ), strtotime( $item['last_crawled'] ) );
+ }
+
+ /**
+ * Formatting the output of the column first detected into a dateformat
+ *
+ * @param array $item Item data array.
+ *
+ * @return string
+ */
+ protected function column_first_detected( $item ) {
+ return date_i18n( get_option( 'date_format' ), strtotime( $item['first_detected'] ) );
+ }
+
+ /**
+ * URL column
+ *
+ * @param array $item Item data array.
+ *
+ * @return string
+ */
+ protected function column_url( $item ) {
+ $actions = array();
+
+ if ( $this->can_create_redirect() ) {
+ /**
+ * Modal box
+ */
+ $modal_height = $this->modal_box( $item['url'] );
+
+ $actions['create_redirect'] = '' . __( 'Create redirect', 'wordpress-seo' ) . '';
+ }
+
+ $actions['view'] = '' . __( 'View', 'wordpress-seo' ) . '';
+ $actions['markasfixed'] = '' . __( 'Mark as fixed', 'wordpress-seo' ) . '';
+
+ return sprintf(
+ '%1$s %2$s',
+ $item['url'],
+ $this->row_actions( $actions )
+ );
+ }
+
+ /**
+ * Running the setup of the columns
+ */
+ private function setup_columns() {
+ $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
+ }
+
+ /**
+ * Check if the current category allow creating redirects
+ *
+ * @return bool
+ */
+ private function can_create_redirect() {
+ return in_array( $this->current_view, array( 'soft_404', 'not_found', 'access_denied' ) );
+ }
+
+ /**
+ * Setting the table navigation
+ *
+ * @param int $total_items Total number of items.
+ * @param int $posts_per_page Number of items per page.
+ */
+ private function set_pagination( $total_items, $posts_per_page ) {
+ $this->set_pagination_args( array(
+ 'total_items' => $total_items,
+ 'total_pages' => ceil( ( $total_items / $posts_per_page ) ),
+ 'per_page' => $posts_per_page,
+ ) );
+ }
+
+ /**
+ * Setting the items
+ */
+ private function parse_items() {
+ if ( is_array( $this->items ) && count( $this->items ) > 0 ) {
+ if ( ! empty( $this->search_string ) ) {
+ $this->do_search();
+ }
+
+ $this->set_pagination( count( $this->items ), $this->per_page );
+
+ $this->sort_items();
+ $this->paginate_items();
+ }
+ }
+
+ /**
+ * Search through the items
+ */
+ private function do_search() {
+ $results = array();
+
+ foreach ( $this->items as $item ) {
+ foreach ( $item as $value ) {
+ if ( stristr( $value, $this->search_string ) !== false ) {
+ $results[] = $item;
+ continue;
+ }
+ }
+ }
+
+ $this->items = $results;
+ }
+
+ /**
+ * Running the pagination
+ */
+ private function paginate_items() {
+ // Setting the starting point. If starting point is below 1, overwrite it with value 0, otherwise it will be sliced of at the back.
+ $slice_start = ( $this->current_page - 1 );
+ if ( $slice_start < 0 ) {
+ $slice_start = 0;
+ }
+
+ // Apply 'pagination'.
+ $this->items = array_slice( $this->items, ( $slice_start * $this->per_page ), $this->per_page );
+ }
+
+ /**
+ * Sort the items by callback
+ */
+ private function sort_items() {
+ // Sort the results.
+ usort( $this->items, array( $this, 'do_reorder' ) );
+ }
+
+ /**
+ * Doing the sorting of the issues
+ *
+ * @param array $a First data set for comparison.
+ * @param array $b Second data set for comparison.
+ *
+ * @return int
+ */
+ private function do_reorder( $a, $b ) {
+ // If no sort, default to title.
+ $orderby = ( $orderby = filter_input( INPUT_GET, 'orderby' ) ) ? $orderby : 'url';
+
+ // If no order, default to asc.
+ $order = ( $order = filter_input( INPUT_GET, 'order' ) ) ? $order : 'asc';
+
+ // When there is a raw field of it, sort by this field.
+ if ( array_key_exists( $orderby . '_raw', $a ) && array_key_exists( $orderby . '_raw', $b ) ) {
+ $orderby = $orderby . '_raw';
+ }
+
+ // Determine sort order.
+ $result = strcmp( $a[ $orderby ], $b[ $orderby ] );
+
+ // Send final sort direction to usort.
+ return ( $order === 'asc' ) ? $result : ( - $result );
+ }
+
+ /**
+ * Modal box
+ *
+ * @param string $url URL string.
+ *
+ * @return string
+ */
+ private function modal_box( $url ) {
+ $current_redirect = false;
+ $view_type = $this->modal_box_type( $url, $current_redirect );
+
+ require WPSEO_PATH . '/admin/google_search_console/views/gsc-create-redirect.php';
+
+ return $view_type;
+ }
+
+ /**
+ * Determine which model box type should be rendered
+ *
+ * @param string $url URL string.
+ * @param string $current_redirect Current redirect by reference.
+ *
+ * @return string
+ */
+ private function modal_box_type( $url, &$current_redirect ) {
+ if ( defined( 'WPSEO_PREMIUM_FILE' ) && class_exists( 'WPSEO_Redirect_Manager' ) ) {
+ static $redirect_manager;
+
+ if ( ! $redirect_manager ) {
+ $redirect_manager = new WPSEO_Redirect_Manager();
+ }
+
+ if ( $current_redirect = $redirect_manager->get_redirect( $url ) ) {
+ return 'already_exists';
+ }
+
+ return 'create';
+ }
+
+ return 'no_premium';
+ }
+
+
+ /**
+ * Showing the hidden fields used by the AJAX requests
+ *
+ * @param string $platform Platform (desktop, mobile, feature phone).
+ */
+ private function show_fields( $platform ) {
+ echo "";
+ echo "";
+ echo "";
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc.php b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc.php
new file mode 100644
index 0000000..b3979f5
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/google_search_console/class-gsc.php
@@ -0,0 +1,310 @@
+set_hooks();
+ $this->set_dependencies();
+ $this->request_handler();
+ }
+
+ add_action( 'admin_init', array( $this, 'register_gsc_notification' ) );
+ add_action( 'admin_init', array( $this, 'register_settings' ) );
+ }
+
+ /**
+ * If the Google Search Console has no credentials, add a notification for the user to give him a heads up. This message is dismissable.
+ */
+ public function register_gsc_notification() {
+
+ $notification = $this->get_profile_notification();
+ $notification_center = Yoast_Notification_Center::get();
+
+ if ( WPSEO_GSC_Settings::get_profile() === '' ) {
+ $notification_center->add_notification( $notification );
+ }
+ else {
+ $notification_center->remove_notification( $notification );
+ }
+ }
+
+ /**
+ * Builds the notification used when GSC is not connected to a profile
+ *
+ * @return Yoast_Notification
+ */
+ private function get_profile_notification() {
+ return new Yoast_Notification(
+ sprintf(
+ __( 'Don\'t miss your crawl errors: %1$sconnect with Google Search Console here%2$s.', 'wordpress-seo' ),
+ '',
+ ''
+ ),
+ array(
+ 'type' => Yoast_Notification::WARNING,
+ 'id' => 'wpseo-dismiss-gsc',
+ 'capabilities' => 'manage_options',
+ )
+ );
+ }
+
+ /**
+ * Be sure the settings will be registered, so data can be stored
+ */
+ public function register_settings() {
+ register_setting( 'yoast_wpseo_gsc_options', self::OPTION_WPSEO_GSC );
+ }
+
+ /**
+ * Function that outputs the redirect page
+ */
+ public function display() {
+ require_once WPSEO_PATH . '/admin/google_search_console/views/gsc-display.php';
+ }
+
+ /**
+ * Display the table
+ */
+ public function display_table() {
+ // The list table.
+ $list_table = new WPSEO_GSC_Table( $this->platform, $this->category, $this->issue_fetch->get_issues() );
+
+ // Adding filter to display the category filters.
+ add_filter( 'views_' . $list_table->get_screen_id(), array( $this->category_filter, 'as_array' ) );
+
+ // Preparing and displaying the table.
+ $list_table->prepare_items();
+ $list_table->search_box( __( 'Search', 'wordpress-seo' ), 'wpseo-crawl-issues-search' );
+ $list_table->display();
+ }
+
+ /**
+ * Load the admin redirects scripts
+ */
+ public function page_scripts() {
+
+ $asset_manager = new WPSEO_Admin_Asset_Manager();
+ $asset_manager->enqueue_script( 'admin-gsc' );
+ $asset_manager->enqueue_style( 'metabox-css' );
+ add_screen_option( 'per_page', array(
+ 'label' => __( 'Crawl errors per page', 'wordpress-seo' ),
+ 'default' => 50,
+ 'option' => 'errors_per_page',
+ ) );
+ }
+
+ /**
+ * Set the screen options
+ *
+ * @param string $status Status string.
+ * @param string $option Option key.
+ * @param string $value Value to return.
+ *
+ * @return mixed
+ */
+ public function set_screen_option( $status, $option, $value ) {
+ if ( 'errors_per_page' == $option ) {
+ return $value;
+ }
+ }
+
+ /**
+ * Setting the hooks to be load on page request
+ */
+ private function set_hooks() {
+ add_action( 'admin_enqueue_scripts', array( $this, 'page_scripts' ) );
+ add_filter( 'set-screen-option', array( $this, 'set_screen_option' ), 11, 3 );
+ }
+
+ /**
+ * Handles the POST and GET requests
+ */
+ private function request_handler() {
+
+ // List the table search post to a get.
+ $this->list_table_search_post_to_get();
+
+ // Catch the authorization code POST.
+ $this->catch_authentication_post();
+
+ // Is there a reset post than we will remove the posts and data.
+ if ( filter_input( INPUT_GET, 'gsc_reset' ) ) {
+ // Clear the google data.
+ WPSEO_GSC_Settings::clear_data( $this->service );
+
+ // Adding notification to the notification center.
+ /* Translators: %1$s: expands to Google Search Console. */
+ $this->add_notification( sprintf( __( 'The %1$s data has been removed. You will have to reauthenticate if you want to retrieve the data again.', 'wordpress-seo' ), 'Google Search Console' ), Yoast_Notification::UPDATED );
+
+ // Directly output the notifications.
+ wp_redirect( remove_query_arg( 'gsc_reset' ) );
+ exit;
+ }
+
+ // Reloads al the issues.
+ if ( wp_verify_nonce( filter_input( INPUT_POST, 'reload-crawl-issues-nonce' ), 'reload-crawl-issues' ) && filter_input( INPUT_POST, 'reload-crawl-issues' ) ) {
+ // Reloading all the issues.
+ WPSEO_GSC_Settings::reload_issues();
+
+ // Adding the notification.
+ $this->add_notification( __( 'The issues have been successfully reloaded!', 'wordpress-seo' ), Yoast_Notification::UPDATED );
+
+ // Directly output the notifications.
+ Yoast_Notification_Center::get()->display_notifications();
+ }
+
+ // Catch bulk action request.
+ new WPSEO_GSC_Bulk_Action();
+ }
+
+ /**
+ * Catch the redirects search post and redirect it to a search get
+ */
+ private function list_table_search_post_to_get() {
+ $search_string = filter_input( INPUT_POST, 's' );
+
+ if ( $search_string === null ) {
+ return;
+ }
+
+ // When there is nothing being search and there is no search param in the url, break this method.
+ if ( $search_string === '' && filter_input( INPUT_GET, 's' ) === null ) {
+ return;
+ }
+
+ $url = ( $search_string !== '' ) ? add_query_arg( 's', $search_string ) : remove_query_arg( 's' );
+
+ // Do the redirect.
+ wp_redirect( $url );
+ exit;
+
+ }
+
+ /**
+ * Catch the authentication post
+ */
+ private function catch_authentication_post() {
+ $gsc_values = filter_input( INPUT_POST, 'gsc', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
+ // Catch the authorization code POST.
+ if ( ! empty( $gsc_values['authorization_code'] ) && wp_verify_nonce( $gsc_values['gsc_nonce'], 'wpseo-gsc_nonce' ) ) {
+ if ( ! WPSEO_GSC_Settings::validate_authorization( trim( $gsc_values['authorization_code'] ), $this->service->get_client() ) ) {
+ $this->add_notification( __( 'Incorrect Google Authorization Code.', 'wordpress-seo' ), Yoast_Notification::ERROR );
+ }
+
+ // Redirect user to prevent a post resubmission which causes an oauth error.
+ wp_redirect( admin_url( 'admin.php' ) . '?page=' . esc_attr( filter_input( INPUT_GET, 'page' ) ) . '&tab=settings' );
+ exit;
+ }
+ }
+
+ /**
+ * Adding notification to the yoast notification center
+ *
+ * @param string $message Message string.
+ * @param string $type Message type.
+ */
+ private function add_notification( $message, $type ) {
+ Yoast_Notification_Center::get()->add_notification(
+ new Yoast_Notification( $message, array( 'type' => $type ) )
+ );
+ }
+
+ /**
+ * Setting dependencies which will be used one this page
+ */
+ private function set_dependencies() {
+ // Setting the service object.
+ $this->service = new WPSEO_GSC_Service( WPSEO_GSC_Settings::get_profile() );
+
+ // Setting the platform.
+ $this->platform = WPSEO_GSC_Mapper::get_current_platform( 'tab' );
+
+ // Loading the issue counter.
+ $issue_count = new WPSEO_GSC_Count( $this->service );
+ $issue_count->fetch_counts();
+
+ // Loading the category filters.
+ $this->category_filter = new WPSEO_GSC_Category_Filters( $issue_count->get_platform_counts( $this->platform ) );
+
+ // Setting the current category.
+ $this->category = $this->category_filter->get_category();
+
+ // Listing the issues.
+ $issue_count->list_issues( $this->platform, $this->category );
+
+ // Fetching the issues.
+ $this->issue_fetch = new WPSEO_GSC_Issues( $this->platform, $this->category, $issue_count->get_issues() );
+ }
+
+ /**
+ * Setting the tab help on top of the screen
+ */
+ public function set_help() {
+ $screen = get_current_screen();
+
+ $screen->add_help_tab(
+ array(
+ 'id' => 'basic-help',
+ 'title' => __( 'Issue categories', 'wordpress-seo' ),
+ 'content' => '
' . __( 'Desktop', 'wordpress-seo' ) . ' ' . __( 'Errors that occurred when your site was crawled by Googlebot.', 'wordpress-seo' ) . '
'
+ . '
' . __( 'Smartphone', 'wordpress-seo' ) . ' ' . __( 'Errors that occurred only when your site was crawled by Googlebot-Mobile (errors didn\'t appear for desktop).', 'wordpress-seo' ) . '
'
+ . '
' . __( 'Feature phone', 'wordpress-seo' ) . ' ' . __( 'Errors that only occurred when your site was crawled by Googlebot for feature phones (errors didn\'t appear for desktop).', 'wordpress-seo' ) . '
+ ', __( 'Redirect this broken URL and fix the error', 'wordpress-seo' ), '';
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ' onclick='wpseo_gsc_post_redirect( jQuery( this ) );' />
+
+
+ ', __( 'Error: a redirect for this URL already exists', 'wordpress-seo' ), '';
+ echo '
';
+
+ /* Translators: %1$s: expands to the current URL and %2$s expands to URL the redirects points to. */
+ echo sprintf(
+ __( 'You do not have to create a redirect for URL %1$s because a redirect already exists. The existing redirect points to %2$s. If this is fine you can mark this issue as fixed. If not, please go to the redirects page and change the target URL.', 'wordpress-seo' ),
+ $url,
+ $current_redirect
+ );
+ echo '
';
+ echo '';
+ break;
+
+ case 'no_premium' :
+ /* Translators: %s: expands to Yoast SEO Premium */
+ echo '
', sprintf( __( 'Creating redirects is a %s feature', 'wordpress-seo' ), 'Yoast SEO Premium' ), '
';
+ echo '
';
+ /* Translators: %1$s: expands to 'Yoast SEO Premium', %2$s: links to Yoast SEO Premium plugin page. */
+ echo sprintf(
+ __( 'To be able to create a redirect and fix this issue, you need %1$s. You can buy the plugin, including one year of support and updates, on %2$s.', 'wordpress-seo' ),
+ 'Yoast SEO Premium',
+ 'yoast.com'
+ );
+ echo '
+
+service->get_client()->getAccessToken() ) {
+ $video_url = 'https://yoa.st/screencast-search-console';
+}
+else {
+ $video_url = 'https://yoa.st/screencast-connect-search-console';
+}
+
+$tab = new WPSEO_Option_Tab( 'GSC', __( 'Google Search Console' ), array( 'video_url' => $video_url ) );
+$GSCHelpCenter = new WPSEO_Help_Center( 'google-search-console', $tab );
+$GSCHelpCenter->output_help_center();
+
+switch ( $platform_tabs->current_tab() ) {
+ case 'settings' :
+ // Check if there is an access token.
+ if ( null === $this->service->get_client()->getAccessToken() ) {
+ // Print auth screen.
+ echo '
';
+ /* Translators: %1$s: expands to Yoast SEO, %2$s expands to Google Search Console. */
+ echo sprintf( __( 'To allow %1$s to fetch your %2$s information, please enter your Google Authorization Code. Clicking the button below will open a new window.', 'wordpress-seo' ), 'Yoast SEO', 'Google Search Console' );
+ echo "
\n";
+ echo '';
+ echo "\n";
+
+ echo '
' . __( 'Enter your Google Authorization Code and press the Authenticate button.', 'wordpress-seo' ) . "
';
+
+ }
+ else {
+ echo "';
+ }
+ }
+ break;
+
+ default :
+ $form_action_url = add_query_arg( 'page', esc_attr( filter_input( INPUT_GET, 'page' ) ) );
+
+ get_current_screen()->set_screen_reader_content( array(
+ // There are no views links in this screen, so no need for the views heading.
+ 'heading_views' => null,
+ 'heading_pagination' => __( 'Crawl issues list navigation', 'wordpress-seo' ),
+ 'heading_list' => __( 'Crawl issues list', 'wordpress-seo' ),
+ ) );
+
+ // Open \n";
+
+ break;
+}
+?>
+
+admin_footer( false );
diff --git a/wp-content/plugins/wordpress-seo/admin/import/class-import-aioseo-hooks.php b/wp-content/plugins/wordpress-seo/admin/import/class-import-aioseo-hooks.php
new file mode 100644
index 0000000..739eccf
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/import/class-import-aioseo-hooks.php
@@ -0,0 +1,39 @@
+ wp_create_nonce( 'wpseo-import' ) ), admin_url( 'admin.php?page=wpseo_tools&tool=import-export&import=1&importaioseo=1#top#import-seo' ) );
+ echo '
', sprintf( esc_html__( 'The plugin All-In-One-SEO has been detected. Do you want to %simport its settings%s?', 'wordpress-seo' ), sprintf( '', esc_url( $url ) ), '' ), '
';
+ }
+
+ /**
+ * Throw a notice to inform the user that the plugin has been deactivated
+ *
+ * @since 3.0
+ */
+ public function show_deactivate_notice() {
+ echo '
', esc_html__( 'All-In-One-SEO has been deactivated', 'wordpress-seo' ), '
';
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/import/class-import-hooks.php b/wp-content/plugins/wordpress-seo/admin/import/class-import-hooks.php
new file mode 100644
index 0000000..7c59f32
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/import/class-import-hooks.php
@@ -0,0 +1,89 @@
+is_active() ) {
+ $this->show_import_message();
+ $this->show_deactivate_message();
+ }
+ }
+
+ /**
+ * Handle deactivation & import of the data data
+ *
+ * @since 3.0
+ */
+ public function show_import_message() {
+ if ( filter_input( INPUT_GET, 'tool' ) !== 'import-export' ) {
+ add_action( 'admin_notices', array( $this, 'show_import_settings_notice' ) );
+ }
+ }
+
+ /**
+ * Handle deactivation of the plugin
+ *
+ * @since 3.0
+ */
+ public function show_deactivate_message() {
+ if ( filter_input( INPUT_GET, $this->deactivation_listener ) === '1' ) {
+ // Deactivate AIO.
+ deactivate_plugins( $this->plugin_file );
+
+ // Show notice that aioseo has been deactivated.
+ add_action( 'admin_notices', array( $this, 'show_deactivate_notice' ) );
+
+ // Clean up the referrer url for later use.
+ if ( isset( $_SERVER['REQUEST_URI'] ) ) {
+ $_SERVER['REQUEST_URI'] = remove_query_arg( array( $this->deactivation_listener ), sanitize_text_field( $_SERVER['REQUEST_URI'] ) );
+ }
+ }
+ }
+
+ /**
+ * Check if the plugin is active.
+ *
+ * @return bool
+ */
+ protected function is_active() {
+ return is_plugin_active( $this->plugin_file );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/import/class-import-wpseo-hooks.php b/wp-content/plugins/wordpress-seo/admin/import/class-import-wpseo-hooks.php
new file mode 100644
index 0000000..a37ba99
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/import/class-import-wpseo-hooks.php
@@ -0,0 +1,39 @@
+ wp_create_nonce( 'wpseo-import' ) ), admin_url( 'admin.php?page=wpseo_tools&tool=import-export&import=1&importwpseo=1#top#import-seo' ) );
+ echo '
', sprintf( esc_html__( 'The plugin wpSEO has been detected. Do you want to %simport its settings%s?', 'wordpress-seo' ), sprintf( '', esc_url( $url ) ), '' ), '
';
+ }
+
+ /**
+ * Throw a notice to inform the user wpSEO has been deactivated
+ *
+ * @since 3.0
+ */
+ public function show_deactivate_notice() {
+ echo '
', esc_html__( 'wpSEO has been deactivated', 'wordpress-seo' ), '
';
+
+ printf( $html, esc_attr( $this->name ), $this->tab_links(), $this->tab_content() );
+ }
+ }
+
+ /**
+ * Add a `WPSEO_Metabox_Tab` object to the tabs.
+ *
+ * @param WPSEO_Metabox_Tab $tab Tab to add.
+ */
+ public function add_tab( WPSEO_Metabox_Tab $tab ) {
+ $this->tabs[] = $tab;
+ }
+
+ /**
+ * Checks if any tabs have been added to the section.
+ *
+ * @return bool
+ */
+ protected function has_tabs() {
+ return ! empty( $this->tabs );
+ }
+
+ /**
+ * Concatenates all tabs' links into one html string.
+ *
+ * @return string
+ */
+ private function tab_links() {
+ $links = '';
+ foreach ( $this->tabs as $tab ) {
+ $links .= $tab->link();
+ }
+ return $links;
+ }
+
+ /**
+ * Concatenates all tabs' content into one html string.
+ *
+ * @return string
+ */
+ private function tab_content() {
+ $content = '';
+ foreach ( $this->tabs as $tab ) {
+ $content .= $tab->content();
+ }
+ return $content;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/admin/metabox/class-metabox.php b/wp-content/plugins/wordpress-seo/admin/metabox/class-metabox.php
new file mode 100644
index 0000000..7ab67c2
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/metabox/class-metabox.php
@@ -0,0 +1,1682 @@
+options = WPSEO_Options::get_options( array( 'wpseo', 'wpseo_social' ) );
+
+ // Check if one of the social settings is checked in the options, if so, initialize the social_admin object.
+ if ( $this->options['opengraph'] === true || $this->options['twitter'] === true ) {
+ $this->social_admin = new WPSEO_Social_Admin( $this->options );
+ }
+
+ $this->editor = new WPSEO_Metabox_Editor();
+ $this->editor->register_hooks();
+
+ $this->analysis_seo = new WPSEO_Metabox_Analysis_SEO();
+ $this->analysis_readability = new WPSEO_Metabox_Analysis_Readability();
+ }
+
+ /**
+ * Translate text strings for use in the meta box
+ *
+ * IMPORTANT: if you want to add a new string (option) somewhere, make sure you add that array key to
+ * the main meta box definition array in the class WPSEO_Meta() as well!!!!
+ */
+ public static function translate_meta_boxes() {
+ self::$meta_fields['general']['snippetpreview']['title'] = __( 'Snippet editor', 'wordpress-seo' );
+ self::$meta_fields['general']['snippetpreview']['help'] = sprintf( __( 'This is a rendering of what this post might look like in Google\'s search results. %sLearn more about the Snippet Preview%s.', 'wordpress-seo' ), '', '' );
+ self::$meta_fields['general']['snippetpreview']['help-button'] = __( 'Show information about the snippet editor', 'wordpress-seo' );
+
+ self::$meta_fields['general']['pageanalysis']['title'] = __( 'Analysis', 'wordpress-seo' );
+ self::$meta_fields['general']['pageanalysis']['help'] = sprintf( __( 'This is the content analysis, a collection of content checks that analyze the content of your page. %sLearn more about the Content Analysis Tool%s.', 'wordpress-seo' ), '', '' );
+ self::$meta_fields['general']['pageanalysis']['help-button'] = __( 'Show information about the content analysis', 'wordpress-seo' );
+
+ self::$meta_fields['general']['focuskw_text_input']['title'] = __( 'Focus keyword', 'wordpress-seo' );
+ self::$meta_fields['general']['focuskw_text_input']['label'] = __( 'Enter a focus keyword', 'wordpress-seo' );
+ self::$meta_fields['general']['focuskw_text_input']['help'] = sprintf( __( 'Pick the main keyword or keyphrase that this post/page is about. %sLearn more about the Focus Keyword%s.', 'wordpress-seo' ), '', '' );
+ self::$meta_fields['general']['focuskw_text_input']['help-button'] = __( 'Show information about the focus keyword', 'wordpress-seo' );
+
+ self::$meta_fields['general']['title']['title'] = __( 'SEO title', 'wordpress-seo' );
+
+ self::$meta_fields['general']['metadesc']['title'] = __( 'Meta description', 'wordpress-seo' );
+
+ self::$meta_fields['general']['metakeywords']['title'] = __( 'Meta keywords', 'wordpress-seo' );
+ self::$meta_fields['general']['metakeywords']['label'] = __( 'Enter the meta keywords', 'wordpress-seo' );
+ self::$meta_fields['general']['metakeywords']['description'] = __( 'If you type something above it will override your %smeta keywords template%s.', 'wordpress-seo' );
+
+
+ self::$meta_fields['advanced']['meta-robots-noindex']['title'] = __( 'Meta robots index', 'wordpress-seo' );
+ if ( '0' == get_option( 'blog_public' ) ) {
+ self::$meta_fields['advanced']['meta-robots-noindex']['description'] = '
' . __( 'Warning: even though you can set the meta robots setting here, the entire site is set to noindex in the sitewide privacy settings, so these settings won\'t have an effect.', 'wordpress-seo' ) . '
';
+ }
+ self::$meta_fields['advanced']['meta-robots-noindex']['options']['0'] = __( 'Default for this post type, currently: %s', 'wordpress-seo' );
+ self::$meta_fields['advanced']['meta-robots-noindex']['options']['2'] = 'index';
+ self::$meta_fields['advanced']['meta-robots-noindex']['options']['1'] = 'noindex';
+
+ self::$meta_fields['advanced']['meta-robots-nofollow']['title'] = __( 'Meta robots follow', 'wordpress-seo' );
+ self::$meta_fields['advanced']['meta-robots-nofollow']['options']['0'] = 'follow';
+ self::$meta_fields['advanced']['meta-robots-nofollow']['options']['1'] = 'nofollow';
+
+ self::$meta_fields['advanced']['meta-robots-adv']['title'] = __( 'Meta robots advanced', 'wordpress-seo' );
+ self::$meta_fields['advanced']['meta-robots-adv']['description'] = __( 'Advanced meta robots settings for this page.', 'wordpress-seo' );
+ self::$meta_fields['advanced']['meta-robots-adv']['options']['-'] = __( 'Site-wide default: %s', 'wordpress-seo' );
+ self::$meta_fields['advanced']['meta-robots-adv']['options']['none'] = __( 'None', 'wordpress-seo' );
+ self::$meta_fields['advanced']['meta-robots-adv']['options']['noodp'] = __( 'NO ODP', 'wordpress-seo' );
+ self::$meta_fields['advanced']['meta-robots-adv']['options']['noimageindex'] = __( 'No Image Index', 'wordpress-seo' );
+ self::$meta_fields['advanced']['meta-robots-adv']['options']['noarchive'] = __( 'No Archive', 'wordpress-seo' );
+ self::$meta_fields['advanced']['meta-robots-adv']['options']['nosnippet'] = __( 'No Snippet', 'wordpress-seo' );
+
+ self::$meta_fields['advanced']['bctitle']['title'] = __( 'Breadcrumbs Title', 'wordpress-seo' );
+ self::$meta_fields['advanced']['bctitle']['description'] = __( 'Title to use for this page in breadcrumb paths', 'wordpress-seo' );
+
+ self::$meta_fields['advanced']['canonical']['title'] = __( 'Canonical URL', 'wordpress-seo' );
+ self::$meta_fields['advanced']['canonical']['description'] = sprintf( __( 'The canonical URL that this page should point to, leave empty to default to permalink. %sCross domain canonical%s supported too.', 'wordpress-seo' ), '', '' );
+
+ self::$meta_fields['advanced']['redirect']['title'] = __( '301 Redirect', 'wordpress-seo' );
+ self::$meta_fields['advanced']['redirect']['description'] = __( 'The URL that this page should redirect to.', 'wordpress-seo' );
+
+ do_action( 'wpseo_tab_translate' );
+ }
+
+ /**
+ * Test whether the metabox should be hidden either by choice of the admin or because
+ * the post type is not a public post type
+ *
+ * @since 1.5.0
+ *
+ * @param string $post_type (optional) The post type to test, defaults to the current post post_type.
+ *
+ * @return bool Whether or not the meta box (and associated columns etc) should be hidden
+ */
+ function is_metabox_hidden( $post_type = null ) {
+ if ( ! isset( $post_type ) && ( isset( $GLOBALS['post'] ) && ( is_object( $GLOBALS['post'] ) && isset( $GLOBALS['post']->post_type ) ) ) ) {
+ $post_type = $GLOBALS['post']->post_type;
+ }
+
+ if ( isset( $post_type ) ) {
+ // Don't make static as post_types may still be added during the run.
+ $cpts = get_post_types( array( 'public' => true ), 'names' );
+ $options = get_option( 'wpseo_titles' );
+
+ return ( ( isset( $options[ 'hideeditbox-' . $post_type ] ) && $options[ 'hideeditbox-' . $post_type ] === true ) || in_array( $post_type, $cpts ) === false );
+ }
+ return false;
+ }
+
+ /**
+ * Sets up all the functionality related to the prominence of the page analysis functionality.
+ */
+ public function setup_page_analysis() {
+ if ( apply_filters( 'wpseo_use_page_analysis', true ) === true ) {
+ add_action( 'post_submitbox_start', array( $this, 'publish_box' ) );
+ }
+ }
+
+ /**
+ * Outputs the page analysis score in the Publish Box.
+ */
+ public function publish_box() {
+ if ( $this->is_metabox_hidden() === true ) {
+ return;
+ }
+
+ $post = $this->get_metabox_post();
+ if ( self::get_value( 'meta-robots-noindex', $post->ID ) === '1' ) {
+ $score_label = 'noindex';
+ $title = __( 'Post is set to noindex.', 'wordpress-seo' );
+ $score_title = $title;
+ }
+ else {
+ $score = self::get_value( 'linkdex', $post->ID );
+ if ( $score === '' ) {
+ $score_label = 'na';
+ $title = __( 'No focus keyword set.', 'wordpress-seo' );
+ }
+ else {
+ $score_label = WPSEO_Utils::translate_score( $score );
+ }
+
+ $score_title = WPSEO_Utils::translate_score( $score, false );
+ if ( ! isset( $title ) ) {
+ $title = $score_title;
+ }
+ }
+ }
+
+ /**
+ * Adds the Yoast SEO meta box to the edit boxes in the edit post, page,
+ * attachment, and custom post types pages.
+ */
+ public function add_meta_box() {
+ $post_types = get_post_types( array( 'public' => true ) );
+
+ if ( is_array( $post_types ) && $post_types !== array() ) {
+ foreach ( $post_types as $post_type ) {
+ if ( $this->is_metabox_hidden( $post_type ) === false ) {
+ $product_title = 'Yoast SEO';
+ if ( file_exists( WPSEO_PATH . 'premium/' ) ) {
+ $product_title .= ' Premium';
+ }
+
+ if ( null !== get_current_screen() ) {
+ $screen_id = get_current_screen()->id;
+ add_filter( "postbox_classes_{$screen_id}_wpseo_meta", array( $this, 'wpseo_metabox_class' ) );
+ }
+
+ add_meta_box( 'wpseo_meta', $product_title, array(
+ $this,
+ 'meta_box',
+ ), $post_type, 'normal', apply_filters( 'wpseo_metabox_prio', 'high' ) );
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds CSS classes to the meta box.
+ *
+ * @param array $classes An array of postbox CSS classes.
+ *
+ * @return array
+ */
+ public function wpseo_metabox_class( $classes ) {
+ $classes[] = 'yoast wpseo-metabox';
+ return $classes;
+ }
+
+ /**
+ * Pass variables to js for use with the post-scraper
+ *
+ * @return array
+ */
+ public function localize_post_scraper_script() {
+ $post = $this->get_metabox_post();
+ $permalink = '';
+
+ if ( is_object( $post ) ) {
+ $permalink = get_sample_permalink( $post->ID );
+ $permalink = $permalink[0];
+ }
+
+ $post_formatter = new WPSEO_Metabox_Formatter(
+ new WPSEO_Post_Metabox_Formatter( $post, WPSEO_Options::get_option( 'wpseo_titles' ), $permalink )
+ );
+
+ return $post_formatter->get_values();
+ }
+
+ /**
+ * Pass some variables to js for replacing variables.
+ */
+ public function localize_replace_vars_script() {
+ return array(
+ 'no_parent_text' => __( '(no parent)', 'wordpress-seo' ),
+ 'replace_vars' => $this->get_replace_vars(),
+ 'scope' => $this->determine_scope(),
+ );
+ }
+
+ /**
+ * Determines the scope based on the post type.
+ * This can be used by the replacevar plugin to determine if a replacement needs to be executed.
+ *
+ * @return string String decribing the current scope.
+ */
+ private function determine_scope() {
+ $post_type = get_post_type( $this->get_metabox_post() );
+
+ if ( $post_type === 'page' ) {
+ return 'page';
+ }
+
+ return 'post';
+ }
+
+ /**
+ * Pass some variables to js for the edit / post page overview, snippet preview, etc.
+ *
+ * @return array
+ */
+ public function localize_shortcode_plugin_script() {
+ return array(
+ 'wpseo_filter_shortcodes_nonce' => wp_create_nonce( 'wpseo-filter-shortcodes' ),
+ 'wpseo_shortcode_tags' => $this->get_valid_shortcode_tags(),
+ );
+ }
+
+ /**
+ * Output a tab in the Yoast SEO Metabox
+ *
+ * @param string $id CSS ID of the tab.
+ * @param string $heading Heading for the tab.
+ * @param string $content Content of the tab. This content should be escaped.
+ */
+ public function do_tab( $id, $heading, $content ) {
+ ?>
+
';
+ printf(
+ /* translators: %1$s expands to Yoast SEO */
+ _n( 'The following file is blocking your XML sitemaps from working properly. Either delete it (this can be done with the "Fix it" button) or disable %1$s XML sitemaps.', 'The following files are blocking your XML sitemaps from working properly. Either delete them (this can be done with the "Fix it" button) or disable %1$s XML sitemaps.', count( $options['blocking_files'] ), 'wordpress-seo' ),
+ 'Yoast SEO'
+ );
+ foreach ( $options['blocking_files'] as $file ) {
+ echo ' ', '', esc_html( $file ), '';
+ }
+ unset( $file );
+ echo ' ';
+ echo '
';
+ }
+}
+
+$tabs = new WPSEO_Option_Tabs( 'dashboard' );
+$tabs->add_tab( new WPSEO_Option_Tab( 'dashboard', __( 'Dashboard', 'wordpress-seo' ), array( 'video_url' => 'https://yoa.st/screencast-notification-center' ) ) );
+$tabs->add_tab( new WPSEO_Option_Tab( 'general', __( 'General', 'wordpress-seo' ), array( 'video_url' => 'https://yoa.st/screencast-general' ) ) );
+$tabs->add_tab( new WPSEO_Option_Tab( 'features', __( 'Features', 'wordpress-seo' ) ) );
+$knowledge_graph_label = ( 'company' === $options['company_or_person'] ) ? __( 'Company Info', 'wordpress-seo' ) : __( 'Your Info', 'wordpress-seo' );
+$tabs->add_tab( new WPSEO_Option_Tab( 'knowledge-graph', __( $knowledge_graph_label, 'wordpress-seo' ), array( 'video_url' => 'https://yoa.st/screencast-knowledge-graph' ) ) );
+$tabs->add_tab( new WPSEO_Option_Tab( 'webmaster-tools', __( 'Webmaster Tools', 'wordpress-seo' ), array( 'video_url' => 'https://yoa.st/screencast-general-search-console' ) ) );
+$tabs->add_tab( new WPSEO_Option_Tab( 'security', __( 'Security', 'wordpress-seo' ), array( 'video_url' => 'https://yoa.st/screencast-security' ) ) );
+
+do_action( 'wpseo_settings_tabs_dashboard', $tabs );
+
+$tabs->display( $yform, $options );
+
+do_action( 'wpseo_dashboard' );
+
+$yform->admin_footer();
diff --git a/wp-content/plugins/wordpress-seo/admin/pages/licenses.php b/wp-content/plugins/wordpress-seo/admin/pages/licenses.php
new file mode 100644
index 0000000..26b688e
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/pages/licenses.php
@@ -0,0 +1,239 @@
+ (object) array(
+ 'url' => 'https://yoast.com/wordpress/plugins/seo-premium/',
+ 'title' => 'Yoast SEO Premium',
+ /* translators: %1$s expands to Yoast SEO */
+ 'desc' => sprintf( __( 'The premium version of %1$s with more features & support.', 'wordpress-seo' ), 'Yoast SEO' ),
+ 'installed' => false,
+ 'image' => plugins_url( 'images/extensions-premium-ribbon.png', WPSEO_FILE ),
+ 'benefits' => array(),
+ ),
+ 'video-seo' => (object) array(
+ 'url' => 'https://yoast.com/wordpress/plugins/video-seo/',
+ 'title' => 'Video SEO',
+ 'desc' => __( 'Optimize your videos to show them off in search results and get more clicks!', 'wordpress-seo' ),
+ 'installed' => false,
+ 'image' => plugins_url( 'images/extensions-video.png', WPSEO_FILE ),
+ 'benefits' => array(
+ __( 'Show your videos in Google Videos', 'wordpress-seo' ),
+ __( 'Enhance the experience of sharing posts with videos', 'wordpress-seo' ),
+ __( 'Make videos responsive through enabling fitvids.js', 'wordpress-seo' ),
+ ),
+ ),
+ 'news-seo' => (object) array(
+ 'url' => 'https://yoast.com/wordpress/plugins/news-seo/',
+ 'title' => 'News SEO',
+ 'desc' => __( 'Are you in Google News? Increase your traffic from Google News by optimizing for it!', 'wordpress-seo' ),
+ 'installed' => false,
+ 'image' => plugins_url( 'images/extensions-news.png', WPSEO_FILE ),
+ 'benefits' => array(
+ __( 'Optimize your site for Google News', 'wordpress-seo' ),
+ __( 'Immediately pings Google on the publication of a new post', 'wordpress-seo' ),
+ __( 'Creates XML News Sitemaps', 'wordpress-seo' ),
+ ),
+ ),
+ 'local-seo' => (object) array(
+ 'url' => 'https://yoast.com/wordpress/plugins/local-seo/',
+ 'title' => 'Local SEO',
+ 'desc' => __( 'Rank better locally and in Google Maps, without breaking a sweat!', 'wordpress-seo' ),
+ 'installed' => false,
+ 'image' => plugins_url( 'images/extensions-local.png', WPSEO_FILE ),
+ 'benefits' => array(
+ __( 'Get found by potential clients', 'wordpress-seo' ),
+ __( 'Easily insert Google Maps, a store locator, opening hours and more', 'wordpress-seo' ),
+ __( 'Improve the usability of your contact page', 'wordpress-seo' ),
+ ),
+ ),
+ 'woocommerce-seo' => (object) array(
+ 'url' => 'https://yoast.com/wordpress/plugins/yoast-woocommerce-seo/',
+ 'title' => 'Yoast WooCommerce SEO',
+ /* translators: %1$s expands to Yoast SEO */
+ 'desc' => sprintf( __( 'Seamlessly integrate WooCommerce with %1$s and get extra features!', 'wordpress-seo' ), 'Yoast SEO' ),
+ 'installed' => false,
+ 'image' => plugins_url( 'images/extensions-woo.png', WPSEO_FILE ),
+ 'benefits' => array(
+ /* %1$s expands to Pinterest */
+ sprintf( __( 'Improve sharing on Pinterest', 'wordpress-seo' ) ),
+
+ /* %1$s expands to Yoast, %2$s expands to WooCommerce */
+ sprintf( __( 'Use %1$s breadcrumbs instead of %2$s ones', 'wordpress-seo' ), 'Yoast', 'WooCommerce' ),
+
+ /* %1$s expands to Yoast SEO, %2$s expands to WooCommerce */
+ sprintf( __( 'A seamless integration between %1$s and %2$s', 'wordpress-seo' ), 'Yoast SEO', 'WooCommerce' ),
+ ),
+ 'buy_button' => 'WooCommerce SEO',
+ ),
+);
+
+if ( class_exists( 'WPSEO_Premium' ) ) {
+ $extensions['seo-premium']->installed = true;
+}
+if ( class_exists( 'wpseo_Video_Sitemap' ) ) {
+ $extensions['video-seo']->installed = true;
+}
+if ( class_exists( 'WPSEO_News' ) ) {
+ $extensions['news-seo']->installed = true;
+}
+if ( defined( 'WPSEO_LOCAL_VERSION' ) ) {
+ $extensions['local-seo']->installed = true;
+}
+if ( ! class_exists( 'Woocommerce' ) ) {
+ unset( $extensions['woocommerce-seo'] );
+}
+elseif ( class_exists( 'Yoast_WooCommerce_SEO' ) ) {
+ $extensions['woocommerce-seo']->installed = true;
+}
+
+$utm_buy = '#utm_source=wordpress-seo-config&utm_medium=button-buy&utm_campaign=extension-page-banners';
+$utm_info = '#utm_source=wordpress-seo-config&utm_medium=button-info&utm_campaign=extension-page-banners';
+
+?>
+
+
' . sprintf( __( 'The title & metas settings for %1$s are made up of variables that are replaced by specific values from the page when the page is displayed. The tabs on the left explain the available variables.', 'wordpress-seo' ), 'Yoast SEO' ) . '
' . '
' . __( 'Note that not all variables can be used in every template.', 'wordpress-seo' ) . '
+ Yoast SEO 3.0 brought a way for theme builders and custom field plugins to integrate with Yoast SEO. These
+ integrations make sure that all the data on your page is used for the content analysis. On this
+ page, we highlight the frameworks that have nicely working integrations.
+
+ ';
+ _e( 'Your homepage can be indexed by search engines.', 'wordpress-seo' );
+
+ break;
+ case WPSEO_OnPage_Option::IS_NOT_INDEXABLE :
+ echo '';
+ printf(
+ /* translators: 1: opens a link to a related knowledge base article. 2: closes the link */
+ __( '%1$sYour homepage cannot be indexed by search engines%2$s. This is very bad for SEO and should be fixed.', 'wordpress-seo' ),
+ '',
+ ''
+ );
+ break;
+ case WPSEO_OnPage_Option::CANNOT_FETCH :
+ echo '';
+ printf(
+ /* translators: %1$s opens a link to a related knowledge base article, %2$s expands to Yoast SEO, %3$s closes the link. */
+ __( '%1$s%2$s has not been able to fetch your site\'s indexability status%3$s from OnPage.org', 'wordpress-seo' ),
+ '',
+ 'Yoast SEO',
+ ''
+ );
+ break;
+ case WPSEO_OnPage_Option::NOT_FETCHED :
+ echo '';
+ echo esc_html( sprintf(
+ /* translators: %s expands to Yoast SEO. */
+ __( '%s has not fetched your site\'s indexability status yet from OnPage.org', 'wordpress-seo' ),
+ 'Yoast SEO'
+ ) );
+ break;
+ endswitch;
+ ?>
+
' . __( 'Attachments to posts are stored in the database as posts, this means they\'re accessible under their own URLs if you do not redirect them, enabling this will redirect them to the post they were attached to.', 'wordpress-seo' ) . '
';
+
+echo '
', __( 'Clean up permalinks', 'wordpress-seo' ), '
';
+$yform->light_switch( 'cleanslugs', __( 'Stop words in slugs.', 'wordpress-seo' ), $remove_buttons, false );
+echo '
' . __( 'This helps you to create cleaner URLs by automatically removing the stopwords from them.', 'wordpress-seo' ) . '
' . __( 'This prevents threaded replies from working when the user has JavaScript disabled, but on a large site can mean a huge improvement in crawl efficiency for search engines when you have a lot of comments.', 'wordpress-seo' ) . '
';
+
+$options = WPSEO_Options::get_all();
+if ( substr( get_option( 'permalink_structure' ), -1 ) !== '/' && $options['trailingslash'] ) {
+ $yform->light_switch( 'trailingslash', __( 'Enforce a trailing slash on all category and tag URLs', 'wordpress-seo' ) );
+ echo '
' . __( 'Note: this feature has been deprecated, as the SEO value is close to 0 these days. If you disable it you will not be able to put it back on.', 'wordpress-seo' ) . '
';
+ /* translators: %1$s expands to .html, %2$s expands to / */
+ echo '
' . sprintf( __( 'If you choose a permalink for your posts with %1$s, or anything else but a %2$s at the end, this will force WordPress to add a trailing slash to non-post pages nonetheless.', 'wordpress-seo' ), '.html', '/' ) . '
';
+}
+
+$yform->light_switch( 'cleanpermalinks', __( 'Redirect ugly URLs to clean permalinks. (Not recommended in many cases!)', 'wordpress-seo' ), $redirect_buttons );
+echo '
' . __( 'People make mistakes in their links towards you sometimes, or unwanted parameters are added to the end of your URLs, this allows you to redirect them all away. Please note that while this is a feature that is actively maintained, it is known to break several plugins, and should for that reason be the first feature you disable when you encounter issues after installing this plugin.', 'wordpress-seo' ) . '
';
+
+echo '
';
+$yform->light_switch( 'cleanpermalink-googlesitesearch', __( 'Prevent cleaning out Google Site Search URLs.', 'wordpress-seo' ) );
+echo '
' . __( 'Google Site Search URLs look weird, and ugly, but if you\'re using Google Site Search, you probably do not want them cleaned out.', 'wordpress-seo' ) . '
';
+
+$yform->light_switch( 'cleanpermalink-googlecampaign', __( 'Prevent cleaning out Google Analytics Campaign & Google AdWords Parameters.', 'wordpress-seo' ) );
+/* translators: %s expands to ?utm_ */
+echo '
' . sprintf( __( 'If you use Google Analytics campaign parameters starting with %s, check this box. However, you\'re advised not to use these. Instead, use the version with a hash.', 'wordpress-seo' ), '?utm_' ) . '
';
+
+$yform->textinput( 'cleanpermalink-extravars', __( 'Other variables not to clean', 'wordpress-seo' ) );
+echo '
' . __( 'You might have extra variables you want to prevent from cleaning out, add them here, comma separated.', 'wordpress-seo' ) . '
' . __( "This feature is used to automatically add content to your RSS, more specifically, it's meant to add links back to your blog and your blog posts, so dumb scrapers will automatically add these links too, helping search engines identify you as the original source of the content.", 'wordpress-seo' ) . '
';
+
+$textarea_atts = array(
+ 'cols' => '50',
+ 'rows' => '5',
+);
+$yform->textarea( 'rssbefore', __( 'Content to put before each post in the feed', 'wordpress-seo' ), '', $textarea_atts );
+$yform->textarea( 'rssafter', __( 'Content to put after each post in the feed', 'wordpress-seo' ), '', $textarea_atts );
+?>
+
+
+
+
+
%%AUTHORLINK%%
+
+
+
+
%%POSTLINK%%
+
+
+
+
%%BLOGLINK%%
+
+
+
+
%%BLOGDESCLINK%%
+
+
+
diff --git a/wp-content/plugins/wordpress-seo/admin/views/tabs/dashboard/dashboard.php b/wp-content/plugins/wordpress-seo/admin/views/tabs/dashboard/dashboard.php
new file mode 100644
index 0000000..6a2a05b
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/views/tabs/dashboard/dashboard.php
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wp-content/plugins/wordpress-seo/admin/views/tabs/dashboard/features.php b/wp-content/plugins/wordpress-seo/admin/views/tabs/dashboard/features.php
new file mode 100644
index 0000000..3365069
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/views/tabs/dashboard/features.php
@@ -0,0 +1,67 @@
+ __( 'Advanced settings pages', 'wordpress-seo' ),
+ 'setting' => 'enable_setting_pages',
+ 'label' => __( 'The advanced settings include site-wide settings for your titles and meta descriptions, social metadata, sitemaps and much more.', 'wordpress-seo' ),
+ ),
+ (object) array(
+ 'name' => __( 'OnPage.org', 'wordpress-seo' ),
+ 'setting' => 'onpage_indexability',
+ /* translators: %1$s expands to OnPage.org */
+ 'label' => sprintf( __( 'The %1$s integration checks daily if your site is still indexable by search engines and notifies you when this is not the case.', 'wordpress-seo' ), 'OnPage.org' ),
+ ),
+ (object) array(
+ 'name' => __( 'Admin bar menu', 'wordpress-seo' ),
+ 'setting' => 'enable_admin_bar_menu',
+ /* translators: %1$s expands to Yoast SEO*/
+ 'label' => sprintf( __( 'The %1$s admin bar menu contains useful links to third-party tools for analyzing pages and makes it easy to see if you have new notifications.', 'wordpress-seo' ), 'Yoast SEO' ),
+ ),
+);
+
+/**
+ * Filter to add feature toggles from add-ons.
+ *
+ * @param array $feature_toggles Array with feature toggle objects where each object should have a `name`, `setting` and `label` property.
+ */
+$feature_toggles = apply_filters( 'wpseo_feature_toggles', $feature_toggles );
+
+?>
+
diff --git a/wp-content/plugins/wordpress-seo/admin/views/tabs/dashboard/security.php b/wp-content/plugins/wordpress-seo/admin/views/tabs/dashboard/security.php
new file mode 100644
index 0000000..c5dde67
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/views/tabs/dashboard/security.php
@@ -0,0 +1,22 @@
+' . esc_html__( 'Security setting', 'wordpress-seo' ) . '';
+
+$yform->toggle_switch(
+ 'disableadvanced_meta',
+ array( 'off' => __( 'Enabled', 'wordpress-seo' ), 'on' => __( 'Disabled', 'wordpress-seo' ) ),
+ /* translators: %1$s expands to Yoast SEO */
+ sprintf( __( 'Advanced part of the %1$s meta box', 'wordpress-seo' ), 'Yoast SEO' )
+);
+
+/* translators: %1$s expands to Yoast SEO */
+echo '
', sprintf( __( 'The advanced section of the %1$s meta box allows a user to noindex posts or change the canonical. These are things you might not want if you don\'t trust your authors, so by default, only administrators can do this. Enabling the advanced box allows all users to change these settings.', 'wordpress-seo' ), 'Yoast SEO' ), '
', __( 'You can use the boxes below to verify with the different Webmaster Tools, if your site is already verified, you can just forget about these. Enter the verify meta values for:', 'wordpress-seo' ) );
+
+$yform->textinput( 'msverify', '' . __( 'Bing Webmaster Tools', 'wordpress-seo' ) . '' );
+$yform->textinput( 'googleverify', 'Google Search Console' );
+$yform->textinput( 'yandexverify', '' . __( 'Yandex Webmaster Tools', 'wordpress-seo' ) . '' );
diff --git a/wp-content/plugins/wordpress-seo/admin/views/tabs/metas/archives.php b/wp-content/plugins/wordpress-seo/admin/views/tabs/metas/archives.php
new file mode 100644
index 0000000..5e950f9
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/views/tabs/metas/archives.php
@@ -0,0 +1,69 @@
+';
+/* translators: %1$s / %2$s: links to an article about duplicate content on yoast.com */
+printf( __( 'If you\'re running a one author blog, the author archive will be exactly the same as your homepage. This is what\'s called a %1$sduplicate content problem%2$s.', 'wordpress-seo' ), '', '' );
+echo ' ';
+/* translators: %s expands to noindex, follow */
+printf( __( 'If this is the case on your site, you can choose to either disable it (which makes it redirect to the homepage), or to add %s to it so it doesn\'t show up in the search results.', 'wordpress-seo' ), 'noindex,follow' );
+echo ' ';
+echo __( 'Note that links to archives might be still output by your theme and you would need to remove them separately.', 'wordpress-seo' );
+echo ' ';
+_e( 'Date-based archives could in some cases also be seen as duplicate content.', 'wordpress-seo' );
+echo '';
+
+echo "
', sprintf( __( '%1$s has auto-detected whether it needs to force rewrite the titles for your pages, if you think it\'s wrong and you know what you\'re doing, you can change the setting here.', 'wordpress-seo' ), 'Yoast SEO' ) . '
', __( 'Choose the symbol to use as your title separator. This will display, for instance, between your post title and site name.', 'wordpress-seo' ), ' ', __( 'Symbols are shown in the size they\'ll appear in the search results.', 'wordpress-seo' ), '
', esc_html__( 'Homepage & Front page', 'wordpress-seo' ), '
';
+ echo '
';
+ printf( __( 'You can determine the title and description for the front page by %sediting the front page itself »%s', 'wordpress-seo' ), '', '' );
+ echo '
', __( 'I don\'t know why you\'d want to use meta keywords, but if you want to, enable this.', 'wordpress-seo' ), '
';
+
+/* translators: %s expands to noodp */
+$yform->light_switch( 'noodp', sprintf( __( 'Force %s meta robots tag sitewide', 'wordpress-seo' ), 'noodp' ) );
+/* translators: %s expands to noodp */
+echo '
', sprintf( __( 'Prevents search engines from using the DMOZ description in the search results for all pages on this site. Note: If you set a custom description for a page or post, it will have the %s tag regardless of this setting.', 'wordpress-seo' ), 'noodp' ), '
';
+ if ( $options['redirectattachment'] === true && $name === 'attachment' ) {
+ // The `inline` CSS class prevents the notice from being moved to the top via JavaScript.
+ echo '
';
+ /* translators: %1$s and %2$s expand to a link to the SEO Permalinks settings page. */
+ echo sprintf( __( 'As you are redirecting attachment URLs to parent post URLs, these settings will currently only have an effect on unattached media items! So remember: If you change the %1$sattachment redirection setting%2$s in the future, the below settings will take effect for *all* media items.', 'wordpress-seo' ), '', '' );
+ echo '
';
+ /**
+ * Allow adding a custom checkboxes to the admin meta page - Post Types tab
+ *
+ * @api WPSEO_Admin_Pages $yform The WPSEO_Admin_Pages object
+ * @api String $name The post type name
+ */
+ do_action( 'wpseo_admin_page_meta_post_types', $yform, $name );
+ echo '
' . esc_html__( 'Custom Post Type Archives', 'wordpress-seo' ) . '
';
+ echo '
' . __( 'Note: instead of templates these are the actual titles and meta descriptions for these custom post type archive pages.', 'wordpress-seo' ) . '
', sprintf( __( 'You can exclude posts from the sitemap by entering a comma separated string with the Post ID\'s. The format will become something like: %1$s.', 'wordpress-seo' ), '1,2,99,100' ), '
';
+ /* translators: %1$s opening tag of the link to the Sitemap, %2$s closing tag for the link. */
+ printf(
+ esc_html__( 'You can find your XML Sitemap here: %1$sXML Sitemap%2$s', 'wordpress-seo' ),
+ '',
+ ''
+ );
+ echo ' ';
+ echo ' ';
+ _e( 'You do not need to generate the XML sitemap, nor will it take up time to generate after publishing a post.', 'wordpress-seo' );
+ echo '
';
+}
+else {
+ echo '
', __( 'Save your settings to activate your XML Sitemap.', 'wordpress-seo' ), '
+ <head> */
+ printf( __( 'Add Open Graph meta data to your site\'s %s section, Facebook and other social networks use this data when your pages are shared.', 'wordpress-seo' ), '<head>' );
+ ?>
+
', __( 'If you have a Google+ page for your business, add that URL here and link it on your Google+ page\'s about page.', 'wordpress-seo' ) );
+
+$yform->textinput( 'plus-publisher', __( 'Google Publisher Page', 'wordpress-seo' ) );
+
+do_action( 'wpseo_admin_googleplus_section' );
diff --git a/wp-content/plugins/wordpress-seo/admin/views/tabs/social/pinterest.php b/wp-content/plugins/wordpress-seo/admin/views/tabs/social/pinterest.php
new file mode 100644
index 0000000..b9cace3
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/admin/views/tabs/social/pinterest.php
@@ -0,0 +1,23 @@
+' . esc_html__( 'Pinterest settings', 'wordpress-seo' ) . '';
+
+printf( '
%s
', __( 'Pinterest uses Open Graph metadata just like Facebook, so be sure to keep the Open Graph checkbox on the Facebook tab checked if you want to optimize your site for Pinterest.', 'wordpress-seo' ) );
+printf( '
%s
', __( 'If you have already confirmed your website with Pinterest, you can skip the step below.', 'wordpress-seo' ) );
+
+/* translators: %1$s / %2$s expands to a link to pinterest.com's help page. */
+$p = sprintf( __( 'To %1$sconfirm your site with Pinterest%2$s, add the meta tag here:', 'wordpress-seo' ), '', '' );
+printf( '
+ Generated by YoastSEO, this is an XML Sitemap, meant for consumption by search engines.
+ You can find more information about XML sitemaps on sitemaps.org.
+
+
+
+ This XML Sitemap Index file contains sitemaps.
+
';
+
+ return $table;
+ }
+
+ /**
+ * Create the help text table for the basic variables for use in a help tab
+ *
+ * @return string
+ */
+ public static function get_basic_help_texts() {
+ return self::create_variable_help_table( 'basic' );
+ }
+
+
+ /**
+ * Create the help text table for the advanced variables for use in a help tab
+ *
+ * @return string
+ */
+ public static function get_advanced_help_texts() {
+ return self::create_variable_help_table( 'advanced' );
+ }
+
+
+ /**
+ * Set the help text for a user/plugin/theme defined extra variable.
+ *
+ * @param string $type Type of variable: 'basic' or 'advanced'.
+ * @param string $replace Variable to replace, i.e. '%%var%%'.
+ * @param string $help_text The actual help text string.
+ */
+ private static function register_help_text( $type, $replace, $help_text = '' ) {
+ if ( is_string( $replace ) && $replace !== '' ) {
+ $replace = self::remove_var_delimiter( $replace );
+
+ if ( ( is_string( $type ) && in_array( $type, array(
+ 'basic',
+ 'advanced',
+ ), true ) ) && ( $replace !== '' && ! isset( self::$help_texts[ $type ][ $replace ] ) )
+ ) {
+ self::$help_texts[ $type ][ $replace ] = $help_text;
+ }
+ }
+ }
+
+
+ /**
+ * Set/translate the help texts for the WPSEO standard basic variables.
+ */
+ private static function set_basic_help_texts() {
+ self::$help_texts['basic'] = array(
+ 'date' => __( 'Replaced with the date of the post/page', 'wordpress-seo' ),
+ 'title' => __( 'Replaced with the title of the post/page', 'wordpress-seo' ),
+ 'parent_title' => __( 'Replaced with the title of the parent page of the current page', 'wordpress-seo' ),
+ 'sitename' => __( 'The site\'s name', 'wordpress-seo' ),
+ 'sitedesc' => __( 'The site\'s tag line / description', 'wordpress-seo' ),
+ 'excerpt' => __( 'Replaced with the post/page excerpt (or auto-generated if it does not exist)', 'wordpress-seo' ),
+ 'excerpt_only' => __( 'Replaced with the post/page excerpt (without auto-generation)', 'wordpress-seo' ),
+ 'tag' => __( 'Replaced with the current tag/tags', 'wordpress-seo' ),
+ 'category' => __( 'Replaced with the post categories (comma separated)', 'wordpress-seo' ),
+ 'primary_category' => __( 'Replaced with the primary category of the post/page', 'wordpress-seo' ),
+ 'category_description' => __( 'Replaced with the category description', 'wordpress-seo' ),
+ 'tag_description' => __( 'Replaced with the tag description', 'wordpress-seo' ),
+ 'term_description' => __( 'Replaced with the term description', 'wordpress-seo' ),
+ 'term_title' => __( 'Replaced with the term name', 'wordpress-seo' ),
+ 'searchphrase' => __( 'Replaced with the current search phrase', 'wordpress-seo' ),
+ 'sep' => sprintf(
+ /* translators: %s: wp_title() function */
+ __( 'The separator defined in your theme\'s %s tag.', 'wordpress-seo' ),
+ 'wp_title()'
+ ),
+ );
+ }
+
+ /**
+ * Set/translate the help texts for the WPSEO standard advanced variables.
+ */
+ private static function set_advanced_help_texts() {
+ self::$help_texts['advanced'] = array(
+ 'pt_single' => __( 'Replaced with the post type single label', 'wordpress-seo' ),
+ 'pt_plural' => __( 'Replaced with the post type plural label', 'wordpress-seo' ),
+ 'modified' => __( 'Replaced with the post/page modified time', 'wordpress-seo' ),
+ 'id' => __( 'Replaced with the post/page ID', 'wordpress-seo' ),
+ 'name' => __( 'Replaced with the post/page author\'s \'nicename\'', 'wordpress-seo' ),
+ 'user_description' => __( 'Replaced with the post/page author\'s \'Biographical Info\'', 'wordpress-seo' ),
+ 'userid' => __( 'Replaced with the post/page author\'s userid', 'wordpress-seo' ),
+ 'currenttime' => __( 'Replaced with the current time', 'wordpress-seo' ),
+ 'currentdate' => __( 'Replaced with the current date', 'wordpress-seo' ),
+ 'currentday' => __( 'Replaced with the current day', 'wordpress-seo' ),
+ 'currentmonth' => __( 'Replaced with the current month', 'wordpress-seo' ),
+ 'currentyear' => __( 'Replaced with the current year', 'wordpress-seo' ),
+ 'page' => __( 'Replaced with the current page number with context (i.e. page 2 of 4)', 'wordpress-seo' ),
+ 'pagetotal' => __( 'Replaced with the current page total', 'wordpress-seo' ),
+ 'pagenumber' => __( 'Replaced with the current page number', 'wordpress-seo' ),
+ 'caption' => __( 'Attachment caption', 'wordpress-seo' ),
+ 'focuskw' => __( 'Replaced with the posts focus keyword', 'wordpress-seo' ),
+ 'term404' => __( 'Replaced with the slug which caused the 404', 'wordpress-seo' ),
+ 'cf_' => __( 'Replaced with a posts custom field value', 'wordpress-seo' ),
+ 'ct_' => __( 'Replaced with a posts custom taxonomies, comma separated.', 'wordpress-seo' ),
+ 'ct_desc_' => __( 'Replaced with a custom taxonomies description', 'wordpress-seo' ),
+ );
+ }
+
+
+
+
+ /* *********************** GENERAL HELPER METHODS ************************** */
+
+ /**
+ * Remove the '%%' delimiters from a variable string
+ *
+ * @param string $string Variable string to be cleaned.
+ *
+ * @return string
+ */
+ private static function remove_var_delimiter( $string ) {
+ return trim( $string, '%' );
+ }
+
+ /**
+ * Add the '%%' delimiters to a variable string
+ *
+ * @param string $string Variable string to be delimited.
+ *
+ * @return string
+ */
+ private static function add_var_delimiter( $string ) {
+ return '%%' . $string . '%%';
+ }
+
+ /**
+ * Retrieve a post's terms, comma delimited.
+ *
+ * @param int $id ID of the post to get the terms for.
+ * @param string $taxonomy The taxonomy to get the terms for this post from.
+ * @param bool $return_single If true, return the first term.
+ *
+ * @return string either a single term or a comma delimited string of terms.
+ */
+ public function get_terms( $id, $taxonomy, $return_single = false ) {
+
+ $output = '';
+
+ // If we're on a specific tag, category or taxonomy page, use that.
+ if ( is_category() || is_tag() || is_tax() ) {
+ $term = $GLOBALS['wp_query']->get_queried_object();
+ $output = $term->name;
+ }
+ elseif ( ! empty( $id ) && ! empty( $taxonomy ) ) {
+ $terms = get_the_terms( $id, $taxonomy );
+ if ( is_array( $terms ) && $terms !== array() ) {
+ foreach ( $terms as $term ) {
+ if ( $return_single ) {
+ $output = $term->name;
+ break;
+ }
+ else {
+ $output .= $term->name . ', ';
+ }
+ }
+ $output = rtrim( trim( $output ), ',' );
+ }
+ }
+ unset( $terms, $term );
+
+ /**
+ * Allows filtering of the terms list used to replace %%category%%, %%tag%% and %%ct_%% variables
+ *
+ * @api string $output Comma-delimited string containing the terms
+ */
+ return apply_filters( 'wpseo_terms', $output );
+ }
+} /* End of class WPSEO_Replace_Vars */
+
+
+/**
+ * Setup the class statics when the file is first loaded
+ */
+WPSEO_Replace_Vars::setup_statics_once();
diff --git a/wp-content/plugins/wordpress-seo/inc/class-wpseo-statistics.php b/wp-content/plugins/wordpress-seo/inc/class-wpseo-statistics.php
new file mode 100644
index 0000000..5ebb81d
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/class-wpseo-statistics.php
@@ -0,0 +1,138 @@
+get_rank() ) {
+ $posts = array(
+ 'meta_query' => array(
+ 'relation' => 'OR',
+ array(
+ 'key' => WPSEO_Meta::$meta_prefix . 'focuskw',
+ 'value' => 'needs-a-value-anyway',
+ 'compare' => 'NOT EXISTS',
+ )
+ ),
+ );
+ }
+ elseif ( WPSEO_Rank::NO_INDEX === $rank->get_rank() ) {
+ $posts = array(
+ 'meta_key' => WPSEO_Meta::$meta_prefix . 'meta-robots-noindex',
+ 'meta_value' => '1',
+ 'compare' => '=',
+ );
+ }
+ else {
+ $posts = array(
+ 'meta_key' => WPSEO_Meta::$meta_prefix . 'linkdex',
+ 'meta_value' => array( $rank->get_starting_score(), $rank->get_end_score() ),
+ 'meta_compare' => 'BETWEEN',
+ 'meta_type' => 'NUMERIC',
+ );
+ }
+
+ $posts['fields'] = 'ids';
+ $posts['post_status'] = 'publish';
+
+ if ( current_user_can( 'edit_others_posts' ) === false ) {
+ $posts['author'] = get_current_user_id();
+ }
+
+ $posts = new WP_Query( $posts );
+
+ return $posts->found_posts;
+ }
+
+ /**
+ * Returns the amount of posts that have no focus keyword
+ *
+ * @deprecated
+ *
+ * @return int
+ */
+ public function get_no_focus_post_count() {
+ _deprecated_function( 'get_no_focus_post_count', 'WPSEO 3.0', 'WPSEO_Statistics::get_post_count' );
+
+ return $this->get_post_count( new WPSEO_Rank( WPSEO_Rank::NO_FOCUS ) );
+ }
+
+ /**
+ * Returns the amount of posts that have a bad SEO ranking
+ *
+ * @deprecated
+ *
+ * @return int
+ */
+ public function get_bad_seo_post_count() {
+ _deprecated_function( 'get_bad_seo_post_count', 'WPSEO 3.0', 'WPSEO_Statistics::get_post_count' );
+
+ return $this->get_post_count( new WPSEO_Rank( WPSEO_Rank::BAD ) );
+ }
+
+ /**
+ * Returns the amount of posts that have a poor SEO ranking
+ *
+ * @deprecated
+ *
+ * @return int
+ */
+ public function get_poor_seo_post_count() {
+ _deprecated_function( 'get_poor_seo_post_count', 'WPSEO 3.0', 'WPSEO_Statistics::get_post_count' );
+
+ return $this->get_post_count( new WPSEO_Rank( 'poor' ) );
+ }
+
+ /**
+ * Returns the amount of posts that have an ok SEO ranking
+ *
+ * @deprecated
+ *
+ * @return int
+ */
+ public function get_ok_seo_post_count() {
+ _deprecated_function( 'get_ok_seo_post_count', 'WPSEO 3.0', 'WPSEO_Statistics::get_post_count' );
+
+ return $this->get_post_count( new WPSEO_Rank( WPSEO_Rank::OK ) );
+ }
+
+ /**
+ * Returns the amount of posts that have a good SEO ranking
+ *
+ * @deprecated
+ *
+ * @return int
+ */
+ public function get_good_seo_post_count() {
+ _deprecated_function( 'get_good_seo_post_count', 'WPSEO 3.0', 'WPSEO_Statistics::get_post_count' );
+
+ return $this->get_post_count( new WPSEO_Rank( WPSEO_Rank::GOOD ) );
+ }
+
+ /**
+ * Returns the amount of posts that have no SEO ranking
+ *
+ * @deprecated
+ *
+ * @return int
+ */
+ public function get_no_index_post_count() {
+ _deprecated_function( 'get_no_index_post_count', 'WPSEO 3.0', 'WPSEO_Statistics::get_post_count' );
+
+ return $this->get_post_count( new WPSEO_Rank( WPSEO_Rank::NO_INDEX ) );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/class-wpseo-utils.php b/wp-content/plugins/wordpress-seo/inc/class-wpseo-utils.php
new file mode 100644
index 0000000..04f78a9
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/class-wpseo-utils.php
@@ -0,0 +1,969 @@
+get_names();
+
+ return $roles;
+ }
+
+ /**
+ * Standardize whitespace in a string
+ *
+ * Replace line breaks, carriage returns, tabs with a space, then remove double spaces.
+ *
+ * @param string $string String input to standardize.
+ *
+ * @return string
+ */
+ public static function standardize_whitespace( $string ) {
+ return trim( str_replace( ' ', ' ', str_replace( array( "\t", "\n", "\r", "\f" ), ' ', $string ) ) );
+ }
+
+ /**
+ * First strip out registered and enclosing shortcodes using native WordPress strip_shortcodes function.
+ * Then strip out the shortcodes with a filthy regex, because people don't properly register their shortcodes.
+ *
+ * @static
+ *
+ * @param string $text Input string that might contain shortcodes.
+ *
+ * @return string $text string without shortcodes
+ */
+ public static function strip_shortcode( $text ) {
+ return preg_replace( '`\[[^\]]+\]`s', '', strip_shortcodes( $text ) );
+ }
+
+ /**
+ * Recursively trim whitespace round a string value or of string values within an array
+ * Only trims strings to avoid typecasting a variable (to string)
+ *
+ * @static
+ *
+ * @param mixed $value Value to trim or array of values to trim.
+ *
+ * @return mixed Trimmed value or array of trimmed values
+ */
+ public static function trim_recursive( $value ) {
+ if ( is_string( $value ) ) {
+ $value = trim( $value );
+ }
+ elseif ( is_array( $value ) ) {
+ $value = array_map( array( __CLASS__, 'trim_recursive' ), $value );
+ }
+
+ return $value;
+ }
+
+ /**
+ * Translates a decimal analysis score into a textual one.
+ *
+ * @static
+ *
+ * @param int $val The decimal score to translate.
+ * @param bool $css_value Whether to return the i18n translated score or the CSS class value.
+ *
+ * @return string
+ */
+ public static function translate_score( $val, $css_value = true ) {
+ $seo_rank = WPSEO_Rank::from_numeric_score( $val );
+
+ if ( $css_value ) {
+ return $seo_rank->get_css_class();
+ }
+
+ return $seo_rank->get_label();
+ }
+
+ /**
+ * Emulate the WP native sanitize_text_field function in a %%variable%% safe way
+ *
+ * @see https://core.trac.wordpress.org/browser/trunk/src/wp-includes/formatting.php for the original
+ *
+ * Sanitize a string from user input or from the db
+ *
+ * check for invalid UTF-8,
+ * Convert single < characters to entity,
+ * strip all tags,
+ * remove line breaks, tabs and extra white space,
+ * strip octets - BUT DO NOT REMOVE (part of) VARIABLES WHICH WILL BE REPLACED.
+ *
+ * @param string $value String value to sanitize.
+ *
+ * @return string
+ */
+ public static function sanitize_text_field( $value ) {
+ $filtered = wp_check_invalid_utf8( $value );
+
+ if ( strpos( $filtered, '<' ) !== false ) {
+ $filtered = wp_pre_kses_less_than( $filtered );
+ // This will strip extra whitespace for us.
+ $filtered = wp_strip_all_tags( $filtered, true );
+ }
+ else {
+ $filtered = trim( preg_replace( '`[\r\n\t ]+`', ' ', $filtered ) );
+ }
+
+ $found = false;
+ while ( preg_match( '`[^%](%[a-f0-9]{2})`i', $filtered, $match ) ) {
+ $filtered = str_replace( $match[1], '', $filtered );
+ $found = true;
+ }
+ unset( $match );
+
+ if ( $found ) {
+ // Strip out the whitespace that may now exist after removing the octets.
+ $filtered = trim( preg_replace( '` +`', ' ', $filtered ) );
+ }
+
+ /**
+ * Filter a sanitized text field string.
+ *
+ * @since WP 2.9.0
+ *
+ * @param string $filtered The sanitized string.
+ * @param string $str The string prior to being sanitized.
+ */
+
+ return apply_filters( 'sanitize_text_field', $filtered, $value );
+ }
+
+ /**
+ * Sanitize a url for saving to the database
+ * Not to be confused with the old native WP function
+ *
+ * @todo [JRF => whomever] check/improve url verification
+ *
+ * @param string $value String URL value to sanitize.
+ * @param array $allowed_protocols Optional set of allowed protocols.
+ *
+ * @return string
+ */
+ public static function sanitize_url( $value, $allowed_protocols = array( 'http', 'https' ) ) {
+ return esc_url_raw( sanitize_text_field( rawurldecode( $value ) ), $allowed_protocols );
+ }
+
+ /**
+ * Validate a value as boolean
+ *
+ * @static
+ *
+ * @param mixed $value Value to validate.
+ *
+ * @return bool
+ */
+ public static function validate_bool( $value ) {
+ if ( ! isset( self::$has_filters ) ) {
+ self::$has_filters = extension_loaded( 'filter' );
+ }
+
+ if ( self::$has_filters ) {
+ return filter_var( $value, FILTER_VALIDATE_BOOLEAN );
+ }
+ else {
+ return self::emulate_filter_bool( $value );
+ }
+ }
+
+ /**
+ * Cast a value to bool
+ *
+ * @static
+ *
+ * @param mixed $value Value to cast.
+ *
+ * @return bool
+ */
+ public static function emulate_filter_bool( $value ) {
+ $true = array(
+ '1',
+ 'true',
+ 'True',
+ 'TRUE',
+ 'y',
+ 'Y',
+ 'yes',
+ 'Yes',
+ 'YES',
+ 'on',
+ 'On',
+ 'ON',
+
+ );
+ $false = array(
+ '0',
+ 'false',
+ 'False',
+ 'FALSE',
+ 'n',
+ 'N',
+ 'no',
+ 'No',
+ 'NO',
+ 'off',
+ 'Off',
+ 'OFF',
+ );
+
+ if ( is_bool( $value ) ) {
+ return $value;
+ }
+ else if ( is_int( $value ) && ( $value === 0 || $value === 1 ) ) {
+ return (bool) $value;
+ }
+ else if ( ( is_float( $value ) && ! is_nan( $value ) ) && ( $value === (float) 0 || $value === (float) 1 ) ) {
+ return (bool) $value;
+ }
+ else if ( is_string( $value ) ) {
+ $value = trim( $value );
+ if ( in_array( $value, $true, true ) ) {
+ return true;
+ }
+ else if ( in_array( $value, $false, true ) ) {
+ return false;
+ }
+ else {
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Validate a value as integer
+ *
+ * @static
+ *
+ * @param mixed $value Value to validate.
+ *
+ * @return int|bool int or false in case of failure to convert to int
+ */
+ public static function validate_int( $value ) {
+ if ( ! isset( self::$has_filters ) ) {
+ self::$has_filters = extension_loaded( 'filter' );
+ }
+
+ if ( self::$has_filters ) {
+ return filter_var( $value, FILTER_VALIDATE_INT );
+ }
+ else {
+ return self::emulate_filter_int( $value );
+ }
+ }
+
+ /**
+ * Cast a value to integer
+ *
+ * @static
+ *
+ * @param mixed $value Value to cast.
+ *
+ * @return int|bool
+ */
+ public static function emulate_filter_int( $value ) {
+ if ( is_int( $value ) ) {
+ return $value;
+ }
+ else if ( is_float( $value ) ) {
+ if ( (int) $value == $value && ! is_nan( $value ) ) {
+ return (int) $value;
+ }
+ else {
+ return false;
+ }
+ }
+ else if ( is_string( $value ) ) {
+ $value = trim( $value );
+ if ( $value === '' ) {
+ return false;
+ }
+ else if ( ctype_digit( $value ) ) {
+ return (int) $value;
+ }
+ else if ( strpos( $value, '-' ) === 0 && ctype_digit( substr( $value, 1 ) ) ) {
+ return (int) $value;
+ }
+ else {
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Clears the WP or W3TC cache depending on which is used
+ *
+ * @static
+ */
+ public static function clear_cache() {
+ if ( function_exists( 'w3tc_pgcache_flush' ) ) {
+ w3tc_pgcache_flush();
+ }
+ elseif ( function_exists( 'wp_cache_clear_cache' ) ) {
+ wp_cache_clear_cache();
+ }
+ }
+
+ /**
+ * Flush W3TC cache after succesfull update/add of taxonomy meta option
+ *
+ * @static
+ */
+ public static function flush_w3tc_cache() {
+ if ( defined( 'W3TC_DIR' ) && function_exists( 'w3tc_objectcache_flush' ) ) {
+ w3tc_objectcache_flush();
+ }
+ }
+
+ /**
+ * Clear rewrite rules
+ *
+ * @static
+ */
+ public static function clear_rewrites() {
+ delete_option( 'rewrite_rules' );
+ }
+
+ /**
+ * Do simple reliable math calculations without the risk of wrong results
+ *
+ * @see http://floating-point-gui.de/
+ * @see the big red warning on http://php.net/language.types.float.php
+ *
+ * In the rare case that the bcmath extension would not be loaded, it will return the normal calculation results
+ *
+ * @static
+ *
+ * @since 1.5.0
+ *
+ * @param mixed $number1 Scalar (string/int/float/bool).
+ * @param string $action Calculation action to execute. Valid input:
+ * '+' or 'add' or 'addition',
+ * '-' or 'sub' or 'subtract',
+ * '*' or 'mul' or 'multiply',
+ * '/' or 'div' or 'divide',
+ * '%' or 'mod' or 'modulus'
+ * '=' or 'comp' or 'compare'.
+ * @param mixed $number2 Scalar (string/int/float/bool).
+ * @param bool $round Whether or not to round the result. Defaults to false.
+ * Will be disregarded for a compare operation.
+ * @param int $decimals Decimals for rounding operation. Defaults to 0.
+ * @param int $precision Calculation precision. Defaults to 10.
+ *
+ * @return mixed Calculation Result or false if either or the numbers isn't scalar or
+ * an invalid operation was passed
+ * - for compare the result will always be an integer
+ * - for all other operations, the result will either be an integer (preferred)
+ * or a float
+ */
+ public static function calc( $number1, $action, $number2, $round = false, $decimals = 0, $precision = 10 ) {
+ static $bc;
+
+ if ( ! is_scalar( $number1 ) || ! is_scalar( $number2 ) ) {
+ return false;
+ }
+
+ if ( ! isset( $bc ) ) {
+ $bc = extension_loaded( 'bcmath' );
+ }
+
+ if ( $bc ) {
+ $number1 = number_format( $number1, 10, '.', '' );
+ $number2 = number_format( $number2, 10, '.', '' );
+ }
+
+ $result = null;
+ $compare = false;
+
+ switch ( $action ) {
+ case '+':
+ case 'add':
+ case 'addition':
+ $result = ( $bc ) ? bcadd( $number1, $number2, $precision ) /* string */ : ( $number1 + $number2 );
+ break;
+
+ case '-':
+ case 'sub':
+ case 'subtract':
+ $result = ( $bc ) ? bcsub( $number1, $number2, $precision ) /* string */ : ( $number1 - $number2 );
+ break;
+
+ case '*':
+ case 'mul':
+ case 'multiply':
+ $result = ( $bc ) ? bcmul( $number1, $number2, $precision ) /* string */ : ( $number1 * $number2 );
+ break;
+
+ case '/':
+ case 'div':
+ case 'divide':
+ if ( $bc ) {
+ $result = bcdiv( $number1, $number2, $precision ); // String, or NULL if right_operand is 0.
+ }
+ elseif ( $number2 != 0 ) {
+ $result = ( $number1 / $number2 );
+ }
+
+ if ( ! isset( $result ) ) {
+ $result = 0;
+ }
+ break;
+
+ case '%':
+ case 'mod':
+ case 'modulus':
+ if ( $bc ) {
+ $result = bcmod( $number1, $number2 ); // String, or NULL if modulus is 0.
+ }
+ elseif ( $number2 != 0 ) {
+ $result = ( $number1 % $number2 );
+ }
+
+ if ( ! isset( $result ) ) {
+ $result = 0;
+ }
+ break;
+
+ case '=':
+ case 'comp':
+ case 'compare':
+ $compare = true;
+ if ( $bc ) {
+ $result = bccomp( $number1, $number2, $precision ); // Returns int 0, 1 or -1.
+ }
+ else {
+ $result = ( $number1 == $number2 ) ? 0 : ( ( $number1 > $number2 ) ? 1 : - 1 );
+ }
+ break;
+ }
+
+ if ( isset( $result ) ) {
+ if ( $compare === false ) {
+ if ( $round === true ) {
+ $result = round( floatval( $result ), $decimals );
+ if ( $decimals === 0 ) {
+ $result = (int) $result;
+ }
+ }
+ else {
+ $result = ( intval( $result ) == $result ) ? intval( $result ) : floatval( $result );
+ }
+ }
+
+ return $result;
+ }
+
+ return false;
+ }
+
+ /**
+ * Trim whitespace and NBSP (Non-breaking space) from string
+ *
+ * @param string $string String input to trim.
+ *
+ * @return string
+ */
+ public static function trim_nbsp_from_string( $string ) {
+ $find = array( ' ', chr( 0xC2 ) . chr( 0xA0 ) );
+ $string = str_replace( $find, ' ', $string );
+ $string = trim( $string );
+
+ return $string;
+ }
+
+ /**
+ * Check if a string is a valid datetime
+ *
+ * @param string $datetime String input to check as valid input for DateTime class.
+ *
+ * @return bool
+ */
+ public static function is_valid_datetime( $datetime ) {
+
+ if ( substr( $datetime, 0, 1 ) === '-' ) {
+ return false;
+ }
+
+ try {
+ return new DateTime( $datetime ) !== false;
+ } catch ( Exception $exc ) {
+ return false;
+ }
+ }
+
+ /**
+ * Format the URL to be sure it is okay for using as a redirect url.
+ *
+ * This method will parse the URL and combine them in one string.
+ *
+ * @param string $url URL string.
+ *
+ * @return mixed
+ */
+ public static function format_url( $url ) {
+ $parsed_url = wp_parse_url( $url );
+
+ $formatted_url = '';
+ if ( ! empty( $parsed_url['path'] ) ) {
+ $formatted_url = $parsed_url['path'];
+ }
+
+ // Prepend a slash if first char != slash.
+ if ( stripos( $formatted_url, '/' ) !== 0 ) {
+ $formatted_url = '/' . $formatted_url;
+ }
+
+ // Append 'query' string if it exists.
+ if ( isset( $parsed_url['query'] ) && '' != $parsed_url['query'] ) {
+ $formatted_url .= '?' . $parsed_url['query'];
+ }
+
+ return apply_filters( 'wpseo_format_admin_url', $formatted_url );
+ }
+
+
+ /**
+ * Get plugin name from file
+ *
+ * @param string $plugin Plugin path relative to plugins directory.
+ *
+ * @return string|bool
+ */
+ public static function get_plugin_name( $plugin ) {
+ $plugin_details = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
+
+ if ( $plugin_details['Name'] != '' ) {
+ return $plugin_details['Name'];
+ }
+
+ return false;
+ }
+
+ /**
+ * Retrieves the sitename.
+ *
+ * @return string
+ */
+ public static function get_site_name() {
+ return trim( strip_tags( get_bloginfo( 'name' ) ) );
+ }
+
+ /**
+ * Retrieves the title separator.
+ *
+ * @return string
+ */
+ public static function get_title_separator() {
+ $replacement = WPSEO_Options::get_default( 'wpseo_titles', 'separator' );
+
+ // Get the titles option and the separator options.
+ $titles_options = WPSEO_Options::get_option( 'wpseo_titles' );
+ $seperator_options = WPSEO_Option_Titles::get_instance()->get_separator_options();
+
+ // This should always be set, but just to be sure.
+ if ( isset( $seperator_options[ $titles_options['separator'] ] ) ) {
+ // Set the new replacement.
+ $replacement = $seperator_options[ $titles_options['separator'] ];
+ }
+
+ /**
+ * Filter: 'wpseo_replacements_filter_sep' - Allow customization of the separator character(s)
+ *
+ * @api string $replacement The current separator
+ */
+ return apply_filters( 'wpseo_replacements_filter_sep', $replacement );
+ }
+
+ /**
+ * Check if the current opened page is a Yoast SEO page.
+ *
+ * @return bool
+ */
+ public static function is_yoast_seo_page() {
+ static $is_yoast_seo;
+
+ if ( $is_yoast_seo === null ) {
+ $current_page = filter_input( INPUT_GET, 'page' );
+ $is_yoast_seo = ( substr( $current_page, 0, 6 ) === 'wpseo_' );
+ }
+
+ return $is_yoast_seo;
+ }
+
+ /**
+ * Check if the current opened page belongs to Yoast SEO Free.
+ *
+ * @param string $current_page the current page the user is on.
+ *
+ * @return bool
+ */
+ public static function is_yoast_seo_free_page( $current_page ) {
+ $yoast_seo_free_pages = array(
+ 'wpseo_dashboard',
+ 'wpseo_titles',
+ 'wpseo_social',
+ 'wpseo_xml',
+ 'wpseo_advanced',
+ 'wpseo_tools',
+ 'wpseo_search_console',
+ 'wpseo_licenses',
+ );
+
+ return in_array( $current_page, $yoast_seo_free_pages );
+ }
+
+ /**
+ * Determine if Yoast SEO is in development mode?
+ *
+ * Inspired by JetPack (https://github.com/Automattic/jetpack/blob/master/class.jetpack.php#L1383-L1406).
+ *
+ * @return bool
+ */
+ public static function is_development_mode() {
+ $development_mode = false;
+
+ if ( defined( 'WPSEO_DEBUG' ) ) {
+ $development_mode = WPSEO_DEBUG;
+ }
+ elseif ( site_url() && false === strpos( site_url(), '.' ) ) {
+ $development_mode = true;
+ }
+
+ /**
+ * Filter the Yoast SEO development mode.
+ *
+ * @since 3.0
+ *
+ * @param bool $development_mode Is Yoast SEOs development mode active.
+ */
+
+ return apply_filters( 'yoast_seo_development_mode', $development_mode );
+ }
+
+ /**
+ * Retrieve home URL with proper trailing slash.
+ *
+ * @param string $path Path relative to home URL.
+ * @param string|null $scheme Scheme to apply.
+ *
+ * @return string Home URL with optional path, appropriately slashed if not.
+ */
+ public static function home_url( $path = '', $scheme = null ) {
+
+ $home_url = home_url( $path, $scheme );
+
+ if ( ! empty( $path ) ) {
+ return $home_url;
+ }
+
+ $home_path = parse_url( $home_url, PHP_URL_PATH );
+
+ if ( '/' === $home_path ) { // Home at site root, already slashed.
+ return $home_url;
+ }
+
+ if ( is_null( $home_path ) ) { // Home at site root, always slash.
+ return trailingslashit( $home_url );
+ }
+
+ if ( is_string( $home_path ) ) { // Home in subdirectory, slash if permalink structure has slash.
+ return user_trailingslashit( $home_url );
+ }
+
+ return $home_url;
+ }
+
+ /**
+ * Returns a base64 URL for the svg for use in the menu
+ *
+ * @param bool $base64 Whether or not to return base64'd output.
+ *
+ * @return string
+ */
+ public static function get_icon_svg( $base64 = true ) {
+ $svg = '';
+
+ if ( $base64 ) {
+ return 'data:image/svg+xml;base64,' . base64_encode( $svg );
+ }
+
+ return $svg;
+ }
+
+ /**
+ * Returns the language part of a given locale, defaults to english when the $locale is empty
+ *
+ * @param string $locale The locale to get the language of.
+ * @returns string The language part of the locale.
+ */
+ public static function get_language( $locale ) {
+ $language = 'en';
+
+ if ( ! empty( $locale ) && strlen( $locale ) >= 2 ) {
+ $language = substr( $locale, 0, 2 );
+ }
+
+ return $language;
+ }
+
+ /**
+ * Returns the user locale for the language to be used in the admin.
+ *
+ * WordPress 4.7 introduced the ability for users to specify an Admin language
+ * different from the language used on the front end. This checks if the feature
+ * is available and returns the user's language, with a fallback to the site's language.
+ * Can be removed when support for WordPress 4.6 will be dropped, in favor
+ * of WordPress get_user_locale() that already fallbacks to the site’s locale.
+ *
+ * @returns string The locale.
+ */
+ public static function get_user_locale() {
+ if ( function_exists( 'get_user_locale' ) ) {
+ return get_user_locale();
+ }
+ return get_locale();
+ }
+
+ /**
+ * Checks if the WP-REST-API is available.
+ *
+ * @since 3.6
+ *
+ * @param string $minimum_version The minimum version the API should be.
+ *
+ * @return bool Returns true if the API is available.
+ */
+ public static function is_api_available( $minimum_version = '2.0' ) {
+ return ( defined( 'REST_API_VERSION' )
+ && version_compare( REST_API_VERSION, $minimum_version, '>=' ) );
+ }
+
+ /**
+ * Wrapper for the PHP filter input function.
+ *
+ * This is used because stupidly enough, the `filter_input` function is not available on all hosts...
+ *
+ * @deprecated Passes through to PHP call, no longer used in code.
+ *
+ * @param int $type Input type constant.
+ * @param string $variable_name Variable name to get.
+ * @param int $filter Filter to apply.
+ *
+ * @return mixed
+ */
+ public static function filter_input( $type, $variable_name, $filter = FILTER_DEFAULT ) {
+ return filter_input( $type, $variable_name, $filter );
+ }
+
+ /**
+ * Adds a hook that when given option is updated, the XML sitemap transient cache is cleared
+ *
+ * @deprecated
+ * @see WPSEO_Sitemaps_Cache::register_clear_on_option_update()
+ *
+ * @param string $option Option name.
+ * @param string $type Sitemap type.
+ */
+ public static function register_cache_clear_option( $option, $type = '' ) {
+ WPSEO_Sitemaps_Cache::register_clear_on_option_update( $option, $type );
+ }
+
+ /**
+ * Clears the transient cache when a given option is updated, if that option has been registered before
+ *
+ * @deprecated
+ * @see WPSEO_Sitemaps_Cache::clear_on_option_update()
+ *
+ * @param string $option The option that's being updated.
+ */
+ public static function clear_transient_cache( $option ) {
+ WPSEO_Sitemaps_Cache::clear_on_option_update( $option );
+ }
+
+ /**
+ * Clear entire XML sitemap cache
+ *
+ * @deprecated
+ * @see WPSEO_Sitemaps_Cache::clear()
+ *
+ * @param array $types Set of sitemap types to invalidate cache for.
+ */
+ public static function clear_sitemap_cache( $types = array() ) {
+ WPSEO_Sitemaps_Cache::clear( $types );
+ }
+
+ /**
+ * Wrapper for encoding the array as a json string. Includes a fallback if wp_json_encode doesn't exist.
+ *
+ * @deprecated 3.3 Core versions without wp_json_encode() no longer supported, fallback unnecessary.
+ *
+ * @param array $array_to_encode The array which will be encoded.
+ * @param int $options Optional. Array with options which will be passed in to the encoding methods.
+ * @param int $depth Optional. Maximum depth to walk through $data. Must be greater than 0. Default 512.
+ *
+ * @return false|string
+ */
+ public static function json_encode( array $array_to_encode, $options = 0, $depth = 512 ) {
+ return wp_json_encode( $array_to_encode, $options, $depth );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/index.php b/wp-content/plugins/wordpress-seo/inc/index.php
new file mode 100644
index 0000000..e94d9a4
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/index.php
@@ -0,0 +1,4 @@
+get_defaults();
+ * @internal Note: Some of the default values are added via the translate_defaults() method
+ */
+ protected $defaults = array(
+ 'breadcrumbs-404crumb' => '', // Text field.
+ 'breadcrumbs-blog-remove' => false,
+ 'breadcrumbs-boldlast' => false,
+ 'breadcrumbs-archiveprefix' => '', // Text field.
+ 'breadcrumbs-enable' => false,
+ 'breadcrumbs-home' => '', // Text field.
+ 'breadcrumbs-prefix' => '', // Text field.
+ 'breadcrumbs-searchprefix' => '', // Text field.
+ 'breadcrumbs-sep' => '»', // Text field.
+
+ /**
+ * Uses enrich_defaults() to add more along the lines of:
+ * - 'post_types-' . $pt->name . '-maintax' => 0 / string
+ * - 'taxonomy-' . $tax->name . '-ptparent' => 0 / string
+ */
+ );
+
+ /**
+ * @var array Array of variable option name patterns for the option
+ */
+ protected $variable_array_key_patterns = array(
+ 'post_types-',
+ 'taxonomy-',
+ );
+
+
+ /**
+ * Get the singleton instance of this class
+ *
+ * @return object
+ */
+ public static function get_instance() {
+ if ( ! ( self::$instance instanceof self ) ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+
+ /**
+ * Translate strings used in the option defaults
+ *
+ * @return void
+ */
+ public function translate_defaults() {
+ $this->defaults['breadcrumbs-404crumb'] = __( 'Error 404: Page not found', 'wordpress-seo' );
+ $this->defaults['breadcrumbs-archiveprefix'] = __( 'Archives for', 'wordpress-seo' );
+ $this->defaults['breadcrumbs-home'] = __( 'Home', 'wordpress-seo' );
+ $this->defaults['breadcrumbs-searchprefix'] = __( 'You searched for', 'wordpress-seo' );
+ }
+
+
+ /**
+ * Add dynamically created default options based on available post types and taxonomies
+ *
+ * @return void
+ */
+ public function enrich_defaults() {
+
+ // Retrieve all the relevant post type and taxonomy arrays.
+ $post_type_names = get_post_types( array( 'public' => true ), 'names' );
+ $taxonomy_names_custom = get_taxonomies( array( 'public' => true, '_builtin' => false ), 'names' );
+
+ if ( $post_type_names !== array() ) {
+ foreach ( $post_type_names as $pt ) {
+ $pto_taxonomies = get_object_taxonomies( $pt, 'names' );
+ if ( $pto_taxonomies !== array() ) {
+ $this->defaults[ 'post_types-' . $pt . '-maintax' ] = 0; // Select box.
+ }
+ unset( $pto_taxonomies );
+ }
+ unset( $pt );
+ }
+
+ if ( $taxonomy_names_custom !== array() ) {
+ foreach ( $taxonomy_names_custom as $tax ) {
+ $this->defaults[ 'taxonomy-' . $tax . '-ptparent' ] = 0; // Select box;.
+ }
+ unset( $tax );
+ }
+ }
+
+
+ /**
+ * Validate the option
+ *
+ * @param array $dirty New value for the option.
+ * @param array $clean Clean value for the option, normally the defaults.
+ * @param array $old Old value of the option.
+ *
+ * @return array Validated clean value for the option to be saved to the database
+ */
+ protected function validate_option( $dirty, $clean, $old ) {
+
+ $allowed_post_types = $this->get_allowed_post_types();
+
+ foreach ( $clean as $key => $value ) {
+
+ $switch_key = $this->get_switch_key( $key );
+
+ switch ( $switch_key ) {
+ /* text fields */
+ case 'breadcrumbs-404crumb':
+ case 'breadcrumbs-archiveprefix':
+ case 'breadcrumbs-home':
+ case 'breadcrumbs-prefix':
+ case 'breadcrumbs-searchprefix':
+ case 'breadcrumbs-sep':
+ if ( isset( $dirty[ $key ] ) ) {
+ $clean[ $key ] = wp_kses_post( $dirty[ $key ] );
+ }
+ break;
+
+
+ /* 'post_types-' . $pt->name . '-maintax' fields */
+ case 'post_types-':
+ $post_type = str_replace( array( 'post_types-', '-maintax' ), '', $key );
+ $taxonomies = get_object_taxonomies( $post_type, 'names' );
+
+ if ( isset( $dirty[ $key ] ) ) {
+ if ( $taxonomies !== array() && in_array( $dirty[ $key ], $taxonomies, true ) ) {
+ $clean[ $key ] = $dirty[ $key ];
+ }
+ elseif ( (string) $dirty[ $key ] === '0' || (string) $dirty[ $key ] === '' ) {
+ $clean[ $key ] = 0;
+ }
+ elseif ( sanitize_title_with_dashes( $dirty[ $key ] ) === $dirty[ $key ] ) {
+ // Allow taxonomies which may not be registered yet.
+ $clean[ $key ] = $dirty[ $key ];
+ }
+ else {
+ if ( isset( $old[ $key ] ) ) {
+ $clean[ $key ] = sanitize_title_with_dashes( $old[ $key ] );
+ }
+ if ( function_exists( 'add_settings_error' ) ) {
+ /**
+ * @todo [JRF => whomever] maybe change the untranslated $pt name in the
+ * error message to the nicely translated label ?
+ */
+ add_settings_error(
+ $this->group_name, // Slug title of the setting.
+ '_' . $key, // Suffix-id for the error message box.
+ sprintf( __( 'Please select a valid taxonomy for post type "%s"', 'wordpress-seo' ), $post_type ), // The error message.
+ 'error' // Error type, either 'error' or 'updated'.
+ );
+ }
+ }
+ }
+ elseif ( isset( $old[ $key ] ) ) {
+ $clean[ $key ] = sanitize_title_with_dashes( $old[ $key ] );
+ }
+ unset( $taxonomies, $post_type );
+ break;
+
+
+ /* 'taxonomy-' . $tax->name . '-ptparent' fields */
+ case 'taxonomy-':
+ if ( isset( $dirty[ $key ] ) ) {
+ if ( $allowed_post_types !== array() && in_array( $dirty[ $key ], $allowed_post_types, true ) ) {
+ $clean[ $key ] = $dirty[ $key ];
+ }
+ elseif ( (string) $dirty[ $key ] === '0' || (string) $dirty[ $key ] === '' ) {
+ $clean[ $key ] = 0;
+ }
+ elseif ( sanitize_key( $dirty[ $key ] ) === $dirty[ $key ] ) {
+ // Allow taxonomies which may not be registered yet.
+ $clean[ $key ] = $dirty[ $key ];
+ }
+ else {
+ if ( isset( $old[ $key ] ) ) {
+ $clean[ $key ] = sanitize_key( $old[ $key ] );
+ }
+ if ( function_exists( 'add_settings_error' ) ) {
+ /**
+ * @todo [JRF =? whomever] maybe change the untranslated $tax name in the
+ * error message to the nicely translated label ?
+ */
+ $tax = str_replace( array( 'taxonomy-', '-ptparent' ), '', $key );
+ add_settings_error(
+ $this->group_name, // Slug title of the setting.
+ '_' . $tax, // Suffix-id for the error message box.
+ sprintf( __( 'Please select a valid post type for taxonomy "%s"', 'wordpress-seo' ), $tax ), // The error message.
+ 'error' // Error type, either 'error' or 'updated'.
+ );
+ unset( $tax );
+ }
+ }
+ }
+ elseif ( isset( $old[ $key ] ) ) {
+ $clean[ $key ] = sanitize_key( $old[ $key ] );
+ }
+ break;
+
+
+ /*
+ Boolean fields
+ */
+
+ /*
+ Covers:
+ * 'breadcrumbs-blog-remove'
+ * 'breadcrumbs-boldlast'
+ * 'breadcrumbs-enable'
+ */
+ default:
+ $clean[ $key ] = ( isset( $dirty[ $key ] ) ? WPSEO_Utils::validate_bool( $dirty[ $key ] ) : false );
+ break;
+ }
+ }
+
+ return $clean;
+ }
+
+
+ /**
+ * Retrieve a list of the allowed post types as breadcrumb parent for a taxonomy
+ * Helper method for validation
+ *
+ * @internal don't make static as new types may still be registered
+ *
+ * @return array
+ */
+ protected function get_allowed_post_types() {
+ $allowed_post_types = array();
+
+ $post_types = get_post_types( array( 'public' => true ), 'objects' );
+
+ if ( get_option( 'show_on_front' ) == 'page' && get_option( 'page_for_posts' ) > 0 ) {
+ $allowed_post_types[] = 'post';
+ }
+
+ if ( is_array( $post_types ) && $post_types !== array() ) {
+ foreach ( $post_types as $type ) {
+ if ( $type->has_archive ) {
+ $allowed_post_types[] = $type->name;
+ }
+ }
+ }
+
+ return $allowed_post_types;
+ }
+
+
+ /**
+ * Clean a given option value
+ *
+ * @param array $option_value Old (not merged with defaults or filtered) option value to
+ * clean according to the rules for this option.
+ * @param string $current_version (optional) Version from which to upgrade, if not set,
+ * version specific upgrades will be disregarded.
+ * @param array $all_old_option_values (optional) Only used when importing old options to have
+ * access to the real old values, in contrast to the saved ones.
+ *
+ * @return array Cleaned option
+ */
+ protected function clean_option( $option_value, $current_version = null, $all_old_option_values = null ) {
+
+ /* Make sure the old fall-back defaults for empty option keys are now added to the option */
+ if ( isset( $current_version ) && version_compare( $current_version, '1.5.2.3', '<' ) ) {
+ if ( has_action( 'init', array( 'WPSEO_Options', 'bring_back_breadcrumb_defaults' ) ) === false ) {
+ add_action( 'init', array( 'WPSEO_Options', 'bring_back_breadcrumb_defaults' ), 3 );
+ }
+ }
+
+ /*
+ Make sure the values of the variable option key options are cleaned as they
+ may be retained and would not be cleaned/validated then
+ */
+ if ( is_array( $option_value ) && $option_value !== array() ) {
+
+ $allowed_post_types = $this->get_allowed_post_types();
+
+ foreach ( $option_value as $key => $value ) {
+ $switch_key = $this->get_switch_key( $key );
+
+ // Similar to validation routine - any changes made there should be made here too.
+ switch ( $switch_key ) {
+ /* 'post_types-' . $pt->name . '-maintax' fields */
+ case 'post_types-':
+ $post_type = str_replace( array( 'post_types-', '-maintax' ), '', $key );
+ $taxonomies = get_object_taxonomies( $post_type, 'names' );
+
+ if ( $taxonomies !== array() && in_array( $value, $taxonomies, true ) ) {
+ $option_value[ $key ] = $value;
+ }
+ elseif ( (string) $value === '0' || (string) $value === '' ) {
+ $option_value[ $key ] = 0;
+ }
+ elseif ( sanitize_title_with_dashes( $value ) === $value ) {
+ // Allow taxonomies which may not be registered yet.
+ $option_value[ $key ] = $value;
+ }
+ unset( $taxonomies, $post_type );
+ break;
+
+
+ /* 'taxonomy-' . $tax->name . '-ptparent' fields */
+ case 'taxonomy-':
+ if ( $allowed_post_types !== array() && in_array( $value, $allowed_post_types, true ) ) {
+ $option_value[ $key ] = $value;
+ }
+ elseif ( (string) $value === '0' || (string) $value === '' ) {
+ $option_value[ $key ] = 0;
+ }
+ elseif ( sanitize_key( $option_value[ $key ] ) === $option_value[ $key ] ) {
+ // Allow post types which may not be registered yet.
+ $option_value[ $key ] = $value;
+ }
+ break;
+ }
+ }
+ }
+
+ return $option_value;
+ }
+
+ /**
+ * With the changes to v1.5, the defaults for some of the textual breadcrumb settings are added
+ * dynamically, but empty strings are allowed.
+ * This caused issues for people who left the fields empty on purpose relying on the defaults.
+ * This little routine fixes that.
+ * Needs to be run on 'init' hook at prio 3 to make sure the defaults are translated.
+ */
+ public function bring_back_defaults() {
+ $option = get_option( $this->option_name );
+
+ $values_to_bring_back = array(
+ 'breadcrumbs-404crumb',
+ 'breadcrumbs-archiveprefix',
+ 'breadcrumbs-home',
+ 'breadcrumbs-searchprefix',
+ 'breadcrumbs-sep',
+ );
+ foreach ( $values_to_bring_back as $key ) {
+ if ( $option[ $key ] === '' && $this->defaults[ $key ] !== '' ) {
+ $option[ $key ] = $this->defaults[ $key ];
+ }
+ }
+ update_option( $this->option_name, $option );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-ms.php b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-ms.php
new file mode 100644
index 0000000..f259e61
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-ms.php
@@ -0,0 +1,220 @@
+get_defaults();
+ */
+ protected $defaults = array(
+ 'access' => 'admin',
+ 'defaultblog' => '', // Numeric blog ID or empty.
+ );
+
+ /**
+ * @var array $allowed_access_options Available options for the 'access' setting
+ * Used for input validation
+ *
+ * @static
+ *
+ * @internal Important: Make sure the options added to the array here are in line with the keys
+ * for the options set for the select box in the admin/pages/network.php file
+ */
+ public static $allowed_access_options = array(
+ 'admin',
+ 'superadmin',
+ );
+
+
+ /**
+ * Get the singleton instance of this class
+ *
+ * @return object
+ */
+ public static function get_instance() {
+ if ( ! ( self::$instance instanceof self ) ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Only run parent constructor in multisite context.
+ */
+ public function __construct() {
+ if ( is_multisite() ) {
+ parent::__construct();
+ }
+ }
+
+ /**
+ * Add filters to make sure that the option default is returned if the option is not set
+ *
+ * @return void
+ */
+ public function add_default_filters() {
+ // Don't change, needs to check for false as could return prio 0 which would evaluate to false.
+ if ( has_filter( 'default_site_option_' . $this->option_name, array( $this, 'get_defaults' ) ) === false ) {
+ add_filter( 'default_site_option_' . $this->option_name, array( $this, 'get_defaults' ) );
+ }
+ }
+
+
+ /**
+ * Remove the default filters.
+ * Called from the validate() method to prevent failure to add new options
+ *
+ * @return void
+ */
+ public function remove_default_filters() {
+ remove_filter( 'default_site_option_' . $this->option_name, array( $this, 'get_defaults' ) );
+ }
+
+
+ /**
+ * Add filters to make sure that the option is merged with its defaults before being returned
+ *
+ * @return void
+ */
+ public function add_option_filters() {
+ // Don't change, needs to check for false as could return prio 0 which would evaluate to false.
+ if ( has_filter( 'site_option_' . $this->option_name, array( $this, 'get_option' ) ) === false ) {
+ add_filter( 'site_option_' . $this->option_name, array( $this, 'get_option' ) );
+ }
+ }
+
+
+ /**
+ * Remove the option filters.
+ * Called from the clean_up methods to make sure we retrieve the original old option
+ *
+ * @return void
+ */
+ public function remove_option_filters() {
+ remove_filter( 'site_option_' . $this->option_name, array( $this, 'get_option' ) );
+ }
+
+
+ /* *********** METHODS influencing add_uption(), update_option() and saving from admin pages *********** */
+
+
+ /**
+ * Validate the option
+ *
+ * @param array $dirty New value for the option.
+ * @param array $clean Clean value for the option, normally the defaults.
+ * @param array $old Old value of the option.
+ *
+ * @return array Validated clean value for the option to be saved to the database
+ */
+ protected function validate_option( $dirty, $clean, $old ) {
+
+ foreach ( $clean as $key => $value ) {
+ switch ( $key ) {
+ case 'access':
+ if ( isset( $dirty[ $key ] ) && in_array( $dirty[ $key ], self::$allowed_access_options, true ) ) {
+ $clean[ $key ] = $dirty[ $key ];
+ }
+ elseif ( function_exists( 'add_settings_error' ) ) {
+ add_settings_error(
+ $this->group_name, // Slug title of the setting.
+ '_' . $key, // Suffix-id for the error message box.
+ /* translators: %1$s expands to the option name and %2$sexpands to Yoast SEO */
+ sprintf( __( '%1$s is not a valid choice for who should be allowed access to the %2$s settings. Value reset to the default.', 'wordpress-seo' ), esc_html( sanitize_text_field( $dirty[ $key ] ) ), 'Yoast SEO' ), // The error message.
+ 'error' // Error type, either 'error' or 'updated'.
+ );
+ }
+ break;
+
+
+ case 'defaultblog':
+ if ( isset( $dirty[ $key ] ) && ( $dirty[ $key ] !== '' && $dirty[ $key ] !== '-' ) ) {
+ $int = WPSEO_Utils::validate_int( $dirty[ $key ] );
+ if ( $int !== false && $int > 0 ) {
+ // Check if a valid blog number has been received.
+ $exists = get_blog_details( $int, false );
+ if ( $exists && $exists->deleted == 0 ) {
+ $clean[ $key ] = $int;
+ }
+ elseif ( function_exists( 'add_settings_error' ) ) {
+ add_settings_error(
+ $this->group_name, // Slug title of the setting.
+ '_' . $key, // Suffix-id for the error message box.
+ esc_html__( 'The default blog setting must be the numeric blog id of the blog you want to use as default.', 'wordpress-seo' ) . ' ' . sprintf( esc_html__( 'This must be an existing blog. Blog %s does not exist or has been marked as deleted.', 'wordpress-seo' ), '' . esc_html( sanitize_text_field( $dirty[ $key ] ) ) . '' ), // The error message.
+ 'error' // Error type, either 'error' or 'updated'.
+ );
+ }
+ unset( $exists );
+ }
+ elseif ( function_exists( 'add_settings_error' ) ) {
+ add_settings_error(
+ $this->group_name, // Slug title of the setting.
+ '_' . $key, // Suffix-id for the error message box.
+ esc_html__( 'The default blog setting must be the numeric blog id of the blog you want to use as default.', 'wordpress-seo' ) . ' ' . esc_html__( 'No numeric value was received.', 'wordpress-seo' ), // The error message.
+ 'error' // Error type, either 'error' or 'updated'.
+ );
+ }
+ unset( $int );
+ }
+ break;
+
+ default:
+ $clean[ $key ] = ( isset( $dirty[ $key ] ) ? WPSEO_Utils::validate_bool( $dirty[ $key ] ) : false );
+ break;
+ }
+ }
+
+ return $clean;
+ }
+
+
+ /**
+ * Clean a given option value
+ *
+ * @param array $option_value Old (not merged with defaults or filtered) option value to
+ * clean according to the rules for this option.
+ * @param string $current_version (optional) Version from which to upgrade, if not set,
+ * version specific upgrades will be disregarded.
+ * @param array $all_old_option_values (optional) Only used when importing old options to have
+ * access to the real old values, in contrast to the saved ones.
+ *
+ * @return array Cleaned option
+ */
+
+ /*
+ Protected function clean_option( $option_value, $current_version = null, $all_old_option_values = null ) {
+
+ return $option_value;
+ }
+ */
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-permalinks.php b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-permalinks.php
new file mode 100644
index 0000000..e2ae859
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-permalinks.php
@@ -0,0 +1,131 @@
+get_defaults();
+ */
+ protected $defaults = array(
+ 'cleanpermalinks' => false,
+ 'cleanpermalink-extravars' => '', // Text field.
+ 'cleanpermalink-googlecampaign' => false,
+ 'cleanpermalink-googlesitesearch' => false,
+ 'cleanreplytocom' => false,
+ 'cleanslugs' => true,
+ 'redirectattachment' => false,
+ 'stripcategorybase' => false,
+ 'trailingslash' => false,
+ );
+
+
+ /**
+ * Add the actions and filters for the option
+ *
+ * @todo [JRF => testers] Check if the extra actions below would run into problems if an option
+ * is updated early on and if so, change the call to schedule these for a later action on add/update
+ * instead of running them straight away
+ *
+ * @return \WPSEO_Option_Permalinks
+ */
+ protected function __construct() {
+ parent::__construct();
+ add_action( 'update_option_' . $this->option_name, array( 'WPSEO_Utils', 'clear_rewrites' ) );
+ }
+
+
+ /**
+ * Get the singleton instance of this class
+ *
+ * @return object
+ */
+ public static function get_instance() {
+ if ( ! ( self::$instance instanceof self ) ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+
+ /**
+ * Validate the option
+ *
+ * @param array $dirty New value for the option.
+ * @param array $clean Clean value for the option, normally the defaults.
+ * @param array $old Old value of the option (not used here as all fields will always be in the form).
+ *
+ * @return array Validated clean value for the option to be saved to the database
+ */
+ protected function validate_option( $dirty, $clean, $old ) {
+
+ foreach ( $clean as $key => $value ) {
+ switch ( $key ) {
+ /* text fields */
+ case 'cleanpermalink-extravars':
+ if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
+ $clean[ $key ] = sanitize_text_field( $dirty[ $key ] );
+ }
+ break;
+
+ /*
+ Boolean (checkbox) fields
+ */
+
+ /*
+ Covers:
+ * 'cleanpermalinks'
+ * 'cleanpermalink-googlesitesearch'
+ * 'cleanpermalink-googlecampaign'
+ * 'cleanreplytocom'
+ * 'cleanslugs'
+ * 'hide-rsdlink'
+ * 'hide-wlwmanifest'
+ * 'hide-shortlink'
+ * 'hide-feedlinks'
+ * 'redirectattachment'
+ * 'stripcategorybase'
+ * 'trailingslash'
+ */
+ default:
+ $clean[ $key ] = ( isset( $dirty[ $key ] ) ? WPSEO_Utils::validate_bool( $dirty[ $key ] ) : false );
+ break;
+ }
+ }
+
+ return $clean;
+ }
+
+
+ /**
+ * Clean a given option value
+ *
+ * @param array $option_value Old (not merged with defaults or filtered) option value to
+ * clean according to the rules for this option.
+ * @param string $current_version (optional) Version from which to upgrade, if not set,
+ * version specific upgrades will be disregarded.
+ * @param array $all_old_option_values (optional) Only used when importing old options to have
+ * access to the real old values, in contrast to the saved ones.
+ *
+ * @return array Cleaned option
+ */
+
+ /*
+ Protected function clean_option( $option_value, $current_version = null, $all_old_option_values = null ) {
+
+ return $option_value;
+ }
+ */
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-rss.php b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-rss.php
new file mode 100644
index 0000000..8c9898a
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-rss.php
@@ -0,0 +1,69 @@
+get_defaults();
+ * @internal Note: Some of the default values are added via the translate_defaults() method
+ */
+ protected $defaults = array(
+ 'rssbefore' => '', // Text area.
+ 'rssafter' => '', // Text area.
+ );
+
+
+ /**
+ * Get the singleton instance of this class
+ *
+ * @return object
+ */
+ public static function get_instance() {
+ if ( ! ( self::$instance instanceof self ) ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+
+ /**
+ * Translate strings used in the option defaults
+ *
+ * @return void
+ */
+ public function translate_defaults() {
+ $this->defaults['rssafter'] = sprintf( __( 'The post %s appeared first on %s.', 'wordpress-seo' ), '%%POSTLINK%%', '%%BLOGLINK%%' );
+ }
+
+
+ /**
+ * Validate the option
+ *
+ * @param array $dirty New value for the option.
+ * @param array $clean Clean value for the option, normally the defaults.
+ * @param array $old Old value of the option.
+ *
+ * @return array Validated clean value for the option to be saved to the database
+ */
+ protected function validate_option( $dirty, $clean, $old ) {
+ foreach ( $clean as $key => $value ) {
+ if ( isset( $dirty[ $key ] ) ) {
+ $clean[ $key ] = wp_kses_post( $dirty[ $key ] );
+ }
+ }
+
+ return $clean;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-social.php b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-social.php
new file mode 100644
index 0000000..414bea6
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-social.php
@@ -0,0 +1,319 @@
+get_defaults();
+ */
+ protected $defaults = array(
+ // Non-form fields, set via procedural code in admin/pages/social.php.
+ 'fb_admins' => array(), // Array of user id's => array( name => '', link => '' ).
+
+ // Non-form field, set via translate_defaults() and validate_option() methods.
+ 'fbconnectkey' => '',
+ // Form fields:
+ 'facebook_site' => '', // Text field.
+ 'instagram_url' => '',
+ 'linkedin_url' => '',
+ 'myspace_url' => '',
+ 'og_default_image' => '', // Text field.
+ 'og_frontpage_title' => '', // Text field.
+ 'og_frontpage_desc' => '', // Text field.
+ 'og_frontpage_image' => '', // Text field.
+ 'opengraph' => true,
+ 'pinterest_url' => '',
+ 'pinterestverify' => '',
+ 'plus-publisher' => '', // Text field.
+ 'twitter' => true,
+ 'twitter_site' => '', // Text field.
+ 'twitter_card_type' => 'summary',
+ 'youtube_url' => '',
+ 'google_plus_url' => '',
+ // Form field, but not always available:
+ 'fbadminapp' => '', // Facebook app ID.
+ );
+
+ /**
+ * @var array Array of sub-options which should not be overloaded with multi-site defaults
+ */
+ public $ms_exclude = array(
+ /* privacy */
+ 'fb_admins',
+ 'fbconnectkey',
+ 'fbadminapp',
+ 'pinterestverify',
+ );
+
+
+ /**
+ * @var array Array of allowed twitter card types
+ * While we only have the options summary and summary_large_image in the
+ * interface now, we might change that at some point.
+ *
+ * @internal Uncomment any of these to allow them in validation *and* automatically add them as a choice
+ * in the options page
+ */
+ public static $twitter_card_types = array(
+ 'summary' => '',
+ 'summary_large_image' => '',
+ // 'photo' => '',
+ // 'gallery' => '',
+ // 'app' => '',
+ // 'player' => '',
+ // 'product' => '',
+ );
+
+
+ /**
+ * Get the singleton instance of this class
+ *
+ * @return object
+ */
+ public static function get_instance() {
+ if ( ! ( self::$instance instanceof self ) ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+
+ /**
+ * Translate/set strings used in the option defaults
+ *
+ * @return void
+ */
+ public function translate_defaults() {
+ /* Auto-magically set the fb connect key */
+ $this->defaults['fbconnectkey'] = self::get_fbconnectkey();
+
+ self::$twitter_card_types['summary'] = __( 'Summary', 'wordpress-seo' );
+ self::$twitter_card_types['summary_large_image'] = __( 'Summary with large image', 'wordpress-seo' );
+ }
+
+
+ /**
+ * Get a Facebook connect key for the blog
+ *
+ * @static
+ * @return string
+ */
+ public static function get_fbconnectkey() {
+ return md5( get_bloginfo( 'url' ) . rand() );
+ }
+
+
+ /**
+ * Validate the option
+ *
+ * @param array $dirty New value for the option.
+ * @param array $clean Clean value for the option, normally the defaults.
+ * @param array $old Old value of the option.
+ *
+ * @return array Validated clean value for the option to be saved to the database
+ */
+ protected function validate_option( $dirty, $clean, $old ) {
+
+ foreach ( $clean as $key => $value ) {
+ switch ( $key ) {
+ /* Automagic Facebook connect key */
+ case 'fbconnectkey':
+ if ( ( isset( $old[ $key ] ) && $old[ $key ] !== '' ) && preg_match( '`^[a-f0-9]{32}$`', $old[ $key ] ) > 0 ) {
+ $clean[ $key ] = $old[ $key ];
+ }
+ else {
+ $clean[ $key ] = self::get_fbconnectkey();
+ }
+ break;
+
+
+ /* Will not always exist in form */
+ case 'fb_admins':
+ if ( isset( $dirty[ $key ] ) && is_array( $dirty[ $key ] ) ) {
+ if ( $dirty[ $key ] === array() ) {
+ $clean[ $key ] = array();
+ }
+ else {
+ foreach ( $dirty[ $key ] as $user_id => $fb_array ) {
+ /*
+ * @todo [JRF/JRF => Yoast/whomever] add user_id validation -
+ * are these WP user-ids or FB user-ids ? Probably FB user-ids,
+ * if so, find out the rules for FB user-ids
+ */
+ if ( is_array( $fb_array ) && $fb_array !== array() ) {
+ foreach ( $fb_array as $fb_key => $fb_value ) {
+ switch ( $fb_key ) {
+ case 'name':
+ /**
+ * @todo [JRF => whomever] add validation for name based
+ * on rules if there are any
+ * Input comes from: $_GET['userrealname']
+ */
+ $clean[ $key ][ $user_id ][ $fb_key ] = sanitize_text_field( $fb_value );
+ break;
+
+ case 'link':
+ $clean[ $key ][ $user_id ][ $fb_key ] = WPSEO_Utils::sanitize_url( $fb_value );
+ break;
+ }
+ }
+ }
+ }
+ unset( $user_id, $fb_array, $fb_key, $fb_value );
+ }
+ }
+ elseif ( isset( $old[ $key ] ) && is_array( $old[ $key ] ) ) {
+ $clean[ $key ] = $old[ $key ];
+ }
+ break;
+
+ /* text fields */
+ case 'og_frontpage_desc':
+ case 'og_frontpage_title':
+ if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
+ $clean[ $key ] = WPSEO_Utils::sanitize_text_field( $dirty[ $key ] );
+ }
+ break;
+
+
+ /* url text fields - no ftp allowed */
+ case 'facebook_site':
+ case 'instagram_url':
+ case 'linkedin_url':
+ case 'myspace_url':
+ case 'pinterest_url':
+ case 'plus-publisher':
+ case 'og_default_image':
+ case 'og_frontpage_image':
+ case 'youtube_url':
+ case 'google_plus_url':
+ $this->validate_url( $key, $dirty, $old, $clean );
+ break;
+
+ case 'pinterestverify':
+ $this->validate_verification_string( $key, $dirty, $old, $clean );
+ break;
+
+ /* twitter user name */
+ case 'twitter_site':
+ if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
+ $twitter_id = sanitize_text_field( ltrim( $dirty[ $key ], '@' ) );
+ /**
+ * From the Twitter documentation about twitter screen names:
+ * Typically a maximum of 15 characters long, but some historical accounts
+ * may exist with longer names.
+ * A username can only contain alphanumeric characters (letters A-Z, numbers 0-9)
+ * with the exception of underscores
+ *
+ * @link https://support.twitter.com/articles/101299-why-can-t-i-register-certain-usernames
+ * @link https://dev.twitter.com/docs/platform-objects/users
+ */
+ if ( preg_match( '`^[A-Za-z0-9_]{1,25}$`', $twitter_id ) ) {
+ $clean[ $key ] = $twitter_id;
+ }
+ elseif ( preg_match( '`^http(?:s)?://(?:www\.)?twitter\.com/(?P[A-Za-z0-9_]{1,25})/?$`', $twitter_id, $matches ) ) {
+ $clean[ $key ] = $matches['handle'];
+ }
+ else {
+ if ( isset( $old[ $key ] ) && $old[ $key ] !== '' ) {
+ $twitter_id = sanitize_text_field( ltrim( $old[ $key ], '@' ) );
+ if ( preg_match( '`^[A-Za-z0-9_]{1,25}$`', $twitter_id ) ) {
+ $clean[ $key ] = $twitter_id;
+ }
+ }
+ if ( function_exists( 'add_settings_error' ) ) {
+ add_settings_error(
+ $this->group_name, // Slug title of the setting.
+ '_' . $key, // Suffix-id for the error message box.
+ sprintf( __( '%s does not seem to be a valid Twitter user-id. Please correct.', 'wordpress-seo' ), '' . esc_html( sanitize_text_field( $dirty[ $key ] ) ) . '' ), // The error message.
+ 'error' // Error type, either 'error' or 'updated'.
+ );
+ }
+ }
+ unset( $twitter_id );
+ }
+ break;
+
+ case 'twitter_card_type':
+ if ( isset( $dirty[ $key ], self::$twitter_card_types[ $dirty[ $key ] ] ) && $dirty[ $key ] !== '' ) {
+ $clean[ $key ] = $dirty[ $key ];
+ }
+ break;
+
+ /* boolean fields */
+ case 'opengraph':
+ case 'twitter':
+ $clean[ $key ] = ( isset( $dirty[ $key ] ) ? WPSEO_Utils::validate_bool( $dirty[ $key ] ) : false );
+ break;
+ }
+ }
+
+ /**
+ * Only validate 'fbadminapp', so leave the clean default.
+ */
+ if ( isset( $dirty['fbadminapp'] ) && ! empty( $dirty['fbadminapp'] ) ) {
+ $clean['fbadminapp'] = $dirty['fbadminapp'];
+ }
+
+
+ return $clean;
+ }
+
+
+ /**
+ * Clean a given option value
+ *
+ * @param array $option_value Old (not merged with defaults or filtered) option value to
+ * clean according to the rules for this option.
+ * @param string $current_version (optional) Version from which to upgrade, if not set,
+ * version specific upgrades will be disregarded.
+ * @param array $all_old_option_values (optional) Only used when importing old options to have
+ * access to the real old values, in contrast to the saved ones.
+ *
+ * @return array Cleaned option
+ */
+ protected function clean_option( $option_value, $current_version = null, $all_old_option_values = null ) {
+
+ /* Move options from very old option to this one */
+ $old_option = null;
+ if ( isset( $all_old_option_values ) ) {
+ // Ok, we have an import.
+ if ( isset( $all_old_option_values['wpseo_indexation'] ) && is_array( $all_old_option_values['wpseo_indexation'] ) && $all_old_option_values['wpseo_indexation'] !== array() ) {
+ $old_option = $all_old_option_values['wpseo_indexation'];
+ }
+ }
+ else {
+ $old_option = get_option( 'wpseo_indexation' );
+ }
+
+ if ( is_array( $old_option ) && $old_option !== array() ) {
+ $move = array(
+ 'opengraph',
+ 'fb_adminid',
+ 'fb_appid',
+ );
+ foreach ( $move as $key ) {
+ if ( isset( $old_option[ $key ] ) && ! isset( $option_value[ $key ] ) ) {
+ $option_value[ $key ] = $old_option[ $key ];
+ }
+ }
+ unset( $move, $key );
+ }
+ unset( $old_option );
+
+
+ return $option_value;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-titles.php b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-titles.php
new file mode 100644
index 0000000..38d528a
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-titles.php
@@ -0,0 +1,613 @@
+get_defaults();
+ * @internal Note: Some of the default values are added via the translate_defaults() method
+ */
+ protected $defaults = array(
+ // Non-form fields, set via (ajax) function.
+ 'title_test' => 0,
+ // Form fields.
+ 'forcerewritetitle' => false,
+ 'content-analysis-active' => true,
+ 'keyword-analysis-active' => true,
+ 'separator' => 'sc-dash',
+ 'noodp' => false,
+ 'usemetakeywords' => false,
+ 'title-home-wpseo' => '%%sitename%% %%page%% %%sep%% %%sitedesc%%', // Text field.
+ 'title-author-wpseo' => '', // Text field.
+ 'title-archive-wpseo' => '%%date%% %%page%% %%sep%% %%sitename%%', // Text field.
+ 'title-search-wpseo' => '', // Text field.
+ 'title-404-wpseo' => '', // Text field.
+
+ 'metadesc-home-wpseo' => '', // Text area.
+ 'metadesc-author-wpseo' => '', // Text area.
+ 'metadesc-archive-wpseo' => '', // Text area.
+ 'metakey-home-wpseo' => '', // Text field.
+ 'metakey-author-wpseo' => '', // Text field.
+
+ 'noindex-subpages-wpseo' => false,
+ 'noindex-author-wpseo' => false,
+ 'noindex-archive-wpseo' => true,
+
+ 'disable-author' => false,
+ 'disable-date' => false,
+ 'disable-post_format' => false,
+
+ /**
+ * Uses enrich_defaults to add more along the lines of:
+ * - 'title-' . $pt->name => ''; // Text field.
+ * - 'metadesc-' . $pt->name => ''; // Text field.
+ * - 'metakey-' . $pt->name => ''; // Text field.
+ * - 'noindex-' . $pt->name => false;
+ * - 'showdate-' . $pt->name => false;
+ * - 'hideeditbox-' . $pt->name => false;
+ *
+ * - 'title-ptarchive-' . $pt->name => ''; // Text field.
+ * - 'metadesc-ptarchive-' . $pt->name => ''; // Text field.
+ * - 'metakey-ptarchive-' . $pt->name => ''; // Text field.
+ * - 'bctitle-ptarchive-' . $pt->name => ''; // Text field.
+ * - 'noindex-ptarchive-' . $pt->name => false;
+ *
+ * - 'title-tax-' . $tax->name => '''; // Text field.
+ * - 'metadesc-tax-' . $tax->name => ''; // Text field.
+ * - 'metakey-tax-' . $tax->name => ''; // Text field.
+ * - 'noindex-tax-' . $tax->name => false;
+ * - 'hideeditbox-tax-' . $tax->name => false;
+ */
+ );
+
+ /**
+ * @var array Array of variable option name patterns for the option
+ */
+ protected $variable_array_key_patterns = array(
+ 'title-',
+ 'metadesc-',
+ 'metakey-',
+ 'noindex-',
+ 'showdate-',
+ 'hideeditbox-',
+ 'bctitle-ptarchive-',
+ );
+
+ /**
+ * @var array Array of sub-options which should not be overloaded with multi-site defaults
+ */
+ public $ms_exclude = array(
+ /* theme dependent */
+ 'title_test',
+ 'forcerewritetitle',
+ );
+
+ /**
+ * @var array Array of the separator options. To get these options use WPSEO_Option_Titles::get_instance()->get_separator_options()
+ */
+ private $separator_options = array(
+ 'sc-dash' => '-',
+ 'sc-ndash' => '–',
+ 'sc-mdash' => '—',
+ 'sc-middot' => '·',
+ 'sc-bull' => '•',
+ 'sc-star' => '*',
+ 'sc-smstar' => '⋆',
+ 'sc-pipe' => '|',
+ 'sc-tilde' => '~',
+ 'sc-laquo' => '«',
+ 'sc-raquo' => '»',
+ 'sc-lt' => '<',
+ 'sc-gt' => '>',
+ );
+
+ /**
+ * Add the actions and filters for the option
+ *
+ * @todo [JRF => testers] Check if the extra actions below would run into problems if an option
+ * is updated early on and if so, change the call to schedule these for a later action on add/update
+ * instead of running them straight away
+ *
+ * @return \WPSEO_Option_Titles
+ */
+ protected function __construct() {
+ parent::__construct();
+ add_action( 'update_option_' . $this->option_name, array( 'WPSEO_Utils', 'clear_cache' ) );
+ add_action( 'init', array( $this, 'end_of_init' ), 999 );
+ }
+
+
+ /**
+ * Make sure we can recognize the right action for the double cleaning
+ */
+ public function end_of_init() {
+ do_action( 'wpseo_double_clean_titles' );
+ }
+
+ /**
+ * Get the singleton instance of this class
+ *
+ * @return object
+ */
+ public static function get_instance() {
+ if ( ! ( self::$instance instanceof self ) ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Get the available separator options
+ *
+ * @return array
+ */
+ public function get_separator_options() {
+ $separators = $this->separator_options;
+
+ /**
+ * Allow altering the array with separator options
+ *
+ * @api array $separator_options Array with the separator options
+ */
+ $filtered_separators = apply_filters( 'wpseo_separator_options', $separators );
+
+ if ( is_array( $filtered_separators ) && $filtered_separators !== array() ) {
+ $separators = array_merge( $separators, $filtered_separators );
+ }
+
+ return $separators;
+ }
+
+ /**
+ * Translate strings used in the option defaults
+ *
+ * @return void
+ */
+ public function translate_defaults() {
+ $this->defaults['title-author-wpseo'] = sprintf( __( '%s, Author at %s', 'wordpress-seo' ), '%%name%%', '%%sitename%%' ) . ' %%page%% ';
+ $this->defaults['title-search-wpseo'] = sprintf( __( 'You searched for %s', 'wordpress-seo' ), '%%searchphrase%%' ) . ' %%page%% %%sep%% %%sitename%%';
+ $this->defaults['title-404-wpseo'] = __( 'Page not found', 'wordpress-seo' ) . ' %%sep%% %%sitename%%';
+ }
+
+
+ /**
+ * Add dynamically created default options based on available post types and taxonomies
+ *
+ * @return void
+ */
+ public function enrich_defaults() {
+
+ // Retrieve all the relevant post type and taxonomy arrays.
+ $post_type_names = get_post_types( array( 'public' => true ), 'names' );
+
+ $post_type_objects_custom = get_post_types( array( 'public' => true, '_builtin' => false ), 'objects' );
+
+ $taxonomy_names = get_taxonomies( array( 'public' => true ), 'names' );
+
+
+ if ( $post_type_names !== array() ) {
+ foreach ( $post_type_names as $pt ) {
+ $this->defaults[ 'title-' . $pt ] = '%%title%% %%page%% %%sep%% %%sitename%%'; // Text field.
+ $this->defaults[ 'metadesc-' . $pt ] = ''; // Text area.
+ $this->defaults[ 'metakey-' . $pt ] = ''; // Text field.
+ $this->defaults[ 'noindex-' . $pt ] = false;
+ $this->defaults[ 'showdate-' . $pt ] = false;
+ $this->defaults[ 'hideeditbox-' . $pt ] = false;
+ }
+ unset( $pt );
+ }
+
+ if ( $post_type_objects_custom !== array() ) {
+ $archive = sprintf( __( '%s Archive', 'wordpress-seo' ), '%%pt_plural%%' );
+ foreach ( $post_type_objects_custom as $pt ) {
+ if ( ! $pt->has_archive ) {
+ continue;
+ }
+
+ $this->defaults[ 'title-ptarchive-' . $pt->name ] = $archive . ' %%page%% %%sep%% %%sitename%%'; // Text field.
+ $this->defaults[ 'metadesc-ptarchive-' . $pt->name ] = ''; // Text area.
+ $this->defaults[ 'metakey-ptarchive-' . $pt->name ] = ''; // Text field.
+ $this->defaults[ 'bctitle-ptarchive-' . $pt->name ] = ''; // Text field.
+ $this->defaults[ 'noindex-ptarchive-' . $pt->name ] = false;
+ }
+ unset( $pt );
+ }
+
+ if ( $taxonomy_names !== array() ) {
+ $archives = sprintf( __( '%s Archives', 'wordpress-seo' ), '%%term_title%%' );
+ foreach ( $taxonomy_names as $tax ) {
+ $this->defaults[ 'title-tax-' . $tax ] = $archives . ' %%page%% %%sep%% %%sitename%%'; // Text field.
+ $this->defaults[ 'metadesc-tax-' . $tax ] = ''; // Text area.
+ $this->defaults[ 'metakey-tax-' . $tax ] = ''; // Text field.
+ $this->defaults[ 'hideeditbox-tax-' . $tax ] = false;
+
+ if ( $tax !== 'post_format' ) {
+ $this->defaults[ 'noindex-tax-' . $tax ] = false;
+ }
+ else {
+ $this->defaults[ 'noindex-tax-' . $tax ] = true;
+ }
+ }
+ unset( $tax );
+ }
+ }
+
+
+ /**
+ * Validate the option
+ *
+ * @param array $dirty New value for the option.
+ * @param array $clean Clean value for the option, normally the defaults.
+ * @param array $old Old value of the option.
+ *
+ * @return array Validated clean value for the option to be saved to the database
+ */
+ protected function validate_option( $dirty, $clean, $old ) {
+ foreach ( $clean as $key => $value ) {
+ $switch_key = $this->get_switch_key( $key );
+
+ switch ( $switch_key ) {
+ /*
+ Text fields
+ */
+
+ /*
+ Covers:
+ 'title-home-wpseo', 'title-author-wpseo', 'title-archive-wpseo',
+ 'title-search-wpseo', 'title-404-wpseo'
+ 'title-' . $pt->name
+ 'title-ptarchive-' . $pt->name
+ 'title-tax-' . $tax->name
+ */
+ case 'title-':
+ if ( isset( $dirty[ $key ] ) ) {
+ $clean[ $key ] = WPSEO_Utils::sanitize_text_field( $dirty[ $key ] );
+ }
+ break;
+
+ /*
+ Covers:
+ 'metadesc-home-wpseo', 'metadesc-author-wpseo', 'metadesc-archive-wpseo'
+ 'metadesc-' . $pt->name
+ 'metadesc-ptarchive-' . $pt->name
+ 'metadesc-tax-' . $tax->name
+ */
+ case 'metadesc-':
+ /*
+ Covers:
+ 'metakey-home-wpseo', 'metakey-author-wpseo'
+ 'metakey-' . $pt->name
+ 'metakey-ptarchive-' . $pt->name
+ 'metakey-tax-' . $tax->name
+ */
+ case 'metakey-':
+ /*
+ Covers:
+ ''bctitle-ptarchive-' . $pt->name
+ */
+ case 'bctitle-ptarchive-':
+ if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
+ $clean[ $key ] = WPSEO_Utils::sanitize_text_field( $dirty[ $key ] );
+ }
+ break;
+
+
+ /* integer field - not in form*/
+ case 'title_test':
+ if ( isset( $dirty[ $key ] ) ) {
+ $int = WPSEO_Utils::validate_int( $dirty[ $key ] );
+ if ( $int !== false && $int >= 0 ) {
+ $clean[ $key ] = $int;
+ }
+ }
+ elseif ( isset( $old[ $key ] ) ) {
+ $int = WPSEO_Utils::validate_int( $old[ $key ] );
+ if ( $int !== false && $int >= 0 ) {
+ $clean[ $key ] = $int;
+ }
+ }
+ break;
+
+ /* Separator field - Radio */
+ case 'separator':
+ if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
+
+ // Get separator fields.
+ $separator_fields = $this->get_separator_options();
+
+ // Check if the given separator is exists.
+ if ( isset( $separator_fields[ $dirty[ $key ] ] ) ) {
+ $clean[ $key ] = $dirty[ $key ];
+ }
+ }
+ break;
+
+ /*
+ Boolean fields
+ */
+
+ /*
+ Covers:
+ * 'noindex-subpages-wpseo', 'noindex-author-wpseo', 'noindex-archive-wpseo'
+ * 'noindex-' . $pt->name
+ * 'noindex-ptarchive-' . $pt->name
+ * 'noindex-tax-' . $tax->name
+ * 'forcerewritetitle':
+ * 'usemetakeywords':
+ * 'noodp':
+ * 'noydir':
+ * 'disable-author':
+ * 'disable-date':
+ * 'disable-post_format';
+ * 'noindex-'
+ * 'showdate-'
+ * 'showdate-'. $pt->name
+ * 'hideeditbox-'
+ * 'hideeditbox-'. $pt->name
+ * 'hideeditbox-tax-' . $tax->name
+ */
+ default:
+ $clean[ $key ] = ( isset( $dirty[ $key ] ) ? WPSEO_Utils::validate_bool( $dirty[ $key ] ) : false );
+ break;
+ }
+ }
+
+ return $clean;
+ }
+
+
+ /**
+ * Clean a given option value
+ *
+ * @param array $option_value Old (not merged with defaults or filtered) option value to
+ * clean according to the rules for this option.
+ * @param string $current_version (optional) Version from which to upgrade, if not set,
+ * version specific upgrades will be disregarded.
+ * @param array $all_old_option_values (optional) Only used when importing old options to have
+ * access to the real old values, in contrast to the saved ones.
+ *
+ * @return array Cleaned option
+ */
+ protected function clean_option( $option_value, $current_version = null, $all_old_option_values = null ) {
+ static $original = null;
+
+ // Double-run this function to ensure renaming of the taxonomy options will work.
+ if ( ! isset( $original ) && has_action( 'wpseo_double_clean_titles', array(
+ $this,
+ 'clean',
+ ) ) === false
+ ) {
+ add_action( 'wpseo_double_clean_titles', array( $this, 'clean' ) );
+ $original = $option_value;
+ }
+
+ /*
+ Move options from very old option to this one
+ @internal Don't rename to the 'current' names straight away as that would prevent
+ the rename/unset combi below from working
+ @todo [JRF] maybe figure out a smarter way to deal with this
+ */
+ $old_option = null;
+ if ( isset( $all_old_option_values ) ) {
+ // Ok, we have an import.
+ if ( isset( $all_old_option_values['wpseo_indexation'] ) && is_array( $all_old_option_values['wpseo_indexation'] ) && $all_old_option_values['wpseo_indexation'] !== array() ) {
+ $old_option = $all_old_option_values['wpseo_indexation'];
+ }
+ }
+ else {
+ $old_option = get_option( 'wpseo_indexation' );
+ }
+ if ( is_array( $old_option ) && $old_option !== array() ) {
+ $move = array(
+ 'noindexauthor' => 'noindex-author',
+ 'disableauthor' => 'disable-author',
+ 'noindexdate' => 'noindex-archive',
+ 'noindexcat' => 'noindex-category',
+ 'noindextag' => 'noindex-post_tag',
+ 'noindexpostformat' => 'noindex-post_format',
+ 'noindexsubpages' => 'noindex-subpages',
+ );
+ foreach ( $move as $old => $new ) {
+ if ( isset( $old_option[ $old ] ) && ! isset( $option_value[ $new ] ) ) {
+ $option_value[ $new ] = $old_option[ $old ];
+ }
+ }
+ unset( $move, $old, $new );
+ }
+ unset( $old_option );
+
+
+ // Fix wrongness created by buggy version 1.2.2.
+ if ( isset( $option_value['title-home'] ) && $option_value['title-home'] === '%%sitename%% - %%sitedesc%% - 12345' ) {
+ $option_value['title-home-wpseo'] = '%%sitename%% - %%sitedesc%%';
+ }
+
+
+ /*
+ Renaming these options to avoid ever overwritting these if a (bloody stupid) user /
+ programmer would use any of the following as a custom post type or custom taxonomy:
+ 'home', 'author', 'archive', 'search', '404', 'subpages'
+
+ Similarly, renaming the tax options to avoid a custom post type and a taxonomy
+ with the same name occupying the same option
+ */
+ $rename = array(
+ 'title-home' => 'title-home-wpseo',
+ 'title-author' => 'title-author-wpseo',
+ 'title-archive' => 'title-archive-wpseo',
+ 'title-search' => 'title-search-wpseo',
+ 'title-404' => 'title-404-wpseo',
+ 'metadesc-home' => 'metadesc-home-wpseo',
+ 'metadesc-author' => 'metadesc-author-wpseo',
+ 'metadesc-archive' => 'metadesc-archive-wpseo',
+ 'metakey-home' => 'metakey-home-wpseo',
+ 'metakey-author' => 'metakey-author-wpseo',
+ 'noindex-subpages' => 'noindex-subpages-wpseo',
+ 'noindex-author' => 'noindex-author-wpseo',
+ 'noindex-archive' => 'noindex-archive-wpseo',
+ );
+ foreach ( $rename as $old => $new ) {
+ if ( isset( $option_value[ $old ] ) && ! isset( $option_value[ $new ] ) ) {
+ $option_value[ $new ] = $option_value[ $old ];
+ unset( $option_value[ $old ] );
+ }
+ }
+ unset( $rename, $old, $new );
+
+
+ /**
+ * @internal This clean-up action can only be done effectively once the taxonomies and post_types
+ * have been registered, i.e. at the end of the init action.
+ */
+ if ( isset( $original ) && current_filter() === 'wpseo_double_clean_titles' || did_action( 'wpseo_double_clean_titles' ) > 0 ) {
+ $rename = array(
+ 'title-' => 'title-tax-',
+ 'metadesc-' => 'metadesc-tax-',
+ 'metakey-' => 'metakey-tax-',
+ 'noindex-' => 'noindex-tax-',
+ 'tax-hideeditbox-' => 'hideeditbox-tax-',
+
+ );
+ $taxonomy_names = get_taxonomies( array( 'public' => true ), 'names' );
+ $post_type_names = get_post_types( array( 'public' => true ), 'names' );
+ $defaults = $this->get_defaults();
+ if ( $taxonomy_names !== array() ) {
+ foreach ( $taxonomy_names as $tax ) {
+ foreach ( $rename as $old_prefix => $new_prefix ) {
+ if (
+ ( isset( $original[ $old_prefix . $tax ] ) && ! isset( $original[ $new_prefix . $tax ] ) )
+ && ( ! isset( $option_value[ $new_prefix . $tax ] )
+ || ( isset( $option_value[ $new_prefix . $tax ] )
+ && $option_value[ $new_prefix . $tax ] === $defaults[ $new_prefix . $tax ] ) )
+ ) {
+ $option_value[ $new_prefix . $tax ] = $original[ $old_prefix . $tax ];
+
+ /*
+ Check if there is a cpt with the same name as the tax,
+ if so, we should make sure that the old setting hasn't been removed
+ */
+ if ( ! isset( $post_type_names[ $tax ] ) && isset( $option_value[ $old_prefix . $tax ] ) ) {
+ unset( $option_value[ $old_prefix . $tax ] );
+ }
+ else {
+ if ( isset( $post_type_names[ $tax ] ) && ! isset( $option_value[ $old_prefix . $tax ] ) ) {
+ $option_value[ $old_prefix . $tax ] = $original[ $old_prefix . $tax ];
+ }
+ }
+
+ if ( $old_prefix === 'tax-hideeditbox-' ) {
+ unset( $option_value[ $old_prefix . $tax ] );
+ }
+ }
+ }
+ }
+ }
+ unset( $rename, $taxonomy_names, $post_type_names, $defaults, $tax, $old_prefix, $new_prefix );
+ }
+
+
+ /*
+ Make sure the values of the variable option key options are cleaned as they
+ may be retained and would not be cleaned/validated then
+ */
+ if ( is_array( $option_value ) && $option_value !== array() ) {
+ foreach ( $option_value as $key => $value ) {
+ $switch_key = $this->get_switch_key( $key );
+
+ // Similar to validation routine - any changes made there should be made here too.
+ switch ( $switch_key ) {
+ /* text fields */
+ case 'title-':
+ case 'metadesc-':
+ case 'metakey-':
+ case 'bctitle-ptarchive-':
+ $option_value[ $key ] = WPSEO_Utils::sanitize_text_field( $value );
+ break;
+
+ case 'separator':
+ if ( ! array_key_exists( $value, $this->get_separator_options() ) ) {
+ $option_value[ $key ] = false;
+ }
+ break;
+
+ /*
+ Boolean fields
+ */
+
+ /*
+ Covers:
+ * 'noindex-'
+ * 'showdate-'
+ * 'hideeditbox-'
+ */
+ default:
+ $option_value[ $key ] = WPSEO_Utils::validate_bool( $value );
+ break;
+ }
+ }
+ unset( $key, $value, $switch_key );
+ }
+
+ return $option_value;
+ }
+
+
+ /**
+ * Make sure that any set option values relating to post_types and/or taxonomies are retained,
+ * even when that post_type or taxonomy may not yet have been registered.
+ *
+ * @internal Overrule the abstract class version of this to make sure one extra renamed variable key
+ * does not get removed. IMPORTANT: keep this method in line with the parent on which it is based!
+ *
+ * @param array $dirty Original option as retrieved from the database.
+ * @param array $clean Filtered option where any options which shouldn't be in our option
+ * have already been removed and any options which weren't set
+ * have been set to their defaults.
+ *
+ * @return array
+ */
+ protected function retain_variable_keys( $dirty, $clean ) {
+ if ( ( is_array( $this->variable_array_key_patterns ) && $this->variable_array_key_patterns !== array() ) && ( is_array( $dirty ) && $dirty !== array() ) ) {
+
+ // Add the extra pattern.
+ $patterns = $this->variable_array_key_patterns;
+ $patterns[] = 'tax-hideeditbox-';
+
+ /**
+ * Allow altering the array with variable array key patterns
+ *
+ * @api array $patterns Array with the variable array key patterns
+ */
+ $patterns = apply_filters( 'wpseo_option_titles_variable_array_key_patterns', $patterns );
+
+ foreach ( $dirty as $key => $value ) {
+
+ // Do nothing if already in filtered option array.
+ if ( isset( $clean[ $key ] ) ) {
+ continue;
+ }
+
+ foreach ( $patterns as $pattern ) {
+ if ( strpos( $key, $pattern ) === 0 ) {
+ $clean[ $key ] = $value;
+ break;
+ }
+ }
+ }
+ }
+
+ return $clean;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-wpseo.php b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-wpseo.php
new file mode 100644
index 0000000..13b831f
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-wpseo.php
@@ -0,0 +1,244 @@
+get_defaults();
+ */
+ protected $defaults = array(
+ // Non-form fields, set via (ajax) function.
+ 'blocking_files' => array(),
+ 'ms_defaults_set' => false,
+ // Non-form field, should only be set via validation routine.
+ 'version' => '', // Leave default as empty to ensure activation/upgrade works.
+
+ // Form fields.
+ 'company_logo' => '',
+ 'company_name' => '',
+ 'company_or_person' => '',
+ 'disableadvanced_meta' => true,
+ 'onpage_indexability' => true,
+ 'googleverify' => '', // Text field.
+ 'msverify' => '', // Text field.
+ 'person_name' => '',
+ 'website_name' => '',
+ 'alternate_website_name' => '',
+ 'yandexverify' => '',
+ 'site_type' => '', // List of options.
+ 'has_multiple_authors' => '',
+ 'environment_type' => '',
+ 'enable_setting_pages' => true,
+ 'enable_admin_bar_menu' => true,
+ 'show_onboarding_notice' => false,
+ 'first_activated_on' => false,
+ );
+
+ /**
+ * @var array Sub-options which should not be overloaded with multi-site defaults
+ */
+ public $ms_exclude = array(
+ /* privacy */
+ 'alexaverify',
+ 'googleverify',
+ 'msverify',
+ 'yandexverify',
+ );
+
+ /** @var array Possible values for the site_type option */
+ protected $site_types = array(
+ '',
+ 'blog',
+ 'news',
+ 'smallBusiness',
+ 'corporateOther',
+ 'personalOther',
+ );
+
+ /** @var array Possible environment types. */
+ protected $environment_types = array(
+ '',
+ 'production',
+ 'staging',
+ 'development',
+ );
+
+ /**
+ * Add the actions and filters for the option
+ *
+ * @todo [JRF => testers] Check if the extra actions below would run into problems if an option
+ * is updated early on and if so, change the call to schedule these for a later action on add/update
+ * instead of running them straight away
+ *
+ * @return \WPSEO_Option_Wpseo
+ */
+ protected function __construct() {
+ parent::__construct();
+
+ /* Clear the cache on update/add */
+ add_action( 'add_option_' . $this->option_name, array( 'WPSEO_Utils', 'clear_cache' ) );
+ add_action( 'update_option_' . $this->option_name, array( 'WPSEO_Utils', 'clear_cache' ) );
+
+ /**
+ * Filter the `wpseo` option defaults.
+ *
+ * @param array $defaults Array the defaults for the `wpseo` option attributes.
+ */
+ $this->defaults = apply_filters( 'wpseo_option_wpseo_defaults', $this->defaults );
+ }
+
+
+ /**
+ * Get the singleton instance of this class
+ *
+ * @return object
+ */
+ public static function get_instance() {
+ if ( ! ( self::$instance instanceof self ) ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Validate the option
+ *
+ * @param array $dirty New value for the option.
+ * @param array $clean Clean value for the option, normally the defaults.
+ * @param array $old Old value of the option.
+ *
+ * @return array Validated clean value for the option to be saved to the database
+ */
+ protected function validate_option( $dirty, $clean, $old ) {
+
+ foreach ( $clean as $key => $value ) {
+ switch ( $key ) {
+ case 'version':
+ $clean[ $key ] = WPSEO_VERSION;
+ break;
+
+
+ case 'blocking_files':
+ /**
+ * @internal [JRF] to really validate this we should also do a file_exists()
+ * on each array entry and remove files which no longer exist, but that might be overkill
+ */
+ if ( isset( $dirty[ $key ] ) && is_array( $dirty[ $key ] ) ) {
+ $clean[ $key ] = array_unique( $dirty[ $key ] );
+ }
+ elseif ( isset( $old[ $key ] ) && is_array( $old[ $key ] ) ) {
+ $clean[ $key ] = array_unique( $old[ $key ] );
+ }
+ break;
+
+ case 'company_or_person':
+ if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
+ if ( in_array( $dirty[ $key ], array( 'company', 'person' ) ) ) {
+ $clean[ $key ] = $dirty[ $key ];
+ }
+ }
+ break;
+
+ /* text fields */
+ case 'company_name':
+ case 'person_name':
+ case 'website_name':
+ case 'alternate_website_name':
+ if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
+ $clean[ $key ] = sanitize_text_field( $dirty[ $key ] );
+ }
+ break;
+
+ case 'company_logo':
+ $this->validate_url( $key, $dirty, $old, $clean );
+ break;
+
+ /* verification strings */
+ case 'googleverify':
+ case 'msverify':
+ case 'yandexverify':
+ $this->validate_verification_string( $key, $dirty, $old, $clean );
+ break;
+
+ /*
+ Boolean dismiss warnings - not fields - may not be in form
+ (and don't need to be either as long as the default is false)
+ */
+ case 'ms_defaults_set':
+ if ( isset( $dirty[ $key ] ) ) {
+ $clean[ $key ] = WPSEO_Utils::validate_bool( $dirty[ $key ] );
+ }
+ elseif ( isset( $old[ $key ] ) ) {
+ $clean[ $key ] = WPSEO_Utils::validate_bool( $old[ $key ] );
+ }
+ break;
+
+ case 'site_type':
+ $clean[ $key ] = '';
+ if ( isset( $dirty[ $key ] ) && in_array( $dirty[ $key ], $this->site_types, true ) ) {
+ $clean[ $key ] = $dirty[ $key ];
+ }
+ break;
+ case 'environment_type':
+ $clean[ $key ] = '';
+ if ( isset( $dirty[ $key ] ) && in_array( $dirty[ $key ], $this->environment_types, true ) ) {
+ $clean[ $key ] = $dirty[ $key ];
+ }
+ break;
+
+ case 'first_activated_on' :
+ $clean[ $key ] = false;
+ if ( isset( $dirty[ $key ] ) ) {
+ if ( $dirty[ $key ] === false || WPSEO_Utils::validate_int( $dirty[ $key ] ) ) {
+ $clean[ $key ] = $dirty[ $key ];
+ }
+ }
+ break;
+
+ /*
+ Boolean (checkbox) fields
+ */
+
+ /*
+ Covers
+ * 'disableadvanced_meta'
+ * 'yoast_tracking'
+ */
+ default:
+ $clean[ $key ] = ( isset( $dirty[ $key ] ) ? WPSEO_Utils::validate_bool( $dirty[ $key ] ) : false );
+ break;
+ }
+ }
+
+ return $clean;
+ }
+
+
+ /**
+ * Clean a given option value
+ *
+ * @param array $option_value Old (not merged with defaults or filtered) option value to
+ * clean according to the rules for this option.
+ * @param string $current_version (optional) Version from which to upgrade, if not set,
+ * version specific upgrades will be disregarded.
+ * @param array $all_old_option_values (optional) Only used when importing old options to have
+ * access to the real old values, in contrast to the saved ones.
+ *
+ * @return array Cleaned option
+ */
+ protected function clean_option( $option_value, $current_version = null, $all_old_option_values = null ) {
+ return $option_value;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-xml.php b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-xml.php
new file mode 100644
index 0000000..6b14eb4
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option-xml.php
@@ -0,0 +1,259 @@
+get_defaults();
+ */
+ protected $defaults = array(
+ 'disable_author_sitemap' => true,
+ 'disable_author_noposts' => true,
+ 'enablexmlsitemap' => true,
+ 'entries-per-page' => 1000,
+ 'excluded-posts' => '',
+
+ /**
+ * Uses enrich_defaults to add more along the lines of:
+ * - 'user_role-' . $role_name . '-not_in_sitemap' => bool
+ * - 'post_types-' . $pt->name . '-not_in_sitemap' => bool
+ * - 'taxonomies-' . $tax->name . '-not_in_sitemap' => bool
+ */
+ );
+
+ /**
+ * @var array Array of variable option name patterns for the option
+ */
+ protected $variable_array_key_patterns = array(
+ 'user_role-',
+ 'post_types-',
+ 'taxonomies-',
+ );
+
+
+ /**
+ * Add the actions and filters for the option
+ *
+ * @todo [JRF => testers] Check if the extra actions below would run into problems if an option
+ * is updated early on and if so, change the call to schedule these for a later action on add/update
+ * instead of running them straight away
+ *
+ * @return \WPSEO_Option_XML
+ */
+ protected function __construct() {
+ parent::__construct();
+ add_action( 'update_option_' . $this->option_name, array( 'WPSEO_Utils', 'clear_rewrites' ) );
+ add_action( 'update_option_' . $this->option_name, array( 'WPSEO_Sitemaps_Cache', 'clear' ) );
+ }
+
+
+ /**
+ * Get the singleton instance of this class
+ *
+ * @return object
+ */
+ public static function get_instance() {
+ if ( ! ( self::$instance instanceof self ) ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Add dynamically created default options based on available post types and taxonomies
+ *
+ * @return void
+ */
+ public function enrich_defaults() {
+
+ $user_roles = WPSEO_Utils::get_roles();
+ $filtered_user_roles = apply_filters( 'wpseo_sitemaps_supported_user_roles', $user_roles );
+ if ( is_array( $filtered_user_roles ) && $filtered_user_roles !== array() ) {
+ foreach ( $filtered_user_roles as $role_name => $role_value ) {
+ $this->defaults[ 'user_role-' . $role_name . '-not_in_sitemap' ] = false;
+
+ unset( $user_role );
+ }
+ unset( $role_name, $role_value );
+ }
+ unset( $user_roles, $filtered_user_roles );
+
+ $post_type_names = get_post_types( array( 'public' => true ), 'names' );
+ $filtered_post_types = apply_filters( 'wpseo_sitemaps_supported_post_types', $post_type_names );
+
+ if ( is_array( $filtered_post_types ) && $filtered_post_types !== array() ) {
+ foreach ( $filtered_post_types as $pt ) {
+ if ( $pt !== 'attachment' ) {
+ $this->defaults[ 'post_types-' . $pt . '-not_in_sitemap' ] = false;
+ }
+ else {
+ $this->defaults[ 'post_types-' . $pt . '-not_in_sitemap' ] = true;
+ }
+ }
+ unset( $pt );
+ }
+ unset( $post_type_names, $filtered_post_types );
+
+ $taxonomy_objects = get_taxonomies( array( 'public' => true ), 'objects' );
+ $filtered_taxonomies = apply_filters( 'wpseo_sitemaps_supported_taxonomies', $taxonomy_objects );
+ if ( is_array( $filtered_taxonomies ) && $filtered_taxonomies !== array() ) {
+ foreach ( $filtered_taxonomies as $tax ) {
+ if ( isset( $tax->labels->name ) && trim( $tax->labels->name ) != '' ) {
+ $this->defaults[ 'taxonomies-' . $tax->name . '-not_in_sitemap' ] = false;
+ }
+ }
+ unset( $tax );
+ }
+ unset( $taxonomy_objects, $filtered_taxonomies );
+
+ }
+
+
+ /**
+ * Validate the option
+ *
+ * @param array $dirty New value for the option.
+ * @param array $clean Clean value for the option, normally the defaults.
+ * @param array $old Old value of the option.
+ *
+ * @return array Validated clean value for the option to be saved to the database
+ */
+ protected function validate_option( $dirty, $clean, $old ) {
+
+ foreach ( $clean as $key => $value ) {
+ $switch_key = $this->get_switch_key( $key );
+
+ switch ( $switch_key ) {
+ /* integer fields */
+ case 'entries-per-page':
+
+ if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
+
+ $int = WPSEO_Utils::validate_int( $dirty[ $key ] );
+
+ if ( $int !== false && $int > 0 ) {
+
+ if ( $int > 50000 ) {
+
+ $error_message = sprintf(
+ __( '"Max entries per sitemap page" should be below %s to meet Google\'s requirements, which %s is not.', 'wordpress-seo' ),
+ number_format_i18n( 50000 ), '' . esc_html( sanitize_text_field( $dirty[ $key ] ) ) . ''
+ );
+ add_settings_error( $this->group_name, '_' . $key, $error_message, 'error' );
+
+ $int = 50000;
+ }
+
+ $clean[ $key ] = $int;
+ }
+ else {
+
+ if ( isset( $old[ $key ] ) && $old[ $key ] !== '' ) {
+
+ $int = WPSEO_Utils::validate_int( $old[ $key ] );
+
+ if ( $int !== false && $int > 0 ) {
+ $clean[ $key ] = $int;
+ }
+ }
+
+ $error_message = sprintf(
+ __( '"Max entries per sitemap page" should be a positive number, which %s is not. Please correct.', 'wordpress-seo' ),
+ '' . esc_html( sanitize_text_field( $dirty[ $key ] ) ) . ''
+ );
+ add_settings_error( $this->group_name, '_' . $key, $error_message, 'error' );
+ }
+ unset( $int );
+ }
+ break;
+
+ case 'excluded-posts' :
+ if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
+ if ( $filtered_array = filter_var_array( explode( ',', $dirty[ $key ] ), FILTER_VALIDATE_INT ) ) {
+ $clean[ $key ] = implode( ',', array_filter( $filtered_array, 'is_integer' ) );
+
+ unset( $filtered_array );
+ }
+ }
+
+ break;
+
+ /*
+ Boolean fields
+ */
+
+ /*
+ Covers:
+ * 'disable_author_sitemap':
+ * 'disable_author_noposts':
+ * 'enablexmlsitemap':
+ * 'user_role-':
+ * 'user_role' . $role_name . '-not_in_sitemap' fields
+ * 'post_types-':
+ * 'post_types-' . $pt->name . '-not_in_sitemap' fields
+ * 'taxonomies-':
+ * 'taxonomies-' . $tax->name . '-not_in_sitemap' fields
+ */
+ default:
+ $clean[ $key ] = ( isset( $dirty[ $key ] ) ? WPSEO_Utils::validate_bool( $dirty[ $key ] ) : false );
+ break;
+ }
+ }
+
+ return $clean;
+ }
+
+
+ /**
+ * Clean a given option value
+ *
+ * @param array $option_value Old (not merged with defaults or filtered) option value to
+ * clean according to the rules for this option.
+ * @param string $current_version (optional) Version from which to upgrade, if not set,
+ * version specific upgrades will be disregarded.
+ * @param array $all_old_option_values (optional) Only used when importing old options to have
+ * access to the real old values, in contrast to the saved ones.
+ *
+ * @return array Cleaned option
+ */
+ protected function clean_option( $option_value, $current_version = null, $all_old_option_values = null ) {
+ /*
+ Make sure the values of the variable option key options are cleaned as they
+ may be retained and would not be cleaned/validated then
+ */
+ if ( is_array( $option_value ) && $option_value !== array() ) {
+
+ foreach ( $option_value as $key => $value ) {
+ $switch_key = $this->get_switch_key( $key );
+
+ // Similar to validation routine - any changes made there should be made here too.
+ switch ( $switch_key ) {
+ case 'user_role-': /* 'user_role-' . $role_name. '-not_in_sitemap' fields */
+ case 'post_types-': /* 'post_types-' . $pt->name . '-not_in_sitemap' fields */
+ case 'taxonomies-': /* 'taxonomies-' . $tax->name . '-not_in_sitemap' fields */
+ $option_value[ $key ] = WPSEO_Utils::validate_bool( $value );
+ break;
+ }
+ }
+ }
+
+ return $option_value;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option.php b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option.php
new file mode 100644
index 0000000..80d959c
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-option.php
@@ -0,0 +1,854 @@
+ testers] double check that validation will not cause errors when called
+ * from upgrade routine (some of the WP functions may not yet be available)
+ */
+abstract class WPSEO_Option {
+
+ /**
+ * @var string Option name - MUST be set in concrete class and set to public.
+ */
+ protected $option_name;
+
+ /**
+ * @var string Option group name for use in settings forms
+ * - will be set automagically if not set in concrete class
+ * (i.e. if it confirm to the normal pattern 'yoast' . $option_name . 'options',
+ * only set in conrete class if it doesn't)
+ */
+ public $group_name;
+
+ /**
+ * @var bool Whether to include the option in the return for WPSEO_Options::get_all().
+ * Also determines which options are copied over for ms_(re)set_blog().
+ */
+ public $include_in_all = true;
+
+ /**
+ * @var bool Whether this option is only for when the install is multisite.
+ */
+ public $multisite_only = false;
+
+ /**
+ * @var array Array of defaults for the option - MUST be set in concrete class.
+ * Shouldn't be requested directly, use $this->get_defaults();
+ */
+ protected $defaults;
+
+ /**
+ * @var array Array of variable option name patterns for the option - if any -
+ * Set this when the option contains array keys which vary based on post_type
+ * or taxonomy
+ */
+ protected $variable_array_key_patterns;
+
+ /**
+ * @var array Array of sub-options which should not be overloaded with multi-site defaults
+ */
+ public $ms_exclude = array();
+
+ /**
+ * @var object Instance of this class
+ */
+ protected static $instance;
+
+
+ /* *********** INSTANTIATION METHODS *********** */
+
+ /**
+ * Add all the actions and filters for the option
+ *
+ * @return \WPSEO_Option
+ */
+ protected function __construct() {
+
+ /* Add filters which get applied to the get_options() results */
+ $this->add_default_filters(); // Return defaults if option not set.
+ $this->add_option_filters(); // Merge with defaults if option *is* set.
+
+
+ if ( $this->multisite_only !== true ) {
+ /**
+ * The option validation routines remove the default filters to prevent failing
+ * to insert an option if it's new. Let's add them back afterwards.
+ */
+ add_action( 'add_option', array( $this, 'add_default_filters' ) ); // Adding back after INSERT.
+
+ if ( version_compare( $GLOBALS['wp_version'], '3.7', '!=' ) ) { // Adding back after non-WP 3.7 UPDATE.
+ add_action( 'update_option', array( $this, 'add_default_filters' ) );
+ }
+ else { // Adding back after WP 3.7 UPDATE.
+ add_filter( 'pre_update_option_' . $this->option_name, array( $this, 'wp37_add_default_filters' ) );
+ }
+ }
+ else if ( is_multisite() ) {
+ /*
+ The option validation routines remove the default filters to prevent failing
+ to insert an option if it's new. Let's add them back afterwards.
+
+ For site_options, this method is not foolproof as these actions are not fired
+ on an insert/update failure. Please use the WPSEO_Options::update_site_option() method
+ for updating site options to make sure the filters are in place.
+ */
+ add_action( 'add_site_option_' . $this->option_name, array( $this, 'add_default_filters' ) );
+ add_action( 'update_site_option_' . $this->option_name, array( $this, 'add_default_filters' ) );
+
+ }
+
+
+ /*
+ Make sure the option will always get validated, independently of register_setting()
+ (only available on back-end)
+ */
+ add_filter( 'sanitize_option_' . $this->option_name, array( $this, 'validate' ) );
+
+ /* Register our option for the admin pages */
+ add_action( 'admin_init', array( $this, 'register_setting' ) );
+
+
+ /* Set option group name if not given */
+ if ( ! isset( $this->group_name ) || $this->group_name === '' ) {
+ $this->group_name = 'yoast_' . $this->option_name . '_options';
+ }
+
+ /* Translate some defaults as early as possible - textdomain is loaded in init on priority 1 */
+ if ( method_exists( $this, 'translate_defaults' ) ) {
+ add_action( 'init', array( $this, 'translate_defaults' ), 2 );
+ }
+
+ /**
+ * Enrich defaults once custom post types and taxonomies have been registered
+ * which is normally done on the init action.
+ *
+ * @todo - [JRF/testers] verify that none of the options which are only available after
+ * enrichment are used before the enriching
+ */
+ if ( method_exists( $this, 'enrich_defaults' ) ) {
+ add_action( 'init', array( $this, 'enrich_defaults' ), 99 );
+ }
+ }
+
+// @codingStandardsIgnoreStart
+
+ /**
+ * All concrete classes *must* contain the get_instance method
+ * @internal Unfortunately I can't define it as an abstract as it also *has* to be static....
+ */
+ // abstract protected static function get_instance();
+
+
+ /**
+ * Concrete classes *may* contain a translate_defaults method
+ */
+ // abstract public function translate_defaults();
+
+
+ /**
+ * Concrete classes *may* contain a enrich_defaults method to add additional defaults once
+ * all post_types and taxonomies have been registered
+ */
+ // abstract public function enrich_defaults();
+
+// @codingStandardsIgnoreEnd
+
+ /* *********** METHODS INFLUENCING get_option() *********** */
+
+ /**
+ * Add filters to make sure that the option default is returned if the option is not set
+ *
+ * @return void
+ */
+ public function add_default_filters() {
+ // Don't change, needs to check for false as could return prio 0 which would evaluate to false.
+ if ( has_filter( 'default_option_' . $this->option_name, array( $this, 'get_defaults' ) ) === false ) {
+ add_filter( 'default_option_' . $this->option_name, array( $this, 'get_defaults' ) );
+ }
+ }
+
+
+ /**
+ * Abusing a filter to re-add our default filters
+ * WP 3.7 specific as update_option action hook was in the wrong place temporarily
+ *
+ * @see http://core.trac.wordpress.org/ticket/25705
+ *
+ * @param mixed $new_value Pass through value in filter.
+ *
+ * @deprecated 3.7 version no longer supported.
+ *
+ * @todo Drop this and logic adding it. R.
+ *
+ * @return mixed unchanged value
+ */
+ public function wp37_add_default_filters( $new_value ) {
+ $this->add_default_filters();
+
+ return $new_value;
+ }
+
+ /**
+ * Validate webmaster tools & Pinterest verification strings
+ *
+ * @param string $key Key to check, by type of service.
+ * @param array $dirty Dirty data.
+ * @param array $old Old data.
+ * @param array $clean Clean data by reference.
+ */
+ public function validate_verification_string( $key, $dirty, $old, &$clean ) {
+ if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
+ $meta = $dirty[ $key ];
+ if ( strpos( $meta, 'content=' ) ) {
+ // Make sure we only have the real key, not a complete meta tag.
+ preg_match( '`content=([\'"])?([^\'"> ]+)(?:\1|[ />])`', $meta, $match );
+ if ( isset( $match[2] ) ) {
+ $meta = $match[2];
+ }
+ unset( $match );
+ }
+
+ $meta = sanitize_text_field( $meta );
+ if ( $meta !== '' ) {
+ $regex = '`^[A-Fa-f0-9_-]+$`';
+ $service = '';
+
+ switch ( $key ) {
+ case 'googleverify':
+ $regex = '`^[A-Za-z0-9_-]+$`';
+ $service = 'Google Webmaster tools';
+ break;
+
+ case 'msverify':
+ $service = 'Bing Webmaster tools';
+ break;
+
+ case 'pinterestverify':
+ $service = 'Pinterest';
+ break;
+
+ case 'yandexverify':
+ $service = 'Yandex Webmaster tools';
+ break;
+ }
+
+ if ( preg_match( $regex, $meta ) ) {
+ $clean[ $key ] = $meta;
+ }
+ else {
+ if ( isset( $old[ $key ] ) && preg_match( $regex, $old[ $key ] ) ) {
+ $clean[ $key ] = $old[ $key ];
+ }
+ if ( function_exists( 'add_settings_error' ) ) {
+ add_settings_error(
+ $this->group_name, // Slug title of the setting.
+ '_' . $key, // Suffix-id for the error message box.
+ sprintf( __( '%s does not seem to be a valid %s verification string. Please correct.', 'wordpress-seo' ), '' . esc_html( $meta ) . '', $service ), // The error message.
+ 'error' // Error type, either 'error' or 'updated'.
+ );
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @param string $key Key to check, by type of service.
+ * @param array $dirty Dirty data.
+ * @param array $old Old data.
+ * @param array $clean Clean data by reference.
+ */
+ public function validate_url( $key, $dirty, $old, &$clean ) {
+ if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
+ $url = WPSEO_Utils::sanitize_url( $dirty[ $key ] );
+ if ( $url !== '' ) {
+ $clean[ $key ] = $url;
+ }
+ else {
+ if ( isset( $old[ $key ] ) && $old[ $key ] !== '' ) {
+ $url = WPSEO_Utils::sanitize_url( $old[ $key ] );
+ if ( $url !== '' ) {
+ $clean[ $key ] = $url;
+ }
+ }
+ if ( function_exists( 'add_settings_error' ) ) {
+ $url = WPSEO_Utils::sanitize_url( $dirty[ $key ] );
+ add_settings_error(
+ $this->group_name, // Slug title of the setting.
+ '_' . $key, // Suffix-id for the error message box.
+ sprintf( __( '%s does not seem to be a valid url. Please correct.', 'wordpress-seo' ), '' . esc_html( $url ) . '' ), // The error message.
+ 'error' // Error type, either 'error' or 'updated'.
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove the default filters.
+ * Called from the validate() method to prevent failure to add new options
+ *
+ * @return void
+ */
+ public function remove_default_filters() {
+ remove_filter( 'default_option_' . $this->option_name, array( $this, 'get_defaults' ) );
+ }
+
+
+ /**
+ * Get the enriched default value for an option
+ *
+ * Checks if the concrete class contains an enrich_defaults() method and if so, runs it.
+ *
+ * @internal the enrich_defaults method is used to set defaults for variable array keys in an option,
+ * such as array keys depending on post_types and/or taxonomies
+ *
+ * @return array
+ */
+ public function get_defaults() {
+ if ( method_exists( $this, 'translate_defaults' ) ) {
+ $this->translate_defaults();
+ }
+
+ if ( method_exists( $this, 'enrich_defaults' ) ) {
+ $this->enrich_defaults();
+ }
+
+ return apply_filters( 'wpseo_defaults', $this->defaults, $this->option_name );
+ }
+
+
+ /**
+ * Add filters to make sure that the option is merged with its defaults before being returned
+ *
+ * @return void
+ */
+ public function add_option_filters() {
+ // Don't change, needs to check for false as could return prio 0 which would evaluate to false.
+ if ( has_filter( 'option_' . $this->option_name, array( $this, 'get_option' ) ) === false ) {
+ add_filter( 'option_' . $this->option_name, array( $this, 'get_option' ) );
+ }
+ }
+
+
+ /**
+ * Remove the option filters.
+ * Called from the clean_up methods to make sure we retrieve the original old option
+ *
+ * @return void
+ */
+ public function remove_option_filters() {
+ remove_filter( 'option_' . $this->option_name, array( $this, 'get_option' ) );
+ }
+
+
+ /**
+ * Merge an option with its default values
+ *
+ * This method should *not* be called directly!!! It is only meant to filter the get_option() results
+ *
+ * @param mixed $options Option value.
+ *
+ * @return mixed Option merged with the defaults for that option
+ */
+ public function get_option( $options = null ) {
+ $filtered = $this->array_filter_merge( $options );
+
+ /*
+ If the option contains variable option keys, make sure we don't remove those settings
+ - even if the defaults are not complete yet.
+ Unfortunately this means we also won't be removing the settings for post types or taxonomies
+ which are no longer in the WP install, but rather that than the other way around
+ */
+ if ( isset( $this->variable_array_key_patterns ) ) {
+ $filtered = $this->retain_variable_keys( $options, $filtered );
+ }
+
+ return $filtered;
+ }
+
+
+ /* *********** METHODS influencing add_uption(), update_option() and saving from admin pages *********** */
+
+ /**
+ * Register (whitelist) the option for the configuration pages.
+ * The validation callback is already registered separately on the sanitize_option hook,
+ * so no need to double register.
+ *
+ * @return void
+ */
+ public function register_setting() {
+ if ( WPSEO_Utils::grant_access() ) {
+ register_setting( $this->group_name, $this->option_name );
+ }
+ }
+
+
+ /**
+ * Validate the option
+ *
+ * @param mixed $option_value The unvalidated new value for the option.
+ *
+ * @return array Validated new value for the option
+ */
+ public function validate( $option_value ) {
+ $clean = $this->get_defaults();
+
+ /* Return the defaults if the new value is empty */
+ if ( ! is_array( $option_value ) || $option_value === array() ) {
+ return $clean;
+ }
+
+
+ $option_value = array_map( array( 'WPSEO_Utils', 'trim_recursive' ), $option_value );
+ if ( $this->multisite_only !== true ) {
+ $old = get_option( $this->option_name );
+ }
+ else {
+ $old = get_site_option( $this->option_name );
+ }
+ $clean = $this->validate_option( $option_value, $clean, $old );
+
+ /* Retain the values for variable array keys even when the post type/taxonomy is not yet registered */
+ if ( isset( $this->variable_array_key_patterns ) ) {
+ $clean = $this->retain_variable_keys( $option_value, $clean );
+ }
+
+ $this->remove_default_filters();
+
+ return $clean;
+ }
+
+
+ /**
+ * All concrete classes must contain a validate_option() method which validates all
+ * values within the option
+ *
+ * @param array $dirty New value for the option.
+ * @param array $clean Clean value for the option, normally the defaults.
+ * @param array $old Old value of the option.
+ */
+ abstract protected function validate_option( $dirty, $clean, $old );
+
+
+ /* *********** METHODS for ADDING/UPDATING/UPGRADING the option *********** */
+
+ /**
+ * Retrieve the real old value (unmerged with defaults)
+ *
+ * @return array|bool the original option value (which can be false if the option doesn't exist)
+ */
+ protected function get_original_option() {
+ $this->remove_default_filters();
+ $this->remove_option_filters();
+
+ // Get (unvalidated) array, NOT merged with defaults.
+ if ( $this->multisite_only !== true ) {
+ $option_value = get_option( $this->option_name );
+ }
+ else {
+ $option_value = get_site_option( $this->option_name );
+ }
+
+ $this->add_option_filters();
+ $this->add_default_filters();
+
+ return $option_value;
+ }
+
+ /**
+ * Add the option if it doesn't exist for some strange reason
+ *
+ * @uses WPSEO_Option::get_original_option()
+ *
+ * @return void
+ */
+ public function maybe_add_option() {
+ if ( $this->get_original_option() === false ) {
+ if ( $this->multisite_only !== true ) {
+ update_option( $this->option_name, $this->get_defaults() );
+ }
+ else {
+ $this->update_site_option( $this->get_defaults() );
+ }
+ }
+ }
+
+
+ /**
+ * Update a site_option
+ *
+ * @internal This special method is only needed for multisite options, but very needed indeed there.
+ * The order in which certain functions and hooks are run is different between get_option() and
+ * get_site_option() which means in practice that the removing of the default filters would be
+ * done too late and the re-adding of the default filters might not be done at all.
+ * Aka: use the WPSEO_Options::update_site_option() method (which calls this method) for
+ * safely adding/updating multisite options.
+ *
+ * @param mixed $value The new value for the option.
+ *
+ * @return bool whether the update was succesfull
+ */
+ public function update_site_option( $value ) {
+ if ( $this->multisite_only === true && is_multisite() ) {
+ $this->remove_default_filters();
+ $result = update_site_option( $this->option_name, $value );
+ $this->add_default_filters();
+
+ return $result;
+ }
+ else {
+ return false;
+ }
+ }
+
+
+ /**
+ * Retrieve the real old value (unmerged with defaults), clean and re-save the option
+ *
+ * @uses WPSEO_Option::get_original_option()
+ * @uses WPSEO_Option::import()
+ *
+ * @param string $current_version (optional) Version from which to upgrade, if not set, version specific upgrades will be disregarded.
+ *
+ * @return void
+ */
+ public function clean( $current_version = null ) {
+ $option_value = $this->get_original_option();
+ $this->import( $option_value, $current_version );
+ }
+
+
+ /**
+ * Clean and re-save the option
+ *
+ * @uses clean_option() method from concrete class if it exists
+ *
+ * @todo [JRF/whomever] Figure out a way to show settings error during/after the upgrade - maybe
+ * something along the lines of:
+ * -> add them to a property in this class
+ * -> if that property isset at the end of the routine and add_settings_error function does not exist,
+ * save as transient (or update the transient if one already exists)
+ * -> next time an admin is in the WP back-end, show the errors and delete the transient or only delete it
+ * once the admin has dismissed the message (add ajax function)
+ * Important: all validation routines which add_settings_errors would need to be changed for this to work
+ *
+ * @param array $option_value Option value to be imported.
+ * @param string $current_version (optional) Version from which to upgrade, if not set, version specific upgrades will be disregarded.
+ * @param array $all_old_option_values (optional) Only used when importing old options to have access to the real old values, in contrast to the saved ones.
+ *
+ * @return void
+ */
+ public function import( $option_value, $current_version = null, $all_old_option_values = null ) {
+ if ( $option_value === false ) {
+ $option_value = $this->get_defaults();
+ }
+ elseif ( is_array( $option_value ) && method_exists( $this, 'clean_option' ) ) {
+ $option_value = $this->clean_option( $option_value, $current_version, $all_old_option_values );
+ }
+
+ /*
+ Save the cleaned value - validation will take care of cleaning out array keys which
+ should no longer be there
+ */
+ if ( $this->multisite_only !== true ) {
+ update_option( $this->option_name, $option_value );
+ }
+ else {
+ $this->update_site_option( $this->option_name, $option_value );
+ }
+ }
+
+
+ /**
+ * Concrete classes *may* contain a clean_option method which will clean out old/renamed
+ * values within the option
+ */
+ // abstract public function clean_option( $option_value, $current_version = null, $all_old_option_values = null );
+ /* *********** HELPER METHODS for internal use *********** */
+
+ /**
+ * Helper method - Combines a fixed array of default values with an options array
+ * while filtering out any keys which are not in the defaults array.
+ *
+ * @todo [JRF] - shouldn't this be a straight array merge ? at the end of the day, the validation
+ * removes any invalid keys on save
+ *
+ * @param array $options (Optional) Current options. If not set, the option defaults for the $option_key will be returned.
+ *
+ * @return array Combined and filtered options array.
+ */
+ protected function array_filter_merge( $options = null ) {
+
+ $defaults = $this->get_defaults();
+
+ if ( ! isset( $options ) || $options === false || $options === array() ) {
+ return $defaults;
+ }
+
+ $options = (array) $options;
+
+ /*
+ $filtered = array();
+
+ if ( $defaults !== array() ) {
+ foreach ( $defaults as $key => $default_value ) {
+ // @todo should this walk through array subkeys ?
+ $filtered[ $key ] = ( isset( $options[ $key ] ) ? $options[ $key ] : $default_value );
+ }
+ }
+ */
+ $filtered = array_merge( $defaults, $options );
+
+ return $filtered;
+ }
+
+
+ /**
+ * Make sure that any set option values relating to post_types and/or taxonomies are retained,
+ * even when that post_type or taxonomy may not yet have been registered.
+ *
+ * @internal The wpseo_titles concrete class overrules this method. Make sure that any changes
+ * applied here, also get ported to that version.
+ *
+ * @param array $dirty Original option as retrieved from the database.
+ * @param array $clean Filtered option where any options which shouldn't be in our option
+ * have already been removed and any options which weren't set
+ * have been set to their defaults.
+ *
+ * @return array
+ */
+ protected function retain_variable_keys( $dirty, $clean ) {
+ if ( ( is_array( $this->variable_array_key_patterns ) && $this->variable_array_key_patterns !== array() ) && ( is_array( $dirty ) && $dirty !== array() ) ) {
+ foreach ( $dirty as $key => $value ) {
+
+ // Do nothing if already in filtered options.
+ if ( isset( $clean[ $key ] ) ) {
+ continue;
+ }
+
+ foreach ( $this->variable_array_key_patterns as $pattern ) {
+
+ if ( strpos( $key, $pattern ) === 0 ) {
+ $clean[ $key ] = $value;
+ break;
+ }
+ }
+ }
+ }
+
+ return $clean;
+ }
+
+
+ /**
+ * Check whether a given array key conforms to one of the variable array key patterns for this option
+ *
+ * @usedby validate_option() methods for options with variable array keys
+ *
+ * @param string $key Array key to check.
+ *
+ * @return string Pattern if it conforms, original array key if it doesn't or if the option
+ * does not have variable array keys
+ */
+ protected function get_switch_key( $key ) {
+ if ( ! isset( $this->variable_array_key_patterns ) || ( ! is_array( $this->variable_array_key_patterns ) || $this->variable_array_key_patterns === array() ) ) {
+ return $key;
+ }
+
+ foreach ( $this->variable_array_key_patterns as $pattern ) {
+ if ( strpos( $key, $pattern ) === 0 ) {
+ return $pattern;
+ }
+ }
+
+ return $key;
+ }
+
+
+ /* *********** DEPRECATED METHODS *********** */
+
+ /**
+ * Emulate the WP native sanitize_text_field function in a %%variable%% safe way
+ *
+ * @see https://core.trac.wordpress.org/browser/trunk/src/wp-includes/formatting.php for the original
+ *
+ * @deprecated 1.5.6.1
+ * @deprecated use WPSEO_Utils::sanitize_text_field()
+ * @see WPSEO_Utils::sanitize_text_field()
+ *
+ * @param string $value String value to sanitize.
+ *
+ * @return string
+ */
+ public static function sanitize_text_field( $value ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.5.6.1', 'WPSEO_Utils::sanitize_text_field()' );
+
+ return WPSEO_Utils::sanitize_text_field( $value );
+ }
+
+
+ /**
+ * Sanitize a url for saving to the database
+ * Not to be confused with the old native WP function
+ *
+ * @deprecated 1.5.6.1
+ * @deprecated use WPSEO_Utils::sanitize_url()
+ * @see WPSEO_Utils::sanitize_url()
+ *
+ * @param string $value URL string to sanitize.
+ * @param array $allowed_protocols Set of allowed protocols.
+ *
+ * @return string
+ */
+ public static function sanitize_url( $value, $allowed_protocols = array( 'http', 'https' ) ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.5.6.1', 'WPSEO_Utils::sanitize_url()' );
+
+ return WPSEO_Utils::sanitize_url( $value, $allowed_protocols );
+ }
+
+ /**
+ * Validate a value as boolean
+ *
+ * @deprecated 1.5.6.1
+ * @deprecated use WPSEO_Utils::validate_bool()
+ * @see WPSEO_Utils::validate_bool()
+ *
+ * @static
+ *
+ * @param mixed $value Value to validate.
+ *
+ * @return bool
+ */
+ public static function validate_bool( $value ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.5.6.1', 'WPSEO_Utils::validate_bool()' );
+
+ return WPSEO_Utils::validate_bool( $value );
+ }
+
+ /**
+ * Cast a value to bool
+ *
+ * @deprecated 1.5.6.1
+ * @deprecated use WPSEO_Utils::emulate_filter_bool()
+ * @see WPSEO_Utils::emulate_filter_bool()
+ *
+ * @static
+ *
+ * @param mixed $value Value to cast.
+ *
+ * @return bool
+ */
+ public static function emulate_filter_bool( $value ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.5.6.1', 'WPSEO_Utils::emulate_filter_bool()' );
+
+ return WPSEO_Utils::emulate_filter_bool( $value );
+ }
+
+
+ /**
+ * Validate a value as integer
+ *
+ * @deprecated 1.5.6.1
+ * @deprecated use WPSEO_Utils::validate_int()
+ * @see WPSEO_Utils::validate_int()
+ *
+ * @param mixed $value Value to validate.
+ *
+ * @return mixed int or false in case of failure to convert to int
+ */
+ public static function validate_int( $value ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.5.6.1', 'WPSEO_Utils::validate_int()' );
+
+ return WPSEO_Utils::validate_int( $value );
+ }
+
+ /**
+ * Cast a value to integer
+ *
+ * @deprecated 1.5.6.1
+ * @deprecated use WPSEO_Utils::emulate_filter_int()
+ * @see WPSEO_Utils::emulate_filter_int()
+ *
+ * @static
+ *
+ * @param mixed $value Value to cast.
+ *
+ * @return int|bool
+ */
+ public static function emulate_filter_int( $value ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.5.6.1', 'WPSEO_Utils::emulate_filter_int()' );
+
+ return WPSEO_Utils::emulate_filter_int( $value );
+ }
+
+
+ /**
+ * Recursively trim whitespace round a string value or of string values within an array
+ * Only trims strings to avoid typecasting a variable (to string)
+ *
+ * @deprecated 1.5.6.1
+ * @deprecated use WPSEO_Utils::trim_recursive()
+ * @see WPSEO_Utils::trim_recursive()
+ *
+ * @static
+ *
+ * @param mixed $value Value to trim or array of values to trim.
+ *
+ * @return mixed Trimmed value or array of trimmed values
+ */
+ public static function trim_recursive( $value ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.5.6.1', 'WPSEO_Utils::trim_recursive()' );
+
+ return WPSEO_Utils::trim_recursive( $value );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-options.php b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-options.php
new file mode 100644
index 0000000..4002624
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-options.php
@@ -0,0 +1,455 @@
+ (string) name of concrete class for the option
+ * @static
+ */
+ public static $options = array(
+ 'wpseo' => 'WPSEO_Option_Wpseo',
+ 'wpseo_permalinks' => 'WPSEO_Option_Permalinks',
+ 'wpseo_titles' => 'WPSEO_Option_Titles',
+ 'wpseo_social' => 'WPSEO_Option_Social',
+ 'wpseo_rss' => 'WPSEO_Option_RSS',
+ 'wpseo_internallinks' => 'WPSEO_Option_InternalLinks',
+ 'wpseo_xml' => 'WPSEO_Option_XML',
+ 'wpseo_ms' => 'WPSEO_Option_MS',
+ 'wpseo_taxonomy_meta' => 'WPSEO_Taxonomy_Meta',
+ );
+
+ /**
+ * @var array Array of instantiated option objects
+ */
+ protected static $option_instances = array();
+
+ /**
+ * @var object Instance of this class
+ */
+ protected static $instance;
+
+
+ /**
+ * Instantiate all the WPSEO option management classes
+ */
+ protected function __construct() {
+ $is_multisite = is_multisite();
+
+ foreach ( self::$options as $option_name => $option_class ) {
+ $instance = call_user_func( array( $option_class, 'get_instance' ) );
+
+ if ( ! $instance->multisite_only || $is_multisite ) {
+ self::$option_instances[ $option_name ] = $instance;
+ }
+ else {
+ unset( self::$options[ $option_name ] );
+ }
+ }
+ }
+
+ /**
+ * Get the singleton instance of this class
+ *
+ * @return object
+ */
+ public static function get_instance() {
+ if ( ! ( self::$instance instanceof self ) ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Get the group name of an option for use in the settings form
+ *
+ * @param string $option_name the option for which you want to retrieve the option group name.
+ *
+ * @return string|bool
+ */
+ public static function get_group_name( $option_name ) {
+ if ( isset( self::$option_instances[ $option_name ] ) ) {
+ return self::$option_instances[ $option_name ]->group_name;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get a specific default value for an option
+ *
+ * @param string $option_name The option for which you want to retrieve a default.
+ * @param string $key The key within the option who's default you want.
+ *
+ * @return mixed
+ */
+ public static function get_default( $option_name, $key ) {
+ if ( isset( self::$option_instances[ $option_name ] ) ) {
+ $defaults = self::$option_instances[ $option_name ]->get_defaults();
+ if ( isset( $defaults[ $key ] ) ) {
+ return $defaults[ $key ];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Update a site_option
+ *
+ * @param string $option_name The option name of the option to save.
+ * @param mixed $value The new value for the option.
+ *
+ * @return bool
+ */
+ public static function update_site_option( $option_name, $value ) {
+ if ( is_network_admin() && isset( self::$option_instances[ $option_name ] ) ) {
+ return self::$option_instances[ $option_name ]->update_site_option( $value );
+ }
+ else {
+ return false;
+ }
+ }
+
+ /**
+ * Get the instantiated option instance
+ *
+ * @param string $option_name The option for which you want to retrieve the instance.
+ *
+ * @return object|bool
+ */
+ public static function get_option_instance( $option_name ) {
+ if ( isset( self::$option_instances[ $option_name ] ) ) {
+ return self::$option_instances[ $option_name ];
+ }
+
+ return false;
+ }
+
+ /**
+ * Retrieve an array of the options which should be included in get_all() and reset().
+ *
+ * @static
+ * @return array Array of option names
+ */
+ public static function get_option_names() {
+ static $option_names = array();
+
+ if ( $option_names === array() ) {
+ foreach ( self::$option_instances as $option_name => $option_object ) {
+ if ( $option_object->include_in_all === true ) {
+ $option_names[] = $option_name;
+ }
+ }
+ $option_names = apply_filters( 'wpseo_options', $option_names );
+ }
+
+ return $option_names;
+ }
+
+ /**
+ * Retrieve all the options for the SEO plugin in one go.
+ *
+ * @todo [JRF] see if we can get some extra efficiency for this one, though probably not as options may
+ * well change between calls (enriched defaults and such)
+ *
+ * @static
+ * @return array Array combining the values of all the options
+ */
+ public static function get_all() {
+ return self::get_options( self::get_option_names() );
+ }
+
+ /**
+ * Retrieve one or more options for the SEO plugin.
+ *
+ * @static
+ *
+ * @param array $option_names An array of option names of the options you want to get.
+ *
+ * @return array Array combining the values of the requested options
+ */
+ public static function get_options( array $option_names ) {
+ $options = array();
+ $option_names = array_filter( $option_names, 'is_string' );
+ foreach ( $option_names as $option_name ) {
+ if ( isset( self::$option_instances[ $option_name ] ) ) {
+ $option = self::get_option( $option_name );
+ $options = array_merge( $options, $option );
+ }
+ }
+
+ return $options;
+ }
+
+ /**
+ * Retrieve a single option for the SEO plugin.
+ *
+ * @static
+ *
+ * @param string $option_name the name of the option you want to get.
+ *
+ * @return array Array containing the requested option
+ */
+ public static function get_option( $option_name ) {
+ $option = null;
+ if ( is_string( $option_name ) && ! empty( $option_name ) ) {
+ if ( isset( self::$option_instances[ $option_name ] ) ) {
+ if ( self::$option_instances[ $option_name ]->multisite_only !== true ) {
+ $option = get_option( $option_name );
+ }
+ else {
+ $option = get_site_option( $option_name );
+ }
+ }
+ }
+
+ return $option;
+ }
+
+ /**
+ * Run the clean up routine for one or all options
+ *
+ * @param array|string $option_name (optional) the option you want to clean or an array of
+ * option names for the options you want to clean.
+ * If not set, all options will be cleaned.
+ * @param string $current_version (optional) Version from which to upgrade, if not set,
+ * version specific upgrades will be disregarded.
+ *
+ * @return void
+ */
+ public static function clean_up( $option_name = null, $current_version = null ) {
+ if ( isset( $option_name ) && is_string( $option_name ) && $option_name !== '' ) {
+ if ( isset( self::$option_instances[ $option_name ] ) ) {
+ self::$option_instances[ $option_name ]->clean( $current_version );
+ }
+ }
+ elseif ( isset( $option_name ) && is_array( $option_name ) && $option_name !== array() ) {
+ foreach ( $option_name as $option ) {
+ if ( isset( self::$option_instances[ $option ] ) ) {
+ self::$option_instances[ $option ]->clean( $current_version );
+ }
+ }
+ unset( $option );
+ }
+ else {
+ foreach ( self::$option_instances as $instance ) {
+ $instance->clean( $current_version );
+ }
+ unset( $instance );
+
+ // If we've done a full clean-up, we can safely remove this really old option.
+ delete_option( 'wpseo_indexation' );
+ }
+ }
+
+
+ /**
+ * Check that all options exist in the database and add any which don't
+ *
+ * @return void
+ */
+ public static function ensure_options_exist() {
+ foreach ( self::$option_instances as $instance ) {
+ $instance->maybe_add_option();
+ }
+ }
+
+ /**
+ * Correct the inadvertent removal of the fallback to default values from the breadcrumbs
+ *
+ * @since 1.5.2.3
+ */
+ public static function bring_back_breadcrumb_defaults() {
+ if ( isset( self::$option_instances['wpseo_internallinks'] ) ) {
+ self::$option_instances['wpseo_internallinks']->bring_back_defaults();
+ }
+ }
+
+ /**
+ * Initialize some options on first install/activate/reset
+ *
+ * @static
+ * @return void
+ */
+ public static function initialize() {
+ /* Force WooThemes to use Yoast SEO data. */
+ if ( function_exists( 'woo_version_init' ) ) {
+ update_option( 'seo_woo_use_third_party_data', 'true' );
+ }
+ }
+
+ /**
+ * Reset all options to their default values and rerun some tests
+ *
+ * @static
+ * @return void
+ */
+ public static function reset() {
+ if ( ! is_multisite() ) {
+ $option_names = self::get_option_names();
+ if ( is_array( $option_names ) && $option_names !== array() ) {
+ foreach ( $option_names as $option_name ) {
+ delete_option( $option_name );
+ update_option( $option_name, get_option( $option_name ) );
+ }
+ }
+ unset( $option_names );
+ }
+ else {
+ // Reset MS blog based on network default blog setting.
+ self::reset_ms_blog( get_current_blog_id() );
+ }
+
+ self::initialize();
+ }
+
+ /**
+ * Initialize default values for a new multisite blog
+ *
+ * @static
+ *
+ * @param bool $force_init Whether to always do the initialization routine (title/desc test).
+ *
+ * @return void
+ */
+ public static function maybe_set_multisite_defaults( $force_init = false ) {
+ $option = get_option( 'wpseo' );
+
+ if ( is_multisite() ) {
+ if ( $option['ms_defaults_set'] === false ) {
+ self::reset_ms_blog( get_current_blog_id() );
+ self::initialize();
+ }
+ else if ( $force_init === true ) {
+ self::initialize();
+ }
+ }
+ }
+
+ /**
+ * Reset all options for a specific multisite blog to their default values based upon a
+ * specified default blog if one was chosen on the network page or the plugin defaults if it was not
+ *
+ * @static
+ *
+ * @param int|string $blog_id Blog id of the blog for which to reset the options.
+ *
+ * @return void
+ */
+ public static function reset_ms_blog( $blog_id ) {
+ if ( is_multisite() ) {
+ $options = get_site_option( 'wpseo_ms' );
+ $option_names = self::get_option_names();
+
+ if ( is_array( $option_names ) && $option_names !== array() ) {
+ $base_blog_id = $blog_id;
+ if ( $options['defaultblog'] !== '' && $options['defaultblog'] != 0 ) {
+ $base_blog_id = $options['defaultblog'];
+ }
+
+ foreach ( $option_names as $option_name ) {
+ delete_blog_option( $blog_id, $option_name );
+
+ $new_option = get_blog_option( $base_blog_id, $option_name );
+
+ /* Remove sensitive, theme dependent and site dependent info */
+ if ( isset( self::$option_instances[ $option_name ] ) && self::$option_instances[ $option_name ]->ms_exclude !== array() ) {
+ foreach ( self::$option_instances[ $option_name ]->ms_exclude as $key ) {
+ unset( $new_option[ $key ] );
+ }
+ }
+
+ if ( $option_name === 'wpseo' ) {
+ $new_option['ms_defaults_set'] = true;
+ }
+
+ update_blog_option( $blog_id, $option_name, $new_option );
+ }
+ }
+ }
+ }
+
+ /**
+ * Saves the option to the database.
+ *
+ * @param string $wpseo_options_group_name The name for the wpseo option group in the database.
+ * @param string $option_name The name for the option to set.
+ * @param * $option_value The value for the option.
+ *
+ * @return boolean Returns true if the option is successfully saved in the database.
+ */
+ public static function save_option( $wpseo_options_group_name, $option_name, $option_value ) {
+ $options = WPSEO_Options::get_option( $wpseo_options_group_name );
+ $options[ $option_name ] = $option_value;
+ update_option( $wpseo_options_group_name, $options );
+
+ // Check if everything got saved properly.
+ $saved_option = self::get_option( $wpseo_options_group_name );
+ return $saved_option[ $option_name ] === $options[ $option_name ];
+ }
+
+ /********************** DEPRECATED FUNCTIONS **********************/
+
+ /**
+ * Check whether the current user is allowed to access the configuration.
+ *
+ * @deprecated 1.5.6.1
+ * @deprecated use WPSEO_Utils::grant_access()
+ * @see WPSEO_Utils::grant_access()
+ *
+ * @return boolean
+ */
+ public static function grant_access() {
+ _deprecated_function( __METHOD__, 'WPSEO 1.5.6.1', 'WPSEO_Utils::grant_access()' );
+
+ return WPSEO_Utils::grant_access();
+ }
+
+ /**
+ * Clears the WP or W3TC cache depending on which is used
+ *
+ * @deprecated 1.5.6.1
+ * @deprecated use WPSEO_Utils::clear_cache()
+ * @see WPSEO_Utils::clear_cache()
+ */
+ public static function clear_cache() {
+ _deprecated_function( __METHOD__, 'WPSEO 1.5.6.1', 'WPSEO_Utils::clear_cache()' );
+ WPSEO_Utils::clear_cache();
+ }
+
+
+ /**
+ * Flush W3TC cache after succesfull update/add of taxonomy meta option
+ *
+ * @deprecated 1.5.6.1
+ * @deprecated use WPSEO_Utils::flush_w3tc_cache()
+ * @see WPSEO_Utils::flush_w3tc_cache()
+ */
+ public static function flush_w3tc_cache() {
+ _deprecated_function( __METHOD__, 'WPSEO 1.5.6.1', 'WPSEO_Utils::flush_w3tc_cache()' );
+ WPSEO_Utils::flush_w3tc_cache();
+ }
+
+
+ /**
+ * Clear rewrite rules
+ *
+ * @deprecated 1.5.6.1
+ * @deprecated use WPSEO_Utils::clear_rewrites()
+ * @see WPSEO_Utils::clear_rewrites()
+ */
+ public static function clear_rewrites() {
+ _deprecated_function( __METHOD__, 'WPSEO 1.5.6.1', 'WPSEO_Utils::clear_rewrites()' );
+ WPSEO_Utils::clear_rewrites();
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-taxonomy-meta.php b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-taxonomy-meta.php
new file mode 100644
index 0000000..c8c0d15
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/options/class-wpseo-taxonomy-meta.php
@@ -0,0 +1,600 @@
+get_defaults();
+ * @internal Important: in contrast to most defaults, the below array format is
+ * very bare. The real option is in the format [taxonomy_name][term_id][...]
+ * where [...] is any of the $defaults_per_term options shown below.
+ * This is of course taken into account in the below methods.
+ */
+ protected $defaults = array();
+
+
+ /**
+ * @var string Option name - same as $option_name property, but now also available to static methods
+ * @static
+ */
+ public static $name;
+
+ /**
+ * @var array Array of defaults for individual taxonomy meta entries
+ * @static
+ */
+ public static $defaults_per_term = array(
+ 'wpseo_title' => '',
+ 'wpseo_desc' => '',
+ 'wpseo_metakey' => '',
+ 'wpseo_canonical' => '',
+ 'wpseo_bctitle' => '',
+ 'wpseo_noindex' => 'default',
+ 'wpseo_sitemap_include' => '-',
+ 'wpseo_focuskw' => '',
+ 'wpseo_linkdex' => '',
+ 'wpseo_content_score' => '',
+
+ // Social fields.
+ 'wpseo_opengraph-title' => '',
+ 'wpseo_opengraph-description' => '',
+ 'wpseo_opengraph-image' => '',
+ 'wpseo_twitter-title' => '',
+ 'wpseo_twitter-description' => '',
+ 'wpseo_twitter-image' => '',
+ );
+
+ /**
+ * @var array Available index options
+ * Used for form generation and input validation
+ *
+ * @static
+ *
+ * @internal Labels (translation) added on admin_init via WPSEO_Taxonomy::translate_meta_options()
+ */
+ public static $no_index_options = array(
+ 'default' => '',
+ 'index' => '',
+ 'noindex' => '',
+ );
+
+ /**
+ * @var array Available sitemap include options
+ * Used for form generation and input validation
+ *
+ * @static
+ *
+ * @internal Labels (translation) added on admin_init via WPSEO_Taxonomy::translate_meta_options()
+ */
+ public static $sitemap_include_options = array(
+ '-' => '',
+ 'always' => '',
+ 'never' => '',
+ );
+
+
+ /**
+ * Add the actions and filters for the option
+ *
+ * @todo [JRF => testers] Check if the extra actions below would run into problems if an option
+ * is updated early on and if so, change the call to schedule these for a later action on add/update
+ * instead of running them straight away
+ *
+ * @return \WPSEO_Taxonomy_Meta
+ */
+ protected function __construct() {
+ parent::__construct();
+
+ self::$name = $this->option_name;
+
+ /* On succesfull update/add of the option, flush the W3TC cache */
+ add_action( 'add_option_' . $this->option_name, array( 'WPSEO_Utils', 'flush_w3tc_cache' ) );
+ add_action( 'update_option_' . $this->option_name, array( 'WPSEO_Utils', 'flush_w3tc_cache' ) );
+ }
+
+
+ /**
+ * Get the singleton instance of this class
+ *
+ * @return object
+ */
+ public static function get_instance() {
+ if ( ! ( self::$instance instanceof self ) ) {
+ self::$instance = new self();
+ self::$name = self::$instance->option_name;
+ }
+
+ return self::$instance;
+ }
+
+
+ /**
+ * Add extra default options received from a filter
+ */
+ public function enrich_defaults() {
+ $extra_defaults_per_term = apply_filters( 'wpseo_add_extra_taxmeta_term_defaults', array() );
+ if ( is_array( $extra_defaults_per_term ) ) {
+ self::$defaults_per_term = array_merge( $extra_defaults_per_term, self::$defaults_per_term );
+ }
+ }
+
+
+ /**
+ * Helper method - Combines a fixed array of default values with an options array
+ * while filtering out any keys which are not in the defaults array.
+ *
+ * @static
+ *
+ * @param string $option_key Option name of the option we're doing the merge for.
+ * @param array $options (Optional) Current options. If not set, the option defaults for the $option_key will be returned.
+ *
+ * @return array Combined and filtered options array.
+ */
+
+ /*
+ Public function array_filter_merge( $option_key, $options = null ) {
+
+ $defaults = $this->get_defaults( $option_key );
+
+ if ( ! isset( $options ) || $options === false ) {
+ return $defaults;
+ }
+
+ / *
+ @internal Adding the defaults to all taxonomy terms each time the option is retrieved
+ will be quite inefficient if there are a lot of taxonomy terms
+ As long as taxonomy_meta is only retrieved via methods in this class, we shouldn't need this
+
+ $options = (array) $options;
+ $filtered = array();
+
+ if ( $options !== array() ) {
+ foreach ( $options as $taxonomy => $terms ) {
+ if ( is_array( $terms ) && $terms !== array() ) {
+ foreach ( $terms as $id => $term_meta ) {
+ foreach ( self::$defaults_per_term as $name => $default ) {
+ if ( isset( $options[ $taxonomy ][ $id ][ $name ] ) ) {
+ $filtered[ $taxonomy ][ $id ][ $name ] = $options[ $taxonomy ][ $id ][ $name ];
+ }
+ else {
+ $filtered[ $name ] = $default;
+ }
+ }
+ }
+ }
+ }
+ unset( $taxonomy, $terms, $id, $term_meta, $name, $default );
+ }
+ // end of may be remove.
+
+ return $filtered;
+ * /
+
+ return (array) $options;
+ }
+ */
+
+
+ /**
+ * Validate the option
+ *
+ * @param array $dirty New value for the option.
+ * @param array $clean Clean value for the option, normally the defaults.
+ * @param array $old Old value of the option.
+ *
+ * @return array Validated clean value for the option to be saved to the database
+ */
+ protected function validate_option( $dirty, $clean, $old ) {
+ /*
+ Prevent complete validation (which can be expensive when there are lots of terms)
+ if only one item has changed and has already been validated
+ */
+ if ( isset( $dirty['wpseo_already_validated'] ) && $dirty['wpseo_already_validated'] === true ) {
+ unset( $dirty['wpseo_already_validated'] );
+
+ return $dirty;
+ }
+
+
+ foreach ( $dirty as $taxonomy => $terms ) {
+ /* Don't validate taxonomy - may not be registered yet and we don't want to remove valid ones */
+ if ( is_array( $terms ) && $terms !== array() ) {
+ foreach ( $terms as $term_id => $meta_data ) {
+ /* Only validate term if the taxonomy exists */
+ if ( taxonomy_exists( $taxonomy ) && get_term_by( 'id', $term_id, $taxonomy ) === false ) {
+ /* Is this term id a special case ? */
+ if ( has_filter( 'wpseo_tax_meta_special_term_id_validation_' . $term_id ) !== false ) {
+ $clean[ $taxonomy ][ $term_id ] = apply_filters( 'wpseo_tax_meta_special_term_id_validation_' . $term_id, $meta_data, $taxonomy, $term_id );
+ }
+ continue;
+ }
+
+ if ( is_array( $meta_data ) && $meta_data !== array() ) {
+ /* Validate meta data */
+ $old_meta = self::get_term_meta( $term_id, $taxonomy );
+ $meta_data = self::validate_term_meta_data( $meta_data, $old_meta );
+ if ( $meta_data !== array() ) {
+ $clean[ $taxonomy ][ $term_id ] = $meta_data;
+ }
+ }
+
+ // Deal with special cases (for when taxonomy doesn't exist yet).
+ if ( ! isset( $clean[ $taxonomy ][ $term_id ] ) && has_filter( 'wpseo_tax_meta_special_term_id_validation_' . $term_id ) !== false ) {
+ $clean[ $taxonomy ][ $term_id ] = apply_filters( 'wpseo_tax_meta_special_term_id_validation_' . $term_id, $meta_data, $taxonomy, $term_id );
+ }
+ }
+ }
+ }
+
+ return $clean;
+ }
+
+
+ /**
+ * Validate the meta data for one individual term and removes default values (no need to save those)
+ *
+ * @static
+ *
+ * @param array $meta_data New values.
+ * @param array $old_meta The original values.
+ *
+ * @return array Validated and filtered value
+ */
+ public static function validate_term_meta_data( $meta_data, $old_meta ) {
+
+ $clean = self::$defaults_per_term;
+ $meta_data = array_map( array( 'WPSEO_Utils', 'trim_recursive' ), $meta_data );
+
+ if ( ! is_array( $meta_data ) || $meta_data === array() ) {
+ return $clean;
+ }
+
+ foreach ( $clean as $key => $value ) {
+ switch ( $key ) {
+
+ case 'wpseo_noindex':
+ if ( isset( $meta_data[ $key ] ) ) {
+ if ( isset( self::$no_index_options[ $meta_data[ $key ] ] ) ) {
+ $clean[ $key ] = $meta_data[ $key ];
+ }
+ }
+ elseif ( isset( $old_meta[ $key ] ) ) {
+ // Retain old value if field currently not in use.
+ $clean[ $key ] = $old_meta[ $key ];
+ }
+ break;
+
+ case 'wpseo_sitemap_include':
+ if ( isset( $meta_data[ $key ], self::$sitemap_include_options[ $meta_data[ $key ] ] ) ) {
+ $clean[ $key ] = $meta_data[ $key ];
+ }
+ break;
+
+ case 'wpseo_canonical':
+ if ( isset( $meta_data[ $key ] ) && $meta_data[ $key ] !== '' ) {
+ $url = WPSEO_Utils::sanitize_url( $meta_data[ $key ] );
+ if ( $url !== '' ) {
+ $clean[ $key ] = $url;
+ }
+ unset( $url );
+ }
+ break;
+
+ case 'wpseo_metakey':
+ case 'wpseo_bctitle':
+ if ( isset( $meta_data[ $key ] ) ) {
+ $clean[ $key ] = WPSEO_Utils::sanitize_text_field( stripslashes( $meta_data[ $key ] ) );
+ }
+ elseif ( isset( $old_meta[ $key ] ) ) {
+ // Retain old value if field currently not in use.
+ $clean[ $key ] = $old_meta[ $key ];
+ }
+ break;
+ case 'wpseo_focuskw':
+ case 'wpseo_title':
+ case 'wpseo_desc':
+ case 'wpseo_linkdex':
+ default:
+ if ( isset( $meta_data[ $key ] ) && is_string( $meta_data[ $key ] ) ) {
+ $clean[ $key ] = WPSEO_Utils::sanitize_text_field( stripslashes( $meta_data[ $key ] ) );
+ }
+
+ if ( 'wpseo_focuskw' === $key ) {
+ $clean[ $key ] = str_replace( array(
+ '<',
+ '>',
+ '"',
+ '`',
+ '<',
+ '>',
+ '"',
+ '`',
+ ), '', $clean[ $key ] );
+ }
+ break;
+ }
+
+ $clean[ $key ] = apply_filters( 'wpseo_sanitize_tax_meta_' . $key, $clean[ $key ], ( isset( $meta_data[ $key ] ) ? $meta_data[ $key ] : null ), ( isset( $old_meta[ $key ] ) ? $old_meta[ $key ] : null ) );
+ }
+
+ // Only save the non-default values.
+ return array_diff_assoc( $clean, self::$defaults_per_term );
+ }
+
+
+ /**
+ * Clean a given option value
+ * - Convert old option values to new
+ * - Fixes strings which were escaped (should have been sanitized - escaping is for output)
+ *
+ * @param array $option_value Old (not merged with defaults or filtered) option value to
+ * clean according to the rules for this option.
+ * @param string $current_version (optional) Version from which to upgrade, if not set,
+ * version specific upgrades will be disregarded.
+ * @param array $all_old_option_values (optional) Only used when importing old options to have
+ * access to the real old values, in contrast to the saved ones.
+ *
+ * @return array Cleaned option
+ */
+ protected function clean_option( $option_value, $current_version = null, $all_old_option_values = null ) {
+
+ /* Clean up old values and remove empty arrays */
+ if ( is_array( $option_value ) && $option_value !== array() ) {
+
+ foreach ( $option_value as $taxonomy => $terms ) {
+
+ if ( is_array( $terms ) && $terms !== array() ) {
+
+ foreach ( $terms as $term_id => $meta_data ) {
+ if ( ! is_array( $meta_data ) || $meta_data === array() ) {
+ // Remove empty term arrays.
+ unset( $option_value[ $taxonomy ][ $term_id ] );
+ }
+ else {
+ foreach ( $meta_data as $key => $value ) {
+
+ switch ( $key ) {
+ case 'noindex':
+ if ( $value === 'on' ) {
+ // Convert 'on' to 'noindex'.
+ $option_value[ $taxonomy ][ $term_id ][ $key ] = 'noindex';
+ }
+ break;
+
+ case 'canonical':
+ case 'wpseo_metakey':
+ case 'wpseo_bctitle':
+ case 'wpseo_title':
+ case 'wpseo_desc':
+ case 'wpseo_linkdex':
+ // @todo [JRF => whomever] needs checking, I don't have example data [JRF].
+ if ( $value !== '' ) {
+ // Fix incorrectly saved (encoded) canonical urls and texts.
+ $option_value[ $taxonomy ][ $term_id ][ $key ] = wp_specialchars_decode( stripslashes( $value ), ENT_QUOTES );
+ }
+ break;
+
+ default:
+ // @todo [JRF => whomever] needs checking, I don't have example data [JRF].
+ if ( $value !== '' ) {
+ // Fix incorrectly saved (escaped) text strings.
+ $option_value[ $taxonomy ][ $term_id ][ $key ] = wp_specialchars_decode( $value, ENT_QUOTES );
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ else {
+ // Remove empty taxonomy arrays.
+ unset( $option_value[ $taxonomy ] );
+ }
+ }
+ }
+
+ return $option_value;
+ }
+
+
+ /**
+ * Retrieve a taxonomy term's meta value(s).
+ *
+ * @static
+ *
+ * @param mixed $term Term to get the meta value for
+ * either (string) term name, (int) term id or (object) term.
+ * @param string $taxonomy Name of the taxonomy to which the term is attached.
+ * @param string $meta (optional) Meta value to get (without prefix).
+ *
+ * @return mixed|bool Value for the $meta if one is given, might be the default.
+ * If no meta is given, an array of all the meta data for the term.
+ * False if the term does not exist or the $meta provided is invalid.
+ */
+ public static function get_term_meta( $term, $taxonomy, $meta = null ) {
+ /* Figure out the term id */
+ if ( is_int( $term ) ) {
+ $term = get_term_by( 'id', $term, $taxonomy );
+ }
+ elseif ( is_string( $term ) ) {
+ $term = get_term_by( 'slug', $term, $taxonomy );
+ }
+
+ if ( is_object( $term ) && isset( $term->term_id ) ) {
+ $term_id = $term->term_id;
+ }
+ else {
+ return false;
+ }
+
+ $tax_meta = self::get_term_tax_meta( $term_id, $taxonomy );
+
+ /*
+ Either return the complete array or a single value from it or false if the value does not exist
+ (shouldn't happen after merge with defaults, indicates typo in request)
+ */
+ if ( ! isset( $meta ) ) {
+ return $tax_meta;
+ }
+
+
+ if ( isset( $tax_meta[ 'wpseo_' . $meta ] ) ) {
+ return $tax_meta[ 'wpseo_' . $meta ];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the current queried object and return the meta value
+ *
+ * @param string $meta The meta field that is needed.
+ *
+ * @return bool|mixed
+ */
+ public static function get_meta_without_term( $meta ) {
+ $term = $GLOBALS['wp_query']->get_queried_object();
+
+ return self::get_term_meta( $term, $term->taxonomy, $meta );
+
+ }
+
+ /**
+ * Saving the values for the given term_id
+ *
+ * @param int $term_id ID of the term to save data for.
+ * @param string $taxonomy The taxonomy the term belongs to.
+ * @param array $meta_values The values that will be saved.
+ */
+ public static function set_values( $term_id, $taxonomy, array $meta_values ) {
+ /* Validate the post values */
+ $old = self::get_term_meta( $term_id, $taxonomy );
+ $clean = self::validate_term_meta_data( $meta_values, $old );
+
+ self::save_clean_values( $term_id, $taxonomy, $clean );
+ }
+
+ /**
+ * Setting a single value to the term meta
+ *
+ * @param int $term_id ID of the term to save data for.
+ * @param string $taxonomy The taxonomy the term belongs to.
+ * @param string $meta_key The target meta key to store the value in.
+ * @param string $meta_value The value of the target meta key.
+ */
+ public static function set_value( $term_id, $taxonomy, $meta_key, $meta_value ) {
+
+ if ( substr( strtolower( $meta_key ), 0, 6 ) !== 'wpseo_' ) {
+ $meta_key = 'wpseo_' . $meta_key;
+ }
+
+ self::set_values( $term_id, $taxonomy, array( $meta_key => $meta_value ) );
+ }
+
+ /**
+ * Find the keyword usages in the metas for the taxonomies/terms
+ *
+ * @param string $keyword The keyword to look for.
+ * @param string $current_term_id The current term id.
+ * @param string $current_taxonomy The current taxonomy name.
+ *
+ * @return array
+ */
+ public static function get_keyword_usage( $keyword, $current_term_id, $current_taxonomy ) {
+ $tax_meta = self::get_tax_meta();
+
+
+ $found = array();
+ // Todo check for terms of all taxonomies, not only the current taxonomy.
+ foreach ( $tax_meta as $taxonomy_name => $terms ) {
+ foreach ( $terms as $term_id => $meta_values ) {
+ $is_current = ( $current_taxonomy === $taxonomy_name && (string) $current_term_id === (string) $term_id );
+ if ( ! $is_current && ! empty( $meta_values['wpseo_focuskw'] ) && $meta_values['wpseo_focuskw'] === $keyword ) {
+ $found[] = $term_id;
+ }
+ }
+ }
+
+ return array( $keyword => $found );
+ }
+
+ /**
+ * Saving the values for the given term_id
+ *
+ * @param int $term_id ID of the term to save data for.
+ * @param string $taxonomy The taxonomy the term belongs to.
+ * @param array $clean Array with clean values.
+ */
+ private static function save_clean_values( $term_id, $taxonomy, array $clean ) {
+ $tax_meta = self::get_tax_meta();
+
+ /* Add/remove the result to/from the original option value */
+ if ( $clean !== array() ) {
+ $tax_meta[ $taxonomy ][ $term_id ] = $clean;
+ }
+ else {
+ unset( $tax_meta[ $taxonomy ][ $term_id ] );
+ if ( isset( $tax_meta[ $taxonomy ] ) && $tax_meta[ $taxonomy ] === array() ) {
+ unset( $tax_meta[ $taxonomy ] );
+ }
+ }
+
+ // Prevent complete array validation.
+ $tax_meta['wpseo_already_validated'] = true;
+
+ self::save_tax_meta( $tax_meta );
+ }
+
+ /**
+ * Getting the meta from the options
+ *
+ * @return void|array
+ */
+ private static function get_tax_meta() {
+ return get_option( self::$name );
+ }
+
+ /**
+ * Saving the tax meta values to the database
+ *
+ * @param array $tax_meta Array with the meta values for taxonomy.
+ */
+ private static function save_tax_meta( $tax_meta ) {
+ update_option( self::$name, $tax_meta );
+ }
+
+ /**
+ * Getting the taxonomy meta for the given term_id and taxonomy
+ *
+ * @param int $term_id The id of the term.
+ * @param string $taxonomy Name of the taxonomy to which the term is attached.
+ *
+ * @return array
+ */
+ private static function get_term_tax_meta( $term_id, $taxonomy ) {
+ $tax_meta = self::get_tax_meta();
+
+ /* If we have data for the term, merge with defaults for complete array, otherwise set defaults */
+ if ( isset( $tax_meta[ $taxonomy ][ $term_id ] ) ) {
+ return array_merge( self::$defaults_per_term, $tax_meta[ $taxonomy ][ $term_id ] );
+ }
+
+ return self::$defaults_per_term;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-author-sitemap-provider.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-author-sitemap-provider.php
new file mode 100644
index 0000000..89a9106
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-author-sitemap-provider.php
@@ -0,0 +1,304 @@
+update_user_meta();
+
+ $has_exclude_filter = has_filter( 'wpseo_sitemap_exclude_author' );
+
+ $query_arguments = array();
+
+ if ( ! $has_exclude_filter ) { // We only need full users if legacy filter(s) hooked to exclusion logic. R.
+ $query_arguments['fields'] = 'ID';
+ }
+
+ $users = $this->get_users( $query_arguments );
+
+ if ( $has_exclude_filter ) {
+ $users = $this->exclude_users( $users );
+ $users = wp_list_pluck( $users, 'ID' );
+ }
+
+ if ( empty( $users ) ) {
+ return array();
+ }
+
+ $index = array();
+ $page = 1;
+ $user_pages = array_chunk( $users, $max_entries );
+
+ if ( count( $user_pages ) === 1 ) {
+ $page = '';
+ }
+
+ foreach ( $user_pages as $users_page ) {
+
+ $user_id = array_shift( $users_page ); // Time descending, first user on page is most recently updated.
+ $user = get_user_by( 'id', $user_id );
+ $index[] = array(
+ 'loc' => WPSEO_Sitemaps_Router::get_base_url( 'author-sitemap' . $page . '.xml' ),
+ 'lastmod' => '@' . $user->_yoast_wpseo_profile_updated, // @ for explicit timestamp format
+ );
+
+ $page++;
+ }
+
+ return $index;
+ }
+
+ /**
+ * Retrieve users, taking account of all necessary exclusions.
+ *
+ * @param array $arguments Arguments to add.
+ *
+ * @return array
+ */
+ protected function get_users( $arguments = array() ) {
+
+ global $wpdb;
+
+ $options = WPSEO_Options::get_all();
+
+ $defaults = array(
+ // TODO re-enable after plugin requirements raised to WP 4.6 with the fix.
+ // 'who' => 'authors', Breaks meta keys, see https://core.trac.wordpress.org/ticket/36724#ticket R.
+ 'meta_key' => '_yoast_wpseo_profile_updated',
+ 'orderby' => 'meta_value_num',
+ 'order' => 'DESC',
+ 'meta_query' => array(
+ 'relation' => 'AND',
+ array(
+ 'key' => $wpdb->get_blog_prefix() . 'user_level',
+ 'value' => '0',
+ 'compare' => '!=',
+ ),
+ array(
+ 'relation' => 'OR',
+ array(
+ 'key' => 'wpseo_excludeauthorsitemap',
+ 'value' => 'on',
+ 'compare' => '!=',
+ ),
+ array(
+ 'key' => 'wpseo_excludeauthorsitemap',
+ 'compare' => 'NOT EXISTS',
+ ),
+ ),
+ ),
+ );
+
+ if ( $options['disable_author_noposts'] === true ) {
+ // $defaults['who'] = ''; // Otherwise it cancels out next argument.
+ $defaults['has_published_posts'] = true;
+ }
+
+ $excluded_roles = $this->get_excluded_roles();
+
+ if ( ! empty( $excluded_roles ) ) {
+ // $defaults['who'] = ''; // Otherwise it cancels out next argument.
+ $defaults['role__not_in'] = $excluded_roles;
+ }
+
+ return get_users( array_merge( $defaults, $arguments ) );
+ }
+
+ /**
+ * Retrieve array of roles, excluded in settings.
+ *
+ * @return array
+ */
+ protected function get_excluded_roles() {
+
+ static $excluded_roles;
+
+ if ( isset( $excluded_roles ) ) {
+ return $excluded_roles;
+ }
+
+ $options = WPSEO_Options::get_all();
+ $roles = WPSEO_Utils::get_roles();
+
+ foreach ( $roles as $role_slug => $role_name ) {
+
+ if ( ! empty( $options[ "user_role-{$role_slug}-not_in_sitemap" ] ) ) {
+ $excluded_roles[] = $role_name;
+ }
+ }
+
+ if ( ! empty( $excluded_roles ) ) { // Otherwise it's handled by who=>authors query.
+ $excluded_roles[] = 'Subscriber';
+ }
+
+ return $excluded_roles;
+ }
+
+ /**
+ * Get set of sitemap link data.
+ *
+ * @param string $type Sitemap type.
+ * @param int $max_entries Entries per sitemap.
+ * @param int $current_page Current page of the sitemap.
+ *
+ * @return array
+ */
+ public function get_sitemap_links( $type, $max_entries, $current_page ) {
+
+ $options = WPSEO_Options::get_all();
+
+ $links = array();
+
+ if ( $options['disable-author'] === true || $options['disable_author_sitemap'] === true ) {
+ return $links;
+ }
+
+ $users = $this->get_users( array(
+ 'offset' => ( $current_page - 1 ) * $max_entries,
+ 'number' => $max_entries,
+ ) );
+
+ $users = $this->exclude_users( $users );
+
+ if ( empty( $users ) ) {
+ $users = array();
+ }
+
+ $time = time();
+
+ foreach ( $users as $user ) {
+
+ $author_link = get_author_posts_url( $user->ID );
+
+ if ( empty( $author_link ) ) {
+ continue;
+ }
+
+ $mod = $time;
+
+ if ( isset( $user->_yoast_wpseo_profile_updated ) ) {
+ $mod = $user->_yoast_wpseo_profile_updated;
+ }
+
+ $url = array(
+ 'loc' => $author_link,
+ 'mod' => date( DATE_W3C, $mod ),
+
+ // Deprecated, kept for backwards data compat. R.
+ 'chf' => 'daily',
+ 'pri' => 1,
+ );
+
+ /** This filter is documented at inc/sitemaps/class-post-type-sitemap-provider.php */
+ $url = apply_filters( 'wpseo_sitemap_entry', $url, 'user', $user );
+
+ if ( ! empty( $url ) ) {
+ $links[] = $url;
+ }
+ }
+
+ return $links;
+ }
+
+ /**
+ * Update any users that don't have last profile update timestamp.
+ *
+ * @return int Count of users updated.
+ */
+ protected function update_user_meta() {
+
+ $users = get_users( array(
+ 'who' => 'authors',
+ 'meta_query' => array(
+ array(
+ 'key' => '_yoast_wpseo_profile_updated',
+ 'compare' => 'NOT EXISTS',
+ ),
+ ),
+ ) );
+
+ $time = time();
+
+ foreach ( $users as $user ) {
+ update_user_meta( $user->ID, '_yoast_wpseo_profile_updated', $time );
+ }
+
+ return count( $users );
+ }
+
+ /**
+ * Wrap legacy filter to deduplicate calls.
+ *
+ * @param array $users Array of user objects to filter.
+ *
+ * @return array
+ */
+ protected function exclude_users( $users ) {
+
+ /**
+ * Filter the authors, included in XML sitemap.
+ *
+ * @param array $users Array of user objects to filter.
+ */
+ return apply_filters( 'wpseo_sitemap_exclude_author', $users );
+ }
+
+ /**
+ * Sorts an array of WP_User by the _yoast_wpseo_profile_updated meta field.
+ *
+ * @since 1.6
+ *
+ * @deprecated 3.3 User meta sort can now be done by queries.
+ *
+ * @param WP_User $first The first WP user.
+ * @param WP_User $second The second WP user.
+ *
+ * @return int 0 if equal, 1 if $a is larger else or -1;
+ */
+ public function user_map_sorter( $first, $second ) {
+
+ if ( ! isset( $first->_yoast_wpseo_profile_updated ) ) {
+ $first->_yoast_wpseo_profile_updated = time();
+ }
+
+ if ( ! isset( $second->_yoast_wpseo_profile_updated ) ) {
+ $second->_yoast_wpseo_profile_updated = time();
+ }
+
+ if ( $first->_yoast_wpseo_profile_updated === $second->_yoast_wpseo_profile_updated ) {
+ return 0;
+ }
+
+ return ( ( $first->_yoast_wpseo_profile_updated > $second->_yoast_wpseo_profile_updated ) ? 1 : -1 );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-post-type-sitemap-provider.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-post-type-sitemap-provider.php
new file mode 100644
index 0000000..342f524
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-post-type-sitemap-provider.php
@@ -0,0 +1,631 @@
+ true ) );
+ $post_types = array_filter( $post_types, array( $this, 'is_valid_post_type' ) );
+ $last_modified_times = WPSEO_Sitemaps::get_last_modified_gmt( $post_types, true );
+ $index = array();
+
+ foreach ( $post_types as $post_type ) {
+
+ $total_count = $this->get_post_type_count( $post_type );
+
+ if ( $total_count === 0 ) {
+ continue;
+ }
+
+ $max_pages = 1;
+
+ if ( $total_count > $max_entries ) {
+ $max_pages = (int) ceil( $total_count / $max_entries );
+ }
+
+ $all_dates = array();
+
+ if ( $max_pages > 1 ) {
+
+ $sql = "
+ SELECT post_modified_gmt
+ FROM ( SELECT @rownum:=0 ) init
+ JOIN {$wpdb->posts} USE INDEX( type_status_date )
+ WHERE post_status IN ( 'publish', 'inherit' )
+ AND post_type = %s
+ AND ( @rownum:=@rownum+1 ) %% %d = 0
+ ORDER BY post_modified_gmt ASC
+ ";
+
+ $all_dates = $wpdb->get_col( $wpdb->prepare( $sql, $post_type, $max_entries ) );
+ }
+
+ for ( $page_counter = 0; $page_counter < $max_pages; $page_counter++ ) {
+
+ $current_page = ( $max_pages > 1 ) ? ( $page_counter + 1 ) : '';
+ $date = false;
+
+ if ( empty( $current_page ) || $current_page === $max_pages ) {
+
+ if ( ! empty( $last_modified_times[ $post_type ] ) ) {
+ $date = $last_modified_times[ $post_type ];
+ }
+ }
+ else {
+ $date = $all_dates[ $page_counter ];
+ }
+
+ $index[] = array(
+ 'loc' => WPSEO_Sitemaps_Router::get_base_url( $post_type . '-sitemap' . $current_page . '.xml' ),
+ 'lastmod' => $date,
+ );
+ }
+ }
+
+ return $index;
+ }
+
+ /**
+ * Get set of sitemap link data.
+ *
+ * @param string $type Sitemap type.
+ * @param int $max_entries Entries per sitemap.
+ * @param int $current_page Current page of the sitemap.
+ *
+ * @return array
+ */
+ public function get_sitemap_links( $type, $max_entries, $current_page ) {
+
+ $links = array();
+ $post_type = $type;
+
+ if ( ! $this->is_valid_post_type( $post_type ) ) {
+ return $links;
+ }
+
+ $steps = min( 100, $max_entries );
+ $offset = ( $current_page > 1 ) ? ( ( $current_page - 1 ) * $max_entries ) : 0;
+ $total = ( $offset + $max_entries );
+
+ $typecount = $this->get_post_type_count( $post_type );
+
+ if ( $total > $typecount ) {
+ $total = $typecount;
+ }
+
+ if ( $current_page === 1 ) {
+ $links = array_merge( $links, $this->get_first_links( $post_type ) );
+ }
+
+ if ( $typecount === 0 ) {
+
+ return $links;
+ }
+
+ $options = $this->get_options();
+
+ $stacked_urls = array();
+
+ while ( $total > $offset ) {
+
+ $posts = $this->get_posts( $post_type, $steps, $offset );
+
+ $offset += $steps;
+
+ if ( empty( $posts ) ) {
+ continue;
+ }
+
+ $posts_to_exclude = explode( ',', $options['excluded-posts'] );
+
+ foreach ( $posts as $post ) {
+
+ if ( WPSEO_Meta::get_value( 'meta-robots-noindex', $post->ID ) === '1' ) {
+ continue;
+ }
+
+ if ( in_array( $post->ID, $posts_to_exclude ) ) {
+ continue;
+ }
+
+ $url = $this->get_url( $post );
+
+ if ( ! isset( $url['loc'] ) ) {
+ continue;
+ }
+
+ /**
+ * Filter URL entry before it gets added to the sitemap.
+ *
+ * @param array $url Array of URL parts.
+ * @param string $type URL type.
+ * @param object $user Data object for the URL.
+ */
+ $url = apply_filters( 'wpseo_sitemap_entry', $url, 'post', $post );
+
+ if ( empty( $url ) ) {
+ continue;
+ }
+
+ $stacked_urls[] = $url['loc'];
+
+ if ( (int) $post->ID === $this->get_page_for_posts_id() || (int) $post->ID === $this->get_page_on_front_id() ) {
+
+ array_unshift( $links, $url );
+ continue;
+ }
+ $links[] = $url;
+ }
+
+ unset( $post, $url );
+ }
+
+ return $links;
+ }
+
+ /**
+ * Check for relevant post type before invalidation.
+ *
+ * @param int $post_id Post ID to possibly invalidate for.
+ */
+ public function save_post( $post_id ) {
+
+ if ( $this->is_valid_post_type( get_post_type( $post_id ) ) ) {
+ WPSEO_Sitemaps_Cache::invalidate_post( $post_id );
+ }
+ }
+
+ /**
+ * Check if post type should be present in sitemaps.
+ *
+ * @param string $post_type Post type string to check for.
+ *
+ * @return bool
+ */
+ public function is_valid_post_type( $post_type ) {
+
+ $options = $this->get_options();
+
+ if ( ! empty( $options[ "post_types-{$post_type}-not_in_sitemap" ] ) ) {
+ return false;
+ }
+
+ if ( ! in_array( $post_type, get_post_types( array( 'public' => true ) ) ) ) {
+ return false;
+ }
+
+ /**
+ * Filter decision if post type is excluded from the XML sitemap.
+ *
+ * @param bool $exclude Default false.
+ * @param string $post_type Post type name.
+ */
+ if ( apply_filters( 'wpseo_sitemap_exclude_post_type', false, $post_type ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Get count of posts for post type.
+ *
+ * @param string $post_type Post type to retrieve count for.
+ *
+ * @return int
+ */
+ protected function get_post_type_count( $post_type ) {
+
+ global $wpdb;
+
+ /**
+ * Filter JOIN query part for type count of post type.
+ *
+ * @param string $join SQL part, defaults to empty string.
+ * @param string $post_type Post type name.
+ */
+ $join_filter = apply_filters( 'wpseo_typecount_join', '', $post_type );
+
+ /**
+ * Filter WHERE query part for type count of post type.
+ *
+ * @param string $where SQL part, defaults to empty string.
+ * @param string $post_type Post type name.
+ */
+ $where_filter = apply_filters( 'wpseo_typecount_where', '', $post_type );
+
+ $where = $this->get_sql_where_clause( $post_type );
+
+ $sql = "
+ SELECT COUNT({$wpdb->posts}.ID)
+ FROM {$wpdb->posts}
+ {$join_filter}
+ {$where}
+ {$where_filter}
+ ";
+
+ return (int) $wpdb->get_var( $sql );
+ }
+
+ /**
+ * Produces set of links to prepend at start of first sitemap page.
+ *
+ * @param string $post_type Post type to produce links for.
+ *
+ * @return array
+ */
+ protected function get_first_links( $post_type ) {
+
+ $links = array();
+
+ $needs_archive = true;
+
+ if ( ! $this->get_page_on_front_id() && ( $post_type == 'post' || $post_type == 'page' ) ) {
+
+ $links[] = array(
+ 'loc' => $this->get_home_url(),
+
+ // Deprecated, kept for backwards data compat. R.
+ 'chf' => 'daily',
+ 'pri' => 1,
+ );
+
+ $needs_archive = false;
+ }
+ elseif ( $this->get_page_on_front_id() && $post_type === 'post' && $this->get_page_for_posts_id() ) {
+
+ $page_for_posts_url = get_permalink( $this->get_page_for_posts_id() );
+
+ $links[] = array(
+ 'loc' => $page_for_posts_url,
+
+ // Deprecated, kept for backwards data compat. R.
+ 'chf' => 'daily',
+ 'pri' => 1,
+ );
+
+ $needs_archive = false;
+ }
+
+ if ( ! $needs_archive ) {
+ return $links;
+ }
+
+ $archive_url = get_post_type_archive_link( $post_type );
+
+ /**
+ * Filter the URL Yoast SEO uses in the XML sitemap for this post type archive.
+ *
+ * @param string $archive_url The URL of this archive
+ * @param string $post_type The post type this archive is for.
+ */
+ $archive_url = apply_filters( 'wpseo_sitemap_post_type_archive_link', $archive_url, $post_type );
+
+ if ( $archive_url ) {
+ /**
+ * Filter the priority of the URL Yoast SEO uses in the XML sitemap.
+ *
+ * @param float $priority The priority for this URL, ranging from 0 to 1
+ * @param string $post_type The post type this archive is for.
+ */
+ $links[] = array(
+ 'loc' => $archive_url,
+ 'mod' => WPSEO_Sitemaps::get_last_modified_gmt( $post_type ),
+
+ // Deprecated, kept for backwards data compat. R.
+ 'chf' => 'daily',
+ 'pri' => 1,
+ );
+ }
+
+ return $links;
+ }
+
+ /**
+ * Retrieve set of posts with optimized query routine.
+ *
+ * @param string $post_type Post type to retrieve.
+ * @param int $count Count of posts to retrieve.
+ * @param int $offset Starting offset.
+ *
+ * @return object[]
+ */
+ protected function get_posts( $post_type, $count, $offset ) {
+
+ global $wpdb;
+
+ static $filters = array();
+
+ if ( ! isset( $filters[ $post_type ] ) ) {
+ // Make sure you're wpdb->preparing everything you throw into this!!
+ $filters[ $post_type ] = array(
+ /**
+ * Filter JOIN query part for the post type.
+ *
+ * @param string $join SQL part, defaults to false.
+ * @param string $post_type Post type name.
+ */
+ 'join' => apply_filters( 'wpseo_posts_join', false, $post_type ),
+
+ /**
+ * Filter Where query part for the post type.
+ *
+ * @param string $where SQL part, defaults to false.
+ * @param string $post_type Post type name.
+ */
+ 'where' => apply_filters( 'wpseo_posts_where', false, $post_type ),
+ );
+ }
+
+ $join_filter = $filters[ $post_type ]['join'];
+ $where_filter = $filters[ $post_type ]['where'];
+ $where = $this->get_sql_where_clause( $post_type );
+
+ // Optimized query per this thread: http://wordpress.org/support/topic/plugin-wordpress-seo-by-yoast-performance-suggestion.
+ // Also see http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/.
+ $sql = "
+ SELECT l.ID, post_title, post_content, post_name, post_parent, post_author, post_modified_gmt, post_date, post_date_gmt
+ FROM (
+ SELECT {$wpdb->posts}.ID
+ FROM {$wpdb->posts}
+ {$join_filter}
+ {$where}
+ {$where_filter}
+ ORDER BY {$wpdb->posts}.post_modified ASC LIMIT %d OFFSET %d
+ )
+ o JOIN {$wpdb->posts} l ON l.ID = o.ID
+ ";
+
+ $posts = $wpdb->get_results( $wpdb->prepare( $sql, $count, $offset ) );
+
+ $post_ids = array();
+
+ foreach ( $posts as $post ) {
+ $post->post_type = $post_type;
+ $post->post_status = 'publish';
+ $post->filter = 'sample';
+ $post_ids[] = $post->ID;
+ }
+
+ update_meta_cache( 'post', $post_ids );
+
+ return $posts;
+ }
+
+ /**
+ * @param string $post_type Post type slug.
+ *
+ * @return string
+ */
+ protected function get_sql_where_clause( $post_type ) {
+
+ global $wpdb;
+
+ $join = '';
+ $status = "{$wpdb->posts}.post_status = 'publish'";
+
+ // Based on WP_Query->get_posts(). R.
+ if ( 'attachment' === $post_type ) {
+ $join = " LEFT JOIN {$wpdb->posts} AS p2 ON ({$wpdb->posts}.post_parent = p2.ID) ";
+ $status = "p2.post_status = 'publish'";
+ }
+
+ $where_clause = "
+ {$join}
+ WHERE {$status}
+ AND {$wpdb->posts}.post_type = '%s'
+ AND {$wpdb->posts}.post_password = ''
+ AND {$wpdb->posts}.post_date != '0000-00-00 00:00:00'
+ ";
+
+ return $wpdb->prepare( $where_clause, $post_type );
+ }
+
+ /**
+ * Produce array of URL parts for given post object.
+ *
+ * @param object $post Post object to get URL parts for.
+ *
+ * @return array|bool
+ */
+ protected function get_url( $post ) {
+
+ $url = array();
+
+ /**
+ * Filter the URL Yoast SEO uses in the XML sitemap.
+ *
+ * Note that only absolute local URLs are allowed as the check after this removes external URLs.
+ *
+ * @param string $url URL to use in the XML sitemap
+ * @param object $post Post object for the URL.
+ */
+ $url['loc'] = apply_filters( 'wpseo_xml_sitemap_post_url', get_permalink( $post ), $post );
+
+ /**
+ * Do not include external URLs.
+ *
+ * @see https://wordpress.org/plugins/page-links-to/ can rewrite permalinks to external URLs.
+ */
+ if ( false === strpos( $url['loc'], $this->get_home_url() ) ) {
+ return false;
+ }
+
+ $modified = max( $post->post_modified_gmt, $post->post_date_gmt );
+
+ if ( $modified !== '0000-00-00 00:00:00' ) {
+ $url['mod'] = $modified;
+ }
+
+ $url['chf'] = 'daily'; // Deprecated, kept for backwards data compat. R.
+
+ $canonical = WPSEO_Meta::get_value( 'canonical', $post->ID );
+
+ if ( $canonical !== '' && $canonical !== $url['loc'] ) {
+ /*
+ Let's assume that if a canonical is set for this page and it's different from
+ the URL of this post, that page is either already in the XML sitemap OR is on
+ an external site, either way, we shouldn't include it here.
+ */
+ return false;
+ }
+ unset( $canonical );
+
+ $options = $this->get_options();
+ if ( $options['trailingslash'] === true && $post->post_type !== 'post' ) {
+ $url['loc'] = trailingslashit( $url['loc'] );
+ }
+
+ $url['pri'] = 1; // Deprecated, kept for backwards data compat. R.
+ $url['images'] = $this->get_image_parser()->get_images( $post );
+
+ return $url;
+ }
+
+ /**
+ * Calculate the priority of the post.
+ *
+ * @deprecated 3.5 Priority data dropped from sitemaps.
+ *
+ * @param WP_Post $post Post object.
+ *
+ * @return float|mixed
+ */
+ private function calculate_priority( $post ) {
+
+ $return = 0.6;
+ if ( $post->post_parent == 0 && $post->post_type == 'page' ) {
+ $return = 0.8;
+ }
+
+ if ( $post->ID === $this->get_page_on_front_id() || $post->ID === $this->get_page_for_posts_id() ) {
+ $return = 1.0;
+ }
+
+ /**
+ * Filter the priority of the URL Yoast SEO uses in the XML sitemap.
+ *
+ * @param float $priority The priority for this URL, ranging from 0 to 1
+ * @param string $post_type The post type this archive is for.
+ * @param object $post The post object.
+ */
+ $return = apply_filters( 'wpseo_xml_sitemap_post_priority', $return, $post->post_type, $post );
+
+ return $return;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemap-cache-data.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemap-cache-data.php
new file mode 100644
index 0000000..d53779b
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemap-cache-data.php
@@ -0,0 +1,129 @@
+sitemap = $sitemap;
+
+ /**
+ * Empty sitemap is not usable.
+ */
+ if ( ! empty( $sitemap ) ) {
+ $this->set_status( self::OK );
+ }
+ else {
+ $this->set_status( self::ERROR );
+ }
+ }
+
+ /**
+ * Set the status of the sitemap, is it usable.
+ *
+ * @param bool|string $valid Is the sitemap valid or not.
+ *
+ * @return void
+ */
+ public function set_status( $valid ) {
+
+ if ( self::OK === $valid ) {
+ $this->status = self::OK;
+
+ return;
+ }
+
+ if ( self::ERROR === $valid ) {
+ $this->status = self::ERROR;
+ $this->sitemap = '';
+
+ return;
+ }
+
+ $this->status = self::UNKNOWN;
+ }
+
+ /**
+ * Is the sitemap usable.
+ *
+ * @return bool True if usable, False if bad or unknown.
+ */
+ public function is_usable() {
+
+ return self::OK === $this->status;
+ }
+
+ /**
+ * Get the XML content of the sitemap.
+ *
+ * @return string The content of the sitemap.
+ */
+ public function get_sitemap() {
+
+ return $this->sitemap;
+ }
+
+ /**
+ * Get the status of the sitemap.
+ *
+ * @return string Status of the sitemap, 'ok'/'error'/'unknown'
+ */
+ public function get_status() {
+
+ return $this->status;
+ }
+
+ /**
+ * String representation of object
+ *
+ * @link http://php.net/manual/en/serializable.serialize.php
+ * @return string the string representation of the object or null
+ * @since 5.1.0
+ */
+ public function serialize() {
+
+ $data = array(
+ 'status' => $this->status,
+ 'xml' => $this->sitemap,
+ );
+
+ return serialize( $data );
+ }
+
+ /**
+ * Constructs the object
+ *
+ * @link http://php.net/manual/en/serializable.unserialize.php
+ *
+ * @param string $serialized The string representation of the object.
+ *
+ * @return void
+ * @since 5.1.0
+ */
+ public function unserialize( $serialized ) {
+
+ $data = unserialize( $serialized );
+ $this->set_sitemap( $data['xml'] );
+ $this->set_status( $data['status'] );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemap-image-parser.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemap-image-parser.php
new file mode 100644
index 0000000..1cbacab
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemap-image-parser.php
@@ -0,0 +1,428 @@
+home_url = home_url();
+ $parsed_home = wp_parse_url( $this->home_url );
+
+ if ( ! empty( $parsed_home['host'] ) ) {
+ $this->host = str_replace( 'www.', '', $parsed_home['host'] );
+ }
+
+ if ( ! empty( $parsed_home['scheme'] ) ) {
+ $this->scheme = $parsed_home['scheme'];
+ }
+
+ $this->charset = esc_attr( get_bloginfo( 'charset' ) );
+ }
+
+ /**
+ * Get set of image data sets for the given post.
+ *
+ * @param object $post Post object to get images for.
+ *
+ * @return array
+ */
+ public function get_images( $post ) {
+
+ $images = array();
+
+ if ( ! is_object( $post ) ) {
+ return $images;
+ }
+
+ $thumbnail_id = get_post_thumbnail_id( $post->ID );
+
+ if ( $thumbnail_id ) {
+
+ $src = $this->get_absolute_url( $this->image_url( $thumbnail_id ) );
+ $alt = get_post_meta( $thumbnail_id, '_wp_attachment_image_alt', true );
+ $title = get_post_field( 'post_title', $thumbnail_id );
+ $images[] = $this->get_image_item( $post, $src, $title, $alt );
+ }
+
+ $unfiltered_images = $this->parse_html_images( $post->post_content );
+
+ foreach ( $unfiltered_images as $image ) {
+ $images[] = $this->get_image_item( $post, $image['src'], $image['title'], $image['alt'] );
+ }
+
+ foreach ( $this->parse_galleries( $post->post_content, $post->ID ) as $attachment ) {
+
+ $src = $this->get_absolute_url( $this->image_url( $attachment->ID ) );
+ $alt = get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true );
+
+ $images[] = $this->get_image_item( $post, $src, $attachment->post_title, $alt );
+ }
+
+ if ( 'attachment' === $post->post_type && wp_attachment_is_image( $post ) ) {
+
+ $src = $this->get_absolute_url( $this->image_url( $post->ID ) );
+ $alt = get_post_meta( $post->ID, '_wp_attachment_image_alt', true );
+
+ $images[] = $this->get_image_item( $post, $src, $post->post_title, $alt );
+ }
+
+ foreach ( $images as $key => $image ) {
+
+ if ( empty( $image['src'] ) ) {
+ unset( $images[ $key ] );
+ }
+ }
+
+ /**
+ * Filter images to be included for the post in XML sitemap.
+ *
+ * @param array $images Array of image items.
+ * @param int $post_id ID of the post.
+ */
+ $images = apply_filters( 'wpseo_sitemap_urlimages', $images, $post->ID );
+
+ return $images;
+ }
+
+ /**
+ * @param object $term Term to get images from description for.
+ *
+ * @return array
+ */
+ public function get_term_images( $term ) {
+
+ $images = $this->parse_html_images( $term->description );
+
+ foreach ( $this->parse_galleries( $term->description ) as $attachment ) {
+
+ $images[] = array(
+ 'src' => $this->get_absolute_url( $this->image_url( $attachment->ID ) ),
+ 'title' => $attachment->post_title,
+ 'alt' => get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ),
+ );
+ }
+
+ return $images;
+ }
+
+ /**
+ * Parse `` tags in content.
+ *
+ * @param string $content Content string to parse.
+ *
+ * @return array
+ */
+ private function parse_html_images( $content ) {
+
+ $images = array();
+
+ if ( ! class_exists( 'DOMDocument' ) ) {
+ return $images;
+ }
+
+ if ( empty( $content ) ) {
+ return $images;
+ }
+
+ // Prevent DOMDocument from bubbling warnings about invalid HTML.
+ libxml_use_internal_errors( true );
+
+ $post_dom = new DOMDocument();
+ $post_dom->loadHTML( 'charset .'">' . $content );
+
+ // Clear the errors, so they don't get kept in memory.
+ libxml_clear_errors();
+
+ /** @var DOMElement $img */
+ foreach ( $post_dom->getElementsByTagName( 'img' ) as $img ) {
+
+ $src = $img->getAttribute( 'src' );
+
+ if ( empty( $src ) ) {
+ continue;
+ }
+
+ $class = $img->getAttribute( 'class' );
+
+ if ( // This detects WP-inserted images, which we need to upsize. R.
+ ! empty( $class )
+ && false === strpos( $class, 'size-full' )
+ && preg_match( '|wp-image-(?P\d+)|', $class, $matches )
+ && get_post_status( $matches['id'] )
+ ) {
+ $src = $this->image_url( $matches['id'] );
+ }
+
+ $src = $this->get_absolute_url( $src );
+
+ if ( strpos( $src, $this->host ) === false ) {
+ continue;
+ }
+
+ if ( $src !== esc_url( $src ) ) {
+ continue;
+ }
+
+ $images[] = array(
+ 'src' => $src,
+ 'title' => $img->getAttribute( 'title' ),
+ 'alt' => $img->getAttribute( 'alt' ),
+ );
+ }
+
+ return $images;
+ }
+
+ /**
+ * Parse gallery shortcodes in a given content.
+ *
+ * @param string $content Content string.
+ * @param int $post_id Optional ID of post being parsed.
+ *
+ * @return array Set of attachment objects.
+ */
+ private function parse_galleries( $content, $post_id = 0 ) {
+
+ $attachments = array();
+ $galleries = $this->get_content_galleries( $content );
+
+ foreach ( $galleries as $gallery ) {
+
+ $id = $post_id;
+
+ if ( ! empty( $gallery['id'] ) ) {
+ $id = intval( $gallery['id'] );
+ }
+
+ // Forked from core gallery_shortcode() to have exact same logic. R.
+ if ( ! empty( $gallery['ids'] ) ) {
+ $gallery['include'] = $gallery['ids'];
+ }
+
+ $gallery_attachments = array();
+
+ if ( ! empty( $gallery['include'] ) ) {
+
+ $_attachments = get_posts( array(
+ 'include' => $gallery['include'],
+ 'post_status' => 'inherit',
+ 'post_type' => 'attachment',
+ 'post_mime_type' => 'image',
+ ) );
+
+ foreach ( $_attachments as $key => $val ) {
+ $gallery_attachments[ $val->ID ] = $_attachments[ $key ];
+ }
+ }
+ elseif ( ! empty( $gallery['exclude'] ) && ! empty( $id ) ) {
+
+ $gallery_attachments = get_children( array(
+ 'post_parent' => $id,
+ 'exclude' => $gallery['exclude'],
+ 'post_status' => 'inherit',
+ 'post_type' => 'attachment',
+ 'post_mime_type' => 'image',
+ ) );
+ }
+ elseif ( ! empty( $id ) ) {
+
+ $gallery_attachments = get_children( array(
+ 'post_parent' => $id,
+ 'post_status' => 'inherit',
+ 'post_type' => 'attachment',
+ 'post_mime_type' => 'image',
+ ) );
+ }
+
+ $attachments = array_merge( $attachments, $gallery_attachments );
+ }
+
+ return array_unique( $attachments, SORT_REGULAR );
+ }
+
+ /**
+ * Retrieves galleries from the passed content.
+ *
+ * Forked from core to skip executing shortcodes for performance.
+ *
+ * @param string $content Content to parse for shortcodes.
+ *
+ * @return array A list of arrays, each containing gallery data.
+ */
+ protected function get_content_galleries( $content ) {
+
+ if ( ! has_shortcode( $content, 'gallery' ) ) {
+ return array();
+ }
+
+ $galleries = array();
+
+ if ( ! preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER ) ) {
+ return $galleries;
+ }
+
+ foreach ( $matches as $shortcode ) {
+ if ( 'gallery' === $shortcode[2] ) {
+
+ $attributes = shortcode_parse_atts( $shortcode[3] );
+
+ if ( '' === $attributes ) { // Valid shortcode without any attributes. R.
+ $attributes = array();
+ }
+
+ $galleries[] = $attributes;
+ }
+ }
+
+ return $galleries;
+ }
+
+ /**
+ * Get image item array with filters applied.
+ *
+ * @param WP_Post $post Post object for the context.
+ * @param string $src Image URL.
+ * @param string $title Optional image title.
+ * @param string $alt Optional image alt text.
+ *
+ * @return array
+ */
+ protected function get_image_item( $post, $src, $title = '', $alt = '' ) {
+
+ $image = array();
+
+ /**
+ * Filter image URL to be included in XML sitemap for the post.
+ *
+ * @param string $src Image URL.
+ * @param object $post Post object.
+ */
+ $image['src'] = apply_filters( 'wpseo_xml_sitemap_img_src', $src, $post );
+
+ if ( ! empty( $title ) ) {
+ $image['title'] = $title;
+ }
+
+ if ( ! empty( $alt ) ) {
+ $image['alt'] = $alt;
+ }
+
+ /**
+ * Filter image data to be included in XML sitemap for the post.
+ *
+ * @param array $image {
+ * Array of image data.
+ *
+ * @type string $src Image URL.
+ * @type string $title Image title attribute (optional).
+ * @type string $alt Image alt attribute (optional).
+ * }
+ *
+ * @param object $post Post object.
+ */
+ return apply_filters( 'wpseo_xml_sitemap_img', $image, $post );
+ }
+
+ /**
+ * Get attached image URL. Adapted from core for speed.
+ *
+ * @param int $post_id ID of the post.
+ *
+ * @return string
+ */
+ private function image_url( $post_id ) {
+
+ static $uploads;
+
+ if ( empty( $uploads ) ) {
+ $uploads = wp_upload_dir();
+ }
+
+ if ( false !== $uploads['error'] ) {
+ return '';
+ }
+
+ $file = get_post_meta( $post_id, '_wp_attached_file', true );
+
+ if ( empty( $file ) ) {
+ return '';
+ }
+
+ // Check that the upload base exists in the file location.
+ if ( 0 === strpos( $file, $uploads['basedir'] ) ) {
+ return str_replace( $uploads['basedir'], $uploads['baseurl'], $file );
+ }
+
+ // Replace file location with url location.
+ if ( false !== strpos( $file, 'wp-content/uploads' ) ) {
+ return $uploads['baseurl'] . substr( $file, ( strpos( $file, 'wp-content/uploads' ) + 18 ) );
+ }
+
+ // It's a newly uploaded file, therefore $file is relative to the baseurl.
+ return $uploads['baseurl'] . "/$file";
+ }
+
+ /**
+ * Make absolute URL for domain or protocol-relative one.
+ *
+ * @param string $src URL to process.
+ *
+ * @return string
+ */
+ protected function get_absolute_url( $src ) {
+
+ if ( empty( $src ) || ! is_string( $src ) ) {
+ return $src;
+ }
+
+ if ( WPSEO_Utils::is_url_relative( $src ) === true ) {
+
+ if ( $src[0] !== '/' ) {
+ return $src;
+ }
+
+ // The URL is relative, we'll have to make it absolute.
+ return $this->home_url . $src;
+ }
+
+ if ( strpos( $src, 'http' ) !== 0 ) {
+ // Protocol relative url, we add the scheme as the standard requires a protocol.
+ return $this->scheme . ':' . $src;
+ }
+
+ return $src;
+ }
+
+ /**
+ * Cache attached images and thumbnails for a set of posts.
+ *
+ * @deprecated 3.3 Blanket caching no longer makes sense with modern galleries. R.
+ */
+ public function cache_attachments() {
+
+ _deprecated_function( __FUNCTION__, '3.3' );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemap-timezone.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemap-timezone.php
new file mode 100644
index 0000000..15f8cc1
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemap-timezone.php
@@ -0,0 +1,116 @@
+get_datetime_with_timezone( $datetime_string );
+
+ if ( is_null( $date_time ) ) {
+ return '';
+ }
+
+ return $date_time->format( $format );
+ }
+ /**
+ * Get the datetime object, in site's time zone, if the datetime string was valid
+ *
+ * @param string $datetime_string The datetime string in UTC time zone, that needs to be converted to a DateTime object.
+ *
+ * @return DateTime|null in site's time zone
+ */
+ public function get_datetime_with_timezone( $datetime_string ) {
+
+ static $utc_timezone, $local_timezone;
+
+ if ( ! isset( $utc_timezone ) ) {
+ $utc_timezone = new DateTimeZone( 'UTC' );
+ $local_timezone = new DateTimeZone( $this->get_timezone_string() );
+ }
+
+ if ( ! empty( $datetime_string ) && WPSEO_Utils::is_valid_datetime( $datetime_string ) ) {
+ $datetime = new DateTime( $datetime_string, $utc_timezone );
+ $datetime->setTimezone( $local_timezone );
+
+ return $datetime;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the timezone string for a site, even if it's set to a UTC offset
+ *
+ * Adapted from http://www.php.net/manual/en/function.timezone-name-from-abbr.php#89155
+ *
+ * @return string valid PHP timezone string
+ */
+ private function determine_timezone_string() {
+
+ // If site timezone string exists, return it.
+ if ( $timezone = get_option( 'timezone_string' ) ) {
+ return $timezone;
+ }
+
+ // Get UTC offset, if it isn't set then return UTC.
+ if ( 0 === ( $utc_offset = (int) get_option( 'gmt_offset', 0 ) ) ) {
+ return 'UTC';
+ }
+
+ // Adjust UTC offset from hours to seconds.
+ $utc_offset *= HOUR_IN_SECONDS;
+
+ // Attempt to guess the timezone string from the UTC offset.
+ $timezone = timezone_name_from_abbr( '', $utc_offset );
+
+ if ( false !== $timezone ) {
+ return $timezone;
+ }
+
+ // Last try, guess timezone string manually.
+ foreach ( timezone_abbreviations_list() as $abbr ) {
+ foreach ( $abbr as $city ) {
+ if ( $city['offset'] == $utc_offset ) {
+ return $city['timezone_id'];
+ }
+ }
+ }
+
+ // Fallback to UTC.
+ return 'UTC';
+ }
+
+ /**
+ * Returns the correct timezone string
+ *
+ * @return string
+ */
+ private function get_timezone_string() {
+ if ( '' == $this->timezone_string ) {
+ $this->timezone_string = $this->determine_timezone_string();
+ }
+
+ return $this->timezone_string;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-admin.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-admin.php
new file mode 100644
index 0000000..760b811
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-admin.php
@@ -0,0 +1,191 @@
+detect_blocking_filesystem_sitemaps();
+ }
+
+ /**
+ * Find sitemaps residing on disk as they will block our rewrite.
+ *
+ * @since 3.1
+ */
+ public function detect_blocking_filesystem_sitemaps() {
+ $wpseo_xml_options = WPSEO_Options::get_option( 'wpseo_xml' );
+ if ( $wpseo_xml_options['enablexmlsitemap'] !== true ) {
+ return;
+ }
+ unset( $wpseo_xml_options );
+
+ // Find all files and directories containing 'sitemap' and are post-fixed .xml.
+ $blocking_files = glob( ABSPATH . '*sitemap*.xml', ( GLOB_NOSORT | GLOB_MARK ) );
+
+ if ( false === $blocking_files ) { // Some systems might return error on no matches.
+ $blocking_files = array();
+ }
+
+ // Save if we have changes.
+ $wpseo_options = WPSEO_Options::get_option( 'wpseo' );
+
+ if ( $wpseo_options['blocking_files'] !== $blocking_files ) {
+ $wpseo_options['blocking_files'] = $blocking_files;
+
+ update_option( 'wpseo', $wpseo_options );
+ }
+ }
+
+ /**
+ * Hooked into transition_post_status. Will initiate search engine pings
+ * if the post is being published, is a post type that a sitemap is built for
+ * and is a post that is included in sitemaps.
+ *
+ * @param string $new_status New post status.
+ * @param string $old_status Old post status.
+ * @param \WP_Post $post Post object.
+ */
+ public function status_transition( $new_status, $old_status, $post ) {
+ if ( $new_status !== 'publish' ) {
+ return;
+ }
+
+ if ( defined( 'WP_IMPORTING' ) ) {
+ $this->status_transition_bulk( $new_status, $old_status, $post );
+
+ return;
+ }
+
+ $post_type = get_post_type( $post );
+
+ wp_cache_delete( 'lastpostmodified:gmt:' . $post_type, 'timeinfo' ); // #17455.
+
+ // None of our interest..
+ if ( 'nav_menu_item' === $post_type ) {
+ return;
+ }
+
+ $options = WPSEO_Options::get_options( array( 'wpseo_xml', 'wpseo_titles' ) );
+
+ // If the post type is excluded in options, we can stop.
+ $option = sprintf( 'post_types-%s-not_in_sitemap', $post_type );
+ if ( isset( $options[ $option ] ) && $options[ $option ] === true ) {
+ return;
+ }
+
+ if ( WP_CACHE ) {
+ wp_schedule_single_event( ( time() + 300 ), 'wpseo_hit_sitemap_index' );
+ }
+
+ /**
+ * Filter: 'wpseo_allow_xml_sitemap_ping' - Check if pinging is not allowed (allowed by default)
+ *
+ * @api boolean $allow_ping The boolean that is set to true by default.
+ */
+ if ( apply_filters( 'wpseo_allow_xml_sitemap_ping', true ) === false ) {
+ return;
+ }
+
+ // Allow the pinging to happen slightly after the hit sitemap index so the sitemap is fully regenerated when the ping happens.
+ $excluded_posts = explode( ',', $options['excluded-posts'] );
+
+ if ( ! in_array( $post->ID, $excluded_posts ) ) {
+
+ if ( defined( 'YOAST_SEO_PING_IMMEDIATELY' ) && YOAST_SEO_PING_IMMEDIATELY ) {
+ WPSEO_Sitemaps::ping_search_engines();
+ }
+ elseif ( ! wp_next_scheduled( 'wpseo_ping_search_engines' ) ) {
+ wp_schedule_single_event( ( time() + 300 ), 'wpseo_ping_search_engines' );
+ }
+ }
+ }
+
+ /**
+ * While bulk importing, just save unique post_types
+ *
+ * When importing is done, if we have a post_type that is saved in the sitemap
+ * try to ping the search engines
+ *
+ * @param string $new_status New post status.
+ * @param string $old_status Old post status.
+ * @param \WP_Post $post Post object.
+ */
+ private function status_transition_bulk( $new_status, $old_status, $post ) {
+ $this->importing_post_types[] = get_post_type( $post );
+ $this->importing_post_types = array_unique( $this->importing_post_types );
+ }
+
+ /**
+ * After import finished, walk through imported post_types and update info.
+ */
+ public function status_transition_bulk_finished() {
+ if ( ! defined( 'WP_IMPORTING' ) ) {
+ return;
+ }
+
+ if ( empty( $this->importing_post_types ) ) {
+ return;
+ }
+
+ $options = WPSEO_Options::get_option( 'wpseo_xml' );
+
+ $ping_search_engines = false;
+
+ foreach ( $this->importing_post_types as $post_type ) {
+ wp_cache_delete( 'lastpostmodified:gmt:' . $post_type, 'timeinfo' ); // #17455.
+
+ // Just have the cache deleted for nav_menu_item.
+ if ( 'nav_menu_item' === $post_type ) {
+ continue;
+ }
+
+ $option = sprintf( 'post_types-%s-not_in_sitemap', $post_type );
+ if ( ! isset( $options[ $option ] ) || $options[ $option ] === false ) {
+ $ping_search_engines = true;
+ }
+ }
+
+ // Nothing to do.
+ if ( false === $ping_search_engines ) {
+ return;
+ }
+
+ if ( WP_CACHE ) {
+ do_action( 'wpseo_hit_sitemap_index' );
+ }
+
+ WPSEO_Sitemaps::ping_search_engines();
+ }
+} /* End of class */
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-cache-validator.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-cache-validator.php
new file mode 100644
index 0000000..80f7be9
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-cache-validator.php
@@ -0,0 +1,292 @@
+ $max_length ) {
+
+ if ( $max_length < 15 ) {
+ /**
+ * If this happens the most likely cause is a page number that is too high.
+ *
+ * So this would not happen unintentionally..
+ * Either by trying to cause a high server load, finding backdoors or misconfiguration.
+ */
+ throw new OutOfRangeException(
+ __(
+ 'Trying to build the sitemap cache key, but the postfix and prefix combination leaves too little room to do this. You are probably requesting a page that is way out of the expected range.',
+ 'wordpress-seo'
+ )
+ );
+ }
+
+ $half = ( $max_length / 2 );
+
+ $first_part = substr( $type, 0, ( ceil( $half ) - 1 ) );
+ $last_part = substr( $type, ( 1 - floor( $half ) ) );
+
+ $type = $first_part . '..' . $last_part;
+ }
+
+ return $type;
+ }
+
+ /**
+ * Invalidate sitemap cache
+ *
+ * @param null|string $type The type to get the key for. Null for all caches.
+ *
+ * @return void
+ */
+ public static function invalidate_storage( $type = null ) {
+
+ // Global validator gets cleared when no type is provided.
+ $old_validator = null;
+
+ // Get the current type validator.
+ if ( ! is_null( $type ) ) {
+ $old_validator = self::get_validator( $type );
+ }
+
+ // Refresh validator.
+ self::create_validator( $type );
+
+ if ( ! wp_using_ext_object_cache() ) {
+ // Clean up current cache from the database.
+ self::cleanup_database( $type, $old_validator );
+ }
+
+ // External object cache pushes old and unretrieved items out by itself so we don't have to do anything for that.
+ }
+
+ /**
+ * Cleanup invalidated database cache
+ *
+ * @param null|string $type The type of sitemap to clear cache for.
+ * @param null|string $validator The validator to clear cache of.
+ *
+ * @return void
+ */
+ public static function cleanup_database( $type = null, $validator = null ) {
+
+ global $wpdb;
+
+ if ( is_null( $type ) ) {
+ // Clear all cache if no type is provided.
+ $like = sprintf( '%s%%', self::STORAGE_KEY_PREFIX );
+ }
+ else {
+ if ( ! is_null( $validator ) ) {
+ // Clear all cache for provided type-validator.
+ $like = sprintf( '%%_%s', $validator );
+ }
+ else {
+ // Clear type cache for all type keys.
+ $like = sprintf( '%1$s%2$s_%%', self::STORAGE_KEY_PREFIX, $type );
+ }
+ }
+
+ /**
+ * Add slashes to the LIKE "_" single character wildcard.
+ *
+ * We can't use `esc_like` here because we need the % in the query.
+ */
+ $where = array();
+ $where[] = sprintf( "option_name LIKE '%s'", addcslashes( '_transient_' . $like, '_' ) );
+ $where[] = sprintf( "option_name LIKE '%s'", addcslashes( '_transient_timeout_' . $like, '_' ) );
+
+ // Delete transients.
+ $query = sprintf( 'DELETE FROM %1$s WHERE %2$s', $wpdb->options, implode( ' OR ', $where ) );
+ $wpdb->query( $query );
+ }
+
+ /**
+ * Get the current cache validator
+ *
+ * Without the type the global validator is returned.
+ * This can invalidate -all- keys in cache at once
+ *
+ * With the type parameter the validator for that specific
+ * type can be invalidated
+ *
+ * @param string $type Provide a type for a specific type validator, empty for global validator.
+ *
+ * @return null|string The validator for the supplied type.
+ */
+ public static function get_validator( $type = '' ) {
+
+ $key = self::get_validator_key( $type );
+
+ $current = get_option( $key, null );
+ if ( ! is_null( $current ) ) {
+ return $current;
+ }
+
+ if ( self::create_validator( $type ) ) {
+ return self::get_validator( $type );
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the cache validator option key for the specified type
+ *
+ * @param string $type Provide a type for a specific type validator, empty for global validator.
+ *
+ * @return string Validator to be used to generate the cache key.
+ */
+ public static function get_validator_key( $type = '' ) {
+
+ if ( empty( $type ) ) {
+ return self::VALIDATION_GLOBAL_KEY;
+ }
+
+ return sprintf( self::VALIDATION_TYPE_KEY_FORMAT, $type );
+ }
+
+ /**
+ * Refresh the cache validator value
+ *
+ * @param string $type Provide a type for a specific type validator, empty for global validator.
+ *
+ * @return bool True if validator key has been saved as option.
+ */
+ public static function create_validator( $type = '' ) {
+
+ $key = self::get_validator_key( $type );
+
+ // Generate new validator.
+ $microtime = microtime();
+
+ // Remove space.
+ list( $milliseconds, $seconds ) = explode( ' ', $microtime );
+
+ // Transients are purged every 24h.
+ $seconds = ( $seconds % DAY_IN_SECONDS );
+ $milliseconds = intval( substr( $milliseconds, 2, 3 ), 10 );
+
+ // Combine seconds and milliseconds and convert to integer.
+ $validator = intval( $seconds . '' . $milliseconds, 10 );
+
+ // Apply base 61 encoding.
+ $compressed = self::convert_base10_to_base61( $validator );
+
+ return update_option( $key, $compressed, false );
+ }
+
+ /**
+ * Encode to base61 format.
+ *
+ * This is base64 (numeric + alpha + alpha upper case) without the 0.
+ *
+ * @param int $base10 The number that has to be converted to base 61.
+ *
+ * @return string Base 61 converted string.
+ *
+ * @throws InvalidArgumentException When the input is not an integer.
+ */
+ public static function convert_base10_to_base61( $base10 ) {
+
+ if ( ! is_int( $base10 ) ) {
+ throw new InvalidArgumentException( __( 'Expected an integer as input.', 'wordpress-seo' ) );
+ }
+
+ // Characters that will be used in the conversion.
+ $characters = '123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+ $length = strlen( $characters );
+
+ $remainder = $base10;
+ $output = '';
+
+ do {
+ // Building from right to left in the result.
+ $index = ( $remainder % $length );
+
+ // Prepend the character to the output.
+ $output = $characters[ $index ] . $output;
+
+ // Determine the remainder after removing the applied number.
+ $remainder = floor( $remainder / $length );
+
+ // Keep doing it until we have no remainder left.
+ } while ( $remainder );
+
+ return $output;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-cache.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-cache.php
new file mode 100644
index 0000000..84a007c
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-cache.php
@@ -0,0 +1,292 @@
+is_enabled();
+ }
+
+ /**
+ * If cache is enabled.
+ *
+ * @return boolean
+ */
+ public function is_enabled() {
+
+ /**
+ * Filter if XML sitemap transient cache is enabled.
+ *
+ * @param bool $unsigned Enable cache or not, defaults to true
+ */
+ return apply_filters( 'wpseo_enable_xml_sitemap_transient_caching', true );
+ }
+
+
+ /**
+ * Retrieve the sitemap page from cache.
+ *
+ * @param string $type Sitemap type.
+ * @param int $page Page number to retrieve.
+ *
+ * @return string|boolean
+ */
+ public function get_sitemap( $type, $page ) {
+
+ $transient_key = WPSEO_Sitemaps_Cache_Validator::get_storage_key( $type, $page );
+ if ( false === $transient_key ) {
+ return false;
+ }
+
+ return get_transient( $transient_key );
+ }
+
+ /**
+ * Get the sitemap that is cached
+ *
+ * @param string $type Sitemap type.
+ * @param int $page Page number to retrieve.
+ *
+ * @return null|WPSEO_Sitemap_Cache_Data Null on no cache found otherwise object containing sitemap and meta data.
+ */
+ public function get_sitemap_data( $type, $page ) {
+
+ $sitemap = $this->get_sitemap( $type, $page );
+
+ if ( empty( $sitemap ) ) {
+ return null;
+ }
+
+ // Unserialize Cache Data object (is_serialized doesn't recognize classes).
+ if ( is_string( $sitemap ) && 0 === strpos( $sitemap, 'C:24:"WPSEO_Sitemap_Cache_Data"' ) ) {
+
+ $sitemap = unserialize( $sitemap );
+ }
+
+ // What we expect it to be if it is set.
+ if ( $sitemap instanceof WPSEO_Sitemap_Cache_Data_Interface ) {
+ return $sitemap;
+ }
+
+ return null;
+ }
+
+ /**
+ * Store the sitemap page from cache.
+ *
+ * @param string $type Sitemap type.
+ * @param int $page Page number to store.
+ * @param string $sitemap Sitemap body to store.
+ * @param bool $usable Is this a valid sitemap or a cache of an invalid sitemap.
+ *
+ * @return bool
+ */
+ public function store_sitemap( $type, $page, $sitemap, $usable = true ) {
+
+ $transient_key = WPSEO_Sitemaps_Cache_Validator::get_storage_key( $type, $page );
+
+ if ( false === $transient_key ) {
+ return false;
+ }
+
+ $status = ( $usable ) ? WPSEO_Sitemap_Cache_Data::OK : WPSEO_Sitemap_Cache_Data::ERROR;
+
+ $sitemap_data = new WPSEO_Sitemap_Cache_Data();
+ $sitemap_data->set_sitemap( $sitemap );
+ $sitemap_data->set_status( $status );
+
+ return set_transient( $transient_key, $sitemap_data, DAY_IN_SECONDS );
+ }
+
+ /**
+ * Delete cache transients for index and specific type.
+ *
+ * Always deletes the main index sitemaps cache, as that's always invalidated by any other change.
+ *
+ * @param string $type Sitemap type to invalidate.
+ *
+ * @return void
+ */
+ public static function invalidate( $type ) {
+
+ self::clear( array( $type ) );
+ }
+
+ /**
+ * Helper to invalidate in hooks where type is passed as second argument.
+ *
+ * @param int $unused Unused term ID value.
+ * @param string $type Taxonomy to invalidate.
+ *
+ * @return void
+ */
+ public static function invalidate_helper( $unused, $type ) {
+
+ self::invalidate( $type );
+ }
+
+ /**
+ * Invalidate sitemap cache for authors.
+ *
+ * @param int $user_id User ID.
+ */
+ public static function invalidate_author( $user_id ) {
+
+ $user = get_user_by( 'id', $user_id );
+
+ if ( 'user_register' === current_action() ) {
+ update_user_meta( $user_id, '_yoast_wpseo_profile_updated', time() );
+ }
+
+ if ( ! in_array( 'subscriber', $user->roles ) ) {
+ self::invalidate( 'author' );
+ }
+ }
+
+ /**
+ * Invalidate sitemap cache for the post type of a post.
+ *
+ * Don't invalidate for revisions.
+ *
+ * @param int $post_id Post ID to invalidate type for.
+ *
+ * @return void
+ */
+ public static function invalidate_post( $post_id ) {
+
+ if ( wp_is_post_revision( $post_id ) ) {
+ return;
+ }
+
+ self::invalidate( get_post_type( $post_id ) );
+ }
+
+ /**
+ * Delete cache transients for given sitemaps types or all by default.
+ *
+ * @param array $types Set of sitemap types to delete cache transients for.
+ *
+ * @return void
+ */
+ public static function clear( $types = array() ) {
+
+ if ( ! self::$is_enabled ) {
+ return;
+ }
+
+ // No types provided, clear all.
+ if ( empty( $types ) ) {
+ self::$clear_all = true;
+
+ return;
+ }
+
+ // Always invalidate the index sitemap as well.
+ if ( ! in_array( WPSEO_Sitemaps::SITEMAP_INDEX_TYPE, $types ) ) {
+ array_unshift( $types, WPSEO_Sitemaps::SITEMAP_INDEX_TYPE );
+ }
+
+ foreach ( $types as $type ) {
+ if ( ! in_array( $type, self::$clear_types ) ) {
+ self::$clear_types[] = $type;
+ }
+ }
+ }
+
+ /**
+ * Invalidate storage for cache types queued to clear.
+ */
+ public static function clear_queued() {
+
+ if ( self::$clear_all ) {
+
+ WPSEO_Sitemaps_Cache_Validator::invalidate_storage();
+ self::$clear_all = false;
+ self::$clear_types = array();
+
+ return;
+ }
+
+ foreach ( self::$clear_types as $type ) {
+ WPSEO_Sitemaps_Cache_Validator::invalidate_storage( $type );
+ }
+
+ self::$clear_types = array();
+ }
+
+ /**
+ * Adds a hook that when given option is updated, the cache is cleared
+ *
+ * @param string $option Option name.
+ * @param string $type Sitemap type.
+ */
+ public static function register_clear_on_option_update( $option, $type = '' ) {
+
+ self::$cache_clear[ $option ] = $type;
+ }
+
+ /**
+ * Clears the transient cache when a given option is updated, if that option has been registered before
+ *
+ * @param string $option The option name that's being updated.
+ *
+ * @return void
+ */
+ public static function clear_on_option_update( $option ) {
+
+ if ( array_key_exists( $option, self::$cache_clear ) ) {
+
+ if ( empty( self::$cache_clear[ $option ] ) ) {
+ // Clear all caches.
+ self::clear();
+ }
+ else {
+ // Clear specific provided type(s).
+ $types = (array) self::$cache_clear[ $option ];
+ self::clear( $types );
+ }
+ }
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-renderer.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-renderer.php
new file mode 100644
index 0000000..d5b1c29
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-renderer.php
@@ -0,0 +1,322 @@
+stylesheet = '';
+ $this->charset = get_bloginfo( 'charset' );
+ $this->output_charset = $this->charset;
+ $this->timezone = new WPSEO_Sitemap_Timezone();
+
+ if (
+ 'UTF-8' !== $this->charset
+ && function_exists( 'mb_list_encodings' )
+ && in_array( $this->charset, mb_list_encodings(), true )
+ ) {
+ $this->output_charset = 'UTF-8';
+ }
+
+ $this->needs_conversion = $this->output_charset !== $this->charset;
+ }
+
+ /**
+ * @param array $links Set of sitemaps index links.
+ *
+ * @return string
+ */
+ public function get_index( $links ) {
+
+ $xml = '' . "\n";
+
+ foreach ( $links as $link ) {
+ $xml .= $this->sitemap_index_url( $link );
+ }
+
+ /**
+ * Filter to append sitemaps to the index.
+ *
+ * @param string $index String to append to sitemaps index, defaults to empty.
+ */
+ $xml .= apply_filters( 'wpseo_sitemap_index', '' );
+ $xml .= '';
+
+ return $xml;
+ }
+
+ /**
+ * @param array $links Set of sitemap links.
+ * @param string $type Sitemap type.
+ * @param int $current_page Current sitemap page number.
+ *
+ * @return string
+ */
+ public function get_sitemap( $links, $type, $current_page ) {
+
+ $urlset = '' . "\n";
+
+ /**
+ * Filters the `urlset` for a sitemap by type.
+ *
+ * @api string $urlset The output for the sitemap's `urlset`.
+ */
+ $xml = apply_filters( "wpseo_sitemap_{$type}_urlset", $urlset );
+
+ foreach ( $links as $url ) {
+ $xml .= $this->sitemap_url( $url );
+ }
+
+ /**
+ * Filter to add extra URLs to the XML sitemap by type.
+ *
+ * Only runs for the first page, not on all.
+ *
+ * @param string $content String content to add, defaults to empty.
+ */
+ if ( $current_page === 1 ) {
+ $xml .= apply_filters( "wpseo_sitemap_{$type}_content", '' );
+ }
+
+ $xml .= '';
+
+ return $xml;
+ }
+
+ /**
+ * Produce final XML output with debug information.
+ *
+ * @param string $sitemap Sitemap XML.
+ * @param boolean $transient Transient cache flag.
+ *
+ * @return string
+ */
+ public function get_output( $sitemap, $transient ) {
+
+ $output = 'output_charset ) . '"?>';
+
+ if ( $this->stylesheet ) {
+ /**
+ * Filter the stylesheet URL for the XML sitemap.
+ *
+ * @param string $stylesheet Stylesheet URL.
+ */
+ $output .= apply_filters( 'wpseo_stylesheet_url', $this->stylesheet ) . "\n";
+ }
+
+ $output .= $sitemap;
+ $output .= "\n";
+
+ $debug = WP_DEBUG || ( defined( 'WPSEO_DEBUG' ) && true === WPSEO_DEBUG );
+
+ if ( ! WP_DEBUG_DISPLAY || ! $debug ) {
+ return $output;
+ }
+
+ $memory_used = number_format( ( memory_get_peak_usage() / 1048576 ), 2 );
+ $queries_run = ( $transient ) ? 'Served from transient cache' : 'Queries executed ' . absint( $GLOBALS['wpdb']->num_queries );
+
+ $output .= "\n";
+
+ if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
+
+ $queries = print_r( $GLOBALS['wpdb']->queries, true );
+ $output .= "\n";
+ }
+
+ return $output;
+ }
+
+ /**
+ * Get charset for the output.
+ *
+ * @return string
+ */
+ public function get_output_charset() {
+ return $this->output_charset;
+ }
+
+ /**
+ * Set a custom stylesheet for this sitemap. Set to empty to just remove the default stylesheet.
+ *
+ * @param string $stylesheet Full xml-stylesheet declaration.
+ */
+ public function set_stylesheet( $stylesheet ) {
+ $this->stylesheet = $stylesheet;
+ }
+
+ /**
+ * Build the `` tag for a given URL.
+ *
+ * @param array $url Array of parts that make up this entry.
+ *
+ * @return string
+ */
+ protected function sitemap_index_url( $url ) {
+
+ $date = null;
+
+ if ( ! empty( $url['lastmod'] ) ) {
+ $date = $this->timezone->format_date( $url['lastmod'] );
+ }
+
+ $url['loc'] = htmlspecialchars( $url['loc'] );
+
+ $output = "\t\n";
+ $output .= "\t\t" . $url['loc'] . "\n";
+ $output .= empty( $date ) ? '' : "\t\t" . htmlspecialchars( $date ) . "\n";
+ $output .= "\t\n";
+
+ return $output;
+ }
+
+ /**
+ * Build the `` tag for a given URL.
+ *
+ * Public access for backwards compatibility reasons.
+ *
+ * @param array $url Array of parts that make up this entry.
+ *
+ * @return string
+ */
+ public function sitemap_url( $url ) {
+
+ $date = null;
+
+
+ if ( ! empty( $url['mod'] ) ) {
+ // Create a DateTime object date in the correct timezone.
+ $date = $this->timezone->format_date( $url['mod'] );
+ }
+
+ $url['loc'] = htmlspecialchars( $url['loc'] );
+
+ $output = "\t\n";
+ $output .= "\t\t" . $this->encode_url_rfc3986( $url['loc'] ) . "\n";
+ $output .= empty( $date ) ? '' : "\t\t" . htmlspecialchars( $date ) . "\n";
+
+ if ( empty( $url['images'] ) ) {
+ $url['images'] = array();
+ }
+
+ foreach ( $url['images'] as $img ) {
+
+ if ( empty( $img['src'] ) ) {
+ continue;
+ }
+
+ $output .= "\t\t\n";
+ $output .= "\t\t\t" . esc_html( $this->encode_url_rfc3986( $img['src'] ) ) . "\n";
+
+ if ( ! empty( $img['title'] ) ) {
+
+ $title = $img['title'];
+
+ if ( $this->needs_conversion ) {
+ $title = mb_convert_encoding( $title, $this->output_charset, $this->charset );
+ }
+
+ $title = _wp_specialchars( html_entity_decode( $title, ENT_QUOTES, $this->output_charset ) );
+ $output .= "\t\t\t\n";
+ }
+
+ if ( ! empty( $img['alt'] ) ) {
+
+ $alt = $img['alt'];
+
+ if ( $this->needs_conversion ) {
+ $alt = mb_convert_encoding( $alt, $this->output_charset, $this->charset );
+ }
+
+ $alt = _wp_specialchars( html_entity_decode( $alt, ENT_QUOTES, $this->output_charset ) );
+ $output .= "\t\t\t\n";
+ }
+
+ $output .= "\t\t\n";
+ }
+ unset( $img, $title, $alt );
+
+ $output .= "\t\n";
+
+ /**
+ * Filters the output for the sitemap url tag.
+ *
+ * @api string $output The output for the sitemap url tag.
+ *
+ * @param array $url The sitemap url array on which the output is based.
+ */
+ return apply_filters( 'wpseo_sitemap_url', $output, $url );
+ }
+
+ /**
+ * Apply some best effort conversion to comply with RFC3986.
+ *
+ * @param string $url URL to encode.
+ *
+ * @return string
+ */
+ protected function encode_url_rfc3986( $url ) {
+
+ if ( filter_var( $url, FILTER_VALIDATE_URL ) ) {
+ return $url;
+ }
+
+ $path = parse_url( $url, PHP_URL_PATH );
+
+ if ( ! empty( $path ) && '/' !== $path ) {
+
+ $encoded_path = explode( '/', $path );
+ $encoded_path = array_map( 'rawurlencode', $encoded_path );
+ $encoded_path = implode( '/', $encoded_path );
+ $encoded_path = str_replace( '%7E', '~', $encoded_path ); // PHP <5.3.
+
+ $url = str_replace( $path, $encoded_path, $url );
+ }
+
+ $query = parse_url( $url, PHP_URL_QUERY );
+
+ if ( ! empty( $query ) ) {
+
+ parse_str( $query, $parsed_query );
+
+ if ( defined( 'PHP_QUERY_RFC3986' ) ) { // PHP 5.4+.
+ $parsed_query = http_build_query( $parsed_query, null, '&', PHP_QUERY_RFC3986 );
+ }
+ else {
+ $parsed_query = http_build_query( $parsed_query, null, '&' );
+ $parsed_query = str_replace( '+', '%20', $parsed_query );
+ $parsed_query = str_replace( '%7E', '~', $parsed_query );
+ }
+
+ $url = str_replace( $query, $parsed_query, $url );
+ }
+
+ return $url;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-router.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-router.php
new file mode 100644
index 0000000..1c1d0de
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps-router.php
@@ -0,0 +1,98 @@
+add_query_var( 'sitemap' );
+ $wp->add_query_var( 'sitemap_n' );
+ $wp->add_query_var( 'xsl' );
+
+ add_rewrite_rule( 'sitemap_index\.xml$', 'index.php?sitemap=1', 'top' );
+ add_rewrite_rule( '([^/]+?)-sitemap([0-9]+)?\.xml$', 'index.php?sitemap=$matches[1]&sitemap_n=$matches[2]', 'top' );
+ add_rewrite_rule( '([a-z]+)?-?sitemap\.xsl$', 'index.php?xsl=$matches[1]', 'top' );
+ }
+
+ /**
+ * Stop trailing slashes on sitemap.xml URLs.
+ *
+ * @param string $redirect The redirect URL currently determined.
+ *
+ * @return bool|string $redirect
+ */
+ public function redirect_canonical( $redirect ) {
+
+ if ( get_query_var( 'sitemap' ) || get_query_var( 'xsl' ) ) {
+ return false;
+ }
+
+ return $redirect;
+ }
+
+ /**
+ * Redirects sitemap.xml to sitemap_index.xml.
+ */
+ public function template_redirect() {
+
+ global $wp_query;
+
+ $current_url = 'http://';
+
+ if ( ! empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] === 'on' ) {
+ $current_url = 'https://';
+ }
+
+ $current_url .= sanitize_text_field( $_SERVER['SERVER_NAME'] );
+ $current_url .= sanitize_text_field( $_SERVER['REQUEST_URI'] );
+
+ if ( home_url( '/sitemap.xml' ) === $current_url && $wp_query->is_404 ) {
+ wp_redirect( home_url( '/sitemap_index.xml' ), 301 );
+ exit;
+ }
+ }
+
+ /**
+ * Create base URL for the sitemap.
+ *
+ * @param string $page Page to append to the base URL.
+ *
+ * @return string base URL (incl page)
+ */
+ public static function get_base_url( $page ) {
+
+ global $wp_rewrite;
+
+ $base = $wp_rewrite->using_index_permalinks() ? 'index.php/' : '/';
+
+ /**
+ * Filter the base URL of the sitemaps
+ *
+ * @param string $base The string that should be added to home_url() to make the full base URL.
+ */
+ $base = apply_filters( 'wpseo_sitemaps_base_url', $base );
+
+ // Get the scheme from the configured home url instead of letting WordPress determine the scheme based on the requested URI.
+ return home_url( $base . $page, parse_url( get_option( 'home' ), PHP_URL_SCHEME ) );
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps.php
new file mode 100644
index 0000000..c84b440
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-sitemaps.php
@@ -0,0 +1,545 @@
+max_entries = $options['entries-per-page'];
+ $this->timezone = new WPSEO_Sitemap_Timezone();
+ $this->router = new WPSEO_Sitemaps_Router();
+ $this->renderer = new WPSEO_Sitemaps_Renderer();
+ $this->cache = new WPSEO_Sitemaps_Cache();
+ $this->providers = array( // TODO API for add/remove. R.
+ new WPSEO_Post_Type_Sitemap_Provider(),
+ new WPSEO_Taxonomy_Sitemap_Provider(),
+ new WPSEO_Author_Sitemap_Provider(),
+ );
+
+ if ( ! empty( $_SERVER['SERVER_PROTOCOL'] ) ) {
+ $this->http_protocol = sanitize_text_field( $_SERVER['SERVER_PROTOCOL'] );
+ }
+ }
+
+ /**
+ * Check the current request URI, if we can determine it's probably an XML sitemap, kill loading the widgets
+ */
+ public function reduce_query_load() {
+
+ if ( ! isset( $_SERVER['REQUEST_URI'] ) ) {
+ return;
+ }
+
+ $request_uri = $_SERVER['REQUEST_URI'];
+ $extension = substr( $request_uri, -4 );
+
+ if ( false !== stripos( $request_uri, 'sitemap' ) && in_array( $extension, array( '.xml', '.xsl' ) ) ) {
+ remove_all_actions( 'widgets_init' );
+ }
+ }
+
+ /**
+ * Register your own sitemap. Call this during 'init'.
+ *
+ * @param string $name The name of the sitemap.
+ * @param callback $function Function to build your sitemap.
+ * @param string $rewrite Optional. Regular expression to match your sitemap with.
+ */
+ public function register_sitemap( $name, $function, $rewrite = '' ) {
+ add_action( 'wpseo_do_sitemap_' . $name, $function );
+ if ( ! empty( $rewrite ) ) {
+ add_rewrite_rule( $rewrite, 'index.php?sitemap=' . $name, 'top' );
+ }
+ }
+
+ /**
+ * Register your own XSL file. Call this during 'init'.
+ *
+ * @param string $name The name of the XSL file.
+ * @param callback $function Function to build your XSL file.
+ * @param string $rewrite Optional. Regular expression to match your sitemap with.
+ */
+ public function register_xsl( $name, $function, $rewrite = '' ) {
+ add_action( 'wpseo_xsl_' . $name, $function );
+ if ( ! empty( $rewrite ) ) {
+ add_rewrite_rule( $rewrite, 'index.php?xsl=' . $name, 'top' );
+ }
+ }
+
+ /**
+ * Set the sitemap current page to allow creating partial sitemaps with wp-cli
+ * in a one-off process.
+ *
+ * @param integer $current_page The part that should be generated.
+ */
+ public function set_n( $current_page ) {
+ if ( is_scalar( $current_page ) && intval( $current_page ) > 0 ) {
+ $this->current_page = intval( $current_page );
+ }
+ }
+
+ /**
+ * Set the sitemap content to display after you have generated it.
+ *
+ * @param string $sitemap The generated sitemap to output.
+ */
+ public function set_sitemap( $sitemap ) {
+ $this->sitemap = $sitemap;
+ }
+
+ /**
+ * Set as true to make the request 404. Used stop the display of empty sitemaps or invalid requests.
+ *
+ * @param bool $bool Is this a bad request. True or false.
+ */
+ public function set_bad_sitemap( $bool ) {
+ $this->bad_sitemap = (bool) $bool;
+ }
+
+ /**
+ * Prevent stupid plugins from running shutdown scripts when we're obviously not outputting HTML.
+ *
+ * @since 1.4.16
+ */
+ public function sitemap_close() {
+ remove_all_actions( 'wp_footer' );
+ die();
+ }
+
+ /**
+ * Hijack requests for potential sitemaps and XSL files.
+ *
+ * @param \WP_Query $query Main query instance.
+ */
+ public function redirect( $query ) {
+
+ if ( ! $query->is_main_query() ) {
+ return;
+ }
+
+ $xsl = get_query_var( 'xsl' );
+
+ if ( ! empty( $xsl ) ) {
+ $this->xsl_output( $xsl );
+ $this->sitemap_close();
+
+ return;
+ }
+
+ $type = get_query_var( 'sitemap' );
+
+ if ( empty( $type ) ) {
+ return;
+ }
+
+ $this->set_n( get_query_var( 'sitemap_n' ) );
+
+ if ( ! $this->get_sitemap_from_cache( $type, $this->current_page ) ) {
+ $this->build_sitemap( $type );
+ }
+
+ if ( $this->bad_sitemap ) {
+ $query->set_404();
+ status_header( 404 );
+
+ return;
+ }
+
+ $this->output();
+ $this->sitemap_close();
+ }
+
+ /**
+ * Try to get the sitemap from cache
+ *
+ * @param string $type Sitemap type.
+ * @param int $page_number The page number to retrieve.
+ *
+ * @return bool If the sitemap has been retrieved from cache.
+ */
+ private function get_sitemap_from_cache( $type, $page_number ) {
+
+ $this->transient = false;
+
+ if ( true !== $this->cache->is_enabled() ) {
+ return false;
+ }
+
+ /**
+ * Fires before the attempt to retrieve XML sitemap from the transient cache.
+ *
+ * @param WPSEO_Sitemaps $sitemaps Sitemaps object.
+ */
+ do_action( 'wpseo_sitemap_stylesheet_cache_' . $type, $this );
+
+ $sitemap_cache_data = $this->cache->get_sitemap_data( $type, $page_number );
+
+ // No cache was found, refresh it because cache is enabled.
+ if ( empty( $sitemap_cache_data ) ) {
+ return $this->refresh_sitemap_cache( $type, $page_number );
+ }
+
+ // Cache object was found, parse information.
+ $this->transient = true;
+
+ $this->sitemap = $sitemap_cache_data->get_sitemap();
+ $this->bad_sitemap = ! $sitemap_cache_data->is_usable();
+
+ return true;
+ }
+
+ /**
+ * Build and save sitemap to cache.
+ *
+ * @param string $type Sitemap type.
+ * @param int $page_number The page number to save to.
+ *
+ * @return bool
+ */
+ private function refresh_sitemap_cache( $type, $page_number ) {
+ $this->set_n( $page_number );
+ $this->build_sitemap( $type );
+
+ return $this->cache->store_sitemap( $type, $page_number, $this->sitemap, ! $this->bad_sitemap );
+ }
+
+ /**
+ * Attempts to build the requested sitemap.
+ *
+ * Sets $bad_sitemap if this isn't for the root sitemap, a post type or taxonomy.
+ *
+ * @param string $type The requested sitemap's identifier.
+ */
+ public function build_sitemap( $type ) {
+
+ /**
+ * Filter the type of sitemap to build.
+ *
+ * @param string $type Sitemap type, determined by the request.
+ */
+ $type = apply_filters( 'wpseo_build_sitemap_post_type', $type );
+
+ if ( $type === '1' ) {
+ $this->build_root_map();
+
+ return;
+ }
+
+ foreach ( $this->providers as $provider ) {
+ if ( ! $provider->handles_type( $type ) ) {
+ continue;
+ }
+
+ $links = $provider->get_sitemap_links( $type, $this->max_entries, $this->current_page );
+
+ if ( empty( $links ) ) {
+ $this->bad_sitemap = true;
+
+ return;
+ }
+
+ $this->sitemap = $this->renderer->get_sitemap( $links, $type, $this->current_page );
+
+ return;
+ }
+
+ if ( has_action( 'wpseo_do_sitemap_' . $type ) ) {
+ /**
+ * Fires custom handler, if hooked to generate sitemap for the type.
+ */
+ do_action( 'wpseo_do_sitemap_' . $type );
+
+ return;
+ }
+
+ $this->bad_sitemap = true;
+ }
+
+ /**
+ * Build the root sitemap (example.com/sitemap_index.xml) which lists sub-sitemaps for other content types.
+ */
+ public function build_root_map() {
+
+ $links = array();
+
+ foreach ( $this->providers as $provider ) {
+ $links = array_merge( $links, $provider->get_index_links( $this->max_entries ) );
+ }
+
+ if ( empty( $links ) ) {
+ $this->bad_sitemap = true;
+ $this->sitemap = '';
+
+ return;
+ }
+
+ $this->sitemap = $this->renderer->get_index( $links );
+ }
+
+ /**
+ * Spits out the XSL for the XML sitemap.
+ *
+ * @param string $type Type to output.
+ *
+ * @since 1.4.13
+ */
+ public function xsl_output( $type ) {
+
+ if ( $type !== 'main' ) {
+
+ /**
+ * Fires for the output of XSL for XML sitemaps, other than type "main".
+ */
+ do_action( 'wpseo_xsl_' . $type );
+
+ return;
+ }
+
+ header( $this->http_protocol . ' 200 OK', true, 200 );
+ // Prevent the search engines from indexing the XML Sitemap.
+ header( 'X-Robots-Tag: noindex, follow', true );
+ header( 'Content-Type: text/xml' );
+
+ // Make the browser cache this file properly.
+ $expires = YEAR_IN_SECONDS;
+ header( 'Pragma: public' );
+ header( 'Cache-Control: maxage=' . $expires );
+ header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', ( time() + $expires ) ) . ' GMT' );
+
+ require_once( WPSEO_PATH . 'css/xml-sitemap-xsl.php' );
+ }
+
+ /**
+ * Spit out the generated sitemap and relevant headers and encoding information.
+ */
+ public function output() {
+
+ if ( ! headers_sent() ) {
+ header( $this->http_protocol . ' 200 OK', true, 200 );
+ // Prevent the search engines from indexing the XML Sitemap.
+ header( 'X-Robots-Tag: noindex, follow', true );
+ header( 'Content-Type: text/xml; charset=' . esc_attr( $this->renderer->get_output_charset() ) );
+ }
+
+ echo $this->renderer->get_output( $this->sitemap, $this->transient );
+ }
+
+ /**
+ * Make a request for the sitemap index so as to cache it before the arrival of the search engines.
+ */
+ public function hit_sitemap_index() {
+ wp_remote_get( WPSEO_Sitemaps_Router::get_base_url( 'sitemap_index.xml' ) );
+ }
+
+ /**
+ * Get the GMT modification date for the last modified post in the post type.
+ *
+ * @param string|array $post_types Post type or array of types.
+ * @param bool $return_all Flag to return array of values.
+ *
+ * @return string|array|false
+ */
+ static public function get_last_modified_gmt( $post_types, $return_all = false ) {
+
+ global $wpdb;
+
+ static $post_type_dates = null;
+
+ if ( ! is_array( $post_types ) ) {
+ $post_types = array( $post_types );
+ }
+
+ foreach ( $post_types as $post_type ) {
+ if ( ! isset( $post_type_dates[ $post_type ] ) ) { // If we hadn't seen post type before. R.
+ $post_type_dates = null;
+ break;
+ }
+ }
+
+ if ( is_null( $post_type_dates ) ) {
+
+ $sql = "
+ SELECT post_type, MAX(post_modified_gmt) AS date
+ FROM $wpdb->posts
+ WHERE post_status IN ('publish','inherit')
+ AND post_type IN ('" . implode( "','", get_post_types( array( 'public' => true ) ) ) . "')
+ GROUP BY post_type
+ ORDER BY post_modified_gmt DESC
+ ";
+
+ $post_type_dates = array();
+
+ foreach ( $wpdb->get_results( $sql ) as $obj ) {
+ $post_type_dates[ $obj->post_type ] = $obj->date;
+ }
+ }
+
+ $dates = array_intersect_key( $post_type_dates, array_flip( $post_types ) );
+
+ if ( count( $dates ) > 0 ) {
+
+ if ( $return_all ) {
+ return $dates;
+ }
+
+ return max( $dates );
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the modification date for the last modified post in the post type.
+ *
+ * @param array $post_types Post types to get the last modification date for.
+ *
+ * @return string
+ */
+ public function get_last_modified( $post_types ) {
+
+ return $this->timezone->format_date( self::get_last_modified_gmt( $post_types ) );
+ }
+
+ /**
+ * Notify search engines of the updated sitemap.
+ *
+ * @param string|null $url Optional URL to make the ping for.
+ */
+ public static function ping_search_engines( $url = null ) {
+
+ /**
+ * Filter: 'wpseo_allow_xml_sitemap_ping' - Check if pinging is not allowed (allowed by default)
+ *
+ * @api boolean $allow_ping The boolean that is set to true by default.
+ */
+ if ( apply_filters( 'wpseo_allow_xml_sitemap_ping', true ) === false ) {
+ return;
+ }
+
+ if ( '0' === get_option( 'blog_public' ) ) { // Don't ping if blog is not public.
+ return;
+ }
+
+ if ( empty( $url ) ) {
+ $url = urlencode( WPSEO_Sitemaps_Router::get_base_url( 'sitemap_index.xml' ) );
+ }
+
+ // Ping Google and Bing.
+ wp_remote_get( 'http://www.google.com/webmasters/tools/ping?sitemap=' . $url, array( 'blocking' => false ) );
+ wp_remote_get( 'http://www.bing.com/ping?sitemap=' . $url, array( 'blocking' => false ) );
+ }
+
+ /**
+ * Build the `` tag for a given URL.
+ *
+ * @deprecated
+ *
+ * @param array $url Array of parts that make up this entry.
+ *
+ * @return string
+ */
+ public function sitemap_url( $url ) {
+
+ return $this->renderer->sitemap_url( $url );
+ }
+
+ /**
+ * Set a custom stylesheet for this sitemap. Set to empty to just remove the default stylesheet.
+ *
+ * @deprecated
+ *
+ * @param string $stylesheet Full xml-stylesheet declaration.
+ */
+ public function set_stylesheet( $stylesheet ) {
+ $this->renderer->set_stylesheet( $stylesheet );
+ }
+
+ /**
+ * Function to dynamically filter the change frequency.
+ *
+ * @deprecated 3.5 Change frequency data dropped from sitemaps.
+ *
+ * @param string $filter Expands to wpseo_sitemap_$filter_change_freq, allowing for a change of the frequency for
+ * numerous specific URLs.
+ * @param string $default The default value for the frequency.
+ * @param string $url The URL of the current entry.
+ *
+ * @return mixed|void
+ */
+ static public function filter_frequency( $filter, $default, $url ) {
+ /**
+ * Filter the specific change frequency
+ *
+ * @param string $default The default change frequency.
+ * @param string $url URL to filter frequency for.
+ */
+ $change_freq = apply_filters( 'wpseo_sitemap_' . $filter . '_change_freq', $default, $url );
+
+ if ( ! in_array( $change_freq, array(
+ 'always',
+ 'hourly',
+ 'daily',
+ 'weekly',
+ 'monthly',
+ 'yearly',
+ 'never',
+ ) )
+ ) {
+ $change_freq = $default;
+ }
+
+ return $change_freq;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/class-taxonomy-sitemap-provider.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-taxonomy-sitemap-provider.php
new file mode 100644
index 0000000..4d67f4a
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/class-taxonomy-sitemap-provider.php
@@ -0,0 +1,289 @@
+ true ), 'objects' );
+
+ if ( empty( $taxonomies ) ) {
+ return array();
+ }
+
+ $taxonomy_names = array_filter( array_keys( $taxonomies ), array( $this, 'is_valid_taxonomy' ) );
+ $taxonomies = array_intersect_key( $taxonomies, array_flip( $taxonomy_names ) );
+
+ // Retrieve all the taxonomies and their terms so we can do a proper count on them.
+ /**
+ * Filter the setting of excluding empty terms from the XML sitemap.
+ *
+ * @param boolean $exclude Defaults to true.
+ * @param array $taxonomy_names Array of names for the taxonomies being processed.
+ */
+ $hide_empty = apply_filters( 'wpseo_sitemap_exclude_empty_terms', true, $taxonomy_names );
+
+ $all_taxonomies = array();
+
+ foreach ( $taxonomy_names as $taxonomy_name ) {
+
+ $taxonomy_terms = get_terms( $taxonomy_name, array(
+ 'hide_empty' => $hide_empty,
+ 'fields' => 'ids',
+ ) );
+
+ if ( count( $taxonomy_terms ) > 0 ) {
+ $all_taxonomies[ $taxonomy_name ] = $taxonomy_terms;
+ }
+ }
+
+ $index = array();
+
+ foreach ( $taxonomies as $tax_name => $tax ) {
+
+ if ( ! isset( $all_taxonomies[ $tax_name ] ) ) { // No eligible terms found.
+ continue;
+ }
+
+ $total_count = ( isset( $all_taxonomies[ $tax_name ] ) ) ? count( $all_taxonomies[ $tax_name ] ) : 1;
+ $max_pages = 1;
+
+ if ( $total_count > $max_entries ) {
+ $max_pages = (int) ceil( $total_count / $max_entries );
+ }
+
+ $last_modified_gmt = WPSEO_Sitemaps::get_last_modified_gmt( $tax->object_type );
+
+ for ( $page_counter = 0; $page_counter < $max_pages; $page_counter++ ) {
+
+ $current_page = ( $max_pages > 1 ) ? ( $page_counter + 1 ) : '';
+
+ if ( ! is_array( $tax->object_type ) || count( $tax->object_type ) == 0 ) {
+ continue;
+ }
+
+ $terms = array_splice( $all_taxonomies[ $tax_name ], 0, $max_entries );
+
+ if ( ! $terms ) {
+ continue;
+ }
+
+ $args = array(
+ 'post_type' => $tax->object_type,
+ 'tax_query' => array(
+ array(
+ 'taxonomy' => $tax_name,
+ 'terms' => $terms,
+ ),
+ ),
+ 'orderby' => 'modified',
+ 'order' => 'DESC',
+ 'posts_per_page' => 1,
+ );
+ $query = new WP_Query( $args );
+
+ if ( $query->have_posts() ) {
+ $date = $query->posts[0]->post_modified_gmt;
+ }
+ else {
+ $date = $last_modified_gmt;
+ }
+
+ $index[] = array(
+ 'loc' => WPSEO_Sitemaps_Router::get_base_url( $tax_name . '-sitemap' . $current_page . '.xml' ),
+ 'lastmod' => $date,
+ );
+ }
+ }
+
+ return $index;
+ }
+
+ /**
+ * Get set of sitemap link data.
+ *
+ * @param string $type Sitemap type.
+ * @param int $max_entries Entries per sitemap.
+ * @param int $current_page Current page of the sitemap.
+ *
+ * @return array
+ */
+ public function get_sitemap_links( $type, $max_entries, $current_page ) {
+
+ global $wpdb;
+
+ $links = array();
+ $taxonomy = get_taxonomy( $type );
+
+ if ( $taxonomy === false || ! $this->is_valid_taxonomy( $taxonomy->name ) || ! $taxonomy->public ) {
+ return $links;
+ }
+
+ $options = $this->get_options();
+
+ $steps = $max_entries;
+ $offset = ( $current_page > 1 ) ? ( ( $current_page - 1 ) * $max_entries ) : 0;
+
+ /** This filter is documented in inc/sitemaps/class-taxonomy-sitemap-provider.php */
+ $hide_empty = apply_filters( 'wpseo_sitemap_exclude_empty_terms', true, $taxonomy );
+ $terms = get_terms( $taxonomy->name, array( 'hide_empty' => $hide_empty ) );
+ $terms = array_splice( $terms, $offset, $steps );
+
+ if ( empty( $terms ) ) {
+ $terms = array();
+ }
+
+ // Grab last modified date.
+ $sql = "
+ SELECT MAX(p.post_modified_gmt) AS lastmod
+ FROM $wpdb->posts AS p
+ INNER JOIN $wpdb->term_relationships AS term_rel
+ ON term_rel.object_id = p.ID
+ INNER JOIN $wpdb->term_taxonomy AS term_tax
+ ON term_tax.term_taxonomy_id = term_rel.term_taxonomy_id
+ AND term_tax.taxonomy = %s
+ AND term_tax.term_id = %d
+ WHERE p.post_status IN ('publish','inherit')
+ AND p.post_password = ''
+ ";
+
+ foreach ( $terms as $term ) {
+
+ $url = array();
+
+ $tax_noindex = WPSEO_Taxonomy_Meta::get_term_meta( $term, $term->taxonomy, 'noindex' );
+ $tax_sitemap_inc = WPSEO_Taxonomy_Meta::get_term_meta( $term, $term->taxonomy, 'sitemap_include' );
+
+ if ( $tax_noindex === 'noindex' && $tax_sitemap_inc !== 'always' ) {
+ continue;
+ }
+
+ if ( $tax_sitemap_inc === 'never' ) {
+ continue;
+ }
+
+ $url['loc'] = WPSEO_Taxonomy_Meta::get_term_meta( $term, $term->taxonomy, 'canonical' );
+
+ if ( ! is_string( $url['loc'] ) || $url['loc'] === '' ) {
+
+ $url['loc'] = get_term_link( $term, $term->taxonomy );
+
+ if ( $options['trailingslash'] === true ) {
+
+ $url['loc'] = trailingslashit( $url['loc'] );
+ }
+ }
+
+ $url['mod'] = $wpdb->get_var( $wpdb->prepare( $sql, $term->taxonomy, $term->term_id ) );
+ $url['images'] = $this->get_image_parser()->get_term_images( $term );
+
+ // Deprecated, kept for backwards data compat. R.
+ $url['chf'] = 'daily';
+ $url['pri'] = 1;
+
+ /** This filter is documented at inc/sitemaps/class-post-type-sitemap-provider.php */
+ $url = apply_filters( 'wpseo_sitemap_entry', $url, 'term', $term );
+
+ if ( ! empty( $url ) ) {
+ $links[] = $url;
+ }
+ }
+
+ return $links;
+ }
+
+ /**
+ * Check if taxonomy by name is valid to appear in sitemaps.
+ *
+ * @param string $taxonomy_name Taxonomy name to check.
+ *
+ * @return bool
+ */
+ public function is_valid_taxonomy( $taxonomy_name ) {
+
+ $options = $this->get_options();
+ if ( ! empty( $options[ "taxonomies-{$taxonomy_name}-not_in_sitemap" ] ) ) {
+ return false;
+ }
+
+ if ( in_array( $taxonomy_name, array( 'link_category', 'nav_menu' ) ) ) {
+ return false;
+ }
+
+ if ( 'post_format' === $taxonomy_name && ! empty( $options['disable-post_format'] ) ) {
+ return false;
+ }
+
+ /**
+ * Filter to exclude the taxonomy from the XML sitemap.
+ *
+ * @param boolean $exclude Defaults to false.
+ * @param string $taxonomy_name Name of the taxonomy to exclude..
+ */
+ if ( apply_filters( 'wpseo_sitemap_exclude_taxonomy', false, $taxonomy_name ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Get the Image Parser
+ *
+ * @return WPSEO_Sitemap_Image_Parser
+ */
+ protected function get_image_parser() {
+ if ( ! isset( self::$image_parser ) ) {
+ self::$image_parser = new WPSEO_Sitemap_Image_Parser();
+ }
+
+ return self::$image_parser;
+ }
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/sitemaps/interface-sitemap-cache-data.php b/wp-content/plugins/wordpress-seo/inc/sitemaps/interface-sitemap-cache-data.php
new file mode 100644
index 0000000..a2b929b
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/sitemaps/interface-sitemap-cache-data.php
@@ -0,0 +1,56 @@
+get_terms( $id, $taxonomy, $return_single );
+}
+
+/**
+ * Generate an HTML sitemap
+ *
+ * @deprecated 1.5.5.4
+ * @deprecated use plugin Yoast SEO Premium
+ * @see Yoast SEO Premium
+ *
+ * @param array $atts The attributes passed to the shortcode.
+ *
+ * @return string
+ */
+function wpseo_sitemap_handler( $atts ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.5.5.4', 'Functionality has been discontinued after being in beta, it\'ll be available in the Yoast SEO Premium plugin soon.' );
+
+ return '';
+}
+
+add_shortcode( 'wpseo_sitemap', 'wpseo_sitemap_handler' );
+
+/**
+ * Strip out the shortcodes with a filthy regex, because people don't properly register their shortcodes.
+ *
+ * @deprecated 1.6.1
+ * @deprecated use WPSEO_Utils::strip_shortcode()
+ * @see WPSEO_Utils::strip_shortcode()
+ *
+ * @param string $text Input string that might contain shortcodes.
+ *
+ * @return string $text string without shortcodes
+ */
+function wpseo_strip_shortcode( $text ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.6.1', 'WPSEO_Utils::strip_shortcode()' );
+
+ return WPSEO_Utils::strip_shortcode( $text );
+}
+
+/**
+ * Do simple reliable math calculations without the risk of wrong results
+ *
+ * @see http://floating-point-gui.de/
+ * @see the big red warning on http://php.net/language.types.float.php
+ *
+ * @deprecated 1.6.1
+ * @deprecated use WPSEO_Utils::calc()
+ * @see WPSEO_Utils::calc()
+ *
+ * In the rare case that the bcmath extension would not be loaded, it will return the normal calculation results
+ *
+ * @since 1.5.0
+ *
+ * @param mixed $number1 Scalar (string/int/float/bool).
+ * @param string $action Calculation action to execute.
+ * @param mixed $number2 Scalar (string/int/float/bool).
+ * @param bool $round Whether or not to round the result. Defaults to false.
+ * @param int $decimals Decimals for rounding operation. Defaults to 0.
+ * @param int $precision Calculation precision. Defaults to 10.
+ *
+ * @return mixed Calculation Result or false if either or the numbers isn't scalar or
+ * an invalid operation was passed
+ */
+function wpseo_calc( $number1, $action, $number2, $round = false, $decimals = 0, $precision = 10 ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.6.1', 'WPSEO_Utils::calc()' );
+
+ return WPSEO_Utils::calc( $number1, $action, $number2, $round, $decimals, $precision );
+}
+
+/**
+ * Check if the web server is running on Apache
+ *
+ * @deprecated 1.6.1
+ * @deprecated use WPSEO_Utils::is_apache()
+ * @see WPSEO_Utils::is_apache()
+ *
+ * @return bool
+ */
+function wpseo_is_apache() {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.6.1', 'WPSEO_Utils::is_apache()' );
+
+ return WPSEO_Utils::is_apache();
+}
+
+/**
+ * Check if the web service is running on Nginx
+ *
+ * @deprecated 1.6.1
+ * @deprecated use WPSEO_Utils::is_nginx()
+ * @see WPSEO_Utils::is_nginx()
+ *
+ * @return bool
+ */
+function wpseo_is_nginx() {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.6.1', 'WPSEO_Utils::is_nginx()' );
+
+ return WPSEO_Utils::is_nginx();
+}
+
+/**
+ * List all the available user roles
+ *
+ * @deprecated 1.6.1
+ * @deprecated use WPSEO_Utils::get_roles()
+ * @see WPSEO_Utils::get_roles()
+ *
+ * @return array $roles
+ */
+function wpseo_get_roles() {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.6.1', 'WPSEO_Utils::get_roles()' );
+
+ return WPSEO_Utils::get_roles();
+}
+
+/**
+ * Check whether a url is relative
+ *
+ * @deprecated 1.6.1
+ * @deprecated use WPSEO_Utils::is_url_relative()
+ * @see WPSEO_Utils::is_url_relative()
+ *
+ * @param string $url URL input to check.
+ *
+ * @return bool
+ */
+function wpseo_is_url_relative( $url ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.6.1', 'WPSEO_Utils::is_url_relative()' );
+
+ return WPSEO_Utils::is_url_relative( $url );
+}
+
+/**
+ * Standardize whitespace in a string
+ *
+ * @deprecated 1.6.1
+ * @deprecated use WPSEO_Utils::standardize_whitespace()
+ * @see WPSEO_Utils::standardize_whitespace()
+ *
+ * @since 1.6.0
+ *
+ * @param string $string String input to standardize.
+ *
+ * @return string
+ */
+function wpseo_standardize_whitespace( $string ) {
+ _deprecated_function( __FUNCTION__, 'WPSEO 1.6.1', 'WPSEO_Utils::standardize_whitespace()' );
+
+ return WPSEO_Utils::standardize_whitespace( $string );
+}
+
+/**
+ * Initialize sitemaps. Add sitemap & XSL rewrite rules and query vars
+ *
+ * @deprecated 2.4
+ * @see WPSEO_Sitemaps_Router
+ */
+function wpseo_xml_sitemaps_init() {
+ $options = get_option( 'wpseo_xml' );
+ if ( $options['enablexmlsitemap'] !== true ) {
+ return;
+ }
+
+ // Redirects sitemap.xml to sitemap_index.xml.
+ add_action( 'template_redirect', 'wpseo_xml_redirect_sitemap', 0 );
+
+ if ( ! is_object( $GLOBALS['wp'] ) ) {
+ return;
+ }
+
+ $GLOBALS['wp']->add_query_var( 'sitemap' );
+ $GLOBALS['wp']->add_query_var( 'sitemap_n' );
+ $GLOBALS['wp']->add_query_var( 'xsl' );
+ add_rewrite_rule( 'sitemap_index\.xml$', 'index.php?sitemap=1', 'top' );
+ add_rewrite_rule( '([^/]+?)-sitemap([0-9]+)?\.xml$', 'index.php?sitemap=$matches[1]&sitemap_n=$matches[2]', 'top' );
+ add_rewrite_rule( '([a-z]+)?-?sitemap\.xsl$', 'index.php?xsl=$matches[1]', 'top' );
+}
+
+/**
+ * Redirect /sitemap.xml to /sitemap_index.xml
+ *
+ * @deprecated 2.4
+ * @see WPSEO_Sitemaps_Router
+ */
+function wpseo_xml_redirect_sitemap() {
+ $current_url = ( isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] == 'on' ) ? 'https://' : 'http://';
+ $current_url .= sanitize_text_field( $_SERVER['SERVER_NAME'] ) . sanitize_text_field( $_SERVER['REQUEST_URI'] );
+
+ // Must be 'sitemap.xml' and must be 404.
+ if ( home_url( '/sitemap.xml' ) == $current_url && $GLOBALS['wp_query']->is_404 ) {
+ wp_redirect( home_url( '/sitemap_index.xml' ), 301 );
+ exit;
+ }
+}
+
+/**
+ * This invalidates our XML Sitemaps cache.
+ *
+ * @deprecated
+ * @see WPSEO_Sitemaps_Cache
+ *
+ * @param string $type Type of sitemap to invalidate.
+ */
+function wpseo_invalidate_sitemap_cache( $type ) {
+ WPSEO_Sitemaps_Cache::invalidate( $type );
+}
+
+/**
+ * Invalidate XML sitemap cache for taxonomy / term actions
+ *
+ * @deprecated
+ * @see WPSEO_Sitemaps_Cache
+ *
+ * @param int $unused Unused term ID value.
+ * @param string $type Taxonomy to invalidate.
+ */
+function wpseo_invalidate_sitemap_cache_terms( $unused, $type ) {
+ WPSEO_Sitemaps_Cache::invalidate( $type );
+}
+
+/**
+ * Invalidate the XML sitemap cache for a post type when publishing or updating a post
+ *
+ * @deprecated
+ * @see WPSEO_Sitemaps_Cache
+ *
+ * @param int $post_id Post ID to determine post type for invalidation.
+ */
+function wpseo_invalidate_sitemap_cache_on_save_post( $post_id ) {
+ WPSEO_Sitemaps_Cache::invalidate_post( $post_id );
+}
+
+/**
+ * Notify search engines of the updated sitemap.
+ *
+ * @deprecated
+ * @see WPSEO_Sitemaps::ping_search_engines()
+ *
+ * @param string|null $sitemapurl Optional URL to make the ping for.
+ */
+function wpseo_ping_search_engines( $sitemapurl = null ) {
+ WPSEO_Sitemaps::ping_search_engines( $sitemapurl );
+}
+
+/**
+ * Create base URL for the sitemaps and applies filters
+ *
+ * @since 1.5.7
+ *
+ * @deprecated
+ * @see WPSEO_Sitemaps_Router::get_base_url()
+ *
+ * @param string $page page to append to the base URL.
+ *
+ * @return string base URL (incl page) for the sitemaps
+ */
+function wpseo_xml_sitemaps_base_url( $page ) {
+ return WPSEO_Sitemaps_Router::get_base_url( $page );
+}
diff --git a/wp-content/plugins/wordpress-seo/inc/wpseo-functions.php b/wp-content/plugins/wordpress-seo/inc/wpseo-functions.php
new file mode 100644
index 0000000..535928b
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/wpseo-functions.php
@@ -0,0 +1,294 @@
+ID );
+ return $primary_term->get_primary_term();
+ }
+}
+
+if ( ! function_exists( 'yoast_get_primary_term' ) ) {
+ /**
+ * Get the primary term name
+ *
+ * @param string $taxonomy Optional. The taxonomy to get the primary term for. Defaults to category.
+ * @param null|int|WP_Post $post Optional. Post to get the primary term for.
+ *
+ * @return string Name of the primary term.
+ */
+ function yoast_get_primary_term( $taxonomy = 'category', $post = null ) {
+ $primary_term_id = yoast_get_primary_term_id( $taxonomy, $post );
+
+ $term = get_term( $primary_term_id );
+ if ( ! is_wp_error( $term ) && ! empty( $term ) ) {
+ return $term->name;
+ }
+
+ return '';
+ }
+}
+
+/**
+ * Add the bulk edit capability to the proper default roles.
+ */
+function wpseo_add_capabilities() {
+ $roles = array(
+ 'administrator',
+ 'editor',
+ );
+
+ $roles = apply_filters( 'wpseo_bulk_edit_roles', $roles );
+
+ foreach ( $roles as $role ) {
+ $r = get_role( $role );
+ if ( $r ) {
+ $r->add_cap( 'wpseo_bulk_edit' );
+ }
+ }
+}
+
+
+/**
+ * Remove the bulk edit capability from the proper default roles.
+ *
+ * Contributor is still removed for legacy reasons.
+ */
+function wpseo_remove_capabilities() {
+ $roles = array(
+ 'administrator',
+ 'editor',
+ 'author',
+ 'contributor',
+ );
+
+ $roles = apply_filters( 'wpseo_bulk_edit_roles', $roles );
+
+ foreach ( $roles as $role ) {
+ $r = get_role( $role );
+ if ( $r ) {
+ $r->remove_cap( 'wpseo_bulk_edit' );
+ }
+ }
+}
+
+
+/**
+ * Replace `%%variable_placeholders%%` with their real value based on the current requested page/post/cpt
+ *
+ * @param string $string the string to replace the variables in.
+ * @param object $args the object some of the replacement values might come from, could be a post, taxonomy or term.
+ * @param array $omit variables that should not be replaced by this function.
+ *
+ * @return string
+ */
+function wpseo_replace_vars( $string, $args, $omit = array() ) {
+ $replacer = new WPSEO_Replace_Vars;
+
+ return $replacer->replace( $string, $args, $omit );
+}
+
+/**
+ * Register a new variable replacement
+ *
+ * This function is for use by other plugins/themes to easily add their own additional variables to replace.
+ * This function should be called from a function on the 'wpseo_register_extra_replacements' action hook.
+ * The use of this function is preferred over the older 'wpseo_replacements' filter as a way to add new replacements.
+ * The 'wpseo_replacements' filter should still be used to adjust standard WPSEO replacement values.
+ * The function can not be used to replace standard WPSEO replacement value functions and will thrown a warning
+ * if you accidently try.
+ * To avoid conflicts with variables registered by WPSEO and other themes/plugins, try and make the
+ * name of your variable unique. Variable names also can not start with "%%cf_" or "%%ct_" as these are reserved
+ * for the standard WPSEO variable variables 'cf_', 'ct_' and
+ * 'ct_desc_'.
+ * The replacement function will be passed the undelimited name (i.e. stripped of the %%) of the variable
+ * to replace in case you need it.
+ *
+ * Example code:
+ *
+ *
+ *
+ *
+ * @since 1.5.4
+ *
+ * @param string $var The name of the variable to replace, i.e. '%%var%%'
+ * - the surrounding %% are optional, name can only contain [A-Za-z0-9_-].
+ * @param mixed $replace_function Function or method to call to retrieve the replacement value for the variable
+ * Uses the same format as add_filter/add_action function parameter and
+ * should *return* the replacement value. DON'T echo it.
+ * @param string $type Type of variable: 'basic' or 'advanced', defaults to 'advanced'.
+ * @param string $help_text Help text to be added to the help tab for this variable.
+ *
+ * @return bool Whether the replacement function was succesfully registered
+ */
+function wpseo_register_var_replacement( $var, $replace_function, $type = 'advanced', $help_text = '' ) {
+ return WPSEO_Replace_Vars::register_replacement( $var, $replace_function, $type, $help_text );
+}
+
+/**
+ * WPML plugin support: Set titles for custom types / taxonomies as translatable.
+ * It adds new keys to a wpml-config.xml file for a custom post type title, metadesc, title-ptarchive and metadesc-ptarchive fields translation.
+ * Documentation: http://wpml.org/documentation/support/language-configuration-files/
+ *
+ * @global $sitepress
+ *
+ * @param array $config WPML configuration data to filter.
+ *
+ * @return array
+ */
+function wpseo_wpml_config( $config ) {
+ global $sitepress;
+
+ if ( ( is_array( $config ) && isset( $config['wpml-config']['admin-texts']['key'] ) ) && ( is_array( $config['wpml-config']['admin-texts']['key'] ) && $config['wpml-config']['admin-texts']['key'] !== array() ) ) {
+ $admin_texts = $config['wpml-config']['admin-texts']['key'];
+ foreach ( $admin_texts as $k => $val ) {
+ if ( $val['attr']['name'] === 'wpseo_titles' ) {
+ $translate_cp = array_keys( $sitepress->get_translatable_documents() );
+ if ( is_array( $translate_cp ) && $translate_cp !== array() ) {
+ foreach ( $translate_cp as $post_type ) {
+ $admin_texts[ $k ]['key'][]['attr']['name'] = 'title-' . $post_type;
+ $admin_texts[ $k ]['key'][]['attr']['name'] = 'metadesc-' . $post_type;
+ $admin_texts[ $k ]['key'][]['attr']['name'] = 'metakey-' . $post_type;
+ $admin_texts[ $k ]['key'][]['attr']['name'] = 'title-ptarchive-' . $post_type;
+ $admin_texts[ $k ]['key'][]['attr']['name'] = 'metadesc-ptarchive-' . $post_type;
+ $admin_texts[ $k ]['key'][]['attr']['name'] = 'metakey-ptarchive-' . $post_type;
+
+ $translate_tax = $sitepress->get_translatable_taxonomies( false, $post_type );
+ if ( is_array( $translate_tax ) && $translate_tax !== array() ) {
+ foreach ( $translate_tax as $taxonomy ) {
+ $admin_texts[ $k ]['key'][]['attr']['name'] = 'title-tax-' . $taxonomy;
+ $admin_texts[ $k ]['key'][]['attr']['name'] = 'metadesc-tax-' . $taxonomy;
+ $admin_texts[ $k ]['key'][]['attr']['name'] = 'metakey-tax-' . $taxonomy;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ $config['wpml-config']['admin-texts']['key'] = $admin_texts;
+ }
+
+ return $config;
+}
+
+add_filter( 'icl_wpml_config_array', 'wpseo_wpml_config' );
+
+/**
+ * Yoast SEO breadcrumb shortcode
+ * [wpseo_breadcrumb]
+ *
+ * @return string
+ */
+function wpseo_shortcode_yoast_breadcrumb() {
+ return yoast_breadcrumb( '', '', false );
+}
+
+add_shortcode( 'wpseo_breadcrumb', 'wpseo_shortcode_yoast_breadcrumb' );
+
+/**
+ * Emulate PHP native ctype_digit() function for when the ctype extension would be disabled *sigh*
+ * Only emulates the behaviour for when the input is a string, does not handle integer input as ascii value
+ *
+ * @param string $string
+ *
+ * @return bool
+ */
+if ( ! extension_loaded( 'ctype' ) || ! function_exists( 'ctype_digit' ) ) {
+
+ /**
+ * @param string $string String input to validate.
+ *
+ * @return bool
+ */
+ function ctype_digit( $string ) {
+ $return = false;
+ if ( ( is_string( $string ) && $string !== '' ) && preg_match( '`^\d+$`', $string ) === 1 ) {
+ $return = true;
+ }
+
+ return $return;
+ }
+}
+
+/**
+ * Makes sure the taxonomy meta is updated when a taxonomy term is split.
+ *
+ * @link https://make.wordpress.org/core/2015/02/16/taxonomy-term-splitting-in-4-2-a-developer-guide/ Article explaining the taxonomy term splitting in WP 4.2.
+ *
+ * @param string $old_term_id Old term id of the taxonomy term that was splitted.
+ * @param string $new_term_id New term id of the taxonomy term that was splitted.
+ * @param string $term_taxonomy_id Term taxonomy id for the taxonomy that was affected.
+ * @param string $taxonomy The taxonomy that the taxonomy term was splitted for.
+ */
+function wpseo_split_shared_term( $old_term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
+ $tax_meta = get_option( 'wpseo_taxonomy_meta', array() );
+
+ if ( ! empty( $tax_meta[ $taxonomy ][ $old_term_id ] ) ) {
+ $tax_meta[ $taxonomy ][ $new_term_id ] = $tax_meta[ $taxonomy ][ $old_term_id ];
+ unset( $tax_meta[ $taxonomy ][ $old_term_id ] );
+ update_option( 'wpseo_taxonomy_meta', $tax_meta );
+ }
+}
+
+add_action( 'split_shared_term', 'wpseo_split_shared_term', 10, 4 );
diff --git a/wp-content/plugins/wordpress-seo/inc/wpseo-non-ajax-functions.php b/wp-content/plugins/wordpress-seo/inc/wpseo-non-ajax-functions.php
new file mode 100644
index 0000000..272c9a1
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/inc/wpseo-non-ajax-functions.php
@@ -0,0 +1,538 @@
+ID );
+
+ if ( $analysis_seo->is_enabled() ) {
+ $score = wpseo_adminbar_seo_score();
+ }
+ elseif ( $analysis_readability->is_enabled() ) {
+ $score = wpseo_adminbar_content_score();
+ }
+ }
+
+ if ( is_category() || is_tag() || (WPSEO_Taxonomy::is_term_edit( $GLOBALS['pagenow'] ) && ! WPSEO_Taxonomy::is_term_overview( $GLOBALS['pagenow'] ) ) || is_tax() ) {
+ if ( $analysis_seo->is_enabled() ) {
+ $score = wpseo_tax_adminbar_seo_score();
+ }
+ elseif ( $analysis_readability->is_enabled() ) {
+ $score = wpseo_tax_adminbar_content_score();
+ }
+ }
+
+ // Never display notifications for network admin.
+ $counter = '';
+
+ // Set the top level menu item content for admins and network admins.
+ if ( $user_is_admin_or_networkadmin ) {
+
+ // Link the top level menu item to the Yoast Dashboard page.
+ $seo_url = get_admin_url( null, 'admin.php?page=' . WPSEO_Admin::PAGE_IDENTIFIER );
+ // Since admins will get a real link, there's no need for a tabindex attribute.
+ $top_level_link_tabindex = false;
+
+ if ( '' === $score ) {
+
+ // Notification information.
+ $notification_center = Yoast_Notification_Center::get();
+ $notification_count = $notification_center->get_notification_count();
+ $new_notifications = $notification_center->get_new_notifications();
+ $new_notifications_count = count( $new_notifications );
+
+ if ( $notification_count > 0 ) {
+ // Always show Alerts page when clicking on the main link.
+ /* translators: %s: number of notifications */
+ $counter_screen_reader_text = sprintf( _n( '%s notification', '%s notifications', $notification_count, 'wordpress-seo' ), number_format_i18n( $notification_count ) );
+ $counter = sprintf( '
%d%s
', $notification_count, $counter_screen_reader_text );
+ }
+
+ if ( $new_notifications_count ) {
+ $notification = sprintf(
+ /* translators: %d resolves to the number of alerts being added. */
+ _n( 'You have a new issue concerning your SEO!', 'You have %d new issues concerning your SEO!', $new_notifications_count, 'wordpress-seo' ),
+ $new_notifications_count
+ );
+ $counter .= '
');return b},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d1;if(d||c)return a.call(this,b);this.clear();var e=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(e)},b}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e0||0===c.length)){var d=a('×');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return this._transferTabIndex(),d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.trigger("focus")}),b.on("close",function(){e.$search.val(""),e.$search.removeAttr("aria-activedescendant"),e.$search.trigger("focus")}),b.on("enable",function(){e.$search.prop("disabled",!1),e._transferTabIndex()}),b.on("disable",function(){e.$search.prop("disabled",!0)}),b.on("focus",function(a){e.$search.trigger("focus")}),b.on("results:focus",function(a){e.$search.attr("aria-activedescendant",a.id)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e._handleBlur(a)}),this.$selection.on("keydown",".select2-search--inline",function(a){a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented();var b=a.which;if(b===c.BACKSPACE&&""===e.$search.val()){var d=e.$searchContainer.prev(".select2-selection__choice");if(d.length>0){var f=d.data("data");e.searchRemoveChoice(f),a.preventDefault()}}});var f=document.documentMode,g=f&&11>=f;this.$selection.on("input.searchcheck",".select2-search--inline",function(a){return g?void e.$selection.off("input.search input.searchcheck"):void e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(a){if(g&&"input"===a.type)return void e.$selection.off("input.search input.searchcheck");var b=a.which;b!=c.SHIFT&&b!=c.CTRL&&b!=c.ALT&&b!=c.TAB&&e.handleSearch(a)})},d.prototype._transferTabIndex=function(a){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){var c=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch(),c&&this.$search.focus()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.$search.val(b.text),this.handleSearch()},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{var b=this.$search.val().length+1;a=.75*b+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){var a={"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"};return a}),b.define("select2/data/base",["../utils"],function(a){function b(a,c){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(a){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(a,b){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(a,b){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),d+=null!=c.id?"-"+c.id.toString():"-"+a.generateChars(4)},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change");
+if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f=0){var k=f.filter(d(j)),l=this.item(k),m=c.extend(!0,{},j,l),n=this.option(m);k.replaceWith(n)}else{var o=this.option(j);if(j.children){var p=this.convertToOptions(j.children);b.appendMany(o,p)}h.push(o)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(a,b){this.ajaxOptions=this._applyDefaults(b.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),d.__super__.constructor.call(this,a,b)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return c.extend({},a,{q:a.term})},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){d.status&&"0"===d.status||e.trigger("results:message",{message:"errorLoading"})});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url.call(this.$element,a)),"function"==typeof f.data&&(f.data=f.data.call(this.$element,a)),this.ajaxOptions.delay&&null!=a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");void 0!==f&&(this.createTag=f);var g=d.get("insertTag");if(void 0!==g&&(this.insertTag=g),b.call(this,c,d),a.isArray(e))for(var h=0;h0&&b.term.length>this.maximumInputLength?void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;return d.maximumSelectionLength>0&&f>=d.maximumSelectionLength?void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}}):void a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.bind=function(){},c.prototype.position=function(a,b){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a,b){function c(){}return c.prototype.render=function(b){var c=b.call(this),d=a('');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},c.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(b){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("focus",function(){c.isOpen()&&e.$search.focus()}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){var b=e.showSearch(a);b?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},c.prototype.handleSearch=function(a){if(!this._keyUpPrevented){var b=this.$search.val();this.trigger("query",{term:b})}this._keyUpPrevented=!1},c.prototype.showSearch=function(a,b){return!0},c}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){var c=e.$results.offset().top+e.$results.outerHeight(!1),d=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1);c+50>=d&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a(''),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(b,c,d){this.$dropdownParent=d.get("dropdownParent")||a(document.body),b.call(this,c,d)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.destroy=function(a){a.call(this),this.$dropdownContainer.remove()},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a(""),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(a){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c,d){var e=this,f="scroll.select2."+d.id,g="resize.select2."+d.id,h="orientationchange.select2."+d.id,i=this.$container.parents().filter(b.hasScroll);i.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),i.on(f,function(b){var c=a(this).data("select2-scroll-position");a(this).scrollTop(c.y)}),a(window).on(f+" "+g+" "+h,function(a){e._positionDropdown(),e._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c,d){var e="scroll.select2."+d.id,f="resize.select2."+d.id,g="orientationchange.select2."+d.id,h=this.$container.parents().filter(b.hasScroll);h.off(e),a(window).off(e+" "+f+" "+g)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=this.$container.offset();f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.topf.bottom+h.height,l={left:f.left,top:g.bottom},m=this.$dropdownParent;"static"===m.css("position")&&(m=m.offsetParent());var n=m.offset();l.top-=n.top,l.left-=n.left,c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-n.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.position="relative",a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(a){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),(null!=l.tokenSeparators||null!=l.tokenizer)&&(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.multiple?l.selectionAdapter=e:l.selectionAdapter=d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){var h=e.children[g],i=c(d,h);null==i&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var j=b(e.text).toUpperCase(),k=b(d.term).toUpperCase();return j.indexOf(k)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)};var E=new D;return E}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(a.prop("dir")?this.options.dir=a.prop("dir"):a.closest("[dir]").prop("dir")?this.options.dir=a.closest("[dir]").prop("dir"):this.options.dir="ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b=b.replace(/(:|\.|\[|\]|,)/g,""),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return 0>=e?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;i>h;h+=1){var j=g[h].replace(/\s/g,""),k=j.match(c);if(null!==k&&k.length>=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this.$element.on("focus.select2",function(a){b.trigger("focus",a)}),this._syncA=c.bind(this._syncAttributes,this),this._syncS=c.bind(this._syncSubtree,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._syncA);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._syncA),a.each(c,b._syncS)}),this._observer.observe(this.$element[0],{attributes:!0,childList:!0,subtree:!1})):this.$element[0].addEventListener&&(this.$element[0].addEventListener("DOMAttrModified",b._syncA,!1),this.$element[0].addEventListener("DOMNodeInserted",b._syncS,!1),this.$element[0].addEventListener("DOMNodeRemoved",b._syncS,!1))},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle","focus"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("focus",function(a){b.focus(a)}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open",{}),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ESC||c===d.TAB||c===d.UP&&b.altKey?(a.close(),b.preventDefault()):c===d.ENTER?(a.trigger("results:select",{}),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle",{}),b.preventDefault()):c===d.UP?(a.trigger("results:previous",{}),b.preventDefault()):c===d.DOWN&&(a.trigger("results:next",{}),b.preventDefault()):(c===d.ENTER||c===d.SPACE||c===d.DOWN&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable",{})):this.trigger("enable",{})},e.prototype._syncSubtree=function(a,b){var c=!1,d=this;if(!a||!a.target||"OPTION"===a.target.nodeName||"OPTGROUP"===a.target.nodeName){if(b)if(b.addedNodes&&b.addedNodes.length>0)for(var e=0;e0&&(c=!0);else c=!0;c&&this.dataAdapter.current(function(a){d.trigger("selection:update",{data:a})})}},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(void 0===b&&(b={}),a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||this.trigger("query",{})},e.prototype.close=function(){this.isOpen()&&this.trigger("close",{})},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.hasFocus=function(){return this.$container.hasClass("select2-container--focus")},e.prototype.focus=function(a){this.hasFocus()||(this.$container.addClass("select2-container--focus"),this.trigger("focus",{}))},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),(null==a||0===a.length)&&(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._syncA),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&(this.$element[0].removeEventListener("DOMAttrModified",this._syncA,!1),this.$element[0].removeEventListener("DOMNodeInserted",this._syncS,!1),this.$element[0].removeEventListener("DOMNodeRemoved",this._syncS,!1)),this._syncA=null,this._syncS=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null;
+},e.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("jquery-mousewheel",["jquery"],function(a){return a}),b.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults"],function(a,b,c,d){if(null==a.fn.select2){var e=["open","close","destroy"];a.fn.select2=function(b){if(b=b||{},"object"==typeof b)return this.each(function(){var d=a.extend(!0,{},b);new c(a(this),d)}),this;if("string"==typeof b){var d,f=Array.prototype.slice.call(arguments,1);return this.each(function(){var c=a(this).data("select2");null==c&&window.console&&console.error&&console.error("The select2('"+b+"') method was called on an element that is not using Select2."),d=c[b].apply(c,f)}),a.inArray(b,e)>-1?this:d}throw new Error("Invalid arguments for Select2: "+b)}}return null==a.fn.select2.defaults&&(a.fn.select2.defaults=d),c}),{define:b.define,require:b.require}}(),c=b.require("jquery.select2");return a.fn.select2.amd=b,c});
\ No newline at end of file
diff --git a/wp-content/plugins/wordpress-seo/js/dist/wp-seo-admin-400.min.js b/wp-content/plugins/wordpress-seo/js/dist/wp-seo-admin-400.min.js
new file mode 100644
index 0000000..7640c29
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/js/dist/wp-seo-admin-400.min.js
@@ -0,0 +1,27 @@
+!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g0){var d=this.state.results.map(function(a,c){return j.default.createElement(s,{key:a.objectID,post:a,showDetail:b.showDetail.bind(b,c)})});a=j.default.createElement("ul",{role:"list",className:"wpseo-kb-search-results"},d),(0,p.default)(this.props.foundResultsText.replace("%d",c))}else""!==this.state.searchString&&(a=j.default.createElement("p",null,this.props.noResultsText),(0,p.default)(this.props.noResultsText));return a}},{key:"renderDetail",value:function(){var a=this.state.showDetail,b=this.state.results[a];return j.default.createElement("div",{className:"wpseo-kb-search-detail"},j.default.createElement("div",{className:"wpseo-kb-search-navigation"},j.default.createElement("button",{className:"button dashicon-button wpseo-kb-search-back-button","aria-label":this.props.backLabel,onClick:this.hideDetail},this.props.back),j.default.createElement("a",{href:b.permalink,className:"button dashicon-button wpseo-kb-search-ext-link ","aria-label":this.props.openLabel,target:"_blank"},this.props.open)),j.default.createElement(t,{post:b,iframeTitle:this.props.iframeTitle}))}},{key:"renderError",value:function(a){return console.error(a),(0,p.default)(this.props.errorMessage),j.default.createElement("p",null,this.props.errorMessage)}},{key:"render",value:function(){var a="",b=j.default.createElement(r,{headingText:this.props.headingText,submitAction:this.searchButtonClicked,searchString:this.state.searchString,searchButtonText:this.props.searchButtonText});return a=this.state.errorMessage?j.default.createElement("div",null,b,this.renderError(this.state.errorMessage)):this.state.searching?j.default.createElement("div",null,b,j.default.createElement(u,{loadingPlaceholder:this.props.loadingPlaceholder})):this.state.showDetail===!1?j.default.createElement("div",null,b,this.state.results.length>0?j.default.createElement("h2",{className:"screen-reader-text"},this.props.searchResultsHeading):"",this.renderSearchResults()):this.renderDetail(),j.default.createElement("div",{className:"wpseo-kb-search-container"},a)}}]),b}(j.default.Component);q.propTypes={foundResultsText:j.default.PropTypes.string,noResultsText:j.default.PropTypes.string,headingText:j.default.PropTypes.string,searchButtonText:j.default.PropTypes.string,searchResultsHeading:j.default.PropTypes.string,iframeTitle:j.default.PropTypes.string,algoliaApplicationId:j.default.PropTypes.string.isRequired,algoliaApiKey:j.default.PropTypes.string.isRequired,algoliaIndexName:j.default.PropTypes.string.isRequired,errorMessage:j.default.PropTypes.string.isRequired,loadingPlaceholder:j.default.PropTypes.string.isRequired,open:j.default.PropTypes.string.isRequired,openLabel:j.default.PropTypes.string.isRequired,back:j.default.PropTypes.string.isRequired,backLabel:j.default.PropTypes.string.isRequired},q.defaultProps={foundResultsText:"Number of search results: %d",noResultsText:"No results found.",headingText:"Search the Yoast knowledge base",searchButtonText:"Search",searchResultsHeading:"Search results",iframeTitle:"Knowledge base article",algoliaApplicationId:"RC8G2UCWJK",algoliaApiKey:"459903434a7963f83e7d4cd9bfe89c0d",algoliaIndexName:"knowledge_base_all",errorMessage:"Something went wrong. Please try again later.",loadingPlaceholder:"Loading...",back:"Back",backLabel:"Back to search results",open:"Open",openLabel:"Open the knowledge base article in a new window or read it in the iframe below"};var r=function(a){return j.default.createElement("div",{className:"wpseo-kb-search-search-bar"},j.default.createElement("h2",{id:"wpseo-kb-search-heading"},a.headingText),j.default.createElement("form",{onSubmit:function(b){b.preventDefault(),a.submitAction(b)}},j.default.createElement("input",{type:"text","aria-labelledby":"wpseo-kb-search-heading",defaultValue:a.searchString}),j.default.createElement("button",{type:"submit",className:"button wpseo-kb-search-search-button"},a.searchButtonText)))},s=function(a){var b=a.post,c=b.excerpt||b.metadesc;return j.default.createElement("li",null,j.default.createElement("a",{href:b.permalink,onClick:function(b){b.preventDefault(),a.showDetail()},className:"wpseo-kb-search-result-link"},j.default.createElement("div",{className:"wpseo-kb-search-result"},j.default.createElement("h3",{className:"wpseo-kb-search-result-title"},b.post_title),c&&j.default.createElement("p",null,c))))},t=function(a){var b=a.post.permalink+"amp?source=wpseo-kb-search";return j.default.createElement("iframe",{src:b,className:"kb-search-content-frame",title:a.iframeTitle})},u=function(a){return j.default.createElement("div",{className:"wpseo-kb-loader"},a.loadingPlaceholder)};c.default=q},{"a11y-speak":4,algoliasearch:13,"lodash/isUndefined":58,react:215}],3:[function(a,b,c){"use strict";function d(a){return a&&a.__esModule?a:{default:a}}var e=a("./kb-search/wp-seo-kb-search-init"),f=d(e),g=a("a11y-speak"),h=d(g);!function(){function a(a){var b=!1,c="",d=[],e=["userid","name","user_description"],f=["date"],g=["title","parent_title","excerpt","excerpt_only","caption","focuskw","pt_single","pt_plural","modified","id"],i=["term404","searchphrase"],j=["term_title","term_description"],k=["category","category_description","tag","tag_description"];a.hasClass("posttype-template")?d=d.concat(i,j):a.hasClass("homepage-template")?d=d.concat(e,f,g,i,j,k):a.hasClass("taxonomy-template")?d=d.concat(e,f,g,i):a.hasClass("author-template")?d=d.concat(g,f,i,j,k):a.hasClass("date-template")?d=d.concat(e,g,i,j,k):a.hasClass("search-template")?d=d.concat(e,f,g,j,k,["term404"]):a.hasClass("error404-template")&&(d=d.concat(e,f,g,j,k,["searchphrase"])),jQuery.each(d,function(d,e){if(c=a.attr("id")+"-"+e+"-warning",a.val().search("%%"+e+"%%")!==-1){a.addClass("wpseo-variable-warning-element");var f=wpseoAdminL10n.variable_warning.replace("%s","%%"+e+"%%");jQuery("#"+c).length?jQuery("#"+c).html(f):a.after('
'+f+"
"),(0,h.default)(wpseoAdminL10n.variable_warning.replace("%s",e),"assertive"),b=!0}else jQuery("#"+c).length&&jQuery("#"+c).remove()}),b===!1&&a.removeClass("wpseo-variable-warning-element")}function b(a,b,c,d){jQuery.post(ajaxurl,{action:"wpseo_set_option",option:a,newval:b,_wpnonce:d},function(a){a&&jQuery("#"+c).hide()})}function c(a){jQuery.post(ajaxurl,{action:"wpseo_kill_blocking_files",_ajax_nonce:a}).done(function(a){var b=jQuery(".yoast-notice-blocking-files"),c=jQuery("#blocking_files");c.html(a.data.message),b.attr("tabindex","-1").focus(),a.success?b.removeClass("notice-error").addClass("notice-success"):b.addClass("yoast-blocking-files-error")})}function d(){jQuery("#og_frontpage_desc").val(jQuery("#meta_description").val())}function e(){var a=jQuery("#wpseo-conf");if(a.length){var b=a.attr("action").split("#")[0];a.attr("action",b+window.location.hash)}}function g(){var a=jQuery("#TB_ajaxContent");jQuery.post(ajaxurl,{_wpnonce:a.find("input[name=fb_admin_nonce]").val(),admin_name:a.find("input[name=fb_admin_name]").val(),admin_id:a.find("input[name=fb_admin_id]").val(),action:"wpseo_add_fb_admin"},function(b){var c=jQuery.parseJSON(b);switch(a.find("p.notice").remove(),c.success){case 1:a.find("input[type=text]").val(""),jQuery("#user_admin").append(c.html),jQuery("#connected_fb_admins").show(),tb_remove();break;case 0:a.find(".form-wrap").prepend(c.html)}})}function i(){var a="400px";jQuery("#company_or_person").select2({width:a,language:wpseoSelect2Locale}),jQuery("#twitter_card_type").select2({width:a,language:wpseoSelect2Locale}),jQuery("#post_types-post-maintax").select2({width:a,language:wpseoSelect2Locale}),jQuery("#profile").select2({width:a,language:wpseoSelect2Locale})}function j(){var a=window.location.hash.replace("#top#","");""!==a&&"#"!==a.charAt(0)||(a=jQuery(".wpseotab").attr("id")),jQuery("#"+a).addClass("active"),jQuery("#"+a+"-tab").addClass("nav-tab-active").click()}jQuery(window).on("hashchange",e),jQuery(document).on("ready",e),window.wpseoDetectWrongVariables=a,window.setWPOption=b,window.wpseoKillBlockingFiles=c,window.wpseoCopyHomeMeta=d,window.wpseo_add_fb_admin=g,window.wpseoSetTabHash=e,jQuery(document).ready(function(){(0,f.default)(),jQuery("#enablexmlsitemap").change(function(){jQuery("#sitemapinfo").toggle(jQuery(this).is(":checked"))}).change(),jQuery("#disable-author input[type='radio']").change(function(){jQuery(this).is(":checked")&&jQuery("#author-archives-titles-metas-content").toggle("off"===jQuery(this).val())}).change(),jQuery("#disable-date input[type='radio']").change(function(){jQuery(this).is(":checked")&&jQuery("#date-archives-titles-metas-content").toggle("off"===jQuery(this).val())}).change(),jQuery("#disable-post_format").change(function(){jQuery("#post_format-titles-metas").toggle(jQuery(this).is(":not(:checked)"))}).change(),jQuery("#breadcrumbs-enable").change(function(){jQuery("#breadcrumbsinfo").toggle(jQuery(this).is(":checked"))}).change(),jQuery("#disable_author_sitemap").find("input:radio").change(function(){jQuery(this).is(":checked")&&jQuery("#xml_user_block").toggle("off"===jQuery(this).val())}).change(),jQuery("#cleanpermalinks").change(function(){jQuery("#cleanpermalinksdiv").toggle(jQuery(this).is(":checked"))}).change(),jQuery("#wpseo-tabs").find("a").click(function(){jQuery("#wpseo-tabs").find("a").removeClass("nav-tab-active"),jQuery(".wpseotab").removeClass("active");var a=jQuery(this).attr("id").replace("-tab","");jQuery("#"+a).addClass("active"),jQuery(this).addClass("nav-tab-active")}),jQuery("#company_or_person").change(function(){var a=jQuery(this).val();"company"===a?(jQuery("#knowledge-graph-company").show(),jQuery("#knowledge-graph-person").hide()):"person"===a?(jQuery("#knowledge-graph-company").hide(),jQuery("#knowledge-graph-person").show()):(jQuery("#knowledge-graph-company").hide(),jQuery("#knowledge-graph-person").hide())}).change(),jQuery(".template").change(function(){a(jQuery(this))}).change(),jQuery("#blocking_files .button").on("click",function(){c(jQuery(this).data("nonce"))}),jQuery(".switch-yoast-seo input").on("keydown",function(a){"keydown"===a.type&&13===a.which&&a.preventDefault()}),j(),i()})}()},{"./kb-search/wp-seo-kb-search-init":1,"a11y-speak":4}],4:[function(a,b,c){var d,e,f=function(a){a=a||"polite";var b=document.createElement("div");b.id="a11y-speak-"+a,b.className="a11y-speak-region";var c="clip: rect(1px, 1px, 1px, 1px); position: absolute; height: 1px; width: 1px; overflow: hidden;";return b.setAttribute("style",c),b.setAttribute("aria-live",a),b.setAttribute("aria-relevant","additions text"),b.setAttribute("aria-atomic","true"),document.querySelector("body").appendChild(b),b},g=function(a){return"complete"===document.readyState||"loading"!==document.readyState&&!document.documentElement.doScroll?a():void document.addEventListener("DOMContentLoaded",a)};g(function(){d=document.getElementById("a11y-speak-polite"),e=document.getElementById("a11y-speak-assertive"),null===d&&(d=f("polite")),null===e&&(e=f("assertive"))});var h=function(){for(var a=document.querySelectorAll(".a11y-speak-region"),b=0;b]+>/g," "),e&&"assertive"===b?e.textContent=a:d&&(d.textContent=a)};b.exports=i},{}],5:[function(a,b,c){(function(d){function e(){return"undefined"!=typeof document&&"WebkitAppearance"in document.documentElement.style||window.console&&(console.firebug||console.exception&&console.table)||navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31}function f(){var a=arguments,b=this.useColors;if(a[0]=(b?"%c":"")+this.namespace+(b?" %c":" ")+a[0]+(b?"%c ":" ")+"+"+c.humanize(this.diff),!b)return a;var d="color: "+this.color;a=[a[0],d,"color: inherit"].concat(Array.prototype.slice.call(a,1));var e=0,f=0;return a[0].replace(/%[a-z%]/g,function(a){"%%"!==a&&(e++,"%c"===a&&(f=e))}),a.splice(f,0,d),a}function g(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function h(a){try{null==a?c.storage.removeItem("debug"):c.storage.debug=a}catch(a){}}function i(){try{return c.storage.debug}catch(a){}if("undefined"!=typeof d&&"env"in d)return d.env.DEBUG}function j(){try{return window.localStorage}catch(a){}}c=b.exports=a("./debug"),c.log=g,c.formatArgs=f,c.save=h,c.load=i,c.useColors=e,c.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:j(),c.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],c.formatters.j=function(a){try{return JSON.stringify(a)}catch(a){return"[UnexpectedJSONParseError]: "+a.message}},c.enable(i())}).call(this,a("_process"))},{"./debug":6,_process:62}],6:[function(a,b,c){function d(){return c.colors[k++%c.colors.length]}function e(a){function b(){}function e(){var a=e,b=+new Date,f=b-(j||b);a.diff=f,a.prev=j,a.curr=b,j=b,null==a.useColors&&(a.useColors=c.useColors()),null==a.color&&a.useColors&&(a.color=d());for(var g=new Array(arguments.length),h=0;h1e4)){var b=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(a);if(b){var c=parseFloat(b[1]),d=(b[2]||"ms").toLowerCase();switch(d){case"years":case"year":case"yrs":case"yr":case"y":return c*l;case"days":case"day":case"d":return c*k;case"hours":case"hour":case"hrs":case"hr":case"h":return c*j;case"minutes":case"minute":case"mins":case"min":case"m":return c*i;case"seconds":case"second":case"secs":case"sec":case"s":return c*h;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return c;default:return}}}}function e(a){return a>=k?Math.round(a/k)+"d":a>=j?Math.round(a/j)+"h":a>=i?Math.round(a/i)+"m":a>=h?Math.round(a/h)+"s":a+"ms"}function f(a){return g(a,k,"day")||g(a,j,"hour")||g(a,i,"minute")||g(a,h,"second")||a+" ms"}function g(a,b,c){if(!(a0)return d(a);if("number"===c&&isNaN(a)===!1)return b.long?f(a):e(a);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(a))}},{}],8:[function(a,b,c){function d(){i.apply(this,arguments)}function e(){var a="Not implemented in this environment.\nIf you feel this is a mistake, write to support@algolia.com";throw new k.AlgoliaSearchError(a)}b.exports=d;var f=a("./Index.js"),g=a("./deprecate.js"),h=a("./deprecatedMessage.js"),i=a("./AlgoliaSearchCore.js"),j=a("inherits"),k=a("./errors");j(d,i),d.prototype.deleteIndex=function(a,b){return this._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(a),hostType:"write",callback:b})},d.prototype.moveIndex=function(a,b,c){var d={operation:"move",destination:b};return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:d,hostType:"write",callback:c})},d.prototype.copyIndex=function(a,b,c){var d={operation:"copy",destination:b};return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(a)+"/operation",body:d,hostType:"write",callback:c})},d.prototype.getLogs=function(b,c,d){var e=a("./clone.js"),f={};return"object"==typeof b?(f=e(b),d=c):0===arguments.length||"function"==typeof b?d=b:1===arguments.length||"function"==typeof c?(d=c,f.offset=b):(f.offset=b,f.length=c),void 0===f.offset&&(f.offset=0),void 0===f.length&&(f.length=10),this._jsonRequest({method:"GET",url:"/1/logs?"+this._getSearchParams(f,""),hostType:"read",callback:d})},d.prototype.listIndexes=function(a,b){var c="";return void 0===a||"function"==typeof a?b=a:c="?page="+a,this._jsonRequest({method:"GET",url:"/1/indexes"+c,hostType:"read",callback:b})},d.prototype.initIndex=function(a){return new f(this,a)},d.prototype.listUserKeys=function(a){return this._jsonRequest({method:"GET",url:"/1/keys",hostType:"read",callback:a})},d.prototype.getUserKeyACL=function(a,b){return this._jsonRequest({method:"GET",url:"/1/keys/"+a,hostType:"read",callback:b})},d.prototype.deleteUserKey=function(a,b){return this._jsonRequest({method:"DELETE",url:"/1/keys/"+a,hostType:"write",callback:b})},d.prototype.addUserKey=function(b,c,d){var e=a("isarray"),f="Usage: client.addUserKey(arrayOfAcls[, params, callback])";if(!e(b))throw new Error(f);1!==arguments.length&&"function"!=typeof c||(d=c,c=null);var g={acl:b};return c&&(g.validity=c.validity,g.maxQueriesPerIPPerHour=c.maxQueriesPerIPPerHour,g.maxHitsPerQuery=c.maxHitsPerQuery,g.indexes=c.indexes,g.description=c.description,c.queryParameters&&(g.queryParameters=this._getSearchParams(c.queryParameters,"")),g.referers=c.referers),this._jsonRequest({method:"POST",url:"/1/keys",body:g,hostType:"write",callback:d})},d.prototype.addUserKeyWithValidity=g(function(a,b,c){return this.addUserKey(a,b,c)},h("client.addUserKeyWithValidity()","client.addUserKey()")),d.prototype.updateUserKey=function(b,c,d,e){var f=a("isarray"),g="Usage: client.updateUserKey(key, arrayOfAcls[, params, callback])";if(!f(c))throw new Error(g);2!==arguments.length&&"function"!=typeof d||(e=d,d=null);var h={acl:c};return d&&(h.validity=d.validity,h.maxQueriesPerIPPerHour=d.maxQueriesPerIPPerHour,h.maxHitsPerQuery=d.maxHitsPerQuery,h.indexes=d.indexes,h.description=d.description,d.queryParameters&&(h.queryParameters=this._getSearchParams(d.queryParameters,"")),h.referers=d.referers),this._jsonRequest({method:"PUT",url:"/1/keys/"+b,body:h,hostType:"write",callback:e})},d.prototype.startQueriesBatch=g(function(){this._batch=[]},h("client.startQueriesBatch()","client.search()")),d.prototype.addQueryInBatch=g(function(a,b,c){this._batch.push({indexName:a,query:b,params:c})},h("client.addQueryInBatch()","client.search()")),d.prototype.sendQueriesBatch=g(function(a){return this.search(this._batch,a)},h("client.sendQueriesBatch()","client.search()")),d.prototype.batch=function(b,c){var d=a("isarray"),e="Usage: client.batch(operations[, callback])";if(!d(b))throw new Error(e);return this._jsonRequest({method:"POST",url:"/1/indexes/*/batch",body:{requests:b},hostType:"write",callback:c})},d.prototype.destroy=e,d.prototype.enableRateLimitForward=e,d.prototype.disableRateLimitForward=e,d.prototype.useSecuredAPIKey=e,d.prototype.disableSecuredAPIKey=e,d.prototype.generateSecuredApiKey=e},{"./AlgoliaSearchCore.js":9,"./Index.js":10,"./clone.js":19,"./deprecate.js":20,"./deprecatedMessage.js":21,"./errors":22,inherits:56,isarray:57}],9:[function(a,b,c){function d(b,c,d){var f=a("debug")("algoliasearch"),h=a("./clone.js"),j=a("isarray"),k=a("./map.js"),l="Usage: algoliasearch(applicationID, apiKey, opts)";if(d._allowEmptyCredentials!==!0&&!b)throw new i.AlgoliaSearchError("Please provide an application ID. "+l);if(d._allowEmptyCredentials!==!0&&!c)throw new i.AlgoliaSearchError("Please provide an API key. "+l);this.applicationID=b,this.apiKey=c;var m=g([this.applicationID+"-1.algolianet.com",this.applicationID+"-2.algolianet.com",this.applicationID+"-3.algolianet.com"]);this.hosts={read:[],write:[]},this.hostIndex={read:0,write:0},d=d||{};var n=d.protocol||"https:",o=void 0===d.timeout?2e3:d.timeout;if(/:$/.test(n)||(n+=":"),"http:"!==d.protocol&&"https:"!==d.protocol)throw new i.AlgoliaSearchError("protocol must be `http:` or `https:` (was `"+d.protocol+"`)");d.hosts?j(d.hosts)?(this.hosts.read=h(d.hosts),this.hosts.write=h(d.hosts)):(this.hosts.read=h(d.hosts.read),this.hosts.write=h(d.hosts.write)):(this.hosts.read=[this.applicationID+"-dsn.algolia.net"].concat(m),this.hosts.write=[this.applicationID+".algolia.net"].concat(m)),this.hosts.read=k(this.hosts.read,e(n)),this.hosts.write=k(this.hosts.write,e(n)),this.requestTimeout=o,this.extraHeaders=[],this.cache=d._cache||{},this._ua=d._ua,this._useCache=!(void 0!==d._useCache&&!d._cache)||d._useCache,this._useFallback=void 0===d.useFallback||d.useFallback,this._setTimeout=d._setTimeout,f("init done, %j",this)}function e(a){return function(b){return a+"//"+b.toLowerCase()}}function f(a){if(void 0===Array.prototype.toJSON)return JSON.stringify(a);var b=Array.prototype.toJSON;delete Array.prototype.toJSON;var c=JSON.stringify(a);return Array.prototype.toJSON=b,c}function g(a){for(var b,c,d=a.length;0!==d;)c=Math.floor(Math.random()*d),d-=1,b=a[d],a[d]=a[c],a[c]=b;return a}function h(a){var b={};for(var c in a)if(Object.prototype.hasOwnProperty.call(a,c)){var d;d="x-algolia-api-key"===c||"x-algolia-application-id"===c?"**hidden for security purposes**":a[c],b[c]=d}return b}b.exports=d;var i=a("./errors"),j=a("./exitPromise.js"),k=a("./IndexCore.js"),l=500;d.prototype.initIndex=function(a){return new k(this,a)},d.prototype.setExtraHeader=function(a,b){this.extraHeaders.push({name:a.toLowerCase(),value:b})},d.prototype.addAlgoliaAgent=function(a){this._ua+=";"+a},d.prototype._jsonRequest=function(b){function c(a,j){function l(a){var b=a&&a.body&&a.body.message&&a.body.status||a.statusCode||a&&a.body&&200;g("received response: statusCode: %s, computed statusCode: %d, headers: %j",a.statusCode,b,a.headers);var c=2===Math.floor(b/100),f=new Date;if(q.push({currentHost:w,headers:h(e),content:d||null,contentLength:void 0!==d?d.length:null,method:j.method,timeout:j.timeout,url:j.url,startTime:v,endTime:f,duration:f-v,statusCode:b}),c)return m._useCache&&k&&(k[u]=a.responseText),a.body;var l=4!==Math.floor(b/100);if(l)return n+=1,s();g("unrecoverable error");var o=new i.AlgoliaSearchError(a.body&&a.body.message,{debugData:q,statusCode:b});return m._promise.reject(o)}function r(a){g("error: %s, stack: %s",a.message,a.stack);var c=new Date;return q.push({currentHost:w,headers:h(e),content:d||null,contentLength:void 0!==d?d.length:null,method:j.method,timeout:j.timeout,url:j.url,startTime:v,endTime:c,duration:c-v}),a instanceof i.AlgoliaSearchError||(a=new i.Unknown(a&&a.message,a)),n+=1,a instanceof i.Unknown||a instanceof i.UnparsableJSON||n>=m.hosts[b.hostType].length&&(o||!p)?(a.debugData=q,m._promise.reject(a)):a instanceof i.RequestTimeout?t():s()}function s(){return g("retrying request"),m.hostIndex[b.hostType]=(m.hostIndex[b.hostType]+1)%m.hosts[b.hostType].length,c(a,j)}function t(){return g("retrying request with higher timeout"),m.hostIndex[b.hostType]=(m.hostIndex[b.hostType]+1)%m.hosts[b.hostType].length,j.timeout=m.requestTimeout*(n+1),c(a,j)}var u,v=new Date;if(m._useCache&&(u=b.url),m._useCache&&d&&(u+="_body_"+j.body),m._useCache&&k&&void 0!==k[u])return g("serving response from cache"),m._promise.resolve(JSON.parse(k[u]));if(n>=m.hosts[b.hostType].length)return!p||o?(g("could not get any response"),m._promise.reject(new i.AlgoliaSearchError("Cannot connect to the AlgoliaSearch API. Send an email to support@algolia.com to report and resolve the issue. Application id was: "+m.applicationID,{debugData:q}))):(g("switching to fallback"),n=0,j.method=b.fallback.method,j.url=b.fallback.url,j.jsonBody=b.fallback.body,j.jsonBody&&(j.body=f(j.jsonBody)),e=m._computeRequestHeaders(),j.timeout=m.requestTimeout*(n+1),m.hostIndex[b.hostType]=0,o=!0,c(m._request.fallback,j));var w=m.hosts[b.hostType][m.hostIndex[b.hostType]],x=w+j.url,y={body:j.body,jsonBody:j.jsonBody,method:j.method,headers:e,timeout:j.timeout,debug:g};return g("method: %s, url: %s, headers: %j, timeout: %d",y.method,x,y.headers,y.timeout),a===m._request.fallback&&g("using fallback"),a.call(m,x,y).then(l,r)}var d,e,g=a("debug")("algoliasearch:"+b.url),k=b.cache,m=this,n=0,o=!1,p=m._useFallback&&m._request.fallback&&b.fallback;this.apiKey.length>l&&void 0!==b.body&&(void 0!==b.body.params||void 0!==b.body.requests)?(b.body.apiKey=this.apiKey,e=this._computeRequestHeaders(!1)):e=this._computeRequestHeaders(),void 0!==b.body&&(d=f(b.body)),g("request start");var q=[],r=c(m._request,{url:b.url,method:b.method,body:d,jsonBody:b.body,timeout:m.requestTimeout*(n+1)});return b.callback?void r.then(function(a){j(function(){b.callback(null,a)},m._setTimeout||setTimeout)},function(a){j(function(){b.callback(a)},m._setTimeout||setTimeout)}):r},d.prototype._getSearchParams=function(a,b){if(void 0===a||null===a)return b;for(var c in a)null!==c&&void 0!==a[c]&&a.hasOwnProperty(c)&&(b+=""===b?"":"&",b+=c+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(a[c])?f(a[c]):a[c]));return b},d.prototype._computeRequestHeaders=function(b){var c=a("foreach"),d={"x-algolia-agent":this._ua,"x-algolia-application-id":this.applicationID};return b!==!1&&(d["x-algolia-api-key"]=this.apiKey),this.userToken&&(d["x-algolia-usertoken"]=this.userToken),this.securityTags&&(d["x-algolia-tagfilters"]=this.securityTags),this.extraHeaders&&c(this.extraHeaders,function(a){d[a.name]=a.value}),d},d.prototype.search=function(b,c,d){var e=a("isarray"),f=a("./map.js"),g="Usage: client.search(arrayOfQueries[, callback])";if(!e(b))throw new Error(g);"function"==typeof c?(d=c,c={}):void 0===c&&(c={});var h=this,i={requests:f(b,function(a){var b="";return void 0!==a.query&&(b+="query="+encodeURIComponent(a.query)),{indexName:a.indexName,params:h._getSearchParams(a.params,b)}})},j=f(i.requests,function(a,b){return b+"="+encodeURIComponent("/1/indexes/"+encodeURIComponent(a.indexName)+"?"+a.params)}).join("&"),k="/1/indexes/*/queries";return void 0!==c.strategy&&(k+="?strategy="+c.strategy),this._jsonRequest({cache:this.cache,method:"POST",url:k,body:i,hostType:"read",fallback:{method:"GET",url:"/1/indexes/*",body:{params:j}},callback:d})},d.prototype.setSecurityTags=function(a){if("[object Array]"===Object.prototype.toString.call(a)){for(var b=[],c=0;cg&&(b=g),"published"!==a.status?k._promise.delay(b).then(c):a})}function d(a){i(function(){b(null,a)},k._setTimeout||setTimeout)}function e(a){i(function(){b(a)},k._setTimeout||setTimeout)}var f=100,g=5e3,h=0,j=this,k=j.as,l=c();return b?void l.then(d,e):l},d.prototype.clearIndex=function(a){var b=this;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/clear",hostType:"write",callback:a})},d.prototype.getSettings=function(a){var b=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/settings?getVersion=2",hostType:"read",callback:a})},d.prototype.searchSynonyms=function(a,b){return"function"==typeof a?(b=a,a={}):void 0===a&&(a={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/search",body:a,hostType:"read",callback:b})},d.prototype.saveSynonym=function(a,b,c){return"function"==typeof b?(c=b,b={}):void 0===b&&(b={}),this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(a.objectID)+"?forwardToSlaves="+(b.forwardToSlaves?"true":"false"),body:a,hostType:"write",callback:c})},d.prototype.getSynonym=function(a,b){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(a),hostType:"read",callback:b})},d.prototype.deleteSynonym=function(a,b,c){return"function"==typeof b?(c=b,b={}):void 0===b&&(b={}),this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(a)+"?forwardToSlaves="+(b.forwardToSlaves?"true":"false"),hostType:"write",callback:c})},d.prototype.clearSynonyms=function(a,b){return"function"==typeof a?(b=a,a={}):void 0===a&&(a={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/clear?forwardToSlaves="+(a.forwardToSlaves?"true":"false"),hostType:"write",callback:b})},d.prototype.batchSynonyms=function(a,b,c){return"function"==typeof b?(c=b,b={}):void 0===b&&(b={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/batch?forwardToSlaves="+(b.forwardToSlaves?"true":"false")+"&replaceExistingSynonyms="+(b.replaceExistingSynonyms?"true":"false"),hostType:"write",body:a,callback:c})},d.prototype.setSettings=function(a,b,c){1!==arguments.length&&"function"!=typeof b||(c=b,b={});var d=b.forwardToSlaves||!1,e=this;return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(e.indexName)+"/settings?forwardToSlaves="+(d?"true":"false"),hostType:"write",body:a,callback:c})},d.prototype.listUserKeys=function(a){var b=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(b.indexName)+"/keys",hostType:"read",callback:a})},d.prototype.getUserKeyACL=function(a,b){var c=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys/"+a,hostType:"read",callback:b})},d.prototype.deleteUserKey=function(a,b){var c=this;return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(c.indexName)+"/keys/"+a,hostType:"write",callback:b})},d.prototype.addUserKey=function(b,c,d){var e=a("isarray"),f="Usage: index.addUserKey(arrayOfAcls[, params, callback])";if(!e(b))throw new Error(f);1!==arguments.length&&"function"!=typeof c||(d=c,c=null);var g={acl:b};return c&&(g.validity=c.validity,g.maxQueriesPerIPPerHour=c.maxQueriesPerIPPerHour,g.maxHitsPerQuery=c.maxHitsPerQuery,g.description=c.description,c.queryParameters&&(g.queryParameters=this.as._getSearchParams(c.queryParameters,"")),g.referers=c.referers),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys",body:g,hostType:"write",callback:d})},d.prototype.addUserKeyWithValidity=g(function(a,b,c){return this.addUserKey(a,b,c)},h("index.addUserKeyWithValidity()","index.addUserKey()")),d.prototype.updateUserKey=function(b,c,d,e){var f=a("isarray"),g="Usage: index.updateUserKey(key, arrayOfAcls[, params, callback])";if(!f(c))throw new Error(g);2!==arguments.length&&"function"!=typeof d||(e=d,d=null);var h={acl:c};return d&&(h.validity=d.validity,h.maxQueriesPerIPPerHour=d.maxQueriesPerIPPerHour,h.maxHitsPerQuery=d.maxHitsPerQuery,h.description=d.description,d.queryParameters&&(h.queryParameters=this.as._getSearchParams(d.queryParameters,"")),h.referers=d.referers),this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys/"+b,body:h,hostType:"write",callback:e})}},{"./IndexBrowser":11,"./IndexCore.js":12,"./clone.js":19,"./deprecate.js":20,"./deprecatedMessage.js":21,"./errors":22,"./exitPromise.js":23,"./map.js":24,"./merge.js":25,inherits:56,isarray:57}],11:[function(a,b,c){"use strict";function d(){}b.exports=d;var e=a("inherits"),f=a("events").EventEmitter;e(d,f),d.prototype.stop=function(){this._stopped=!0,this._clean()},d.prototype._end=function(){this.emit("end"),this._clean()},d.prototype._error=function(a){this.emit("error",a),this._clean()},d.prototype._result=function(a){this.emit("result",a)},d.prototype._clean=function(){this.removeAllListeners("stop"),this.removeAllListeners("end"),this.removeAllListeners("error"),this.removeAllListeners("result")}},{events:30,inherits:56}],12:[function(a,b,c){function d(a,b){this.indexName=b,this.as=a,this.typeAheadArgs=null,this.typeAheadValueOption=null,this.cache={}}var e=a("./buildSearchMethod.js"),f=a("./deprecate.js"),g=a("./deprecatedMessage.js");b.exports=d,d.prototype.clearCache=function(){this.cache={}},d.prototype.search=e("query"),d.prototype.similarSearch=e("similarQuery"),d.prototype.browse=function(b,c,d){var e,f,g=a("./merge.js"),h=this;0===arguments.length||1===arguments.length&&"function"==typeof arguments[0]?(e=0,d=arguments[0],b=void 0):"number"==typeof arguments[0]?(e=arguments[0],"number"==typeof arguments[1]?f=arguments[1]:"function"==typeof arguments[1]&&(d=arguments[1],f=void 0),b=void 0,c=void 0):"object"==typeof arguments[0]?("function"==typeof arguments[1]&&(d=arguments[1]),c=arguments[0],b=void 0):"string"==typeof arguments[0]&&"function"==typeof arguments[1]&&(d=arguments[1],c=void 0),c=g({},c||{},{page:e,hitsPerPage:f,query:b});var i=this.as._getSearchParams(c,"");return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(h.indexName)+"/browse?"+i,hostType:"read",callback:d})},d.prototype.browseFrom=function(a,b){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/browse?cursor="+encodeURIComponent(a),hostType:"read",callback:b})},d.prototype.searchForFacetValues=function(b,c){var d=a("./clone.js"),e=a("./omit.js"),f="Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])";if(void 0===b.facetName||void 0===b.facetQuery)throw new Error(f);var g=b.facetName,h=e(d(b),function(a){return"facetName"===a}),i=this.as._getSearchParams(h,"");return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/facets/"+encodeURIComponent(g)+"/query",hostType:"read",body:{params:i},callback:c})},d.prototype.searchFacet=f(function(a,b){return this.searchForFacetValues(a,b)},g("index.searchFacet(params[, callback])","index.searchForFacetValues(params[, callback])")),d.prototype._search=function(a,b,c){return this.as._jsonRequest({cache:this.cache,method:"POST",url:b||"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:a},hostType:"read",fallback:{method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName),body:{params:a}},callback:c})},d.prototype.getObject=function(a,b,c){var d=this;1!==arguments.length&&"function"!=typeof b||(c=b,b=void 0);var e="";if(void 0!==b){e="?attributes=";for(var f=0;f was loaded but did not call our provided callback"),JSONPScriptError:e("JSONPScriptError","
\ No newline at end of file
diff --git a/wp-content/plugins/wordpress-seo/wp-seo-main.php b/wp-content/plugins/wordpress-seo/wp-seo-main.php
new file mode 100644
index 0000000..01d45b0
--- /dev/null
+++ b/wp-content/plugins/wordpress-seo/wp-seo-main.php
@@ -0,0 +1,493 @@
+ ABSPATH . 'wp-admin/includes/class-wp-list-table.php',
+ 'walker_category' => ABSPATH . 'wp-includes/category-template.php',
+ 'pclzip' => ABSPATH . 'wp-admin/includes/class-pclzip.php',
+ );
+ }
+
+ $cn = strtolower( $class );
+
+ if ( ! class_exists( $class ) && isset( $classes[ $cn ] ) ) {
+ require_once( $classes[ $cn ] );
+ }
+}
+
+if ( file_exists( WPSEO_PATH . '/vendor/autoload_52.php' ) ) {
+ require WPSEO_PATH . '/vendor/autoload_52.php';
+}
+elseif ( ! class_exists( 'WPSEO_Options' ) ) { // Still checking since might be site-level autoload R.
+ add_action( 'admin_init', 'yoast_wpseo_missing_autoload', 1 );
+
+ return;
+}
+
+if ( function_exists( 'spl_autoload_register' ) ) {
+ spl_autoload_register( 'wpseo_auto_load' );
+}
+
+/* ********************* DEFINES DEPENDING ON AUTOLOADED CODE ********************* */
+
+/**
+ * Defaults to production, for safety
+ */
+if ( ! defined( 'YOAST_ENVIRONMENT' ) ) {
+ define( 'YOAST_ENVIRONMENT', 'production' );
+}
+
+/**
+ * Only use minified assets when we are in a production environment
+ */
+if ( ! defined( 'WPSEO_CSSJS_SUFFIX' ) ) {
+ define( 'WPSEO_CSSJS_SUFFIX', ( 'development' !== YOAST_ENVIRONMENT ) ? '.min' : '' );
+}
+
+/* ***************************** PLUGIN (DE-)ACTIVATION *************************** */
+
+/**
+ * Run single site / network-wide activation of the plugin.
+ *
+ * @param bool $networkwide Whether the plugin is being activated network-wide.
+ */
+function wpseo_activate( $networkwide = false ) {
+ if ( ! is_multisite() || ! $networkwide ) {
+ _wpseo_activate();
+ }
+ else {
+ /* Multi-site network activation - activate the plugin for all blogs */
+ wpseo_network_activate_deactivate( true );
+ }
+}
+
+/**
+ * Run single site / network-wide de-activation of the plugin.
+ *
+ * @param bool $networkwide Whether the plugin is being de-activated network-wide.
+ */
+function wpseo_deactivate( $networkwide = false ) {
+ if ( ! is_multisite() || ! $networkwide ) {
+ _wpseo_deactivate();
+ }
+ else {
+ /* Multi-site network activation - de-activate the plugin for all blogs */
+ wpseo_network_activate_deactivate( false );
+ }
+}
+
+/**
+ * Run network-wide (de-)activation of the plugin
+ *
+ * @param bool $activate True for plugin activation, false for de-activation.
+ */
+function wpseo_network_activate_deactivate( $activate = true ) {
+ global $wpdb;
+
+ $network_blogs = $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE site_id = %d", $wpdb->siteid ) );
+
+ if ( is_array( $network_blogs ) && $network_blogs !== array() ) {
+ foreach ( $network_blogs as $blog_id ) {
+ switch_to_blog( $blog_id );
+
+ if ( $activate === true ) {
+ _wpseo_activate();
+ }
+ else {
+ _wpseo_deactivate();
+ }
+
+ restore_current_blog();
+ }
+ }
+}
+
+/**
+ * Runs on activation of the plugin.
+ */
+function _wpseo_activate() {
+ require_once( WPSEO_PATH . 'inc/wpseo-functions.php' );
+ require_once( WPSEO_PATH . 'inc/class-wpseo-installation.php' );
+
+ wpseo_load_textdomain(); // Make sure we have our translations available for the defaults.
+
+ new WPSEO_Installation();
+
+ WPSEO_Options::get_instance();
+ if ( ! is_multisite() ) {
+ WPSEO_Options::initialize();
+ }
+ else {
+ WPSEO_Options::maybe_set_multisite_defaults( true );
+ }
+ WPSEO_Options::ensure_options_exist();
+
+ if ( is_multisite() && ms_is_switched() ) {
+ delete_option( 'rewrite_rules' );
+ }
+ else {
+ $wpseo_rewrite = new WPSEO_Rewrite();
+ $wpseo_rewrite->schedule_flush();
+ }
+
+ wpseo_add_capabilities();
+
+ // Clear cache so the changes are obvious.
+ WPSEO_Utils::clear_cache();
+
+ do_action( 'wpseo_activate' );
+}
+
+/**
+ * On deactivation, flush the rewrite rules so XML sitemaps stop working.
+ */
+function _wpseo_deactivate() {
+ require_once( WPSEO_PATH . 'inc/wpseo-functions.php' );
+
+ if ( is_multisite() && ms_is_switched() ) {
+ delete_option( 'rewrite_rules' );
+ }
+ else {
+ add_action( 'shutdown', 'flush_rewrite_rules' );
+ }
+
+ wpseo_remove_capabilities();
+
+ // Clear cache so the changes are obvious.
+ WPSEO_Utils::clear_cache();
+
+ do_action( 'wpseo_deactivate' );
+}
+
+/**
+ * Run wpseo activation routine on creation / activation of a multisite blog if WPSEO is activated
+ * network-wide.
+ *
+ * Will only be called by multisite actions.
+ *
+ * @internal Unfortunately will fail if the plugin is in the must-use directory
+ * @see https://core.trac.wordpress.org/ticket/24205
+ *
+ * @param int $blog_id Blog ID.
+ */
+function wpseo_on_activate_blog( $blog_id ) {
+ if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
+ require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
+ }
+
+ if ( is_plugin_active_for_network( plugin_basename( WPSEO_FILE ) ) ) {
+ switch_to_blog( $blog_id );
+ wpseo_activate( false );
+ restore_current_blog();
+ }
+}
+
+
+/* ***************************** PLUGIN LOADING *************************** */
+
+/**
+ * Load translations
+ */
+function wpseo_load_textdomain() {
+ $wpseo_path = str_replace( '\\', '/', WPSEO_PATH );
+ $mu_path = str_replace( '\\', '/', WPMU_PLUGIN_DIR );
+
+ if ( false !== stripos( $wpseo_path, $mu_path ) ) {
+ load_muplugin_textdomain( 'wordpress-seo', dirname( WPSEO_BASENAME ) . '/languages/' );
+ }
+ else {
+ load_plugin_textdomain( 'wordpress-seo', false, dirname( WPSEO_BASENAME ) . '/languages/' );
+ }
+}
+
+add_action( 'plugins_loaded', 'wpseo_load_textdomain' );
+
+
+/**
+ * On plugins_loaded: load the minimum amount of essential files for this plugin
+ */
+function wpseo_init() {
+ require_once( WPSEO_PATH . 'inc/wpseo-functions.php' );
+ require_once( WPSEO_PATH . 'inc/wpseo-functions-deprecated.php' );
+
+ // Make sure our option and meta value validation routines and default values are always registered and available.
+ WPSEO_Options::get_instance();
+ WPSEO_Meta::init();
+
+ $options = WPSEO_Options::get_options( array( 'wpseo', 'wpseo_permalinks', 'wpseo_xml' ) );
+ if ( version_compare( $options['version'], WPSEO_VERSION, '<' ) ) {
+ new WPSEO_Upgrade();
+ // Get a cleaned up version of the $options.
+ $options = WPSEO_Options::get_options( array( 'wpseo', 'wpseo_permalinks', 'wpseo_xml' ) );
+ }
+
+ if ( $options['stripcategorybase'] === true ) {
+ $GLOBALS['wpseo_rewrite'] = new WPSEO_Rewrite;
+ }
+
+ if ( $options['enablexmlsitemap'] === true ) {
+ $GLOBALS['wpseo_sitemaps'] = new WPSEO_Sitemaps;
+ }
+
+ if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
+ require_once( WPSEO_PATH . 'inc/wpseo-non-ajax-functions.php' );
+ }
+
+ // Init it here because the filter must be present on the frontend as well or it won't work in the customizer.
+ new WPSEO_Customizer();
+}
+
+/**
+ * Loads the rest api endpoints.
+ */
+function wpseo_init_rest_api() {
+ // We can't do anything when requirements are not met.
+ if ( WPSEO_Utils::is_api_available() ) {
+ // Boot up REST API.
+ $configuration_service = new WPSEO_Configuration_Service();
+ $configuration_service->initialize();
+ }
+}
+
+/**
+ * Used to load the required files on the plugins_loaded hook, instead of immediately.
+ */
+function wpseo_frontend_init() {
+ add_action( 'init', 'initialize_wpseo_front' );
+
+ $options = WPSEO_Options::get_option( 'wpseo_internallinks' );
+ if ( $options['breadcrumbs-enable'] === true ) {
+ /**
+ * If breadcrumbs are active (which they supposedly are if the users has enabled this settings,
+ * there's no reason to have bbPress breadcrumbs as well.
+ *
+ * @internal The class itself is only loaded when the template tag is encountered via
+ * the template tag function in the wpseo-functions.php file
+ */
+ add_filter( 'bbp_get_breadcrumb', '__return_false' );
+ }
+
+ add_action( 'template_redirect', 'wpseo_frontend_head_init', 999 );
+}
+
+/**
+ * Instantiate the different social classes on the frontend
+ */
+function wpseo_frontend_head_init() {
+ $options = WPSEO_Options::get_option( 'wpseo_social' );
+ if ( $options['twitter'] === true ) {
+ add_action( 'wpseo_head', array( 'WPSEO_Twitter', 'get_instance' ), 40 );
+ }
+
+ if ( $options['opengraph'] === true ) {
+ $GLOBALS['wpseo_og'] = new WPSEO_OpenGraph;
+ }
+
+}
+
+/**
+ * Used to load the required files on the plugins_loaded hook, instead of immediately.
+ */
+function wpseo_admin_init() {
+ new WPSEO_Admin_Init();
+}
+
+
+/* ***************************** BOOTSTRAP / HOOK INTO WP *************************** */
+$spl_autoload_exists = function_exists( 'spl_autoload_register' );
+$filter_exists = function_exists( 'filter_input' );
+
+if ( ! $spl_autoload_exists ) {
+ add_action( 'admin_init', 'yoast_wpseo_missing_spl', 1 );
+}
+
+if ( ! $filter_exists ) {
+ add_action( 'admin_init', 'yoast_wpseo_missing_filter', 1 );
+}
+
+if ( ! function_exists( 'wp_installing' ) ) {
+ /**
+ * We need to define wp_installing in WordPress versions older than 4.4
+ *
+ * @return bool
+ */
+ function wp_installing() {
+ return defined( 'WP_INSTALLING' );
+ }
+}
+
+if ( ! wp_installing() && ( $spl_autoload_exists && $filter_exists ) ) {
+ add_action( 'plugins_loaded', 'wpseo_init', 14 );
+ add_action( 'rest_api_init', 'wpseo_init_rest_api' );
+
+ if ( is_admin() ) {
+
+ new Yoast_Alerts();
+
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
+ require_once( WPSEO_PATH . 'admin/ajax.php' );
+
+ // Plugin conflict ajax hooks.
+ new Yoast_Plugin_Conflict_Ajax();
+
+ if ( filter_input( INPUT_POST, 'action' ) === 'inline-save' ) {
+ add_action( 'plugins_loaded', 'wpseo_admin_init', 15 );
+ }
+ }
+ else {
+ add_action( 'plugins_loaded', 'wpseo_admin_init', 15 );
+ }
+ }
+ else {
+ add_action( 'plugins_loaded', 'wpseo_frontend_init', 15 );
+ }
+
+ add_action( 'plugins_loaded', 'load_yoast_notifications' );
+}
+
+// Activation and deactivation hook.
+register_activation_hook( WPSEO_FILE, 'wpseo_activate' );
+register_deactivation_hook( WPSEO_FILE, 'wpseo_deactivate' );
+add_action( 'wpmu_new_blog', 'wpseo_on_activate_blog' );
+add_action( 'activate_blog', 'wpseo_on_activate_blog' );
+
+// Loading OnPage integration.
+new WPSEO_OnPage();
+
+
+/**
+ * Wraps for notifications center class.
+ */
+function load_yoast_notifications() {
+ // Init Yoast_Notification_Center class.
+ Yoast_Notification_Center::get();
+}
+
+
+/**
+ * Throw an error if the PHP SPL extension is disabled (prevent white screens) and self-deactivate plugin
+ *
+ * @since 1.5.4
+ *
+ * @return void
+ */
+function yoast_wpseo_missing_spl() {
+ if ( is_admin() ) {
+ add_action( 'admin_notices', 'yoast_wpseo_missing_spl_notice' );
+
+ yoast_wpseo_self_deactivate();
+ }
+}
+
+/**
+ * Returns the notice in case of missing spl extension
+ */
+function yoast_wpseo_missing_spl_notice() {
+ $message = esc_html__( 'The Standard PHP Library (SPL) extension seem to be unavailable. Please ask your web host to enable it.', 'wordpress-seo' );
+ yoast_wpseo_activation_failed_notice( $message );
+}
+
+/**
+ * Throw an error if the Composer autoload is missing and self-deactivate plugin
+ *
+ * @return void
+ */
+function yoast_wpseo_missing_autoload() {
+ if ( is_admin() ) {
+ add_action( 'admin_notices', 'yoast_wpseo_missing_autoload_notice' );
+
+ yoast_wpseo_self_deactivate();
+ }
+}
+
+/**
+ * Returns the notice in case of missing Composer autoload
+ */
+function yoast_wpseo_missing_autoload_notice() {
+ /* 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 */
+ $message = esc_html__( 'The %1$s plugin installation is incomplete. Please refer to %2$sinstallation instructions%3$s.', 'wordpress-seo' );
+ $message = sprintf( $message, 'Yoast SEO', '', '' );
+ yoast_wpseo_activation_failed_notice( $message );
+}
+
+/**
+ * Throw an error if the filter extension is disabled (prevent white screens) and self-deactivate plugin
+ *
+ * @since 2.0
+ *
+ * @return void
+ */
+function yoast_wpseo_missing_filter() {
+ if ( is_admin() ) {
+ add_action( 'admin_notices', 'yoast_wpseo_missing_filter_notice' );
+
+ yoast_wpseo_self_deactivate();
+ }
+}
+
+/**
+ * Returns the notice in case of missing filter extension
+ */
+function yoast_wpseo_missing_filter_notice() {
+ $message = esc_html__( 'The filter extension seem to be unavailable. Please ask your web host to enable it.', 'wordpress-seo' );
+ yoast_wpseo_activation_failed_notice( $message );
+}
+
+/**
+ * Echo's the Activation failed notice with any given message.
+ *
+ * @param string $message Message string.
+ */
+function yoast_wpseo_activation_failed_notice( $message ) {
+ echo '