| 1 |
<?php |
| 2 |
/** |
| 3 |
* WPSEO plugin file. |
| 4 |
* |
| 5 |
* @package WPSEO\Admin\Formatter |
| 6 |
*/ |
| 7 |
|
| 8 |
use Yoast\WP\SEO\Config\Schema_Types; |
| 9 |
use Yoast\WP\SEO\Config\SEMrush_Client; |
| 10 |
use Yoast\WP\SEO\Exceptions\OAuth\Authentication_Failed_Exception; |
| 11 |
use Yoast\WP\SEO\Exceptions\OAuth\Tokens\Empty_Property_Exception; |
| 12 |
use Yoast\WP\SEO\Exceptions\OAuth\Tokens\Empty_Token_Exception; |
| 13 |
|
| 14 |
/** |
| 15 |
* This class forces needed methods for the metabox localization. |
| 16 |
*/ |
| 17 |
class WPSEO_Metabox_Formatter { |
| 18 |
|
| 19 |
/** |
| 20 |
* Object that provides formatted values. |
| 21 |
* |
| 22 |
* @var WPSEO_Metabox_Formatter_Interface |
| 23 |
*/ |
| 24 |
private $formatter; |
| 25 |
|
| 26 |
/** |
| 27 |
* Setting the formatter property. |
| 28 |
* |
| 29 |
* @param WPSEO_Metabox_Formatter_Interface $formatter Object that provides the formatted values. |
| 30 |
*/ |
| 31 |
public function __construct( WPSEO_Metabox_Formatter_Interface $formatter ) { |
| 32 |
$this->formatter = $formatter; |
| 33 |
} |
| 34 |
|
| 35 |
/** |
| 36 |
* Returns the values. |
| 37 |
* |
| 38 |
* @return array |
| 39 |
*/ |
| 40 |
public function get_values() { |
| 41 |
$defaults = $this->get_defaults(); |
| 42 |
$values = $this->formatter->get_values(); |
| 43 |
|
| 44 |
return ( $values + $defaults ); |
| 45 |
} |
| 46 |
|
| 47 |
/** |
| 48 |
* Returns array with all the values always needed by a scraper object. |
| 49 |
* |
| 50 |
* @return array Default settings for the metabox. |
| 51 |
*/ |
| 52 |
private function get_defaults() { |
| 53 |
$analysis_seo = new WPSEO_Metabox_Analysis_SEO(); |
| 54 |
$analysis_readability = new WPSEO_Metabox_Analysis_Readability(); |
| 55 |
$schema_types = new Schema_Types(); |
| 56 |
$is_wincher_active = YoastSEO()->helpers->wincher->is_active(); |
| 57 |
|
| 58 |
return [ |
| 59 |
'author_name' => get_the_author_meta( 'display_name' ), |
| 60 |
'site_name' => get_bloginfo( 'name' ), |
| 61 |
'sitewide_social_image' => WPSEO_Options::get( 'og_default_image' ), |
| 62 |
'search_url' => '', |
| 63 |
'post_edit_url' => '', |
| 64 |
'base_url' => '', |
| 65 |
'contentTab' => __( 'Readability', 'wordpress-seo' ), |
| 66 |
'keywordTab' => __( 'Keyphrase:', 'wordpress-seo' ), |
| 67 |
'removeKeyword' => __( 'Remove keyphrase', 'wordpress-seo' ), |
| 68 |
'contentLocale' => get_locale(), |
| 69 |
'userLocale' => \get_user_locale(), |
| 70 |
'translations' => $this->get_translations(), |
| 71 |
'keyword_usage' => [], |
| 72 |
'title_template' => '', |
| 73 |
'metadesc_template' => '', |
| 74 |
'contentAnalysisActive' => $analysis_readability->is_enabled() ? 1 : 0, |
| 75 |
'keywordAnalysisActive' => $analysis_seo->is_enabled() ? 1 : 0, |
| 76 |
'cornerstoneActive' => WPSEO_Options::get( 'enable_cornerstone_content', false ) ? 1 : 0, |
| 77 |
'semrushIntegrationActive' => WPSEO_Options::get( 'semrush_integration_active', true ) ? 1 : 0, |
| 78 |
'intl' => $this->get_content_analysis_component_translations(), |
| 79 |
'isRtl' => is_rtl(), |
| 80 |
'isPremium' => YoastSEO()->helpers->product->is_premium(), |
| 81 |
'wordFormRecognitionActive' => YoastSEO()->helpers->language->is_word_form_recognition_active( WPSEO_Language_Utils::get_language( get_locale() ) ), |
| 82 |
'siteIconUrl' => get_site_icon_url(), |
| 83 |
'countryCode' => WPSEO_Options::get( 'semrush_country_code', false ), |
| 84 |
'SEMrushLoginStatus' => WPSEO_Options::get( 'semrush_integration_active', true ) ? $this->get_semrush_login_status() : false, |
| 85 |
'showSocial' => [ |
| 86 |
'facebook' => WPSEO_Options::get( 'opengraph', false ), |
| 87 |
'twitter' => WPSEO_Options::get( 'twitter', false ), |
| 88 |
], |
| 89 |
'schema' => [ |
| 90 |
'displayFooter' => WPSEO_Capability_Utils::current_user_can( 'wpseo_manage_options' ), |
| 91 |
'pageTypeOptions' => $schema_types->get_page_type_options(), |
| 92 |
'articleTypeOptions' => $schema_types->get_article_type_options(), |
| 93 |
], |
| 94 |
'twitterCardType' => YoastSEO()->helpers->options->get( 'twitter_card_type' ), |
| 95 |
|
| 96 |
/** |
| 97 |
* Filter to determine if the markers should be enabled or not. |
| 98 |
* |
| 99 |
* @param bool $showMarkers Should the markers being enabled. Default = true. |
| 100 |
*/ |
| 101 |
'show_markers' => apply_filters( 'wpseo_enable_assessment_markers', true ), |
| 102 |
'publish_box' => [ |
| 103 |
'labels' => [ |
| 104 |
'content' => [ |
| 105 |
'na' => sprintf( |
| 106 |
/* translators: %1$s expands to the opening anchor tag, %2$s to the closing anchor tag, %3$s to the readability score. */ |
| 107 |
__( '%1$sReadability%2$s: %3$s', 'wordpress-seo' ), |
| 108 |
'<a href="#yoast-readability-analysis-collapsible-metabox">', |
| 109 |
'</a>', |
| 110 |
'<strong>' . __( 'Not available', 'wordpress-seo' ) . '</strong>' |
| 111 |
), |
| 112 |
'bad' => sprintf( |
| 113 |
/* translators: %1$s expands to the opening anchor tag, %2$s to the closing anchor tag, %3$s to the readability score. */ |
| 114 |
__( '%1$sReadability%2$s: %3$s', 'wordpress-seo' ), |
| 115 |
'<a href="#yoast-readability-analysis-collapsible-metabox">', |
| 116 |
'</a>', |
| 117 |
'<strong>' . __( 'Needs improvement', 'wordpress-seo' ) . '</strong>' |
| 118 |
), |
| 119 |
'ok' => sprintf( |
| 120 |
/* translators: %1$s expands to the opening anchor tag, %2$s to the closing anchor tag, %3$s to the readability score. */ |
| 121 |
__( '%1$sReadability%2$s: %3$s', 'wordpress-seo' ), |
| 122 |
'<a href="#yoast-readability-analysis-collapsible-metabox">', |
| 123 |
'</a>', |
| 124 |
'<strong>' . __( 'OK', 'wordpress-seo' ) . '</strong>' |
| 125 |
), |
| 126 |
'good' => sprintf( |
| 127 |
/* translators: %1$s expands to the opening anchor tag, %2$s to the closing anchor tag, %3$s to the readability score. */ |
| 128 |
__( '%1$sReadability%2$s: %3$s', 'wordpress-seo' ), |
| 129 |
'<a href="#yoast-readability-analysis-collapsible-metabox">', |
| 130 |
'</a>', |
| 131 |
'<strong>' . __( 'Good', 'wordpress-seo' ) . '</strong>' |
| 132 |
), |
| 133 |
], |
| 134 |
'keyword' => [ |
| 135 |
'na' => sprintf( |
| 136 |
/* translators: %1$s expands to the opening anchor tag, %2$s to the closing anchor tag, %3$s to the SEO score. */ |
| 137 |
__( '%1$sSEO%2$s: %3$s', 'wordpress-seo' ), |
| 138 |
'<a href="#yoast-seo-analysis-collapsible-metabox">', |
| 139 |
'</a>', |
| 140 |
'<strong>' . __( 'Not available', 'wordpress-seo' ) . '</strong>' |
| 141 |
), |
| 142 |
'bad' => sprintf( |
| 143 |
/* translators: %1$s expands to the opening anchor tag, %2$s to the closing anchor tag, %3$s to the SEO score. */ |
| 144 |
__( '%1$sSEO%2$s: %3$s', 'wordpress-seo' ), |
| 145 |
'<a href="#yoast-seo-analysis-collapsible-metabox">', |
| 146 |
'</a>', |
| 147 |
'<strong>' . __( 'Needs improvement', 'wordpress-seo' ) . '</strong>' |
| 148 |
), |
| 149 |
'ok' => sprintf( |
| 150 |
/* translators: %1$s expands to the opening anchor tag, %2$s to the closing anchor tag, %3$s to the SEO score. */ |
| 151 |
__( '%1$sSEO%2$s: %3$s', 'wordpress-seo' ), |
| 152 |
'<a href="#yoast-seo-analysis-collapsible-metabox">', |
| 153 |
'</a>', |
| 154 |
'<strong>' . __( 'OK', 'wordpress-seo' ) . '</strong>' |
| 155 |
), |
| 156 |
'good' => sprintf( |
| 157 |
/* translators: %1$s expands to the opening anchor tag, %2$s to the closing anchor tag, %3$s to the SEO score. */ |
| 158 |
__( '%1$sSEO%2$s: %3$s', 'wordpress-seo' ), |
| 159 |
'<a href="#yoast-seo-analysis-collapsible-metabox">', |
| 160 |
'</a>', |
| 161 |
'<strong>' . __( 'Good', 'wordpress-seo' ) . '</strong>' |
| 162 |
), |
| 163 |
], |
| 164 |
], |
| 165 |
], |
| 166 |
'markdownEnabled' => $this->is_markdown_enabled(), |
| 167 |
'analysisHeadingTitle' => __( 'Analysis', 'wordpress-seo' ), |
| 168 |
'zapierIntegrationActive' => WPSEO_Options::get( 'zapier_integration_active', false ) ? 1 : 0, |
| 169 |
'zapierConnectedStatus' => ! empty( WPSEO_Options::get( 'zapier_subscription', [] ) ) ? 1 : 0, |
| 170 |
'wincherIntegrationActive' => ( $is_wincher_active ) ? 1 : 0, |
| 171 |
'wincherLoginStatus' => ( $is_wincher_active ) ? YoastSEO()->helpers->wincher->login_status() : false, |
| 172 |
'wincherWebsiteId' => WPSEO_Options::get( 'wincher_website_id', '' ), |
| 173 |
'wincherAutoAddKeyphrases' => WPSEO_Options::get( 'wincher_automatically_add_keyphrases', false ), |
| 174 |
|
| 175 |
/** |
| 176 |
* Filter to determine whether the PreviouslyUsedKeyword assessment should run. |
| 177 |
* |
| 178 |
* @param bool $previouslyUsedKeywordActive Whether the PreviouslyUsedKeyword assessment should run. |
| 179 |
*/ |
| 180 |
'previouslyUsedKeywordActive' => apply_filters( 'wpseo_previously_used_keyword_active', true ), |
| 181 |
]; |
| 182 |
} |
| 183 |
|
| 184 |
/** |
| 185 |
* Returns required yoast-component translations. |
| 186 |
* |
| 187 |
* @return array |
| 188 |
*/ |
| 189 |
private function get_content_analysis_component_translations() { |
| 190 |
// Esc_html is not needed because React already handles HTML in the (translations of) these strings. |
| 191 |
return [ |
| 192 |
'locale' => \get_user_locale(), |
| 193 |
'content-analysis.errors' => __( 'Errors', 'wordpress-seo' ), |
| 194 |
'content-analysis.problems' => __( 'Problems', 'wordpress-seo' ), |
| 195 |
'content-analysis.improvements' => __( 'Improvements', 'wordpress-seo' ), |
| 196 |
'content-analysis.considerations' => __( 'Considerations', 'wordpress-seo' ), |
| 197 |
'content-analysis.good' => __( 'Good results', 'wordpress-seo' ), |
| 198 |
'content-analysis.highlight' => __( 'Highlight this result in the text', 'wordpress-seo' ), |
| 199 |
'content-analysis.nohighlight' => __( 'Remove highlight from the text', 'wordpress-seo' ), |
| 200 |
'content-analysis.disabledButton' => __( 'Marks are disabled in current view', 'wordpress-seo' ), |
| 201 |
'a11yNotice.opensInNewTab' => __( '(Opens in a new browser tab)', 'wordpress-seo' ), |
| 202 |
]; |
| 203 |
} |
| 204 |
|
| 205 |
/** |
| 206 |
* Returns Jed compatible YoastSEO.js translations. |
| 207 |
* |
| 208 |
* @return array |
| 209 |
*/ |
| 210 |
private function get_translations() { |
| 211 |
$locale = \get_user_locale(); |
| 212 |
|
| 213 |
$file = WPSEO_PATH . 'languages/wordpress-seo-' . $locale . '.json'; |
| 214 |
if ( file_exists( $file ) ) { |
| 215 |
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Retrieving a local file. |
| 216 |
$file = file_get_contents( $file ); |
| 217 |
if ( is_string( $file ) && $file !== '' ) { |
| 218 |
return json_decode( $file, true ); |
| 219 |
} |
| 220 |
} |
| 221 |
|
| 222 |
return []; |
| 223 |
} |
| 224 |
|
| 225 |
/** |
| 226 |
* Checks if Jetpack's markdown module is enabled. |
| 227 |
* Can be extended to work with other plugins that parse markdown in the content. |
| 228 |
* |
| 229 |
* @return bool |
| 230 |
*/ |
| 231 |
private function is_markdown_enabled() { |
| 232 |
$is_markdown = false; |
| 233 |
|
| 234 |
if ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'get_active_modules' ) ) { |
| 235 |
$active_modules = Jetpack::get_active_modules(); |
| 236 |
|
| 237 |
// First at all, check if Jetpack's markdown module is active. |
| 238 |
$is_markdown = in_array( 'markdown', $active_modules, true ); |
| 239 |
} |
| 240 |
|
| 241 |
/** |
| 242 |
* Filters whether markdown support is active in the readability- and seo-analysis. |
| 243 |
* |
| 244 |
* @since 11.3 |
| 245 |
* |
| 246 |
* @param array $is_markdown Is markdown support for Yoast SEO active. |
| 247 |
*/ |
| 248 |
return apply_filters( 'wpseo_is_markdown_enabled', $is_markdown ); |
| 249 |
} |
| 250 |
|
| 251 |
/** |
| 252 |
* Checks if the user is logged in to SEMrush. |
| 253 |
* |
| 254 |
* @return bool The SEMrush login status. |
| 255 |
*/ |
| 256 |
private function get_semrush_login_status() { |
| 257 |
try { |
| 258 |
$semrush_client = YoastSEO()->classes->get( SEMrush_Client::class ); |
| 259 |
} catch ( Empty_Property_Exception $e ) { |
| 260 |
// Return false if token is malformed (empty property). |
| 261 |
return false; |
| 262 |
} |
| 263 |
|
| 264 |
// Get token (and refresh it if it's expired). |
| 265 |
try { |
| 266 |
$semrush_client->get_tokens(); |
| 267 |
} catch ( Authentication_Failed_Exception $e ) { |
| 268 |
return false; |
| 269 |
} catch ( Empty_Token_Exception $e ) { |
| 270 |
return false; |
| 271 |
} |
| 272 |
|
| 273 |
return $semrush_client->has_valid_tokens(); |
| 274 |
} |
| 275 |
|
| 276 |
/* ********************* DEPRECATED METHODS ********************* */ |
| 277 |
|
| 278 |
/** |
| 279 |
* Returns the translations for the Add Keyword modal. |
| 280 |
* |
| 281 |
* These strings are not escaped because they're meant to be used with React |
| 282 |
* which already takes care of that. If used in PHP, they should be escaped. |
| 283 |
* |
| 284 |
* @deprecated 15.5 |
| 285 |
* @codeCoverageIgnore |
| 286 |
* |
| 287 |
* @return array Translated text strings for the Add Keyword modal. |
| 288 |
*/ |
| 289 |
public function get_add_keyword_upsell_translations() { |
| 290 |
_deprecated_function( __METHOD__, 'WPSEO 15.5' ); |
| 291 |
|
| 292 |
return [ |
| 293 |
'title' => __( 'Would you like to add more than one keyphrase?', 'wordpress-seo' ), |
| 294 |
'intro' => sprintf( |
| 295 |
/* translators: %s expands to a 'Yoast SEO Premium' text linked to the yoast.com website. */ |
| 296 |
__( 'Great news: you can, with %s!', 'wordpress-seo' ), |
| 297 |
'{{link}}Yoast SEO Premium{{/link}}' |
| 298 |
), |
| 299 |
'link' => WPSEO_Shortlinker::get( 'https://yoa.st/pe-premium-page' ), |
| 300 |
'other' => sprintf( |
| 301 |
/* translators: %s expands to 'Yoast SEO Premium'. */ |
| 302 |
__( 'Other benefits of %s for you:', 'wordpress-seo' ), |
| 303 |
'Yoast SEO Premium' |
| 304 |
), |
| 305 |
'buylink' => WPSEO_Shortlinker::get( 'https://yoa.st/add-keywords-popup' ), |
| 306 |
'buy' => sprintf( |
| 307 |
/* translators: %s expands to 'Yoast SEO Premium'. */ |
| 308 |
__( 'Get %s', 'wordpress-seo' ), |
| 309 |
'Yoast SEO Premium' |
| 310 |
), |
| 311 |
'small' => __( '1 year free support and updates included!', 'wordpress-seo' ), |
| 312 |
'a11yNotice.opensInNewTab' => __( '(Opens in a new browser tab)', 'wordpress-seo' ), |
| 313 |
]; |
| 314 |
} |
| 315 |
} |
| 316 |
|