class-license-page-manager.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Admin
  6. */
  7. /**
  8. * Represents the values for a single Yoast Premium extension plugin.
  9. */
  10. class WPSEO_License_Page_Manager implements WPSEO_WordPress_Integration {
  11. /**
  12. * Version number for License Page Manager.
  13. *
  14. * @var string
  15. */
  16. const VERSION_LEGACY = '1';
  17. /**
  18. * Version number for License Page Manager.
  19. *
  20. * @var string
  21. */
  22. const VERSION_BACKWARDS_COMPATIBILITY = '2';
  23. /**
  24. * Registers all hooks to WordPress.
  25. */
  26. public function register_hooks() {
  27. add_filter( 'http_response', [ $this, 'handle_response' ], 10, 3 );
  28. if ( $this->get_version() === self::VERSION_BACKWARDS_COMPATIBILITY ) {
  29. add_filter( 'yoast-license-valid', '__return_true' );
  30. add_filter( 'yoast-show-license-notice', '__return_false' );
  31. add_action( 'admin_init', [ $this, 'validate_extensions' ], 15 );
  32. }
  33. else {
  34. add_action( 'admin_init', [ $this, 'remove_faulty_notifications' ], 15 );
  35. }
  36. }
  37. /**
  38. * Validates the extensions and show a notice for the invalid extensions.
  39. */
  40. public function validate_extensions() {
  41. if ( filter_input( INPUT_GET, 'page' ) === WPSEO_Admin::PAGE_IDENTIFIER ) {
  42. /**
  43. * Filter: 'yoast-active-extensions' - Collects all active extensions. This hook is implemented in the
  44. * license manager.
  45. *
  46. * @api array $extensions The array with extensions.
  47. */
  48. apply_filters( 'yoast-active-extensions', [] );
  49. }
  50. $extension_list = new WPSEO_Extensions();
  51. $extensions = $extension_list->get();
  52. $notification_center = Yoast_Notification_Center::get();
  53. foreach ( $extensions as $product_name ) {
  54. $notification = $this->create_notification( $product_name );
  55. // Add a notification when the installed plugin isn't activated in My Yoast.
  56. if ( $extension_list->is_installed( $product_name ) && ! $extension_list->is_valid( $product_name ) ) {
  57. $notification_center->add_notification( $notification );
  58. continue;
  59. }
  60. $notification_center->remove_notification( $notification );
  61. }
  62. }
  63. /**
  64. * Removes the faulty set notifications.
  65. */
  66. public function remove_faulty_notifications() {
  67. $extension_list = new WPSEO_Extensions();
  68. $extensions = $extension_list->get();
  69. $notification_center = Yoast_Notification_Center::get();
  70. foreach ( $extensions as $product_name ) {
  71. $notification = $this->create_notification( $product_name );
  72. $notification_center->remove_notification( $notification );
  73. }
  74. }
  75. /**
  76. * Handles the response.
  77. *
  78. * @param array $response HTTP response.
  79. * @param array $request_arguments HTTP request arguments. Unused.
  80. * @param string $url The request URL.
  81. *
  82. * @return array The response array.
  83. */
  84. public function handle_response( array $response, $request_arguments, $url ) {
  85. $response_code = wp_remote_retrieve_response_code( $response );
  86. if ( $response_code === 200 && $this->is_expected_endpoint( $url ) ) {
  87. $response_data = $this->parse_response( $response );
  88. $this->detect_version( $response_data );
  89. }
  90. return $response;
  91. }
  92. /**
  93. * Returns the license page to use based on the version number.
  94. *
  95. * @return string The page to use.
  96. */
  97. public function get_license_page() {
  98. return 'licenses';
  99. }
  100. /**
  101. * Returns the version number of the license server.
  102. *
  103. * @return int The version number
  104. */
  105. protected function get_version() {
  106. return get_option( $this->get_option_name(), self::VERSION_BACKWARDS_COMPATIBILITY );
  107. }
  108. /**
  109. * Returns the option name.
  110. *
  111. * @return string The option name.
  112. */
  113. protected function get_option_name() {
  114. return 'wpseo_license_server_version';
  115. }
  116. /**
  117. * Sets the version when there is a value in the response.
  118. *
  119. * @param array $response The response to extract the version from.
  120. */
  121. protected function detect_version( $response ) {
  122. if ( ! empty( $response['serverVersion'] ) ) {
  123. $this->set_version( $response['serverVersion'] );
  124. }
  125. }
  126. /**
  127. * Sets the version.
  128. *
  129. * @param string $server_version The version number to save.
  130. */
  131. protected function set_version( $server_version ) {
  132. update_option( $this->get_option_name(), $server_version );
  133. }
  134. /**
  135. * Parses the response by getting its body and do a unserialize of it.
  136. *
  137. * @param array $response The response to parse.
  138. *
  139. * @return mixed|string|false The parsed response.
  140. */
  141. protected function parse_response( $response ) {
  142. $response = json_decode( wp_remote_retrieve_body( $response ), true );
  143. $response = maybe_unserialize( $response );
  144. return $response;
  145. }
  146. /**
  147. * Checks if the given url matches the expected endpoint.
  148. *
  149. * @param string $url The url to check.
  150. *
  151. * @return bool True when url matches the endpoint.
  152. */
  153. protected function is_expected_endpoint( $url ) {
  154. $url_parts = wp_parse_url( $url );
  155. $is_yoast_com = ( in_array( $url_parts['host'], [ 'yoast.com', 'my.yoast.com' ], true ) );
  156. $is_edd_api = ( isset( $url_parts['path'] ) && $url_parts['path'] === '/edd-sl-api' );
  157. return $is_yoast_com && $is_edd_api;
  158. }
  159. /**
  160. * Creates an instance of Yoast_Notification.
  161. *
  162. * @param string $product_name The product to create the notification for.
  163. *
  164. * @return Yoast_Notification The created notification.
  165. */
  166. protected function create_notification( $product_name ) {
  167. $notification_options = [
  168. 'type' => Yoast_Notification::ERROR,
  169. 'id' => 'wpseo-dismiss-' . sanitize_title_with_dashes( $product_name, null, 'save' ),
  170. 'capabilities' => 'wpseo_manage_options',
  171. ];
  172. $notification = new Yoast_Notification(
  173. sprintf(
  174. /* translators: %1$s expands to the product name. %2$s expands to a link to My Yoast */
  175. __( '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' ),
  176. $product_name,
  177. '<a href="' . WPSEO_Shortlinker::get( 'https://yoa.st/13j' ) . '" target="_blank">My Yoast</a>'
  178. ),
  179. $notification_options
  180. );
  181. return $notification;
  182. }
  183. }