No Description

License.php 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. <?php
  2. /*******************************************************************************
  3. * Copyright (c) 2019, Code Atlantic LLC
  4. ******************************************************************************/
  5. if ( ! defined( 'ABSPATH' ) ) {
  6. exit;
  7. }
  8. /**
  9. * License handler for Popup Maker
  10. *
  11. * This class should simplify the process of adding license information to new Popup Maker extensions.
  12. *
  13. * Note for wordpress.org admins. This is not called in the free hosted version and is simply used for hooking in addons to one update system rather than including it in each plugin.
  14. *
  15. * @version 1.1
  16. */
  17. class PUM_Extension_License {
  18. private $file;
  19. private $license;
  20. private $item_name;
  21. private $item_id;
  22. private $item_shortname;
  23. private $version;
  24. private $author;
  25. private $api_url = 'https://wppopupmaker.com/edd-sl-api/';
  26. /**
  27. * Class constructor
  28. *
  29. * @param string $_file
  30. * @param string $_item_name
  31. * @param string $_version
  32. * @param string $_author
  33. * @param string $_optname
  34. * @param string $_api_url
  35. * @param int $_item_id
  36. */
  37. function __construct( $_file, $_item_name, $_version, $_author, $_optname = null, $_api_url = null, $_item_id = null ) {
  38. $this->file = $_file;
  39. $this->item_name = $_item_name;
  40. if ( is_numeric( $_item_id ) ) {
  41. $this->item_id = absint( $_item_id );
  42. }
  43. $this->item_shortname = 'popmake_' . preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->item_name ) ) );
  44. $this->version = $_version;
  45. $this->license = trim( PUM_Utils_Options::get( $this->item_shortname . '_license_key', '' ) );
  46. $this->author = $_author;
  47. $this->api_url = is_null( $_api_url ) ? $this->api_url : $_api_url;
  48. /**
  49. * Allows for backwards compatibility with old license options,
  50. * i.e. if the plugins had license key fields previously, the license
  51. * handler will automatically pick these up and use those in lieu of the
  52. * user having to reactive their license.
  53. */
  54. if ( ! empty( $_optname ) ) {
  55. $opt = PUM_Utils_Options::get( $_optname );
  56. if ( isset( $opt ) && empty( $this->license ) ) {
  57. $this->license = trim( $opt );
  58. }
  59. }
  60. // Setup hooks
  61. $this->includes();
  62. $this->hooks();
  63. }
  64. /**
  65. * Include the updater class
  66. *
  67. * @access private
  68. * @return void
  69. */
  70. private function includes() {
  71. }
  72. /**
  73. * Setup hooks
  74. *
  75. * @access private
  76. * @return void
  77. */
  78. private function hooks() {
  79. // Register settings
  80. add_filter( 'pum_settings_fields', array( $this, 'settings' ), 1 );
  81. // Activate license key on settings save
  82. add_action( 'admin_init', array( $this, 'activate_license' ) );
  83. // Deactivate license key
  84. add_action( 'admin_init', array( $this, 'deactivate_license' ) );
  85. // Check that license is valid once per week
  86. add_action( 'popmake_weekly_scheduled_events', array( $this, 'weekly_license_check' ) );
  87. // For testing license notices, uncomment this line to force checks on every page load
  88. //add_action( 'admin_init', array( $this, 'weekly_license_check' ) );
  89. // Updater
  90. add_action( 'admin_init', array( $this, 'auto_updater' ), 0 );
  91. // Display notices to admins
  92. // add_action( 'admin_notices', array( $this, 'notices' ) );
  93. // Display notices to admins
  94. add_filter( 'pum_alert_list', array( $this, 'alerts' ) );
  95. add_action( 'in_plugin_update_message-' . plugin_basename( $this->file ), array( $this, 'plugin_row_license_missing' ), 10, 2 );
  96. // Register plugins for beta support
  97. add_filter( 'pum_beta_enabled_extensions', array( $this, 'register_beta_support' ) );
  98. }
  99. /**
  100. * Auto updater
  101. *
  102. * @access private
  103. * @return void
  104. */
  105. public function auto_updater() {
  106. $args = array(
  107. 'version' => $this->version,
  108. 'license' => $this->license,
  109. 'author' => $this->author,
  110. 'beta' => PUM_Admin_Tools::extension_has_beta_support( $this->item_shortname ),
  111. );
  112. if ( ! empty( $this->item_id ) ) {
  113. $args['item_id'] = $this->item_id;
  114. } else {
  115. $args['item_name'] = $this->item_name;
  116. }
  117. // Setup the updater
  118. $popmake_updater = new PUM_Extension_Updater( $this->api_url, $this->file, $args );
  119. }
  120. /**
  121. * Add license field to settings
  122. *
  123. * @access public
  124. *
  125. * @param array $tabs
  126. *
  127. * @return array
  128. */
  129. public function settings( $tabs = array() ) {
  130. static $license_help_text = false;
  131. if ( ! $license_help_text && ! isset( $tabs['licenses']['main']['license_help_text'] ) ) {
  132. $license_help_text = true;
  133. $tabs['licenses']['main']['license_help_text'] = array(
  134. 'type' => 'html',
  135. 'content' => '<p><strong>' . sprintf( __( 'Enter your extension license keys here to receive updates for purchased extensions. If your license key has expired, please %srenew your license%s.', 'popup-maker' ), '<a href="https://docs.wppopupmaker.com/article/177-license-renewal?utm_medium=license-help-text&utm_campaign=Licensing&utm_source=plugin-settings-page-licenses-tab" target="_blank">', '</a>' ) . '</strong></p>',
  136. 'priority' => 0,
  137. );
  138. }
  139. $tabs['licenses']['main'][ $this->item_shortname . '_license_key' ] = array(
  140. 'type' => 'license_key',
  141. 'label' => sprintf( __( '%1$s', 'popup-maker' ), $this->item_name ),
  142. 'options' => array(
  143. 'is_valid_license_option' => $this->item_shortname . '_license_active',
  144. 'activation_callback' => array( $this, 'activate_license' ),
  145. ),
  146. );
  147. return $tabs;
  148. }
  149. /**
  150. * Activate the license key
  151. *
  152. * @access public
  153. * @return void
  154. */
  155. public function activate_license() {
  156. if ( ! isset( $_POST['pum_settings'] ) ) {
  157. return;
  158. }
  159. if ( ! isset( $_POST['pum_settings'][ $this->item_shortname . '_license_key' ] ) ) {
  160. return;
  161. }
  162. // Don't activate a key when deactivating a different key
  163. if ( ! empty( $_POST['pum_license_deactivate'] ) ) {
  164. return;
  165. }
  166. if ( ! current_user_can( 'manage_options' ) ) {
  167. return;
  168. }
  169. $details = get_option( $this->item_shortname . '_license_active' );
  170. if ( is_object( $details ) && 'valid' === $details->license ) {
  171. return;
  172. }
  173. $license = sanitize_text_field( $_POST['pum_settings'][ $this->item_shortname . '_license_key' ] );
  174. if ( empty( $license ) && empty( $_POST['pum_license_activate'][ $this->item_shortname . '_license_key' ] ) ) {
  175. return;
  176. }
  177. // Data to send to the API
  178. $api_params = array(
  179. 'edd_action' => 'activate_license',
  180. 'license' => $license,
  181. 'item_id' => $this->item_id,
  182. 'item_name' => rawurlencode( $this->item_name ),
  183. 'url' => home_url(),
  184. 'environment' => function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production',
  185. );
  186. // Call the API
  187. $response = wp_remote_post( $this->api_url, array(
  188. 'timeout' => 15,
  189. 'sslverify' => false,
  190. 'body' => $api_params,
  191. ) );
  192. // Make sure there are no errors
  193. if ( is_wp_error( $response ) ) {
  194. return;
  195. }
  196. // Tell WordPress to look for updates
  197. set_site_transient( 'update_plugins', null );
  198. // Decode license data
  199. $license_data = json_decode( wp_remote_retrieve_body( $response ) );
  200. update_option( $this->item_shortname . '_license_active', $license_data );
  201. }
  202. /**
  203. * Deactivate the license key
  204. *
  205. * @access public
  206. * @return void
  207. */
  208. public function deactivate_license() {
  209. if ( ! isset( $_POST['pum_settings'] ) ) {
  210. return;
  211. }
  212. if ( ! isset( $_POST['pum_settings'][ $this->item_shortname . '_license_key' ] ) ) {
  213. return;
  214. }
  215. if ( ! current_user_can( 'manage_options' ) ) {
  216. return;
  217. }
  218. // Run on deactivate button press
  219. if ( isset( $_POST['pum_license_deactivate'][ $this->item_shortname . '_license_key' ] ) ) {
  220. // Data to send to the API
  221. $api_params = array(
  222. 'edd_action' => 'deactivate_license',
  223. 'license' => $this->license,
  224. 'item_name' => urlencode( $this->item_name ),
  225. 'url' => home_url(),
  226. );
  227. // Call the API
  228. $response = wp_remote_post( $this->api_url, array(
  229. 'timeout' => 15,
  230. 'sslverify' => false,
  231. 'body' => $api_params,
  232. ) );
  233. // Make sure there are no errors
  234. if ( is_wp_error( $response ) ) {
  235. return;
  236. }
  237. // Decode the license data
  238. $license_data = json_decode( wp_remote_retrieve_body( $response ) );
  239. delete_option( $this->item_shortname . '_license_active' );
  240. }
  241. }
  242. /**
  243. * Check if license key is valid once per week
  244. *
  245. * @access public
  246. * @since 2.5
  247. * @return void
  248. */
  249. public function weekly_license_check() {
  250. if ( ! empty( $_POST['popmake_settings'] ) ) {
  251. return; // Don't fire when saving settings
  252. }
  253. if ( empty( $this->license ) ) {
  254. return;
  255. }
  256. // data to send in our API request
  257. $api_params = array(
  258. 'edd_action' => 'check_license',
  259. 'license' => $this->license,
  260. 'item_name' => urlencode( $this->item_name ),
  261. 'url' => home_url(),
  262. );
  263. // Call the API
  264. $response = wp_remote_post( $this->api_url, array(
  265. 'timeout' => 15,
  266. 'sslverify' => false,
  267. 'body' => $api_params,
  268. ) );
  269. // make sure the response came back okay
  270. if ( is_wp_error( $response ) ) {
  271. return;
  272. }
  273. $license_data = json_decode( wp_remote_retrieve_body( $response ) );
  274. update_option( $this->item_shortname . '_license_active', $license_data );
  275. }
  276. /**
  277. * Adds an alert to the Popup Maker notification area when the license is invalid, expired, or empty
  278. *
  279. * @param array $alerts The existing alerts from the pum_alert_list filter
  280. * @return array Our modified array of alerts
  281. */
  282. public function alerts( $alerts = array() ) {
  283. static $showed_invalid_message;
  284. // If user can't manage it, or we already showed this alert abort.
  285. if ( ! current_user_can( 'manage_options' ) || $showed_invalid_message ) {
  286. return $alerts;
  287. }
  288. // If this alert is already in the list of alerts, abort.
  289. foreach ( $alerts as $alert ) {
  290. if ( 'license_not_valid' === $alert['code'] ) {
  291. return $alerts;
  292. }
  293. }
  294. // If this license key is not empty, check if it's valid.
  295. if ( ! empty( $this->license ) ) {
  296. $license = get_option( $this->item_shortname . '_license_active' );
  297. if ( ! is_object( $license ) || 'valid' === $license->license ) {
  298. return $alerts;
  299. }
  300. }
  301. $showed_invalid_message = true;
  302. if ( empty( $this->license ) ) {
  303. $alerts[] = array(
  304. 'code' => 'license_not_valid',
  305. 'message' => sprintf( __( 'One or more of your extensions are missing license keys. You will not be able to receive updates until the extension has a valid license key entered. Please go to the %sLicenses page%s to add your license keys.', 'popup-maker' ), '<a href="' . admin_url( 'edit.php?post_type=popup&page=pum-settings&tab=licenses' ) . '">', '</a>' ),
  306. 'type' => 'error',
  307. 'dismissible' => '4 weeks',
  308. 'priority' => 0,
  309. );
  310. } else {
  311. $alerts[] = array(
  312. 'code' => 'license_not_valid',
  313. 'message' => sprintf( __( 'You have invalid or expired license keys for Popup Maker. Please go to the %sLicenses page%s to correct this issue.', 'popup-maker' ), '<a href="' . admin_url( 'edit.php?post_type=popup&page=pum-settings&tab=licenses' ) . '">', '</a>' ),
  314. 'type' => 'error',
  315. 'dismissible' => '4 weeks',
  316. 'priority' => 0,
  317. );
  318. }
  319. return $alerts;
  320. }
  321. /**
  322. * Admin notices for errors
  323. *
  324. * @access public
  325. * @return void
  326. */
  327. public function notices() {
  328. static $showed_invalid_message;
  329. if ( empty( $this->license ) ) {
  330. return;
  331. }
  332. if ( ! current_user_can( 'manage_options' ) || $showed_invalid_message ) {
  333. return;
  334. }
  335. $messages = array();
  336. $license = get_option( $this->item_shortname . '_license_active' );
  337. if ( is_object( $license ) && 'valid' !== $license->license ) {
  338. if ( empty( $_GET['tab'] ) || 'licenses' !== $_GET['tab'] ) {
  339. $messages[] = sprintf( __( 'You have invalid or expired license keys for Popup Maker. Please go to the %sLicenses page%s to correct this issue.', 'popup-maker' ), '<a href="' . admin_url( 'edit.php?post_type=popup&page=pum-settings&tab=licenses' ) . '">', '</a>' );
  340. $showed_invalid_message = true;
  341. }
  342. }
  343. if ( ! empty( $messages ) ) {
  344. foreach ( $messages as $message ) {
  345. echo '<div class="error">';
  346. echo '<p>' . $message . '</p>';
  347. echo '</div>';
  348. }
  349. }
  350. }
  351. /**
  352. * Displays message inline on plugin row that the license key is missing
  353. */
  354. public function plugin_row_license_missing( $plugin_data, $version_info ) {
  355. static $showed_imissing_key_message;
  356. $license = get_option( $this->item_shortname . '_license_active' );
  357. if ( ( ! is_object( $license ) || 'valid' !== $license->license ) && empty( $showed_imissing_key_message[ $this->item_shortname ] ) ) {
  358. echo '&nbsp;<strong><a href="' . esc_url( admin_url( 'edit.php?post_type=popup&page=pum-settings&tab=licenses' ) ) . '">' . __( 'Enter valid license key for automatic updates.', 'popup-maker' ) . '</a></strong>';
  359. $showed_imissing_key_message[ $this->item_shortname ] = true;
  360. }
  361. }
  362. /**
  363. * Adds this plugin to the beta page
  364. *
  365. * @access public
  366. *
  367. * @param array $products
  368. *
  369. * @return array
  370. */
  371. public function register_beta_support( $products ) {
  372. $products[ $this->item_shortname ] = $this->item_name;
  373. return $products;
  374. }
  375. }