api.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. <?php
  2. namespace Elementor;
  3. if ( ! defined( 'ABSPATH' ) ) {
  4. exit; // Exit if accessed directly.
  5. }
  6. /**
  7. * Elementor API.
  8. *
  9. * Elementor API handler class is responsible for communicating with Elementor
  10. * remote servers retrieving templates data and to send uninstall feedback.
  11. *
  12. * @since 1.0.0
  13. */
  14. class Api {
  15. /**
  16. * Elementor library option key.
  17. */
  18. const LIBRARY_OPTION_KEY = 'elementor_remote_info_library';
  19. /**
  20. * Elementor feed option key.
  21. */
  22. const FEED_OPTION_KEY = 'elementor_remote_info_feed_data';
  23. /**
  24. * API info URL.
  25. *
  26. * Holds the URL of the info API.
  27. *
  28. * @access public
  29. * @static
  30. *
  31. * @var string API info URL.
  32. */
  33. public static $api_info_url = 'http://my.elementor.com/api/v1/info/';
  34. /**
  35. * API feedback URL.
  36. *
  37. * Holds the URL of the feedback API.
  38. *
  39. * @access private
  40. * @static
  41. *
  42. * @var string API feedback URL.
  43. */
  44. private static $api_feedback_url = 'http://my.elementor.com/api/v1/feedback/';
  45. /**
  46. * API get template content URL.
  47. *
  48. * Holds the URL of the template content API.
  49. *
  50. * @access private
  51. * @static
  52. *
  53. * @var string API get template content URL.
  54. */
  55. private static $api_get_template_content_url = 'http://my.elementor.com/api/v1/templates/%d';
  56. /**
  57. * Get info data.
  58. *
  59. * This function notifies the user of upgrade notices, new templates and contributors.
  60. *
  61. * @since 2.0.0
  62. * @access private
  63. * @static
  64. *
  65. * @param bool $force_update Optional. Whether to force the data retrieval or
  66. * not. Default is false.
  67. *
  68. * @return array|false Info data, or false.
  69. */
  70. private static function get_info_data( $force_update = false ) {
  71. $cache_key = 'elementor_remote_info_api_data_' . ELEMENTOR_VERSION;
  72. $info_data = get_transient( $cache_key );
  73. if ( $force_update || false === $info_data ) {
  74. $timeout = ( $force_update ) ? 25 : 8;
  75. $response = wp_remote_post( self::$api_info_url, [
  76. 'timeout' => $timeout,
  77. 'body' => [
  78. // Which API version is used.
  79. 'api_version' => ELEMENTOR_VERSION,
  80. // Which language to return.
  81. 'site_lang' => get_bloginfo( 'language' ),
  82. ],
  83. ] );
  84. if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
  85. set_transient( $cache_key, [], 2 * HOUR_IN_SECONDS );
  86. return false;
  87. }
  88. $info_data = json_decode( wp_remote_retrieve_body( $response ), true );
  89. if ( empty( $info_data ) || ! is_array( $info_data ) ) {
  90. set_transient( $cache_key, [], 2 * HOUR_IN_SECONDS );
  91. return false;
  92. }
  93. if ( isset( $info_data['library'] ) ) {
  94. $info_data['library']['categories'] = json_decode( $info_data['library']['categories'] );
  95. update_option( self::LIBRARY_OPTION_KEY, $info_data['library'], 'no' );
  96. unset( $info_data['library'] );
  97. }
  98. if ( isset( $info_data['feed'] ) ) {
  99. update_option( self::FEED_OPTION_KEY, $info_data['feed'], 'no' );
  100. unset( $info_data['feed'] );
  101. }
  102. set_transient( $cache_key, $info_data, 12 * HOUR_IN_SECONDS );
  103. }
  104. return $info_data;
  105. }
  106. /**
  107. * Get upgrade notice.
  108. *
  109. * Retrieve the upgrade notice if one exists, or false otherwise.
  110. *
  111. * @since 1.0.0
  112. * @access public
  113. * @static
  114. *
  115. * @return array|false Upgrade notice, or false none exist.
  116. */
  117. public static function get_upgrade_notice() {
  118. $data = self::get_info_data();
  119. if ( empty( $data['upgrade_notice'] ) ) {
  120. return false;
  121. }
  122. return $data['upgrade_notice'];
  123. }
  124. /**
  125. * Get templates data.
  126. *
  127. * Retrieve the templates data from a remote server.
  128. *
  129. * @since 2.0.0
  130. * @access public
  131. * @static
  132. *
  133. * @param bool $force_update Optional. Whether to force the data update or
  134. * not. Default is false.
  135. *
  136. * @return array The templates data.
  137. */
  138. public static function get_library_data( $force_update = false ) {
  139. self::get_info_data( $force_update );
  140. $library_data = get_option( self::LIBRARY_OPTION_KEY );
  141. if ( empty( $library_data ) ) {
  142. return [];
  143. }
  144. return $library_data;
  145. }
  146. /**
  147. * Get feed data.
  148. *
  149. * Retrieve the feed info data from remote elementor server.
  150. *
  151. * @since 1.9.0
  152. * @access public
  153. * @static
  154. *
  155. * @param bool $force_update Optional. Whether to force the data update or
  156. * not. Default is false.
  157. *
  158. * @return array Feed data.
  159. */
  160. public static function get_feed_data( $force_update = false ) {
  161. self::get_info_data( $force_update );
  162. $feed = get_option( self::FEED_OPTION_KEY );
  163. if ( empty( $feed ) ) {
  164. return [];
  165. }
  166. return $feed;
  167. }
  168. /**
  169. * Get template content.
  170. *
  171. * Retrieve the templates content received from a remote server.
  172. *
  173. * @since 1.0.0
  174. * @access public
  175. * @static
  176. *
  177. * @param int $template_id The template ID.
  178. *
  179. * @return array The template content.
  180. */
  181. public static function get_template_content( $template_id ) {
  182. $url = sprintf( self::$api_get_template_content_url, $template_id );
  183. $body_args = [
  184. // Which API version is used.
  185. 'api_version' => ELEMENTOR_VERSION,
  186. // Which language to return.
  187. 'site_lang' => get_bloginfo( 'language' ),
  188. ];
  189. /**
  190. * API: Template body args.
  191. *
  192. * Filters the body arguments send with the GET request when fetching the content.
  193. *
  194. * @since 1.0.0
  195. *
  196. * @param array $body_args Body arguments.
  197. */
  198. $body_args = apply_filters( 'elementor/api/get_templates/body_args', $body_args );
  199. $response = wp_remote_get( $url, [
  200. 'timeout' => 40,
  201. 'body' => $body_args,
  202. ] );
  203. if ( is_wp_error( $response ) ) {
  204. return $response;
  205. }
  206. $response_code = (int) wp_remote_retrieve_response_code( $response );
  207. if ( 200 !== $response_code ) {
  208. return new \WP_Error( 'response_code_error', sprintf( 'The request returned with a status code of %s.', $response_code ) );
  209. }
  210. $template_content = json_decode( wp_remote_retrieve_body( $response ), true );
  211. if ( isset( $template_content['error'] ) ) {
  212. return new \WP_Error( 'response_error', $template_content['error'] );
  213. }
  214. if ( empty( $template_content['data'] ) && empty( $template_content['content'] ) ) {
  215. return new \WP_Error( 'template_data_error', 'An invalid data was returned.' );
  216. }
  217. return $template_content;
  218. }
  219. /**
  220. * Send Feedback.
  221. *
  222. * Fires a request to Elementor server with the feedback data.
  223. *
  224. * @since 1.0.0
  225. * @access public
  226. * @static
  227. *
  228. * @param string $feedback_key Feedback key.
  229. * @param string $feedback_text Feedback text.
  230. *
  231. * @return array The response of the request.
  232. */
  233. public static function send_feedback( $feedback_key, $feedback_text ) {
  234. return wp_remote_post( self::$api_feedback_url, [
  235. 'timeout' => 30,
  236. 'body' => [
  237. 'api_version' => ELEMENTOR_VERSION,
  238. 'site_lang' => get_bloginfo( 'language' ),
  239. 'feedback_key' => $feedback_key,
  240. 'feedback' => $feedback_text,
  241. ],
  242. ] );
  243. }
  244. /**
  245. * Ajax reset API data.
  246. *
  247. * Reset Elementor library API data using an ajax call.
  248. *
  249. * @since 1.0.0
  250. * @access public
  251. * @static
  252. */
  253. public static function ajax_reset_api_data() {
  254. check_ajax_referer( 'elementor_reset_library', '_nonce' );
  255. self::get_info_data( true );
  256. wp_send_json_success();
  257. }
  258. /**
  259. * Init.
  260. *
  261. * Initialize Elementor API.
  262. *
  263. * @since 1.0.0
  264. * @access public
  265. * @static
  266. */
  267. public static function init() {
  268. add_action( 'wp_ajax_elementor_reset_library', [ __CLASS__, 'ajax_reset_api_data' ] );
  269. }
  270. }