| @@ -4,8 +4,12 @@ | ||
| 4 | 4 | * |
| 5 | 5 | * @package WPSEO\Inc |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | +use Yoast\WP\SEO\General\User_Interface\General_Page_Integration; | |
| 9 | +use Yoast\WP\SEO\Plans\User_Interface\Plans_Page_Integration; | |
| 10 | +use Yoast\WP\SEO\Promotions\Application\Promotion_Manager; | |
| 11 | + | |
| 8 | 12 | /** |
| 9 | 13 | * Represents the addon manager. |
| 10 | 14 | */ |
| 11 | 15 | class WPSEO_Addon_Manager { |
| @@ -14,9 +18,9 @@ | ||
| 14 | 18 | * Holds the name of the transient. |
| 15 | 19 | * |
| 16 | 20 | * @var string |
| 17 | 21 | */ |
| 18 | - const SITE_INFORMATION_TRANSIENT = 'wpseo_site_information'; | |
| 22 | + public const SITE_INFORMATION_TRANSIENT = 'wpseo_site_information'; | |
| 19 | 23 | |
| 20 | 24 | /** |
| 21 | 25 | * Holds the name of the transient. |
| 22 | 26 | * |
| @@ -21,9 +25,9 @@ | ||
| 21 | 25 | * Holds the name of the transient. |
| 22 | 26 | * |
| 23 | 27 | * @var string |
| 24 | 28 | */ |
| 25 | - const SITE_INFORMATION_TRANSIENT_QUICK = 'wpseo_site_information_quick'; | |
| 29 | + public const SITE_INFORMATION_TRANSIENT_QUICK = 'wpseo_site_information_quick'; | |
| 26 | 30 | |
| 27 | 31 | /** |
| 28 | 32 | * Holds the slug for YoastSEO free. |
| 29 | 33 | * |
| @@ -28,9 +32,9 @@ | ||
| 28 | 32 | * Holds the slug for YoastSEO free. |
| 29 | 33 | * |
| 30 | 34 | * @var string |
| 31 | 35 | */ |
| 32 | - const FREE_SLUG = 'yoast-seo-wordpress'; | |
| 36 | + public const FREE_SLUG = 'yoast-seo-wordpress'; | |
| 33 | 37 | |
| 34 | 38 | /** |
| 35 | 39 | * Holds the slug for YoastSEO Premium. |
| 36 | 40 | * |
| @@ -35,9 +39,9 @@ | ||
| 35 | 39 | * Holds the slug for YoastSEO Premium. |
| 36 | 40 | * |
| 37 | 41 | * @var string |
| 38 | 42 | */ |
| 39 | - const PREMIUM_SLUG = 'yoast-seo-wordpress-premium'; | |
| 43 | + public const PREMIUM_SLUG = 'yoast-seo-wordpress-premium'; | |
| 40 | 44 | |
| 41 | 45 | /** |
| 42 | 46 | * Holds the slug for Yoast News. |
| 43 | 47 | * |
| @@ -42,9 +46,9 @@ | ||
| 42 | 46 | * Holds the slug for Yoast News. |
| 43 | 47 | * |
| 44 | 48 | * @var string |
| 45 | 49 | */ |
| 46 | - const NEWS_SLUG = 'yoast-seo-news'; | |
| 50 | + public const NEWS_SLUG = 'yoast-seo-news'; | |
| 47 | 51 | |
| 48 | 52 | /** |
| 49 | 53 | * Holds the slug for Video. |
| 50 | 54 | * |
| @@ -49,9 +53,9 @@ | ||
| 49 | 53 | * Holds the slug for Video. |
| 50 | 54 | * |
| 51 | 55 | * @var string |
| 52 | 56 | */ |
| 53 | - const VIDEO_SLUG = 'yoast-seo-video'; | |
| 57 | + public const VIDEO_SLUG = 'yoast-seo-video'; | |
| 54 | 58 | |
| 55 | 59 | /** |
| 56 | 60 | * Holds the slug for WooCommerce. |
| 57 | 61 | * |
| @@ -56,9 +60,9 @@ | ||
| 56 | 60 | * Holds the slug for WooCommerce. |
| 57 | 61 | * |
| 58 | 62 | * @var string |
| 59 | 63 | */ |
| 60 | - const WOOCOMMERCE_SLUG = 'yoast-seo-woocommerce'; | |
| 64 | + public const WOOCOMMERCE_SLUG = 'yoast-seo-woocommerce'; | |
| 61 | 65 | |
| 62 | 66 | /** |
| 63 | 67 | * Holds the slug for Local. |
| 64 | 68 | * |
| @@ -63,14 +67,14 @@ | ||
| 63 | 67 | * Holds the slug for Local. |
| 64 | 68 | * |
| 65 | 69 | * @var string |
| 66 | 70 | */ |
| 67 | - const LOCAL_SLUG = 'yoast-seo-local'; | |
| 71 | + public const LOCAL_SLUG = 'yoast-seo-local'; | |
| 68 | 72 | |
| 69 | 73 | /** |
| 70 | 74 | * The expected addon data. |
| 71 | 75 | * |
| 72 | - * @var array | |
| 76 | + * @var array<string, string> | |
| 73 | 77 | */ |
| 74 | 78 | protected static $addons = [ |
| 75 | 79 | 'wp-seo-premium.php' => self::PREMIUM_SLUG, |
| 76 | 80 | 'wpseo-news.php' => self::NEWS_SLUG, |
| @@ -79,8 +83,41 @@ | ||
| 79 | 83 | 'local-seo.php' => self::LOCAL_SLUG, |
| 80 | 84 | ]; |
| 81 | 85 | |
| 82 | 86 | /** |
| 87 | + * The addon data for the shortlinks. | |
| 88 | + * | |
| 89 | + * @var array<string, array<string, string>> | |
| 90 | + */ | |
| 91 | + private $addon_details = [ | |
| 92 | + self::PREMIUM_SLUG => [ | |
| 93 | + 'name' => 'Yoast SEO Premium', | |
| 94 | + 'short_link_activation' => 'https://yoa.st/13j', | |
| 95 | + 'short_link_renewal' => 'https://yoa.st/4ey', | |
| 96 | + ], | |
| 97 | + self::NEWS_SLUG => [ | |
| 98 | + 'name' => 'Yoast News SEO', | |
| 99 | + 'short_link_activation' => 'https://yoa.st/4xq', | |
| 100 | + 'short_link_renewal' => 'https://yoa.st/4xv', | |
| 101 | + ], | |
| 102 | + self::WOOCOMMERCE_SLUG => [ | |
| 103 | + 'name' => 'Yoast WooCommerce SEO', | |
| 104 | + 'short_link_activation' => 'https://yoa.st/4xs', | |
| 105 | + 'short_link_renewal' => 'https://yoa.st/4xx', | |
| 106 | + ], | |
| 107 | + self::VIDEO_SLUG => [ | |
| 108 | + 'name' => 'Yoast Video SEO', | |
| 109 | + 'short_link_activation' => 'https://yoa.st/4xr', | |
| 110 | + 'short_link_renewal' => 'https://yoa.st/4xw', | |
| 111 | + ], | |
| 112 | + self::LOCAL_SLUG => [ | |
| 113 | + 'name' => 'Yoast Local SEO', | |
| 114 | + 'short_link_activation' => 'https://yoa.st/4xp', | |
| 115 | + 'short_link_renewal' => 'https://yoa.st/4xu', | |
| 116 | + ], | |
| 117 | + ]; | |
| 118 | + | |
| 119 | + /** | |
| 83 | 120 | * Holds the site information data. |
| 84 | 121 | * |
| 85 | 122 | * @var stdClass |
| 86 | 123 | */ |
| @@ -173,9 +210,9 @@ | ||
| 173 | 210 | |
| 174 | 211 | /** |
| 175 | 212 | * Retrieves a list of (subscription) slugs by the active addons. |
| 176 | 213 | * |
| 177 | - * @return array The slugs. | |
| 214 | + * @return array<string, stdClass> The slugs. | |
| 178 | 215 | */ |
| 179 | 216 | public function get_subscriptions_for_active_addons() { |
| 180 | 217 | $active_addons = array_keys( $this->get_active_addons() ); |
| 181 | 218 | $subscription_slugs = array_map( [ $this, 'get_slug_by_plugin_file' ], $active_addons ); |
| @@ -189,9 +226,9 @@ | ||
| 189 | 226 | |
| 190 | 227 | /** |
| 191 | 228 | * Retrieves a list of versions for each addon. |
| 192 | 229 | * |
| 193 | - * @return array The addon versions. | |
| 230 | + * @return array<string, string> The addon versions. | |
| 194 | 231 | */ |
| 195 | 232 | public function get_installed_addons_versions() { |
| 196 | 233 | $addon_versions = []; |
| 197 | 234 | foreach ( $this->get_installed_addons() as $plugin_file => $installed_addon ) { |
| @@ -238,11 +275,9 @@ | ||
| 238 | 275 | * |
| 239 | 276 | * @return stdClass The list of addons activated for this site. |
| 240 | 277 | */ |
| 241 | 278 | public function get_myyoast_site_information() { |
| 242 | - if ( $this->site_information === null ) { | |
| 243 | - $this->site_information = $this->get_site_information_transient(); | |
| 244 | - } | |
| 279 | + $this->site_information ??= $this->get_site_information_transient(); | |
| 245 | 280 | |
| 246 | 281 | if ( $this->site_information ) { |
| 247 | 282 | return $this->site_information; |
| 248 | 283 | } |
| @@ -279,9 +314,9 @@ | ||
| 279 | 314 | |
| 280 | 315 | /** |
| 281 | 316 | * Checks if there are addon updates. |
| 282 | 317 | * |
| 283 | - * @param stdClass|mixed $data The current data for update_plugins. | |
| 318 | + * @param stdClass $data The current data for update_plugins. | |
| 284 | 319 | * |
| 285 | 320 | * @return stdClass Extended data for update_plugins. |
| 286 | 321 | */ |
| 287 | 322 | public function check_for_updates( $data ) { |
| @@ -309,9 +344,9 @@ | ||
| 309 | 344 | |
| 310 | 345 | // If the add-on's version is the latest, we have to do no further checks. |
| 311 | 346 | if ( version_compare( $installed_plugin['Version'], $plugin_data->new_version, '<' ) ) { |
| 312 | 347 | // If we haven't retrieved the Yoast Free requirements for the WP version yet, do nothing. The next run will probably get us that information. |
| 313 | - if ( is_null( $plugin_data->requires ) ) { | |
| 348 | + if ( $plugin_data->requires === null ) { | |
| 314 | 349 | continue; |
| 315 | 350 | } |
| 316 | 351 | |
| 317 | 352 | if ( version_compare( $plugin_data->requires, $wp_version, '<=' ) ) { |
| @@ -360,15 +395,37 @@ | ||
| 360 | 395 | /** |
| 361 | 396 | * If the plugin is lacking an active subscription, throw a warning. |
| 362 | 397 | * |
| 363 | 398 | * @param array $plugin_data The data for the plugin in this row. |
| 399 | + * | |
| 400 | + * @return void | |
| 364 | 401 | */ |
| 365 | 402 | public function expired_subscription_warning( $plugin_data ) { |
| 366 | 403 | $subscription = $this->get_subscription( $plugin_data['slug'] ); |
| 367 | 404 | if ( $subscription && $this->has_subscription_expired( $subscription ) ) { |
| 405 | + $addon_link = ( isset( $this->addon_details[ $plugin_data['slug'] ] ) ) ? $this->addon_details[ $plugin_data['slug'] ]['short_link_renewal'] : $this->addon_details[ self::PREMIUM_SLUG ]['short_link_renewal']; | |
| 406 | + | |
| 407 | + $sale_copy = ''; | |
| 408 | + if ( YoastSEO()->classes->get( Promotion_Manager::class )->is( 'black-friday-promotion' ) ) { | |
| 409 | + $sale_copy = sprintf( | |
| 410 | + /* translators: %1$s and %2$s are a <span> opening and closing tag. */ | |
| 411 | + esc_html__( '%1$s30%% OFF - Black Friday %2$s', 'wordpress-seo' ), | |
| 412 | + '<span class="yoast-update-plugin-bf-sale-badge">', | |
| 413 | + '</span>', | |
| 414 | + ); | |
| 415 | + } | |
| 368 | 416 | echo '<br><br>'; |
| 369 | - /* translators: %1$s is the plugin name, %2$s and %3$s are a link. */ | |
| 370 | - echo '<strong><span class="wp-ui-text-notification alert dashicons dashicons-warning"></span> ' . sprintf( esc_html__( 'A new version of %1$s is available. %2$sRenew your subscription%3$s if you want to update to the latest version.', 'wordpress-seo' ), esc_html( $plugin_data['name'] ), '<a href="' . esc_attr( WPSEO_Shortlinker::get( 'https://yoa.st/4ey' ) ) . '">', '</a>' ) . '</strong>'; | |
| 417 | + echo '<strong><span class="yoast-dashicons-notice warning dashicons dashicons-warning"></span> ' | |
| 418 | + . sprintf( | |
| 419 | + /* translators: %1$s is the plugin name, %2$s and %3$s are a link. */ | |
| 420 | + esc_html__( 'Your %1$s plugin cannot be updated as your subscription has expired. %2$sRenew your product subscription%3$s to restore updates and full feature access.', 'wordpress-seo' ), | |
| 421 | + esc_html( $plugin_data['name'] ), | |
| 422 | + '<a href="' . esc_url( WPSEO_Shortlinker::get( $addon_link ) ) . '">', | |
| 423 | + '</a>', | |
| 424 | + ) | |
| 425 | + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output is escaped above. | |
| 426 | + . $sale_copy | |
| 427 | + . '</strong>'; | |
| 371 | 428 | } |
| 372 | 429 | } |
| 373 | 430 | |
| 374 | 431 | /** |
| @@ -406,8 +463,10 @@ | ||
| 406 | 463 | } |
| 407 | 464 | |
| 408 | 465 | /** |
| 409 | 466 | * Validates the addons and show a notice for the ones that are invalid. |
| 467 | + * | |
| 468 | + * @return void | |
| 410 | 469 | */ |
| 411 | 470 | public function validate_addons() { |
| 412 | 471 | $notification_center = Yoast_Notification_Center::get(); |
| 413 | 472 | |
| @@ -414,19 +473,11 @@ | ||
| 414 | 473 | if ( $notification_center === null ) { |
| 415 | 474 | return; |
| 416 | 475 | } |
| 417 | 476 | |
| 418 | - $addons = [ | |
| 419 | - 'Yoast SEO Premium' => static::PREMIUM_SLUG, | |
| 420 | - 'News SEO' => static::NEWS_SLUG, | |
| 421 | - 'Yoast WooCommerce SEO' => static::WOOCOMMERCE_SLUG, | |
| 422 | - 'Video SEO' => static::VIDEO_SLUG, | |
| 423 | - 'Local SEO' => static::LOCAL_SLUG, | |
| 424 | - ]; | |
| 477 | + foreach ( $this->addon_details as $slug => $addon_info ) { | |
| 478 | + $notification = $this->create_notification( $addon_info['name'], $addon_info['short_link_activation'] ); | |
| 425 | 479 | |
| 426 | - foreach ( $addons as $product_name => $slug ) { | |
| 427 | - $notification = $this->create_notification( $product_name ); | |
| 428 | - | |
| 429 | 480 | // Add a notification when the installed plugin isn't activated in My Yoast. |
| 430 | 481 | if ( $this->is_installed( $slug ) && ! $this->has_valid_subscription( $slug ) ) { |
| 431 | 482 | $notification_center->add_notification( $notification ); |
| 432 | 483 | |
| @@ -437,8 +488,19 @@ | ||
| 437 | 488 | } |
| 438 | 489 | } |
| 439 | 490 | |
| 440 | 491 | /** |
| 492 | + * Checks if the user has any active addons. | |
| 493 | + * | |
| 494 | + * @return bool Whether there are active addons. | |
| 495 | + */ | |
| 496 | + public function has_active_addons() { | |
| 497 | + $active_addons = $this->get_active_addons(); | |
| 498 | + | |
| 499 | + return ! empty( $active_addons ); | |
| 500 | + } | |
| 501 | + | |
| 502 | + /** | |
| 441 | 503 | * Removes the site information transients. |
| 442 | 504 | * |
| 443 | 505 | * @codeCoverageIgnore |
| 444 | 506 | * |
| @@ -452,12 +514,13 @@ | ||
| 452 | 514 | /** |
| 453 | 515 | * Creates an instance of Yoast_Notification. |
| 454 | 516 | * |
| 455 | 517 | * @param string $product_name The product to create the notification for. |
| 518 | + * @param string $short_link The short link for the addon notification. | |
| 456 | 519 | * |
| 457 | 520 | * @return Yoast_Notification The created notification. |
| 458 | 521 | */ |
| 459 | - protected function create_notification( $product_name ) { | |
| 522 | + protected function create_notification( $product_name, $short_link ) { | |
| 460 | 523 | $notification_options = [ |
| 461 | 524 | 'type' => Yoast_Notification::ERROR, |
| 462 | 525 | 'id' => 'wpseo-dismiss-' . sanitize_title_with_dashes( $product_name, null, 'save' ), |
| 463 | 526 | 'capabilities' => 'wpseo_manage_options', |
| @@ -464,14 +527,19 @@ | ||
| 464 | 527 | ]; |
| 465 | 528 | |
| 466 | 529 | return new Yoast_Notification( |
| 467 | 530 | sprintf( |
| 468 | - /* translators: %1$s expands to the product name. %2$s expands to a link to My Yoast */ | |
| 469 | - __( 'You are not receiving updates or support! Fix this problem by adding this site and enabling %1$s for it in %2$s.', 'wordpress-seo' ), | |
| 531 | + /* translators: %1$s expands to a strong tag, %2$s expands to the product name, %3$s expands to a closing strong tag, %4$s expands to an a tag. %5$s expands to MyYoast, %6$s expands to a closing a tag, %7$s expands to the product name */ | |
| 532 | + __( '%1$s %2$s isn\'t working as expected %3$s and you are not receiving updates or support! Make sure to %4$s activate your product subscription in %5$s%6$s to unlock all the features of %7$s.', 'wordpress-seo' ), | |
| 533 | + '<strong>', | |
| 470 | 534 | $product_name, |
| 471 | - '<a href="' . WPSEO_Shortlinker::get( 'https://yoa.st/13j' ) . '" target="_blank">My Yoast</a>' | |
| 535 | + '</strong>', | |
| 536 | + '<a href="' . WPSEO_Shortlinker::get( $short_link ) . '" target="_blank">', | |
| 537 | + 'MyYoast', | |
| 538 | + '</a>', | |
| 539 | + $product_name, | |
| 472 | 540 | ), |
| 473 | - $notification_options | |
| 541 | + $notification_options, | |
| 474 | 542 | ); |
| 475 | 543 | } |
| 476 | 544 | |
| 477 | 545 | /** |
| @@ -487,19 +555,22 @@ | ||
| 487 | 555 | |
| 488 | 556 | /** |
| 489 | 557 | * Converts a subscription to plugin based format. |
| 490 | 558 | * |
| 491 | - * @param stdClass $subscription The subscription to convert. | |
| 492 | - * @param stdClass $yoast_free_data The Yoast Free's data. | |
| 493 | - * @param bool $plugin_info Whether we're in the plugin information modal. | |
| 494 | - * @param string $plugin_file The plugin filename. | |
| 559 | + * @param stdClass $subscription The subscription to convert. | |
| 560 | + * @param stdClass|null $yoast_free_data The Yoast Free's data. | |
| 561 | + * @param bool $plugin_info Whether we're in the plugin information modal. | |
| 562 | + * @param string $plugin_file The plugin filename. | |
| 495 | 563 | * |
| 496 | 564 | * @return stdClass The converted subscription. |
| 497 | 565 | */ |
| 498 | 566 | protected function convert_subscription_to_plugin( $subscription, $yoast_free_data = null, $plugin_info = false, $plugin_file = '' ) { |
| 499 | - // We need to replace h2's and h3's with h4's because the styling expects that. | |
| 500 | - $changelog = str_replace( '</h2', '</h4', str_replace( '<h2', '<h4', $subscription->product->changelog ) ); | |
| 501 | - $changelog = str_replace( '</h3', '</h4', str_replace( '<h3', '<h4', $changelog ) ); | |
| 567 | + $changelog = ''; | |
| 568 | + if ( isset( $subscription->product->changelog ) ) { | |
| 569 | + // We need to replace h2's and h3's with h4's because the styling expects that. | |
| 570 | + $changelog = str_replace( '</h2', '</h4', str_replace( '<h2', '<h4', $subscription->product->changelog ) ); | |
| 571 | + $changelog = str_replace( '</h3', '</h4', str_replace( '<h3', '<h4', $changelog ) ); | |
| 572 | + } | |
| 502 | 573 | |
| 503 | 574 | // If we're running this because we want to just show the plugin info in the version details modal, we can fallback to the Yoast Free constants, since that modal will not be accessible anyway in the event that the new Free version increases those constants. |
| 504 | 575 | $defaults = [ |
| 505 | 576 | // It can be expanded if we have the 'tested' and 'requires_php' data be returned from wp.org in the future. |
| @@ -506,9 +577,9 @@ | ||
| 506 | 577 | 'requires' => ( $plugin_info ) ? YOAST_SEO_WP_REQUIRED : null, |
| 507 | 578 | ]; |
| 508 | 579 | |
| 509 | 580 | return (object) [ |
| 510 | - 'new_version' => $subscription->product->version, | |
| 581 | + 'new_version' => ( $subscription->product->version ?? '' ), | |
| 511 | 582 | 'name' => $subscription->product->name, |
| 512 | 583 | 'slug' => $subscription->product->slug, |
| 513 | 584 | 'plugin' => $plugin_file, |
| 514 | 585 | 'url' => $subscription->product->store_url, |
| @@ -526,9 +597,9 @@ | ||
| 526 | 597 | 'update_supported' => true, |
| 527 | 598 | 'banners' => $this->get_banners( $subscription->product->slug ), |
| 528 | 599 | // If we have extracted Yoast Free's data before, use that. If not, resort to the defaults. |
| 529 | 600 | 'tested' => YOAST_SEO_WP_TESTED, |
| 530 | - 'requires' => isset( $yoast_free_data->requires ) ? $yoast_free_data->requires : $defaults['requires'], | |
| 601 | + 'requires' => ( $yoast_free_data->requires ?? $defaults['requires'] ), | |
| 531 | 602 | 'requires_php' => YOAST_SEO_PHP_REQUIRED, |
| 532 | 603 | ]; |
| 533 | 604 | } |
| 534 | 605 | |
| @@ -670,12 +741,17 @@ | ||
| 670 | 741 | protected function get_site_information_transient() { |
| 671 | 742 | global $pagenow; |
| 672 | 743 | |
| 673 | 744 | // Force re-check on license & dashboard pages. |
| 674 | - $current_page = $this->get_current_page(); | |
| 745 | + $current_page = null; | |
| 746 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information. | |
| 747 | + if ( isset( $_GET['page'] ) && is_string( $_GET['page'] ) ) { | |
| 748 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Reason: We are not processing form information, We are only strictly comparing and thus no need to sanitize. | |
| 749 | + $current_page = wp_unslash( $_GET['page'] ); | |
| 750 | + } | |
| 675 | 751 | |
| 676 | 752 | // Check whether the licenses are valid or whether we need to show notifications. |
| 677 | - $quick = ( $current_page === 'wpseo_licenses' || $current_page === 'wpseo_dashboard' ); | |
| 753 | + $quick = ( $current_page === Plans_Page_Integration::PAGE || $current_page === General_Page_Integration::PAGE ); | |
| 678 | 754 | |
| 679 | 755 | // Also do a fresh request on Plugins & Core Update pages. |
| 680 | 756 | $quick = $quick || $pagenow === 'plugins.php'; |
| 681 | 757 | $quick = $quick || $pagenow === 'update-core.php'; |
| @@ -687,19 +763,8 @@ | ||
| 687 | 763 | return get_transient( self::SITE_INFORMATION_TRANSIENT ); |
| 688 | 764 | } |
| 689 | 765 | |
| 690 | 766 | /** |
| 691 | - * Returns the current page. | |
| 692 | - * | |
| 693 | - * @codeCoverageIgnore | |
| 694 | - * | |
| 695 | - * @return string The current page. | |
| 696 | - */ | |
| 697 | - protected function get_current_page() { | |
| 698 | - return filter_input( INPUT_GET, 'page' ); | |
| 699 | - } | |
| 700 | - | |
| 701 | - /** | |
| 702 | 767 | * Sets the site information transient. |
| 703 | 768 | * |
| 704 | 769 | * @codeCoverageIgnore |
| 705 | 770 | * |
| @@ -786,9 +851,9 @@ | ||
| 786 | 851 | 'slug' => $subscription->product->slug, |
| 787 | 852 | 'last_updated' => $subscription->product->lastUpdated, |
| 788 | 853 | 'store_url' => $subscription->product->storeUrl, |
| 789 | 854 | // Ternary operator is necessary because download can be undefined. |
| 790 | - 'download' => isset( $subscription->product->download ) ? $subscription->product->download : null, | |
| 855 | + 'download' => ( $subscription->product->download ?? null ), | |
| 791 | 856 | 'changelog' => $subscription->product->changelog, |
| 792 | 857 | ], |
| 793 | 858 | ]; |
| 794 | 859 | // phpcs:enable |