PluginProbe
StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more / 3.7.1
StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more v3.7.1
3.7.2 3.7.1 3.7.0 3.6.0 3.6.1 3.5.2 trunk 2.0 2.1 2.2 2.3 2.4 2.4.1 2.4.2 2.4.3 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.6.0 2.6.1 All 73 releases
← All changes | src/class-stockpackquery.php +284 -11 3.5.2 → 3.7.1 View file →
@@ -71,8 +71,13 @@
71 71 $this,
72 72 'license_cost'
73 73 ) ); // executed when logged in
74 74 add_action( 'wp_ajax_download-stockpack', array( $this, 'download' ) ); // executed when logged in
75 + add_action( 'wp_ajax_generate-stockpack', array( $this, 'generate' ) ); // executed when logged in
76 + add_action( 'wp_ajax_generate_status-stockpack', array(
77 + $this,
78 + 'generate_status'
79 + ) ); // executed when logged in
75 80 add_action( 'wp_ajax_cache-stockpack', array( $this, 'cache' ) ); // executed when logged in
76 81 add_action( 'wp_ajax_validate-stockpack', array( $this, 'validate' ) ); // executed when logged in
77 82 add_action( 'wp_ajax_terms-stockpack', array( $this, 'terms' ) ); // executed when logged in
78 83 add_action( 'wp_ajax_token-stockpack', array( $this, 'token' ) ); // executed when logged in
@@ -124,11 +129,36 @@
124 129 if ( $response->data->cost == 1 && ! $response->data->cost_message ) {
125 130 $response->data->cost_message = __( 'You will be charged for one image on you provider account', 'stockpack' );
126 131 }
127 132
133 + if ( $this->already_in_library( $media_id ) ) {
134 + $response->data->cost_message = __( 'This image is already in your library. Adding it again reuses the file you downloaded before, so it will not use another download.', 'stockpack' );
135 + }
136 +
128 137 wp_send_json_success( $response->data, true );
129 138 }
130 139
140 + private function already_in_library( $media_id ) {
141 + if ( ! $media_id ) {
142 + return false;
143 + }
144 +
145 + $query = new WP_Query( array(
146 + 'post_type' => 'attachment',
147 + 'post_status' => 'inherit',
148 + 'fields' => 'ids',
149 + 'posts_per_page' => 1,
150 + 'meta_query' => array(
151 + array(
152 + 'key' => 'stockpack_id',
153 + 'value' => $media_id
154 + )
155 + )
156 + ) );
157 +
158 + return $query->have_posts();
159 + }
160 +
131 161 public function token() {
132 162 $stockpack = StockPack::get_instance();
133 163 check_ajax_referer( 'stockpack_token', 'security' );
134 164 $token = '';
@@ -181,8 +211,99 @@
181 211
182 212 wp_send_json_success( $this->format( $images->data ) );
183 213 }
184 214
215 + public function generate() {
216 + check_ajax_referer( 'stockpack_generate', 'security' );
217 + if ( ! current_user_can( 'upload_files' ) ) {
218 + wp_send_json_error( array( 'message' => __( 'You are not allowed to upload files', 'stockpack' ) ) );
219 + }
220 +
221 + /** @var StockPack $stockpack */
222 + $stockpack = StockPack::get_instance();
223 + if ( ! $stockpack->settings->get_api_key() ) {
224 + wp_send_json_error( array(
225 + 'message' => __( 'Add your StockPack API key in the plugin settings before generating images.',
226 + 'stockpack' )
227 + ) );
228 + }
229 +
230 + $args = array(
231 + 'action' => $this->request_value( 'generate_action', 'generate' ),
232 + );
233 +
234 + if ( 'upscale' === $args['action'] ) {
235 + $args['image_url'] = esc_url_raw( $this->request_value( 'image_url' ) );
236 + $args['scale_factor'] = (int) $this->request_value( 'scale_factor', 2 );
237 +
238 + if ( ! $args['image_url'] ) {
239 + wp_send_json_error( array( 'message' => __( 'Pick an image to upscale.', 'stockpack' ) ) );
240 + }
241 + } else {
242 + $args['prompt'] = $this->request_value( 'prompt' );
243 + $args['model'] = $this->request_value( 'model', 'mystic-25' );
244 + $args['resolution'] = $this->request_value( 'resolution', '2k' );
245 +
246 + $refine = esc_url_raw( $this->request_value( 'refine_url' ) );
247 +
248 + if ( $refine ) {
249 + $args['refine_url'] = $refine;
250 + }
251 +
252 + if ( ! $args['prompt'] ) {
253 + wp_send_json_error( array( 'message' => __( 'Describe the image you want first.', 'stockpack' ) ) );
254 + }
255 + }
256 +
257 + $response = $this->call( 'POST', 'generate', $args );
258 +
259 + if ( is_wp_error( $response ) ) {
260 + wp_send_json_error( $this->error_payload( $response ) );
261 + }
262 +
263 + if ( isset( $response->error ) ) {
264 + wp_send_json_error( $this->handle_search_errors( $response ) );
265 + }
266 +
267 + wp_send_json_success( $this->with_wallet( $response->data ) );
268 + }
269 +
270 + public function generate_status() {
271 + check_ajax_referer( 'stockpack_generate', 'security' );
272 + if ( ! current_user_can( 'upload_files' ) ) {
273 + wp_send_json_error( array( 'message' => __( 'You are not allowed to upload files', 'stockpack' ) ) );
274 + }
275 +
276 + $task = $this->request_value( 'task' );
277 + if ( ! $task ) {
278 + wp_send_json_error( array( 'message' => __( 'Unknown generation task.', 'stockpack' ) ) );
279 + }
280 +
281 + $response = $this->call( 'GET', 'generate/' . rawurlencode( $task ) );
282 +
283 + if ( is_wp_error( $response ) ) {
284 + wp_send_json_error( $this->error_payload( $response ) );
285 + }
286 +
287 + if ( isset( $response->error ) ) {
288 + wp_send_json_error( $this->handle_search_errors( $response ) );
289 + }
290 +
291 + if ( isset( $response->data->status ) && 'pending' === $response->data->status ) {
292 + wp_send_json_success( $response->data );
293 + }
294 +
295 + wp_send_json_success( $this->with_wallet( $response->data ) );
296 + }
297 +
298 + private function request_value( $key, $default = '' ) {
299 + if ( ! isset( $_REQUEST[ $key ] ) ) {
300 + return $default;
301 + }
302 +
303 + return sanitize_text_field( wp_unslash( $_REQUEST[ $key ] ) );
304 + }
305 +
185 306 /**
186 307 *
187 308 */
188 309 public function cache() {
@@ -275,8 +396,14 @@
275 396 );
276 397 }
277 398
278 399 public function images( $query = [] ) {
400 + if ( empty( $query['provider'] ) ) {
401 + $available = $this->settings->get_available_search_provider_slugs();
402 + if ( $available ) {
403 + $query['available_providers'] = implode( ',', $available );
404 + }
405 + }
279 406
280 407 return $this->call( 'GET', 'images/search', $query );
281 408 }
282 409
@@ -300,8 +427,80 @@
300 427 ) );
301 428
302 429 }
303 430
431 + public function get_ai_prices() {
432 + $cached = get_transient( 'stockpack_ai_prices' );
433 +
434 + if ( is_array( $cached ) ) {
435 + return $cached;
436 + }
437 +
438 + return $this->fetch_ai_prices();
439 + }
440 +
441 + public function get_ai_wallet( $fresh = false ) {
442 + $cached = get_transient( 'stockpack_ai_wallet' );
443 +
444 + if ( is_array( $cached ) && ! $fresh ) {
445 + return $cached;
446 + }
447 +
448 + $prices = $this->fetch_ai_prices();
449 +
450 + if ( ! $prices && is_array( $cached ) ) {
451 + return $cached;
452 + }
453 +
454 + return $this->wallet_from( $prices );
455 + }
456 +
457 + public function dashboard_url( $path = '' ) {
458 + $base = defined( 'STOCKPACK_DASHBOARD_URL' ) ? STOCKPACK_DASHBOARD_URL : 'https://stockpack.co';
459 +
460 + return rtrim( $base, '/' ) . ( $path ? '/' . ltrim( $path, '/' ) : '' );
461 + }
462 +
463 + private function fetch_ai_prices() {
464 + $response = $this->call( 'GET', 'generate/prices' );
465 + $prices = array();
466 +
467 + if ( isset( $response->data ) ) {
468 + $prices = json_decode( wp_json_encode( $response->data ), true );
469 + }
470 +
471 + set_transient( 'stockpack_ai_prices', $prices, $prices ? DAY_IN_SECONDS : 5 * MINUTE_IN_SECONDS );
472 +
473 + if ( $prices ) {
474 + set_transient( 'stockpack_ai_wallet', $this->wallet_from( $prices ), MINUTE_IN_SECONDS );
475 + }
476 +
477 + return $prices;
478 + }
479 +
480 + private function wallet_from( $prices ) {
481 + $wallet = isset( $prices['wallet'] ) && is_array( $prices['wallet'] ) ? $prices['wallet'] : array();
482 + $balance = isset( $wallet['balance'] ) ? (int) $wallet['balance'] : null;
483 +
484 + return array(
485 + 'mode' => isset( $wallet['mode'] ) ? $wallet['mode'] : 'byok',
486 + 'balance' => $balance,
487 + 'balance_text' => null === $balance ? '' : number_format_i18n( $balance ),
488 + 'top_up_url' => ! empty( $wallet['top_up_url'] ) ? $wallet['top_up_url'] : $this->dashboard_url( 'billing/credits' ),
489 + 'connect_url' => $this->dashboard_url( 'providers' ),
490 + );
491 + }
492 +
493 + private function with_wallet( $data ) {
494 + $wallet = $this->get_ai_wallet();
495 +
496 + if ( 'managed' === $wallet['mode'] ) {
497 + $data->wallet = $this->get_ai_wallet( true );
498 + }
499 +
500 + return $data;
501 + }
502 +
304 503 public function image( $media_id, $post_id, $description = '', $search = '', $must_license = 0, $provider = 0, $new_filename = '' ) {
305 504
306 505 do_action( 'stockpack_before_attachment_download', $provider,$new_filename, $media_id, $must_license );
307 506
@@ -332,9 +531,9 @@
332 531 if ( is_wp_error( $attachment_id ) ) {
333 532 return $attachment_id;
334 533 }
335 534 if ( ! $attachment_id ) {
336 - return new WP_Error( __( 'upload_failure', 'There has been a problem with the upload. Please try again', 'stockpack' ) );
535 + return new WP_Error( 'upload_failure', __( 'There has been a problem with the upload. Please try again', 'stockpack' ) );
337 536 }
338 537
339 538 update_post_meta( $attachment_id, 'stockpack_id', $media_id );
340 539
@@ -416,17 +615,34 @@
416 615 'user_data' => $stockpack->settings->get_license_state(),
417 616 ]
418 617 );
419 618
420 - $url = $this->url . '/' . self::VERSION . '/' . $path . '?' . http_build_query( $query );
619 + $url = $this->url . '/' . self::VERSION . '/' . $path;
620 + $is_post = 'post' === strtolower( $method );
421 621
622 + if ( ! $is_post ) {
623 + $url .= '?' . http_build_query( $query );
624 + }
625 +
422 626 do_action( 'stockpack_before_api_request', $url, $query );
423 627
424 - $response = wp_remote_get( $url, array(
425 - 'timeout' => 10,
426 - 'sslverify' => false,
427 - ) );
628 + $headers = array( 'Accept' => 'application/json' );
428 629
630 + if ( $is_post ) {
631 + $response = wp_remote_post( $url, array(
632 + 'timeout' => 20,
633 + 'sslverify' => false,
634 + 'headers' => $headers,
635 + 'body' => $query,
636 + ) );
637 + } else {
638 + $response = wp_remote_get( $url, array(
639 + 'timeout' => apply_filters( 'stockpack_api_timeout', $this->timeout_for( $path ), $path ),
640 + 'sslverify' => false,
641 + 'headers' => $headers,
642 + ) );
643 + }
644 +
429 645 do_action( 'stockpack_after_api_request', $url, $query, $response );
430 646
431 647 if ( is_wp_error( $response ) ) {
432 648 return $response;
@@ -439,9 +655,9 @@
439 655 return $this->limit_exceeded( $response );
440 656 case 401: // access denied
441 657 return $this->invalid_token( $response );
442 658 default:
443 - return new WP_Error( 1, __( 'Can\'t connect to StockPack server.', 'stockpack' ) );
659 + return $this->server_error( $response, $response_code );
444 660 }
445 661 }
446 662
447 663 $response_body = wp_remote_retrieve_body( $response );
@@ -448,8 +664,46 @@
448 664
449 665 return json_decode( $response_body );
450 666 }
451 667
668 + private function timeout_for( $path ) {
669 + return strpos( $path, 'images/download' ) === 0 ? 30 : 10;
670 + }
671 +
672 + private function error_payload( $error ) {
673 + $payload = array(
674 + 'code' => $error->get_error_code(),
675 + 'message' => $error->get_error_message(),
676 + );
677 + $wallet = $this->get_ai_wallet();
678 +
679 + if ( 'insufficient_credits' === $payload['code'] ) {
680 + $data = $error->get_error_data();
681 + $payload['link'] = ! empty( $data->top_up_url ) ? $data->top_up_url : $wallet['top_up_url'];
682 + $payload['link_text'] = __( 'Top up credits', 'stockpack' );
683 + }
684 +
685 + if ( 'managed' === $wallet['mode'] ) {
686 + $payload['wallet'] = $this->get_ai_wallet( true );
687 + }
688 +
689 + return $payload;
690 + }
691 +
692 + private function server_error( $response, $response_code ) {
693 + $body = json_decode( wp_remote_retrieve_body( $response ) );
694 +
695 + if ( ! empty( $body->message ) ) {
696 + return new WP_Error( ! empty( $body->code ) ? $body->code : 1, $body->message, $body );
697 + }
698 +
699 + return new WP_Error( 1, sprintf(
700 + /* translators: %d: HTTP status code returned by the StockPack API */
701 + __( 'The StockPack server returned an error (HTTP %d). If this keeps happening, contact StockPack support.', 'stockpack' ),
702 + $response_code
703 + ) );
704 + }
705 +
452 706 private function limit_exceeded( $response ) {
453 707 /** @var StockPack $stockpack */
454 708 $stockpack = StockPack::get_instance();
455 709
@@ -508,8 +762,11 @@
508 762 return new WP_Error( 100, __( 'Image download failed, please try again. Errors:', 'stockpack' ) . PHP_EOL . $get->get_error_message() );
509 763 }
510 764 $type = wp_remote_retrieve_header( $get, 'content-type' );
511 765 if ( ! $type ) {
766 + $type = wp_check_filetype( $name )['type'];
767 + }
768 + if ( ! $type ) {
512 769 return new WP_Error( 100, __( 'Image type couldn\'t be determined', 'stockpack' ) );
513 770 }
514 771 $name = $this->update_extension( $name, $type );
515 772
@@ -523,10 +780,25 @@
523 780 'post_mime_type' => $type
524 781 );
525 782 $attach_id = wp_insert_attachment( $attachment, $mirror['file'], $parent_id );
526 783 require_once( ABSPATH . 'wp-admin/includes/image.php' );
784 +
785 + // An upscale that WordPress immediately scales back down is an
786 + // upscale the user paid for and did not get, so the threshold is
787 + // lifted for the result of one. Priority 999 so it wins over a theme
788 + // or plugin that lowers it.
789 + $is_upscale = isset( $image->data->meta->action ) && 'upscale' === $image->data->meta->action;
790 +
791 + if ( $is_upscale ) {
792 + add_filter( 'big_image_size_threshold', '__return_false', 999 );
793 + }
794 +
527 795 $attach_data = wp_generate_attachment_metadata( $attach_id, $mirror['file'] );
528 796 wp_update_attachment_metadata( $attach_id, $attach_data );
797 +
798 + if ( $is_upscale ) {
799 + remove_filter( 'big_image_size_threshold', '__return_false', 999 );
800 + }
529 801 update_post_meta( $attach_id, '_wp_attachment_image_alt', $description );
530 802 $this->store_attachment_meta($attach_id,$image);
531 803
532 804 do_action( 'stockpack_after_attachment_uploaded', $attach_id, $image );
@@ -536,13 +808,14 @@
536 808 }
537 809
538 810 private function store_attachment_meta($attach_id, $image){
539 811 $data = $image->data;
812 + $meta = isset($data->meta) ? $data->meta : new stdClass();
540 813 update_post_meta($attach_id,'stockpack_media_id',$data->id);
541 - update_post_meta($attach_id,'stockpack_provider',$data->meta->provider);
542 - update_post_meta($attach_id,'stockpack_author_url',$data->meta->author_url);
543 - update_post_meta($attach_id,'stockpack_author_name',$data->meta->author_name);
544 - update_post_meta($attach_id,'stockpack_image_url',$data->meta->image_url);
814 + update_post_meta($attach_id,'stockpack_provider',isset($meta->provider) ? $meta->provider : '');
815 + update_post_meta($attach_id,'stockpack_author_url',isset($meta->author_url) ? $meta->author_url : '');
816 + update_post_meta($attach_id,'stockpack_author_name',isset($meta->author_name) ? $meta->author_name : '');
817 + update_post_meta($attach_id,'stockpack_image_url',isset($meta->image_url) ? $meta->image_url : '');
545 818 update_post_meta($attach_id,'stockpack_download_timestamp',time());
546 819 }
547 820
548 821 /**