Yoast_License_Manager

Class Yoast_License_Manager.

Defined (1)

The class is defined in the following location(s).

/vendor/yoast/license-manager-2/class-license-manager.php  
  1. abstract class Yoast_License_Manager implements iYoast_License_Manager { 
  2.  
  3. /** 
  4. * @const VERSION The version number of the License_Manager class 
  5. */ 
  6. const VERSION = 1; 
  7.  
  8. /** 
  9. * @var Yoast_License The license 
  10. */ 
  11. protected $product; 
  12.  
  13. /** 
  14. * @var string 
  15. */ 
  16. private $license_constant_name = ''; 
  17.  
  18. /** 
  19. * @var boolean True if license is defined with a constant 
  20. */ 
  21. private $license_constant_is_defined = false; 
  22.  
  23. /** 
  24. * @var boolean True if remote license activation just failed 
  25. */ 
  26. private $remote_license_activation_failed = false; 
  27.  
  28. /** 
  29. * @var array Array of license related options 
  30. */ 
  31. private $options = array(); 
  32.  
  33. /** 
  34. * @var string Used to prefix ID's, option names, etc.. 
  35. */ 
  36. protected $prefix; 
  37.  
  38. /** 
  39. * @var bool Boolean indicating whether this plugin is network activated 
  40. */ 
  41. protected $is_network_activated = false; 
  42.  
  43. /** 
  44. * Constructor 
  45. * @param Yoast_Product $product 
  46. */ 
  47. public function __construct( Yoast_Product $product ) { 
  48.  
  49. // Set the license 
  50. $this->product = $product; 
  51.  
  52. // set prefix 
  53. $this->prefix = sanitize_title_with_dashes( $this->product->get_item_name() . '_', null, 'save' ); 
  54.  
  55. // maybe set license key from constant 
  56. $this->maybe_set_license_key_from_constant(); 
  57.  
  58. /** 
  59. * Setup hooks 
  60. */ 
  61. public function setup_hooks() { 
  62.  
  63. // show admin notice if license is not active 
  64. add_action( 'admin_notices', array( $this, 'display_admin_notices' ) ); 
  65.  
  66. // catch POST requests from license form 
  67. add_action( 'admin_init', array( $this, 'catch_post_request' ) ); 
  68.  
  69. // setup item type (plugin|theme) specific hooks 
  70. $this->specific_hooks(); 
  71.  
  72. // setup the auto updater 
  73. $this->setup_auto_updater(); 
  74.  
  75.  
  76. /** 
  77. * Display license specific admin notices, namely: 
  78. * - License for the product isn't activated 
  79. * - External requests are blocked through WP_HTTP_BLOCK_EXTERNAL 
  80. */ 
  81. public function display_admin_notices() { 
  82.  
  83. if ( ! current_user_can( 'manage_options' ) ) { 
  84. return; 
  85.  
  86. // show notice if license is invalid 
  87. if ( ! $this->license_is_valid() ) { 
  88. if ( $this->get_license_key() == '' ) { 
  89. $message = '<b>Warning!</b> You didn\'t set your %s license key yet, which means you\'re missing out on updates and support! <a href="%s">Enter your license key</a> or <a href="%s" target="_blank">get a license here</a>.'; 
  90. } else { 
  91. $message = '<b>Warning!</b> Your %s license is inactive which means you\'re missing out on updates and support! <a href="%s">Activate your license</a> or <a href="%s" target="_blank">get a license here</a>.'; 
  92. ?> 
  93. <div class="error"> 
  94. <p><?php printf( __( $message, $this->product->get_text_domain() ), $this->product->get_item_name(), $this->product->get_license_page_url(), $this->product->get_tracking_url( 'activate-license-notice' ) ); ?></p> 
  95. </div> 
  96. <?php 
  97.  
  98. // show notice if external requests are blocked through the WP_HTTP_BLOCK_EXTERNAL constant 
  99. if ( defined( "WP_HTTP_BLOCK_EXTERNAL" ) && WP_HTTP_BLOCK_EXTERNAL === true ) { 
  100.  
  101. // check if our API endpoint is in the allowed hosts 
  102. $host = parse_url( $this->product->get_api_url(), PHP_URL_HOST ); 
  103.  
  104. if ( ! defined( "WP_ACCESSIBLE_HOSTS" ) || stristr( WP_ACCESSIBLE_HOSTS, $host ) === false ) { 
  105. ?> 
  106. <div class="error"> 
  107. <p><?php printf( __( '<b>Warning!</b> You\'re blocking external requests which means you won\'t be able to get %s updates. Please add %s to %s.', $this->product->get_text_domain() ), $this->product->get_item_name(), '<strong>' . $host . '</strong>', '<code>WP_ACCESSIBLE_HOSTS</code>' ); ?></p> 
  108. </div> 
  109. <?php 
  110.  
  111.  
  112. /** 
  113. * Set a notice to display in the admin area 
  114. * @param string $type error|updated 
  115. * @param string $message The message to display 
  116. */ 
  117. protected function set_notice( $message, $success = true ) { 
  118. $css_class = ( $success ) ? 'updated' : 'error'; 
  119. add_settings_error( $this->prefix . 'license', 'license-notice', $message, $css_class ); 
  120.  
  121. /** 
  122. * Remotely activate License 
  123. * @return boolean True if the license is now activated, false if not 
  124. */ 
  125. public function activate_license() { 
  126.  
  127. $result = $this->call_license_api( 'activate' ); 
  128.  
  129.  
  130. if ( $result ) { 
  131.  
  132. // story expiry date 
  133. if ( isset( $result->expires ) ) { 
  134. $this->set_license_expiry_date( $result->expires ); 
  135. $expiry_date = strtotime( $result->expires ); 
  136. } else { 
  137. $expiry_date = false; 
  138.  
  139. // show success notice if license is valid 
  140. if ( $result->license === 'valid' ) { 
  141.  
  142. $message = sprintf( __( "Your %s license has been activated. ", $this->product->get_text_domain() ), $this->product->get_item_name() ); 
  143.  
  144. // show a custom notice if users have an unlimited license 
  145. if ( $result->license_limit == 0 ) { 
  146. $message .= __( "You have an unlimited license. ", $this->product->get_text_domain() ); 
  147. } else { 
  148. $message .= sprintf( __( "You have used %d/%d activations. ", $this->product->get_text_domain() ), $result->site_count, $result->license_limit ); 
  149.  
  150. // add upgrade notice if user has less than 3 activations left 
  151. if ( $result->license_limit > 0 && ( $result->license_limit - $result->site_count ) <= 3 ) { 
  152. $message .= sprintf( __( '<a href="%s">Did you know you can upgrade your license?</a>', $this->product->get_text_domain() ), $this->product->get_tracking_url( 'license-nearing-limit-notice' ) ); 
  153. // add extend notice if license is expiring in less than 1 month 
  154. } elseif ( $expiry_date !== false && $expiry_date < strtotime( "+1 month" ) ) { 
  155. $days_left = round( ( $expiry_date - strtotime( "now" ) ) / 86400 ); 
  156. $message .= sprintf( __( '<a href="%s">Your license is expiring in %d days, would you like to extend it?</a>', $this->product->get_text_domain() ), $this->product->get_tracking_url( 'license-expiring-notice' ), $days_left ); 
  157.  
  158. $this->set_notice( $message, true ); 
  159.  
  160. } else { 
  161.  
  162. if ( isset( $result->error ) && $result->error === 'no_activations_left' ) { 
  163. // show notice if user is at their activation limit 
  164. $this->set_notice( sprintf( __( 'You\'ve reached your activation limit. You must <a href="%s">upgrade your license</a> to use it on this site.', $this->product->get_text_domain() ), $this->product->get_tracking_url( 'license-at-limit-notice' ) ), false ); 
  165. } elseif ( isset( $result->error ) && $result->error == "expired" ) { 
  166. // show notice if the license is expired 
  167. $this->set_notice( sprintf( __( 'Your license has expired. You must <a href="%s">extend your license</a> in order to use it again.', $this->product->get_text_domain() ), $this->product->get_tracking_url( 'license-expired-notice' ) ), false ); 
  168. } else { 
  169. // show a general notice if it's any other error 
  170. $this->set_notice( __( "Failed to activate your license, your license key seems to be invalid.", $this->product->get_text_domain() ), false ); 
  171.  
  172. $this->remote_license_activation_failed = true; 
  173.  
  174. $this->set_license_status( $result->license ); 
  175.  
  176. return ( $this->license_is_valid() ); 
  177.  
  178. /** 
  179. * Remotely deactivate License 
  180. * @return boolean True if the license is now deactivated, false if not 
  181. */ 
  182. public function deactivate_license() { 
  183.  
  184. $result = $this->call_license_api( 'deactivate' ); 
  185.  
  186. if ( $result ) { 
  187.  
  188. // show notice if license is deactivated 
  189. if ( $result->license === 'deactivated' ) { 
  190. $this->set_notice( sprintf( __( "Your %s license has been deactivated.", $this->product->get_text_domain() ), $this->product->get_item_name() ) ); 
  191. } else { 
  192. $this->set_notice( sprintf( __( "Failed to deactivate your %s license.", $this->product->get_text_domain() ), $this->product->get_item_name() ), false ); 
  193.  
  194. $this->set_license_status( $result->license ); 
  195.  
  196. return ( $this->get_license_status() === 'deactivated' ); 
  197.  
  198. /** 
  199. * @param string $action activate|deactivate 
  200. * @return mixed 
  201. */ 
  202. protected function call_license_api( $action ) { 
  203.  
  204. // don't make a request if license key is empty 
  205. if ( $this->get_license_key() === '' ) { 
  206. return false; 
  207.  
  208. // data to send in our API request 
  209. $api_params = array( 
  210. 'edd_action' => $action . '_license',  
  211. 'license' => $this->get_license_key(),  
  212. 'item_name' => urlencode( trim( $this->product->get_item_name() ) ),  
  213. 'url' => get_option( 'home' ) // grab the URL straight from the option to prevent filters from breaking it. 
  214. ); 
  215.  
  216. // create api request url 
  217. $url = add_query_arg( $api_params, $this->product->get_api_url() ); 
  218.  
  219. require_once dirname( __FILE__ ) . '/class-api-request.php'; 
  220. $request = new Yoast_API_Request( $url ); 
  221.  
  222. if ( $request->is_valid() !== true ) { 
  223. $this->set_notice( sprintf( __( "Request error: \"%s\" (%scommon license notices%s)", $this->product->get_text_domain() ), $request->get_error_message(), '<a href="http://kb.yoast.com/article/13-license-activation-notices">', '</a>' ), false ); 
  224.  
  225. // get response 
  226. $response = $request->get_response(); 
  227.  
  228. // update license status 
  229. $license_data = $response; 
  230.  
  231. return $license_data; 
  232.  
  233.  
  234. /** 
  235. * Set the license status 
  236. * @param string $license_status 
  237. */ 
  238. public function set_license_status( $license_status ) { 
  239. $this->set_option( 'status', $license_status ); 
  240.  
  241. /** 
  242. * Get the license status 
  243. * @return string $license_status; 
  244. */ 
  245. public function get_license_status() { 
  246. $license_status = $this->get_option( 'status' ); 
  247.  
  248. return trim( $license_status ); 
  249.  
  250. /** 
  251. * Set the license key 
  252. * @param string $license_key 
  253. */ 
  254. public function set_license_key( $license_key ) { 
  255. $this->set_option( 'key', $license_key ); 
  256.  
  257. /** 
  258. * Gets the license key from constant or option 
  259. * @return string $license_key 
  260. */ 
  261. public function get_license_key() { 
  262. $license_key = $this->get_option( 'key' ); 
  263.  
  264. return trim( $license_key ); 
  265.  
  266. /** 
  267. * Gets the license expiry date 
  268. * @return string 
  269. */ 
  270. public function get_license_expiry_date() { 
  271. return $this->get_option( 'expiry_date' ); 
  272.  
  273. /** 
  274. * Stores the license expiry date 
  275. */ 
  276. public function set_license_expiry_date( $expiry_date ) { 
  277. $this->set_option( 'expiry_date', $expiry_date ); 
  278.  
  279. /** 
  280. * Checks whether the license status is active 
  281. * @return boolean True if license is active 
  282. */ 
  283. public function license_is_valid() { 
  284. return ( $this->get_license_status() === 'valid' ); 
  285.  
  286. /** 
  287. * Get all license related options 
  288. * @return array Array of license options 
  289. */ 
  290. protected function get_options() { 
  291.  
  292. // create option name 
  293. $option_name = $this->prefix . 'license'; 
  294.  
  295. // get array of options from db 
  296. if ( $this->is_network_activated ) { 
  297. $options = get_site_option( $option_name, array() ); 
  298. } else { 
  299. $options = get_option( $option_name, array() ); 
  300.  
  301. // setup array of defaults 
  302. $defaults = array( 
  303. 'key' => '',  
  304. 'status' => '',  
  305. 'expiry_date' => '' 
  306. ); 
  307.  
  308. // merge options with defaults 
  309. $this->options = wp_parse_args( $options, $defaults ); 
  310.  
  311. return $this->options; 
  312.  
  313. /** 
  314. * Set license related options 
  315. * @param array $options Array of new license options 
  316. */ 
  317. protected function set_options( array $options ) { 
  318. // create option name 
  319. $option_name = $this->prefix . 'license'; 
  320.  
  321. // update db 
  322. if ( $this->is_network_activated ) { 
  323. update_site_option( $option_name, $options ); 
  324. } else { 
  325. update_option( $option_name, $options ); 
  326.  
  327.  
  328. /** 
  329. * Gets a license related option 
  330. * @param string $name The option name 
  331. * @return mixed The option value 
  332. */ 
  333. protected function get_option( $name ) { 
  334. $options = $this->get_options(); 
  335.  
  336. return $options[$name]; 
  337.  
  338. /** 
  339. * Set a license related option 
  340. * @param string $name The option name 
  341. * @param mixed $value The option value 
  342. */ 
  343. protected function set_option( $name, $value ) { 
  344. // get options 
  345. $options = $this->get_options(); 
  346.  
  347. // update option 
  348. $options[$name] = $value; 
  349.  
  350. // save options 
  351. $this->set_options( $options ); 
  352.  
  353. public function show_license_form_heading() { 
  354. ?> 
  355. <h3> 
  356. <?php printf( __( "%s: License Settings", $this->product->get_text_domain() ), $this->product->get_item_name() ); ?>    
  357. </h3> 
  358. <?php 
  359.  
  360. /** 
  361. * Show a form where users can enter their license key 
  362. * @param boolean $embedded Boolean indicating whether this form is embedded in another form? 
  363. */ 
  364. public function show_license_form( $embedded = true ) { 
  365. $key_name = $this->prefix . 'license_key'; 
  366. $nonce_name = $this->prefix . 'license_nonce'; 
  367. $action_name = $this->prefix . 'license_action'; 
  368.  
  369. $api_host_available = $this->get_api_availability(); 
  370.  
  371. $visible_license_key = $this->get_license_key(); 
  372.  
  373. // obfuscate license key 
  374. $obfuscate = ( strlen( $this->get_license_key() ) > 5 && ( $this->license_is_valid() || ! $this->remote_license_activation_failed ) ); 
  375.  
  376. if ( $obfuscate ) { 
  377. $visible_license_key = str_repeat( '*', strlen( $this->get_license_key() ) - 4 ) . substr( $this->get_license_key(), - 4 ); 
  378.  
  379. // make license key readonly when license key is valid or license is defined with a constant 
  380. $readonly = ( $this->license_is_valid() || $this->license_constant_is_defined ); 
  381.  
  382. require dirname( __FILE__ ) . '/views/form.php'; 
  383.  
  384. // enqueue script in the footer 
  385. add_action( 'admin_footer', array( $this, 'output_script' ), 99 ); 
  386.  
  387. /** 
  388. * Check if the license form has been submitted 
  389. */ 
  390. public function catch_post_request() { 
  391.  
  392. $name = $this->prefix . 'license_key'; 
  393.  
  394. // check if license key was posted and not empty 
  395. if ( ! isset( $_POST[$name] ) ) { 
  396. return; 
  397.  
  398. // run a quick security check 
  399. $nonce_name = $this->prefix . 'license_nonce'; 
  400.  
  401. if ( ! check_admin_referer( $nonce_name, $nonce_name ) ) { 
  402. return; 
  403.  
  404. // @TODO: check for user cap? 
  405.  
  406. // get key from posted value 
  407. $license_key = $_POST[$name]; 
  408.  
  409. // check if license key doesn't accidentally contain asterisks 
  410. if ( strstr( $license_key, '*' ) === false ) { 
  411.  
  412. // sanitize key 
  413. $license_key = trim( sanitize_key( $_POST[$name] ) ); 
  414.  
  415. // save license key 
  416. $this->set_license_key( $license_key ); 
  417.  
  418. // does user have an activated valid license 
  419. if ( ! $this->license_is_valid() ) { 
  420.  
  421. // try to auto-activate license 
  422. return $this->activate_license(); 
  423.  
  424.  
  425. $action_name = $this->prefix . 'license_action'; 
  426.  
  427. // was one of the action buttons clicked? 
  428. if ( isset( $_POST[$action_name] ) ) { 
  429.  
  430. $action = trim( $_POST[$action_name] ); 
  431.  
  432. switch ( $action ) { 
  433.  
  434. case 'activate': 
  435. return $this->activate_license(); 
  436. break; 
  437.  
  438. case 'deactivate': 
  439. return $this->deactivate_license(); 
  440. break; 
  441.  
  442.  
  443.  
  444. /** 
  445. * Output the script containing the YoastLicenseManager JS Object 
  446. * This takes care of disabling the 'activate' and 'deactivate' buttons 
  447. */ 
  448. public function output_script() { 
  449. require_once dirname( __FILE__ ) . '/views/script.php'; 
  450.  
  451. /** 
  452. * Set the constant used to define the license 
  453. * @param string $license_constant_name The license constant name 
  454. */ 
  455. public function set_license_constant_name( $license_constant_name ) { 
  456. $this->license_constant_name = trim( $license_constant_name ); 
  457. $this->maybe_set_license_key_from_constant(); 
  458.  
  459. /** 
  460. * Get the API availability information 
  461. * @return array 
  462. */ 
  463. protected function get_api_availability() { 
  464. return array( 
  465. 'url' => $this->product->get_api_url(),  
  466. 'availability' => $this->check_api_host_availability(),  
  467. 'curl_version' => $this->get_curl_version(),  
  468. ); 
  469.  
  470. /** 
  471. * Check if the API host address is available from this server 
  472. * @return bool 
  473. */ 
  474. private function check_api_host_availability() { 
  475. $wp_http = new WP_Http(); 
  476. if ( $wp_http->block_request( $this->product->get_api_url() ) === false ) { 
  477. return true; 
  478.  
  479. return false; 
  480.  
  481. /** 
  482. * Get the current curl version, or false 
  483. * @return mixed 
  484. */ 
  485. protected function get_curl_version() { 
  486. if ( function_exists( 'curl_version' ) ) { 
  487. $curl_version = curl_version(); 
  488.  
  489. if ( isset( $curl_version['version'] ) ) { 
  490. return $curl_version['version']; 
  491.  
  492. return false; 
  493.  
  494. /** 
  495. * Maybe set license key from a defined constant 
  496. */ 
  497. private function maybe_set_license_key_from_constant() { 
  498.  
  499. if ( empty( $this->license_constant_name ) ) { 
  500. // generate license constant name 
  501. $this->set_license_constant_name( strtoupper( str_replace( array( ' ', '-' ), '', sanitize_key( $this->product->get_item_name() ) ) ) . '_LICENSE' ); 
  502.  
  503. // set license key from constant 
  504. if ( defined( $this->license_constant_name ) ) { 
  505.  
  506. $license_constant_value = constant( $this->license_constant_name ); 
  507.  
  508. // update license key value with value of constant 
  509. if ( $this->get_license_key() !== $license_constant_value ) { 
  510. $this->set_license_key( $license_constant_value ); 
  511.  
  512. $this->license_constant_is_defined = true;