ajax.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. <?php
  2. class Meow_WR2X_Ajax {
  3. public $core = null;
  4. public function __construct( $core) {
  5. $this->core = $core;
  6. add_action( 'wp_ajax_wr2x_generate', array( $this, 'wp_ajax_wr2x_generate' ) );
  7. add_action( 'wp_ajax_wr2x_delete', array( $this, 'wp_ajax_wr2x_delete' ) );
  8. add_action( 'wp_ajax_wr2x_delete_full', array( $this, 'wp_ajax_wr2x_delete_full' ) );
  9. add_action( 'wp_ajax_wr2x_list_all', array( $this, 'wp_ajax_wr2x_list_all' ) );
  10. add_action( 'wp_ajax_wr2x_replace', array( $this, 'wp_ajax_wr2x_replace' ) );
  11. add_action( 'wp_ajax_wr2x_upload', array( $this, 'wp_ajax_wr2x_upload' ) );
  12. add_action( 'wp_ajax_wr2x_retina_upload', array( $this, 'wp_ajax_wr2x_retina_upload' ) );
  13. add_action( 'wp_ajax_wr2x_retina_details', array( $this, 'wp_ajax_wr2x_retina_details' ) );
  14. }
  15. /**
  16. * Checks nonce for the specified action
  17. * @param string $action
  18. */
  19. function check_nonce( $action ) {
  20. if ( !wp_verify_nonce( $_POST['nonce'], $action ) ) {
  21. echo json_encode(
  22. array (
  23. 'success' => false,
  24. 'message' => __( "Invalid API request.", 'wp-retina-2x' )
  25. )
  26. );
  27. die();
  28. }
  29. }
  30. /**
  31. * Checks if the current user has sufficient permissions to perform the Ajax actions
  32. */
  33. function check_capability() {
  34. $cap = 'upload_files';
  35. if ( !current_user_can( $cap ) ) {
  36. echo json_encode(
  37. array (
  38. 'success' => false,
  39. 'message' => __( "You do not have permission to upload files.", 'wp-retina-2x' )
  40. )
  41. );
  42. die();
  43. }
  44. }
  45. /**
  46. *
  47. * AJAX SERVER-SIDE
  48. *
  49. */
  50. // Using issuesOnly, only the IDs with a PENDING status will be processed
  51. function wp_ajax_wr2x_list_all( $issuesOnly ) {
  52. $this->check_nonce( 'wr2x_list_all' );
  53. $this->check_capability();
  54. $issuesOnly = intval( $_POST['issuesOnly'] );
  55. if ( $issuesOnly == 1 ) {
  56. $ids = $this->core->get_issues();
  57. echo json_encode(
  58. array(
  59. 'success' => true,
  60. 'message' => "List of issues only.",
  61. 'ids' => $ids,
  62. 'total' => count( $ids )
  63. ) );
  64. die;
  65. }
  66. $reply = array();
  67. try {
  68. $ids = array();
  69. $total = 0;
  70. global $wpdb;
  71. $postids = $wpdb->get_col( "
  72. SELECT p.ID
  73. FROM $wpdb->posts p
  74. WHERE post_status = 'inherit'
  75. AND post_type = 'attachment'
  76. AND ( post_mime_type = 'image/jpeg' OR
  77. post_mime_type = 'image/png' OR
  78. post_mime_type = 'image/gif' )
  79. " );
  80. foreach ($postids as $id) {
  81. if ( $this->core->is_ignore( $id ) )
  82. continue;
  83. array_push( $ids, $id );
  84. $total++;
  85. }
  86. echo json_encode(
  87. array(
  88. 'success' => true,
  89. 'message' => "List of everything.",
  90. 'ids' => $ids,
  91. 'total' => $total
  92. ) );
  93. die;
  94. }
  95. catch (Exception $e) {
  96. echo json_encode(
  97. array(
  98. 'success' => false,
  99. 'message' => $e->getMessage()
  100. ) );
  101. die;
  102. }
  103. }
  104. function wp_ajax_wr2x_delete_full( $pleaseReturn = false ) {
  105. if ( !$pleaseReturn ) $this->check_nonce( 'wr2x_delete_full' );
  106. $this->check_capability();
  107. if ( !isset( $_POST['attachmentId'] ) ) {
  108. echo json_encode(
  109. array(
  110. 'success' => false,
  111. 'message' => __( "The attachment ID is missing.", 'wp-retina-2x' )
  112. )
  113. );
  114. die();
  115. }
  116. $attachmentId = intval( $_POST['attachmentId'] );
  117. $originalfile = get_attached_file( $attachmentId );
  118. $pathinfo = pathinfo( $originalfile );
  119. $retina_file = trailingslashit( $pathinfo['dirname'] ) . $pathinfo['filename'] . $this->core->retina_extension() . $pathinfo['extension'];
  120. if ( $retina_file && file_exists( $retina_file ) )
  121. unlink( $retina_file );
  122. // RESULTS FOR RETINA DASHBOARD
  123. $info = $this->core->html_get_basic_retina_info_full( $attachmentId, $this->core->retina_info( $attachmentId ) );
  124. $results[$attachmentId] = $info;
  125. // Return if that's not the final step.
  126. if ( $pleaseReturn )
  127. return $info;
  128. echo json_encode(
  129. array(
  130. 'results' => $results,
  131. 'success' => true,
  132. 'message' => __( "Full retina file deleted.", 'wp-retina-2x' )
  133. )
  134. );
  135. die();
  136. }
  137. function wp_ajax_wr2x_delete() {
  138. $this->check_nonce( 'wr2x_delete' );
  139. $this->check_capability();
  140. if ( !isset( $_POST['attachmentId'] ) ) {
  141. echo json_encode(
  142. array(
  143. 'success' => false,
  144. 'message' => __( "The attachment ID is missing.", 'wp-retina-2x' )
  145. )
  146. );
  147. die();
  148. }
  149. // Information for the retina version of the full-size
  150. $attachmentId = intval( $_POST['attachmentId'] );
  151. $results_full[$attachmentId] = $this->wp_ajax_wr2x_delete_full( true );
  152. $this->core->delete_attachment( $attachmentId, true );
  153. $meta = wp_get_attachment_metadata( $attachmentId );
  154. // RESULTS FOR RETINA DASHBOARD
  155. $this->core->update_issue_status( $attachmentId );
  156. $info = $this->core->html_get_basic_retina_info( $attachmentId, $this->core->retina_info( $attachmentId ) );
  157. $results[$attachmentId] = $info;
  158. echo json_encode(
  159. array(
  160. 'results' => $results,
  161. 'results_full' => $results_full,
  162. 'success' => true,
  163. 'message' => __( "Retina files deleted.", 'wp-retina-2x' )
  164. )
  165. );
  166. die();
  167. }
  168. function wp_ajax_wr2x_retina_details() {
  169. $this->check_nonce( 'wr2x_retina_details' );
  170. $this->check_capability();
  171. if ( !isset( $_POST['attachmentId'] ) ) {
  172. echo json_encode(
  173. array(
  174. 'success' => false,
  175. 'message' => __( "The attachment ID is missing.", 'wp-retina-2x' )
  176. )
  177. );
  178. die();
  179. }
  180. $attachmentId = intval( $_POST['attachmentId'] );
  181. $info = $this->core->html_get_details_retina_info( $attachmentId, $this->core->retina_info( $attachmentId ) );
  182. echo json_encode(
  183. array(
  184. 'result' => $info,
  185. 'success' => true,
  186. 'message' => __( "Details retrieved.", 'wp-retina-2x' )
  187. )
  188. );
  189. die();
  190. }
  191. function wp_ajax_wr2x_generate() {
  192. $this->check_nonce( 'wr2x_generate' );
  193. $this->check_capability();
  194. if ( !isset( $_POST['attachmentId'] ) ) {
  195. echo json_encode(
  196. array(
  197. 'success' => false,
  198. 'message' => __( "The attachment ID is missing.", 'wp-retina-2x' )
  199. )
  200. );
  201. die();
  202. }
  203. $attachmentId = intval( $_POST['attachmentId'] );
  204. /**
  205. * @param $attachmentId ID of the attchment to regenerate
  206. */
  207. do_action( 'wr2x_before_regenerate', $attachmentId );
  208. $this->core->delete_attachment( $attachmentId, false );
  209. // Regenerate the Thumbnails
  210. $regenerate = get_option( 'wr2x_regenerate_thumbnails', false );
  211. if ( $regenerate ) {
  212. /**
  213. * @param $attachmentId ID of the attachment to generate thumbnails
  214. */
  215. do_action( 'wr2x_before_generate_thumbnails', $attachmentId );
  216. $file = get_attached_file( $attachmentId );
  217. $meta = wp_generate_attachment_metadata( $attachmentId, $file );
  218. wp_update_attachment_metadata( $attachmentId, $meta );
  219. /**
  220. * @param $attachmentId ID of the attachment that has generated its thumbnails
  221. */
  222. do_action( 'wr2x_generate_thumbnails', $attachmentId );
  223. }
  224. // Regenerate Retina
  225. $meta = wp_get_attachment_metadata( $attachmentId );
  226. $this->core->generate_images( $meta );
  227. /**
  228. * @param $attachmentId ID of the attachment that has been regenerated
  229. */
  230. do_action( 'wr2x_regenerate', $attachmentId );
  231. // RESULTS FOR RETINA DASHBOARD
  232. $info = $this->core->html_get_basic_retina_info( $attachmentId, $this->core->retina_info( $attachmentId ) );
  233. $results[$attachmentId] = $info;
  234. echo json_encode(
  235. array(
  236. 'results' => $results,
  237. 'success' => true,
  238. 'message' => __( "Retina files generated.", 'wp-retina-2x' )
  239. )
  240. );
  241. die();
  242. }
  243. function check_get_ajax_uploaded_file() {
  244. $this->check_capability();
  245. $tmpfname = $_FILES['file']['tmp_name'];
  246. // Check if it is an image
  247. $file_info = getimagesize( $tmpfname );
  248. if ( empty( $file_info ) ) {
  249. $this->core->log( "The file is not an image or the upload went wrong." );
  250. unlink( $tmpfname );
  251. echo json_encode( array(
  252. 'success' => false,
  253. 'message' => __( "The file is not an image or the upload went wrong.", 'wp-retina-2x' )
  254. ));
  255. die();
  256. }
  257. $filedata = wp_check_filetype_and_ext( $tmpfname, $_POST['filename'] );
  258. if ( $filedata["ext"] == "" ) {
  259. $this->core->log( "You cannot use this file (wrong extension? wrong type?)." );
  260. unlink( $current_file );
  261. echo json_encode( array(
  262. 'success' => false,
  263. 'message' => __( "You cannot use this file (wrong extension? wrong type?).", 'wp-retina-2x' )
  264. ));
  265. die();
  266. }
  267. $this->core->log( "The temporary file was written successfully." );
  268. return $tmpfname;
  269. }
  270. function wp_ajax_wr2x_upload( $checksNonce = true ) {
  271. if ( $checksNonce ) $this->check_nonce( 'wr2x_upload' );
  272. try {
  273. $tmpfname = $this->check_get_ajax_uploaded_file();
  274. $attachmentId = (int) $_POST['attachmentId'];
  275. $meta = wp_get_attachment_metadata( $attachmentId );
  276. $current_file = get_attached_file( $attachmentId );
  277. $pathinfo = pathinfo( $current_file );
  278. $basepath = $pathinfo['dirname'];
  279. $retinafile = trailingslashit( $pathinfo['dirname'] ) . $pathinfo['filename'] . $this->core->retina_extension() . $pathinfo['extension'];
  280. /**
  281. * @param $attachmentId ID of the attachment that the uploaded retina image is attached to
  282. * @param $retinafile Path to the uploaded retina image
  283. */
  284. do_action( 'wr2x_before_upload_retina', $attachmentId, $retinafile );
  285. if ( file_exists( $retinafile ) )
  286. unlink( $retinafile );
  287. // Insert the new file and delete the temporary one
  288. list( $width, $height ) = getimagesize( $tmpfname );
  289. if ( !$this->core->are_dimensions_ok( $width, $height, $meta['width'] * 2, $meta['height'] * 2 ) ) {
  290. echo json_encode( array(
  291. 'success' => false,
  292. 'message' => "This image has a resolution of ${width}×${height} but your Full Size image requires a retina image of at least " . ( $meta['width'] * 2 ) . "x" . ( $meta['height'] * 2 ) . "."
  293. ));
  294. die();
  295. }
  296. $this->core->resize( $tmpfname, $meta['width'] * 2, $meta['height'] * 2, null, $retinafile );
  297. chmod( $retinafile, 0644 );
  298. unlink( $tmpfname );
  299. /**
  300. * @param $attachmentId ID of the attachment that the uploaded retina image is attached to
  301. * @param $retinafile Path to the uploaded retina image
  302. */
  303. do_action( 'wr2x_upload_retina', $attachmentId, $retinafile );
  304. // Get the results
  305. $info = $this->core->retina_info( $attachmentId );
  306. $this->core->update_issue_status( $attachmentId );
  307. $results[$attachmentId] = $this->core->html_get_basic_retina_info_full( $attachmentId, $info );
  308. }
  309. catch (Exception $e) {
  310. echo json_encode( array(
  311. 'success' => false,
  312. 'results' => null,
  313. 'message' => __( "Error: " . $e->getMessage(), 'wp-retina-2x' )
  314. ));
  315. die();
  316. }
  317. echo json_encode( array(
  318. 'success' => true,
  319. 'results' => $results,
  320. 'message' => __( "Uploaded successfully.", 'wp-retina-2x' ),
  321. 'media' => array(
  322. 'id' => $attachmentId,
  323. 'src' => wp_get_attachment_image_src( $attachmentId, 'thumbnail' ),
  324. 'edit_url' => get_edit_post_link( $attachmentId, 'attribute' )
  325. )
  326. ));
  327. die();
  328. }
  329. function wp_ajax_wr2x_retina_upload() {
  330. require_once ABSPATH . 'wp-admin/includes/image.php';
  331. $this->check_nonce( 'wr2x_retina_upload' );
  332. $this->check_capability();
  333. try {
  334. $tmpf = $this->check_get_ajax_uploaded_file();
  335. $image = wp_get_image_editor( $tmpf );
  336. $size = $image->get_size();
  337. // Halve the size of the uploaded image
  338. if ( $size['width'] >= $size['height'] ) $image->resize( round($size['width'] * .5), null );
  339. else $image->resize( null, round($size['height'] * .5) );
  340. $image->set_quality( get_option('wr2x_quality', 90) );
  341. $halved = $image->save( $tmpf . 'H' );
  342. if ( !$halved ) throw new Exception( "Failed to halve the uploaded image" );
  343. if ( is_wp_error($halved) ) throw new Exception( $halved->get_error_message() );
  344. // Upload the halved image
  345. $content = file_get_contents( $halved['path'] );
  346. if ( $content === false ) throw new Exception( "Couldn't read the uploaded file: {$halved['file']}" );
  347. $uploaded = wp_upload_bits( $_POST['filename'], null, $content );
  348. if ( isset($uploaded['error']) && $uploaded['error'] ) throw new Exception( $uploaded['error'] );
  349. // Register the file as a new attachment
  350. $attachTo = 0; // TODO Support specifying which post the media attach to
  351. $ftype = wp_check_filetype( $uploaded['file'] );
  352. $attachment = array (
  353. 'post_mime_type' => $ftype['type'],
  354. 'post_parent' => $attachTo,
  355. 'post_title' => preg_replace( '/\.[^.]+$/', '', $_POST['filename'] ),
  356. 'post_content' => '',
  357. 'post_status' => 'inherit'
  358. );
  359. $attachmentId = wp_insert_attachment( $attachment, $uploaded['file'], $attachTo );
  360. if ( !$attachmentId ) throw new Exception( "Couldn't add an attachment file: {$uploaded['file']}" );
  361. if ( is_wp_error($attachmentId) ) throw new Exception( $attachmentId->get_error_message() );
  362. $meta = wp_generate_attachment_metadata( $attachmentId, $uploaded['file'] );
  363. wp_update_attachment_metadata( $attachmentId, $meta );
  364. } catch ( Exception $e ) {
  365. echo json_encode( array (
  366. 'success' => false,
  367. 'results' => null,
  368. 'message' => __( "Error: " . $e->getMessage(), 'wp-retina-2x' )
  369. ));
  370. die();
  371. }
  372. // Redirect to 'wr2x_upload'
  373. $_POST['attachmentId'] = $attachmentId;
  374. $this->wp_ajax_wr2x_upload( false );
  375. }
  376. function wp_ajax_wr2x_replace() {
  377. $this->check_nonce( 'wr2x_replace' );
  378. $tmpfname = $this->check_get_ajax_uploaded_file();
  379. $attachmentId = (int) $_POST['attachmentId'];
  380. $meta = wp_get_attachment_metadata( $attachmentId );
  381. $current_file = get_attached_file( $attachmentId );
  382. /**
  383. * @param $attachmentId ID of the attachment to replace
  384. * @param $tmpfname Path to the temporary file that is to be the replacement
  385. */
  386. do_action( 'wr2x_before_replace', $attachmentId, $tmpfname );
  387. $this->core->delete_attachment( $attachmentId, false );
  388. $pathinfo = pathinfo( $current_file );
  389. $basepath = $pathinfo['dirname'];
  390. // Let's clean everything first
  391. if ( wp_attachment_is_image( $attachmentId ) ) {
  392. $sizes = $this->core->get_image_sizes();
  393. foreach ($sizes as $name => $attr) {
  394. if ( isset( $meta['sizes'][$name] ) && isset( $meta['sizes'][$name]['file'] ) && file_exists( trailingslashit( $basepath ) . $meta['sizes'][$name]['file'] ) ) {
  395. $normal_file = trailingslashit( $basepath ) . $meta['sizes'][$name]['file'];
  396. $pathinfo = pathinfo( $normal_file );
  397. $retina_file = trailingslashit( $pathinfo['dirname'] ) . $pathinfo['filename'] . $this->core->retina_extension() . $pathinfo['extension'];
  398. // Test if the file exists and if it is actually a file (and not a dir)
  399. // Some old WordPress Media Library are sometimes broken and link to directories
  400. if ( file_exists( $normal_file ) && is_file( $normal_file ) )
  401. unlink( $normal_file );
  402. if ( file_exists( $retina_file ) && is_file( $retina_file ) )
  403. unlink( $retina_file );
  404. }
  405. }
  406. }
  407. if ( file_exists( $current_file ) )
  408. unlink( $current_file );
  409. // Insert the new file and delete the temporary one
  410. rename( $tmpfname, $current_file );
  411. chmod( $current_file, 0644 );
  412. // Generate the images
  413. wp_update_attachment_metadata( $attachmentId, wp_generate_attachment_metadata( $attachmentId, $current_file ) );
  414. $meta = wp_get_attachment_metadata( $attachmentId );
  415. $this->core->generate_images( $meta );
  416. /**
  417. * @param $attachmentId ID of the attachment that has been replaced
  418. */
  419. do_action( 'wr2x_replace', $attachmentId );
  420. // Get the results
  421. $info = $this->core->retina_info( $attachmentId );
  422. $results[$attachmentId] = $this->core->html_get_basic_retina_info( $attachmentId, $info );
  423. echo json_encode( array(
  424. 'success' => true,
  425. 'results' => $results,
  426. 'message' => __( "Replaced successfully.", 'wp-retina-2x' )
  427. ));
  428. die();
  429. }
  430. }
  431. ?>