/** * REST API: WP_REST_Attachments_Controller class * * @package WordPress * @subpackage REST_API * @since 4.7.0 */ /** * Core controller used to access attachments via the REST API. * * @since 4.7.0 * * @see WP_REST_Posts_Controller */ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller { /** * Whether the controller supports batching. * * @since 5.9.0 * @var false */ protected $allow_batch = false; /** * Registers the routes for attachments. * * @since 5.3.0 * * @see register_rest_route() */ public function register_routes() { parent::register_routes(); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)/post-process', array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'post_process_item' ), 'permission_callback' => array( $this, 'post_process_item_permissions_check' ), 'args' => array( 'id' => array( 'description' => __( 'Unique identifier for the attachment.' ), 'type' => 'integer', ), 'action' => array( 'type' => 'string', 'enum' => array( 'create-image-subsizes' ), 'required' => true, ), ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)/edit', array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'edit_media_item' ), 'permission_callback' => array( $this, 'edit_media_item_permissions_check' ), 'args' => $this->get_edit_media_item_args(), ) ); } /** * Determines the allowed query_vars for a get_items() response and * prepares for WP_Query. * * @since 4.7.0 * * @param array $prepared_args Optional. Array of prepared arguments. Default empty array. * @param WP_REST_Request $request Optional. Request to prepare items for. * @return array Array of query arguments. */ protected function prepare_items_query( $prepared_args = array(), $request = null ) { $query_args = parent::prepare_items_query( $prepared_args, $request ); if ( empty( $query_args['post_status'] ) ) { $query_args['post_status'] = 'inherit'; } $media_types = $this->get_media_types(); if ( ! empty( $request['media_type'] ) && isset( $media_types[ $request['media_type'] ] ) ) { $query_args['post_mime_type'] = $media_types[ $request['media_type'] ]; } if ( ! empty( $request['mime_type'] ) ) { $parts = explode( '/', $request['mime_type'] ); if ( isset( $media_types[ $parts[0] ] ) && in_array( $request['mime_type'], $media_types[ $parts[0] ], true ) ) { $query_args['post_mime_type'] = $request['mime_type']; } } // Filter query clauses to include filenames. if ( isset( $query_args['s'] ) ) { add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' ); } return $query_args; } /** * Checks if a given request has access to create an attachment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error Boolean true if the attachment may be created, or a WP_Error if not. */ public function create_item_permissions_check( $request ) { $ret = parent::create_item_permissions_check( $request ); if ( ! $ret || is_wp_error( $ret ) ) { return $ret; } if ( ! current_user_can( 'upload_files' ) ) { return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to upload media on this site.' ), array( 'status' => 400 ) ); } // Attaching media to a post requires ability to edit said post. if ( ! empty( $request['post'] ) && ! current_user_can( 'edit_post', (int) $request['post'] ) ) { return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to upload media to this post.' ), array( 'status' => rest_authorization_required_code() ) ); } $files = $request->get_file_params(); /** * Filter whether the server should prevent uploads for image types it doesn't support. Default true. * * Developers can use this filter to enable uploads of certain image types. By default image types that are not * supported by the server are prevented from being uploaded. * * @since 6.8.0 * * @param bool $check_mime Whether to prevent uploads of unsupported image types. * @param string|null $mime_type The mime type of the file being uploaded (if available). */ $prevent_unsupported_uploads = apply_filters( 'wp_prevent_unsupported_mime_type_uploads', true, isset( $files['file']['type'] ) ? $files['file']['type'] : null ); // If the upload is an image, check if the server can handle the mime type. if ( $prevent_unsupported_uploads && isset( $files['file']['type'] ) && str_starts_with( $files['file']['type'], 'image/' ) ) { // List of non-resizable image formats. $editor_non_resizable_formats = array( 'image/svg+xml', ); // Check if the image editor supports the type or ignore if it isn't a format resizable by an editor. if ( ! in_array( $files['file']['type'], $editor_non_resizable_formats, true ) && ! wp_image_editor_supports( array( 'mime_type' => $files['file']['type'] ) ) ) { return new WP_Error( 'rest_upload_image_type_not_supported', __( 'The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading.' ), array( 'status' => 400 ) ); } } return true; } /** * Creates a single attachment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. */ public function create_item( $request ) { if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ), true ) ) { return new WP_Error( 'rest_invalid_param', __( 'Invalid parent type.' ), array( 'status' => 400 ) ); } $insert = $this->insert_attachment( $request ); if ( is_wp_error( $insert ) ) { return $insert; } $schema = $this->get_item_schema(); // Extract by name. $attachment_id = $insert['attachment_id']; $file = $insert['file']; if ( isset( $request['alt_text'] ) ) { update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) ); } if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) { $thumbnail_update = $this->handle_featured_media( $request['featured_media'], $attachment_id ); if ( is_wp_error( $thumbnail_update ) ) { return $thumbnail_update; } } if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $attachment_id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $attachment = get_post( $attachment_id ); $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $terms_update = $this->handle_terms( $attachment_id, $request ); if ( is_wp_error( $terms_update ) ) { return $terms_update; } $request->set_param( 'context', 'edit' ); /** * Fires after a single attachment is completely created or updated via the REST API. * * @since 5.0.0 * * @param WP_Post $attachment Inserted or updated attachment object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating an attachment, false when updating. */ do_action( 'rest_after_insert_attachment', $attachment, $request, true ); wp_after_insert_post( $attachment, false, null ); if ( wp_is_serving_rest_request() ) { /* * Set a custom header with the attachment_id. * Used by the browser/client to resume creating image sub-sizes after a PHP fatal error. */ header( 'X-WP-Upload-Attachment-ID: ' . $attachment_id ); } // Include media and image functions to get access to wp_generate_attachment_metadata(). require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/image.php'; /* * Post-process the upload (create image sub-sizes, make PDF thumbnails, etc.) and insert attachment meta. * At this point the server may run out of resources and post-processing of uploaded images may fail. */ wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) ); $response = $this->prepare_item_for_response( $attachment, $request ); $response = rest_ensure_response( $response ); $response->set_status( 201 ); $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $attachment_id ) ) ); return $response; } /** * Inserts the attachment post in the database. Does not update the attachment meta. * * @since 5.3.0 * * @param WP_REST_Request $request * @return array|WP_Error */ protected function insert_attachment( $request ) { // Get the file via $_FILES or raw data. $files = $request->get_file_params(); $headers = $request->get_headers(); $time = null; // Matches logic in media_handle_upload(). if ( ! empty( $request['post'] ) ) { $post = get_post( $request['post'] ); // The post date doesn't usually matter for pages, so don't backdate this upload. if ( $post && 'page' !== $post->post_type && substr( $post->post_date, 0, 4 ) > 0 ) { $time = $post->post_date; } } if ( ! empty( $files ) ) { $file = $this->upload_from_file( $files, $headers, $time ); } else { $file = $this->upload_from_data( $request->get_body(), $headers, $time ); } if ( is_wp_error( $file ) ) { return $file; } $name = wp_basename( $file['file'] ); $name_parts = pathinfo( $name ); $name = trim( substr( $name, 0, -( 1 + strlen( $name_parts['extension'] ) ) ) ); $url = $file['url']; $type = $file['type']; $file = $file['file']; // Include image functions to get access to wp_read_image_metadata(). require_once ABSPATH . 'wp-admin/includes/image.php'; // Use image exif/iptc data for title and caption defaults if possible. $image_meta = wp_read_image_metadata( $file ); if ( ! empty( $image_meta ) ) { if ( empty( $request['title'] ) && trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) { $request['title'] = $image_meta['title']; } if ( empty( $request['caption'] ) && trim( $image_meta['caption'] ) ) { $request['caption'] = $image_meta['caption']; } } $attachment = $this->prepare_item_for_database( $request ); $attachment->post_mime_type = $type; $attachment->guid = $url; // If the title was not set, use the original filename. if ( empty( $attachment->post_title ) && ! empty( $files['file']['name'] ) ) { // Remove the file extension (after the last `.`) $tmp_title = substr( $files['file']['name'], 0, strrpos( $files['file']['name'], '.' ) ); if ( ! empty( $tmp_title ) ) { $attachment->post_title = $tmp_title; } } // Fall back to the original approach. if ( empty( $attachment->post_title ) ) { $attachment->post_title = preg_replace( '/\.[^.]+$/', '', wp_basename( $file ) ); } // $post_parent is inherited from $attachment['post_parent']. $id = wp_insert_attachment( wp_slash( (array) $attachment ), $file, 0, true, false ); if ( is_wp_error( $id ) ) { if ( 'db_update_error' === $id->get_error_code() ) { $id->add_data( array( 'status' => 500 ) ); } else { $id->add_data( array( 'status' => 400 ) ); } return $id; } $attachment = get_post( $id ); /** * Fires after a single attachment is created or updated via the REST API. * * @since 4.7.0 * * @param WP_Post $attachment Inserted or updated attachment object. * @param WP_REST_Request $request The request sent to the API. * @param bool $creating True when creating an attachment, false when updating. */ do_action( 'rest_insert_attachment', $attachment, $request, true ); return array( 'attachment_id' => $id, 'file' => $file, ); } /** * Determines the featured media based on a request param. * * @since 6.5.0 * * @param int $featured_media Featured Media ID. * @param int $post_id Post ID. * @return bool|WP_Error Whether the post thumbnail was successfully deleted, otherwise WP_Error. */ protected function handle_featured_media( $featured_media, $post_id ) { $post_type = get_post_type( $post_id ); $thumbnail_support = current_theme_supports( 'post-thumbnails', $post_type ) && post_type_supports( $post_type, 'thumbnail' ); // Similar check as in wp_insert_post(). if ( ! $thumbnail_support && get_post_mime_type( $post_id ) ) { if ( wp_attachment_is( 'audio', $post_id ) ) { $thumbnail_support = post_type_supports( 'attachment:audio', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:audio' ); } elseif ( wp_attachment_is( 'video', $post_id ) ) { $thumbnail_support = post_type_supports( 'attachment:video', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:video' ); } } if ( $thumbnail_support ) { return parent::handle_featured_media( $featured_media, $post_id ); } return new WP_Error( 'rest_no_featured_media', sprintf( /* translators: %s: attachment mime type */ __( 'This site does not support post thumbnails on attachments with MIME type %s.' ), get_post_mime_type( $post_id ) ), array( 'status' => 400 ) ); } /** * Updates a single attachment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. */ public function update_item( $request ) { if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ), true ) ) { return new WP_Error( 'rest_invalid_param', __( 'Invalid parent type.' ), array( 'status' => 400 ) ); } $attachment_before = get_post( $request['id'] ); $response = parent::update_item( $request ); if ( is_wp_error( $response ) ) { return $response; } $response = rest_ensure_response( $response ); $data = $response->get_data(); if ( isset( $request['alt_text'] ) ) { update_post_meta( $data['id'], '_wp_attachment_image_alt', $request['alt_text'] ); } $attachment = get_post( $request['id'] ); if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) { $thumbnail_update = $this->handle_featured_media( $request['featured_media'], $attachment->ID ); if ( is_wp_error( $thumbnail_update ) ) { return $thumbnail_update; } } $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */ do_action( 'rest_after_insert_attachment', $attachment, $request, false ); wp_after_insert_post( $attachment, true, $attachment_before ); $response = $this->prepare_item_for_response( $attachment, $request ); $response = rest_ensure_response( $response ); return $response; } /** * Performs post-processing on an attachment. * * @since 5.3.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. */ public function post_process_item( $request ) { switch ( $request['action'] ) { case 'create-image-subsizes': require_once ABSPATH . 'wp-admin/includes/image.php'; wp_update_image_subsizes( $request['id'] ); break; } $request['context'] = 'edit'; return $this->prepare_item_for_response( get_post( $request['id'] ), $request ); } /** * Checks if a given request can perform post-processing on an attachment. * * @since 5.3.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. */ public function post_process_item_permissions_check( $request ) { return $this->update_item_permissions_check( $request ); } /** * Checks if a given request has access to editing media. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function edit_media_item_permissions_check( $request ) { if ( ! current_user_can( 'upload_files' ) ) { return new WP_Error( 'rest_cannot_edit_image', __( 'Sorry, you are not allowed to upload media on this site.' ), array( 'status' => rest_authorization_required_code() ) ); } return $this->update_item_permissions_check( $request ); } /** * Applies edits to a media item and creates a new attachment record. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. */ public function edit_media_item( $request ) { require_once ABSPATH . 'wp-admin/includes/image.php'; $attachment_id = $request['id']; // This also confirms the attachment is an image. $image_file = wp_get_original_image_path( $attachment_id ); $image_meta = wp_get_attachment_metadata( $attachment_id ); if ( ! $image_meta || ! $image_file || ! wp_image_file_matches_image_meta( $request['src'], $image_meta, $attachment_id ) ) { return new WP_Error( 'rest_unknown_attachment', __( 'Unable to get meta information for file.' ), array( 'status' => 404 ) ); } $supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif', 'image/heic' ); $mime_type = get_post_mime_type( $attachment_id ); if ( ! in_array( $mime_type, $supported_types, true ) ) { return new WP_Error( 'rest_cannot_edit_file_type', __( 'This type of file cannot be edited.' ), array( 'status' => 400 ) ); } // The `modifiers` param takes precedence over the older format. if ( isset( $request['modifiers'] ) ) { $modifiers = $request['modifiers']; } else { $modifiers = array(); if ( ! empty( $request['rotation'] ) ) { $modifiers[] = array( 'type' => 'rotate', 'args' => array( 'angle' => $request['rotation'], ), ); } if ( isset( $request['x'], $request['y'], $request['width'], $request['height'] ) ) { $modifiers[] = array( 'type' => 'crop', 'args' => array( 'left' => $request['x'], 'top' => $request['y'], 'width' => $request['width'], 'height' => $request['height'], ), ); } if ( 0 === count( $modifiers ) ) { return new WP_Error( 'rest_image_not_edited', __( 'The image was not edited. Edit the image before applying the changes.' ), array( 'status' => 400 ) ); } } /* * If the file doesn't exist, attempt a URL fopen on the src link. * This can occur with certain file replication plugins. * Keep the original file path to get a modified name later. */ $image_file_to_edit = $image_file; if ( ! file_exists( $image_file_to_edit ) ) { $image_file_to_edit = _load_image_to_edit_path( $attachment_id ); } $image_editor = wp_get_image_editor( $image_file_to_edit ); if ( is_wp_error( $image_editor ) ) { return new WP_Error( 'rest_unknown_image_file_type', __( 'Unable to edit this image.' ), array( 'status' => 500 ) ); } foreach ( $modifiers as $modifier ) { $args = $modifier['args']; switch ( $modifier['type'] ) { case 'rotate': // Rotation direction: clockwise vs. counterclockwise. $rotate = 0 - $args['angle']; if ( 0 !== $rotate ) { $result = $image_editor->rotate( $rotate ); if ( is_wp_error( $result ) ) { return new WP_Error( 'rest_image_rotation_failed', __( 'Unable to rotate this image.' ), array( 'status' => 500 ) ); } } break; case 'crop': $size = $image_editor->get_size(); $crop_x = (int) round( ( $size['width'] * $args['left'] ) / 100.0 ); $crop_y = (int) round( ( $size['height'] * $args['top'] ) / 100.0 ); $width = (int) round( ( $size['width'] * $args['width'] ) / 100.0 ); $height = (int) round( ( $size['height'] * $args['height'] ) / 100.0 ); if ( $size['width'] !== $width || $size['height'] !== $height ) { $result = $image_editor->crop( $crop_x, $crop_y, $width, $height ); if ( is_wp_error( $result ) ) { return new WP_Error( 'rest_image_crop_failed', __( 'Unable to crop this image.' ), array( 'status' => 500 ) ); } } break; } } // Calculate the file name. $image_ext = pathinfo( $image_file, PATHINFO_EXTENSION ); $image_name = wp_basename( $image_file, ".{$image_ext}" ); /* * Do not append multiple `-edited` to the file name. * The user may be editing a previously edited image. */ if ( preg_match( '/-edited(-\d+)?$/', $image_name ) ) { // Remove any `-1`, `-2`, etc. `wp_unique_filename()` will add the proper number. $image_name = preg_replace( '/-edited(-\d+)?$/', '-edited', $image_name ); } else { // Append `-edited` before the extension. $image_name .= '-edited'; } $filename = "{$image_name}.{$image_ext}"; // Create the uploads subdirectory if needed. $uploads = wp_upload_dir(); // Make the file name unique in the (new) upload directory. $filename = wp_unique_filename( $uploads['path'], $filename ); // Save to disk. $saved = $image_editor->save( $uploads['path'] . "/$filename" ); if ( is_wp_error( $saved ) ) { return $saved; } // Create new attachment post. $new_attachment_post = array( 'post_mime_type' => $saved['mime-type'], 'guid' => $uploads['url'] . "/$filename", 'post_title' => $image_name, 'post_content' => '', ); // Copy post_content, post_excerpt, and post_title from the edited image's attachment post. $attachment_post = get_post( $attachment_id ); if ( $attachment_post ) { $new_attachment_post['post_content'] = $attachment_post->post_content; $new_attachment_post['post_excerpt'] = $attachment_post->post_excerpt; $new_attachment_post['post_title'] = $attachment_post->post_title; } $new_attachment_id = wp_insert_attachment( wp_slash( $new_attachment_post ), $saved['path'], 0, true ); if ( is_wp_error( $new_attachment_id ) ) { if ( 'db_update_error' === $new_attachment_id->get_error_code() ) { $new_attachment_id->add_data( array( 'status' => 500 ) ); } else { $new_attachment_id->add_data( array( 'status' => 400 ) ); } return $new_attachment_id; } // Copy the image alt text from the edited image. $image_alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ); if ( ! empty( $image_alt ) ) { // update_post_meta() expects slashed. update_post_meta( $new_attachment_id, '_wp_attachment_image_alt', wp_slash( $image_alt ) ); } if ( wp_is_serving_rest_request() ) { /* * Set a custom header with the attachment_id. * Used by the browser/client to resume creating image sub-sizes after a PHP fatal error. */ header( 'X-WP-Upload-Attachment-ID: ' . $new_attachment_id ); } // Generate image sub-sizes and meta. $new_image_meta = wp_generate_attachment_metadata( $new_attachment_id, $saved['path'] ); // Copy the EXIF metadata from the original attachment if not generated for the edited image. if ( isset( $image_meta['image_meta'] ) && isset( $new_image_meta['image_meta'] ) && is_array( $new_image_meta['image_meta'] ) ) { // Merge but skip empty values. foreach ( (array) $image_meta['image_meta'] as $key => $value ) { if ( empty( $new_image_meta['image_meta'][ $key ] ) && ! empty( $value ) ) { $new_image_meta['image_meta'][ $key ] = $value; } } } // Reset orientation. At this point the image is edited and orientation is correct. if ( ! empty( $new_image_meta['image_meta']['orientation'] ) ) { $new_image_meta['image_meta']['orientation'] = 1; } // The attachment_id may change if the site is exported and imported. $new_image_meta['parent_image'] = array( 'attachment_id' => $attachment_id, // Path to the originally uploaded image file relative to the uploads directory. 'file' => _wp_relative_upload_path( $image_file ), ); /** * Filters the meta data for the new image created by editing an existing image. * * @since 5.5.0 * * @param array $new_image_meta Meta data for the new image. * @param int $new_attachment_id Attachment post ID for the new image. * @param int $attachment_id Attachment post ID for the edited (parent) image. */ $new_image_meta = apply_filters( 'wp_edited_image_metadata', $new_image_meta, $new_attachment_id, $attachment_id ); wp_update_attachment_metadata( $new_attachment_id, $new_image_meta ); $response = $this->prepare_item_for_response( get_post( $new_attachment_id ), $request ); $response->set_status( 201 ); $response->header( 'Location', rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $new_attachment_id ) ) ); return $response; } /** * Prepares a single attachment for create or update. * * @since 4.7.0 * * @param WP_REST_Request $request Request object. * @return stdClass|WP_Error Post object. */ protected function prepare_item_for_database( $request ) { $prepared_attachment = parent::prepare_item_for_database( $request ); // Attachment caption (post_excerpt internally). if ( isset( $request['caption'] ) ) { if ( is_string( $request['caption'] ) ) { $prepared_attachment->post_excerpt = $request['caption']; } elseif ( isset( $request['caption']['raw'] ) ) { $prepared_attachment->post_excerpt = $request['caption']['raw']; } } // Attachment description (post_content internally). if ( isset( $request['description'] ) ) { if ( is_string( $request['description'] ) ) { $prepared_attachment->post_content = $request['description']; } elseif ( isset( $request['description']['raw'] ) ) { $prepared_attachment->post_content = $request['description']['raw']; } } if ( isset( $request['post'] ) ) { $prepared_attachment->post_parent = (int) $request['post']; } return $prepared_attachment; } /** * Prepares a single attachment output for response. * * @since 4.7.0 * @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Post $item Attachment object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $post = $item; $response = parent::prepare_item_for_response( $post, $request ); $fields = $this->get_fields_for_response( $request ); $data = $response->get_data(); if ( in_array( 'description', $fields, true ) ) { $data['description'] = array( 'raw' => $post->post_content, /** This filter is documented in wp-includes/post-template.php */ 'rendered' => apply_filters( 'the_content', $post->post_content ), ); } if ( in_array( 'caption', $fields, true ) ) { /** This filter is documented in wp-includes/post-template.php */ $caption = apply_filters( 'get_the_excerpt', $post->post_excerpt, $post ); /** This filter is documented in wp-includes/post-template.php */ $caption = apply_filters( 'the_excerpt', $caption ); $data['caption'] = array( 'raw' => $post->post_excerpt, 'rendered' => $caption, ); } if ( in_array( 'alt_text', $fields, true ) ) { $data['alt_text'] = get_post_meta( $post->ID, '_wp_attachment_image_alt', true ); } if ( in_array( 'media_type', $fields, true ) ) { $data['media_type'] = wp_attachment_is_image( $post->ID ) ? 'image' : 'file'; } if ( in_array( 'mime_type', $fields, true ) ) { $data['mime_type'] = $post->post_mime_type; } if ( in_array( 'media_details', $fields, true ) ) { $data['media_details'] = wp_get_attachment_metadata( $post->ID ); // Ensure empty details is an empty object. if ( empty( $data['media_details'] ) ) { $data['media_details'] = new stdClass(); } elseif ( ! empty( $data['media_details']['sizes'] ) ) { foreach ( $data['media_details']['sizes'] as $size => &$size_data ) { if ( isset( $size_data['mime-type'] ) ) { $size_data['mime_type'] = $size_data['mime-type']; unset( $size_data['mime-type'] ); } // Use the same method image_downsize() does. $image_src = wp_get_attachment_image_src( $post->ID, $size ); if ( ! $image_src ) { continue; } $size_data['source_url'] = $image_src[0]; } $full_src = wp_get_attachment_image_src( $post->ID, 'full' ); if ( ! empty( $full_src ) ) { $data['media_details']['sizes']['full'] = array( 'file' => wp_basename( $full_src[0] ), 'width' => $full_src[1], 'height' => $full_src[2], 'mime_type' => $post->post_mime_type, 'source_url' => $full_src[0], ); } } else { $data['media_details']['sizes'] = new stdClass(); } } if ( in_array( 'post', $fields, true ) ) { $data['post'] = ! empty( $post->post_parent ) ? (int) $post->post_parent : null; } if ( in_array( 'source_url', $fields, true ) ) { $data['source_url'] = wp_get_attachment_url( $post->ID ); } if ( in_array( 'missing_image_sizes', $fields, true ) ) { require_once ABSPATH . 'wp-admin/includes/image.php'; $data['missing_image_sizes'] = array_keys( wp_get_missing_image_subsizes( $post->ID ) ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->filter_response_by_context( $data, $context ); $links = $response->get_links(); // Wrap the data in a response object. $response = rest_ensure_response( $data ); foreach ( $links as $rel => $rel_links ) { foreach ( $rel_links as $link ) { $response->add_link( $rel, $link['href'], $link['attributes'] ); } } /** * Filters an attachment returned from the REST API. * * Allows modification of the attachment right before it is returned. * * @since 4.7.0 * * @param WP_REST_Response $response The response object. * @param WP_Post $post The original attachment post. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_attachment', $response, $post, $request ); } /** * Retrieves the attachment's schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array Item schema as an array. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = parent::get_item_schema(); $schema['properties']['alt_text'] = array( 'description' => __( 'Alternative text to display when attachment is not displayed.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ); $schema['properties']['caption'] = array( 'description' => __( 'The attachment caption.' ), 'type' => 'object', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). ), 'properties' => array( 'raw' => array( 'description' => __( 'Caption for the attachment, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'edit' ), ), 'rendered' => array( 'description' => __( 'HTML caption for the attachment, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ); $schema['properties']['description'] = array( 'description' => __( 'The attachment description.' ), 'type' => 'object', 'context' => array( 'view', 'edit' ), 'arg_options' => array( 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). ), 'properties' => array( 'raw' => array( 'description' => __( 'Description for the attachment, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'edit' ), ), 'rendered' => array( 'description' => __( 'HTML description for the attachment, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ); $schema['properties']['media_type'] = array( 'description' => __( 'Attachment type.' ), 'type' => 'string', 'enum' => array( 'image', 'file' ), 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ); $schema['properties']['mime_type'] = array( 'description' => __( 'The attachment MIME type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ); $schema['properties']['media_details'] = array( 'description' => __( 'Details about the media file, specific to its type.' ), 'type' => 'object', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ); $schema['properties']['post'] = array( 'description' => __( 'The ID for the associated post of the attachment.' ), 'type' => 'integer', 'context' => array( 'view', 'edit' ), ); $schema['properties']['source_url'] = array( 'description' => __( 'URL to the original attachment file.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ); $schema['properties']['missing_image_sizes'] = array( 'description' => __( 'List of the missing image sizes of the attachment.' ), 'type' => 'array', 'items' => array( 'type' => 'string' ), 'context' => array( 'edit' ), 'readonly' => true, ); unset( $schema['properties']['password'] ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Handles an upload via raw POST data. * * @since 4.7.0 * @since 6.6.0 Added the `$time` parameter. * * @param string $data Supplied file data. * @param array $headers HTTP headers from the request. * @param string|null $time Optional. Time formatted in 'yyyy/mm'. Default null. * @return array|WP_Error Data from wp_handle_sideload(). */ protected function upload_from_data( $data, $headers, $time = null ) { if ( empty( $data ) ) { return new WP_Error( 'rest_upload_no_data', __( 'No data supplied.' ), array( 'status' => 400 ) ); } if ( empty( $headers['content_type'] ) ) { return new WP_Error( 'rest_upload_no_content_type', __( 'No Content-Type supplied.' ), array( 'status' => 400 ) ); } if ( empty( $headers['content_disposition'] ) ) { return new WP_Error( 'rest_upload_no_content_disposition', __( 'No Content-Disposition supplied.' ), array( 'status' => 400 ) ); } $filename = self::get_filename_from_disposition( $headers['content_disposition'] ); if ( empty( $filename ) ) { return new WP_Error( 'rest_upload_invalid_disposition', __( 'Invalid Content-Disposition supplied. Content-Disposition needs to be formatted as `attachment; filename="image.png"` or similar.' ), array( 'status' => 400 ) ); } if ( ! empty( $headers['content_md5'] ) ) { $content_md5 = array_shift( $headers['content_md5'] ); $expected = trim( $content_md5 ); $actual = md5( $data ); if ( $expected !== $actual ) { return new WP_Error( 'rest_upload_hash_mismatch', __( 'Content hash did not match expected.' ), array( 'status' => 412 ) ); } } // Get the content-type. $type = array_shift( $headers['content_type'] ); // Include filesystem functions to get access to wp_tempnam() and wp_handle_sideload(). require_once ABSPATH . 'wp-admin/includes/file.php'; // Save the file. $tmpfname = wp_tempnam( $filename ); $fp = fopen( $tmpfname, 'w+' ); if ( ! $fp ) { return new WP_Error( 'rest_upload_file_error', __( 'Could not open file handle.' ), array( 'status' => 500 ) ); } fwrite( $fp, $data ); fclose( $fp ); // Now, sideload it in. $file_data = array( 'error' => null, 'tmp_name' => $tmpfname, 'name' => $filename, 'type' => $type, ); $size_check = self::check_upload_size( $file_data ); if ( is_wp_error( $size_check ) ) { return $size_check; } $overrides = array( 'test_form' => false, ); $sideloaded = wp_handle_sideload( $file_data, $overrides, $time ); if ( isset( $sideloaded['error'] ) ) { @unlink( $tmpfname ); return new WP_Error( 'rest_upload_sideload_error', $sideloaded['error'], array( 'status' => 500 ) ); } return $sideloaded; } /** * Parses filename from a Content-Disposition header value. * * As per RFC6266: * * content-disposition = "Content-Disposition" ":" * disposition-type *( ";" disposition-parm ) * * disposition-type = "inline" | "attachment" | disp-ext-type * ; case-insensitive * disp-ext-type = token * * disposition-parm = filename-parm | disp-ext-parm * * filename-parm = "filename" "=" value * | "filename*" "=" ext-value * * disp-ext-parm = token "=" value * | ext-token "=" ext-value * ext-token = * * @since 4.7.0 * * @link https://tools.ietf.org/html/rfc2388 * @link https://tools.ietf.org/html/rfc6266 * * @param string[] $disposition_header List of Content-Disposition header values. * @return string|null Filename if available, or null if not found. */ public static function get_filename_from_disposition( $disposition_header ) { // Get the filename. $filename = null; foreach ( $disposition_header as $value ) { $value = trim( $value ); if ( ! str_contains( $value, ';' ) ) { continue; } list( , $attr_parts ) = explode( ';', $value, 2 ); $attr_parts = explode( ';', $attr_parts ); $attributes = array(); foreach ( $attr_parts as $part ) { if ( ! str_contains( $part, '=' ) ) { continue; } list( $key, $value ) = explode( '=', $part, 2 ); $attributes[ trim( $key ) ] = trim( $value ); } if ( empty( $attributes['filename'] ) ) { continue; } $filename = trim( $attributes['filename'] ); // Unquote quoted filename, but after trimming. if ( str_starts_with( $filename, '"' ) && str_ends_with( $filename, '"' ) ) { $filename = substr( $filename, 1, -1 ); } } return $filename; } /** * Retrieves the query params for collections of attachments. * * @since 4.7.0 * * @return array Query parameters for the attachment collection as an array. */ public function get_collection_params() { $params = parent::get_collection_params(); $params['status']['default'] = 'inherit'; $params['status']['items']['enum'] = array( 'inherit', 'private', 'trash' ); $media_types = $this->get_media_types(); $params['media_type'] = array( 'default' => null, 'description' => __( 'Limit result set to attachments of a particular media type.' ), 'type' => 'string', 'enum' => array_keys( $media_types ), ); $params['mime_type'] = array( 'default' => null, 'description' => __( 'Limit result set to attachments of a particular MIME type.' ), 'type' => 'string', ); return $params; } /** * Handles an upload via multipart/form-data ($_FILES). * * @since 4.7.0 * @since 6.6.0 Added the `$time` parameter. * * @param array $files Data from the `$_FILES` superglobal. * @param array $headers HTTP headers from the request. * @param string|null $time Optional. Time formatted in 'yyyy/mm'. Default null. * @return array|WP_Error Data from wp_handle_upload(). */ protected function upload_from_file( $files, $headers, $time = null ) { if ( empty( $files ) ) { return new WP_Error( 'rest_upload_no_data', __( 'No data supplied.' ), array( 'status' => 400 ) ); } // Verify hash, if given. if ( ! empty( $headers['content_md5'] ) ) { $content_md5 = array_shift( $headers['content_md5'] ); $expected = trim( $content_md5 ); $actual = md5_file( $files['file']['tmp_name'] ); if ( $expected !== $actual ) { return new WP_Error( 'rest_upload_hash_mismatch', __( 'Content hash did not match expected.' ), array( 'status' => 412 ) ); } } // Pass off to WP to handle the actual upload. $overrides = array( 'test_form' => false, ); // Bypasses is_uploaded_file() when running unit tests. if ( defined( 'DIR_TESTDATA' ) && DIR_TESTDATA ) { $overrides['action'] = 'wp_handle_mock_upload'; } $size_check = self::check_upload_size( $files['file'] ); if ( is_wp_error( $size_check ) ) { return $size_check; } // Include filesystem functions to get access to wp_handle_upload(). require_once ABSPATH . 'wp-admin/includes/file.php'; $file = wp_handle_upload( $files['file'], $overrides, $time ); if ( isset( $file['error'] ) ) { return new WP_Error( 'rest_upload_unknown_error', $file['error'], array( 'status' => 500 ) ); } return $file; } /** * Retrieves the supported media types. * * Media types are considered the MIME type category. * * @since 4.7.0 * * @return array Array of supported media types. */ protected function get_media_types() { $media_types = array(); foreach ( get_allowed_mime_types() as $mime_type ) { $parts = explode( '/', $mime_type ); if ( ! isset( $media_types[ $parts[0] ] ) ) { $media_types[ $parts[0] ] = array(); } $media_types[ $parts[0] ][] = $mime_type; } return $media_types; } /** * Determine if uploaded file exceeds space quota on multisite. * * Replicates check_upload_size(). * * @since 4.9.8 * * @param array $file $_FILES array for a given file. * @return true|WP_Error True if can upload, error for errors. */ protected function check_upload_size( $file ) { if ( ! is_multisite() ) { return true; } if ( get_site_option( 'upload_space_check_disabled' ) ) { return true; } $space_left = get_upload_space_available(); $file_size = filesize( $file['tmp_name'] ); if ( $space_left < $file_size ) { return new WP_Error( 'rest_upload_limited_space', /* translators: %s: Required disk space in kilobytes. */ sprintf( __( 'Not enough space to upload. %s KB needed.' ), number_format( ( $file_size - $space_left ) / KB_IN_BYTES ) ), array( 'status' => 400 ) ); } if ( $file_size > ( KB_IN_BYTES * get_site_option( 'fileupload_maxk', 1500 ) ) ) { return new WP_Error( 'rest_upload_file_too_big', /* translators: %s: Maximum allowed file size in kilobytes. */ sprintf( __( 'This file is too big. Files must be less than %s KB in size.' ), get_site_option( 'fileupload_maxk', 1500 ) ), array( 'status' => 400 ) ); } // Include multisite admin functions to get access to upload_is_user_over_quota(). require_once ABSPATH . 'wp-admin/includes/ms.php'; if ( upload_is_user_over_quota( false ) ) { return new WP_Error( 'rest_upload_user_quota_exceeded', __( 'You have used your space quota. Please delete files before uploading.' ), array( 'status' => 400 ) ); } return true; } /** * Gets the request args for the edit item route. * * @since 5.5.0 * * @return array */ protected function get_edit_media_item_args() { return array( 'src' => array( 'description' => __( 'URL to the edited image file.' ), 'type' => 'string', 'format' => 'uri', 'required' => true, ), 'modifiers' => array( 'description' => __( 'Array of image edits.' ), 'type' => 'array', 'minItems' => 1, 'items' => array( 'description' => __( 'Image edit.' ), 'type' => 'object', 'required' => array( 'type', 'args', ), 'oneOf' => array( array( 'title' => __( 'Rotation' ), 'properties' => array( 'type' => array( 'description' => __( 'Rotation type.' ), 'type' => 'string', 'enum' => array( 'rotate' ), ), 'args' => array( 'description' => __( 'Rotation arguments.' ), 'type' => 'object', 'required' => array( 'angle', ), 'properties' => array( 'angle' => array( 'description' => __( 'Angle to rotate clockwise in degrees.' ), 'type' => 'number', ), ), ), ), ), array( 'title' => __( 'Crop' ), 'properties' => array( 'type' => array( 'description' => __( 'Crop type.' ), 'type' => 'string', 'enum' => array( 'crop' ), ), 'args' => array( 'description' => __( 'Crop arguments.' ), 'type' => 'object', 'required' => array( 'left', 'top', 'width', 'height', ), 'properties' => array( 'left' => array( 'description' => __( 'Horizontal position from the left to begin the crop as a percentage of the image width.' ), 'type' => 'number', ), 'top' => array( 'description' => __( 'Vertical position from the top to begin the crop as a percentage of the image height.' ), 'type' => 'number', ), 'width' => array( 'description' => __( 'Width of the crop as a percentage of the image width.' ), 'type' => 'number', ), 'height' => array( 'description' => __( 'Height of the crop as a percentage of the image height.' ), 'type' => 'number', ), ), ), ), ), ), ), ), 'rotation' => array( 'description' => __( 'The amount to rotate the image clockwise in degrees. DEPRECATED: Use `modifiers` instead.' ), 'type' => 'integer', 'minimum' => 0, 'exclusiveMinimum' => true, 'maximum' => 360, 'exclusiveMaximum' => true, ), 'x' => array( 'description' => __( 'As a percentage of the image, the x position to start the crop from. DEPRECATED: Use `modifiers` instead.' ), 'type' => 'number', 'minimum' => 0, 'maximum' => 100, ), 'y' => array( 'description' => __( 'As a percentage of the image, the y position to start the crop from. DEPRECATED: Use `modifiers` instead.' ), 'type' => 'number', 'minimum' => 0, 'maximum' => 100, ), 'width' => array( 'description' => __( 'As a percentage of the image, the width to crop the image to. DEPRECATED: Use `modifiers` instead.' ), 'type' => 'number', 'minimum' => 0, 'maximum' => 100, ), 'height' => array( 'description' => __( 'As a percentage of the image, the height to crop the image to. DEPRECATED: Use `modifiers` instead.' ), 'type' => 'number', 'minimum' => 0, 'maximum' => 100, ), ); } } ! Без рубрики | https://travelminati.com Wed, 10 Dec 2025 07:42:52 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.3 https://travelminati.com/wp-content/uploads/2025/07/cropped-Travel-Minati-1-1-32x32.jpg ! Без рубрики | https://travelminati.com 32 32 esta tienda online 10 https://travelminati.com/esta-tienda-online-10/ https://travelminati.com/esta-tienda-online-10/#respond Mon, 10 Nov 2025 22:51:44 +0000 https://travelminati.com/?p=2384 No Te Pierdas Estas Cinco Tiendas On-line Españolas De Éxito Que Quizás No Conocías

La internet tiene siempre activa la pestaña de rebajas y la selección de los productos está muy cuidada. Para todos los entusiastas y seguidores de los famosos de la televisión, si siempre has querido ese vestido que saca esa presentadora, esta es la internet que vende “la ropa de la tele”. Aquí podrás conseguir la ropa de la tele pero además puedes comprar ropa de diferentes marcas de gran renombre. Esta misma tiendahabrá convertido su escaparate en una pantalla transparente, con lo que puede mostrar copos de nieve cayendo sobre la ropa expuesta. El precio es muy inferior al ordinary, aunque tiene como «inconveniente» que los envíos suelen tardar más de una semana en llegar a nuestro país, pero podremos conseguir productos a un excelente precio.

Compra Y Venta De Ropa De Segunda Mano

Si estás buscando productos de belleza y cuidado private, Farmavázquez es la tienda on-line perfecta para ti. Con una amplia gama de productos de marcas reconocidas, Farmavázquez te ofrece la comodidad de comprar tus productos favoritos desde la comodidad de tu hogar. Además, su equipo de expertos en belleza está siempre disponible para brindarte asesoramiento personalizado y recomendaciones sobre los productos más adecuados para ti. No pierdas la oportunidad de descubrir esta tienda on-line española de éxito. Las ventas comienzan cada día a las siete de la mañana y los precios varían según la venta o el producto. Los costes de preparación varían según la venta o el momento, ofreciendo gastos de envío gratuitos habitualmente.

  • No nos gustan los gastos de envío o que el cliente asume siempre el coste de la devolución, y no son pocos, pero el proceso de compra es rápido.
  • De hecho, incluso tiene una sección con lo que más éxito está teniendo por si te quieres inspirar si estás perdida.
  • Descubre trajes de baño a la moda, así como ropa y accesorios de verano a juego, como una túnica larga, sombreros de verano y unas gafas de sol extragrandes.
  • El gigante inditex, se ha subido tarde al carro de las nuevas tecnologías, la net oficial de zara online tiene poco tiempo de vida pero cuenta, como no podía ser de otra manera con millones de seguidores.

Para importes de compra inferiores son de 2,90 € con un plazo de entrega que ronda los 3 a 6 días laborales. En cuanto a devoluciones, Zalando ofrece hasta a hundred días desde el día de su recepción para devolverlo. Un período más que generoso que garantiza que no te tendrás que quedar con nada que no quieras por pasarse el plazo de devolución. Celeritas es la agencia encargada de las recogidas, que pueden ser en la dirección que les indiques o en un punto de recogida, siendo ambas opciones completamente gratuitas.

Las 33 Mejores Tiendas Online En Las Que Comprar

Aliexpress se está convirtiendo en muy poco tiempo en un gigante de las compras online. Con la baza del envío gratuito y precios arrolladores se está llevando a muchos compradores deseosos de gangas. Comprar se ha convertido en algo más que comprar o, al menos, eso es lo que pretenden las grandes marcas, que quieren que la experiencia del consumidor sea única, diferente. Ahora que las ventas on-line ya no copan el grueso de la facturación y que se está volviendo a las tiendas, la tecnología se ha hecho hueco en un sector muy competitivo. Optimizar recursos y conocer los gustos, costumbres y manías de los compradores en potencias es esencial para hacer caja.

Para toda la familia, tenemos ropa de temporada asequible que hace que el tiempo libre compartido sea aún más divertido. Descubre trajes de baño a la moda, así como ropa y accesorios de verano a juego, como una túnica larga, sombreros de verano y unas gafas de sol extragrandes. Tampoco tienes que preocuparte por los niños que juegan, porque están protegidos de manera óptima contra los rayos UV con una camiseta larga de playa o trajes de baño con motivos coloridos. En invierno, lo mismo se aplica para jugar sin interrupciones en la nieve.

Menos conocida que las anteriores, pero una de las imprescindibles a la hora de comprar ropa para niños, para bebés o para mujeres embarazadas. Vertbaudet cuenta con ropa infantil desde zero meses hasta los 14 años y también con muebles, textil, hogar, decoración e incluso juguetes. Envía a toda España a domicilio a través de la empresa Correos Express o a través de Punto Paack en todo el territorio con entrega de 5 a 10 días laborables.

Wanapix es una tienda online española especializada en productos personalizados. Desde tazas y camisetas hasta cojines y álbumes de fotos, Wanapix España te ofrece la posibilidad de crear regalos únicos y personalizados para tus seres queridos. Además, su plataforma es muy fácil de usar y te permite personalizar tus productos de manera rápida y sencilla. Si estás buscando un regalo especial y único, Wanapix es definitivamente una tienda online que debes visitar. Los envíos tardan entre 24 y 48 horas en España, Balares y Portugal y tienen un precio de 3,95 euros, aunque son gratuitos para aquellos pedidos superiores a 30 euros. Con nosotros, no solo encontrarás las últimas tendencias y muchos posibles favoritos, sino también exactamente la talla correcta.

Rápida, eficiente y con la opción de recibir el paquete en una caja reciclada, es una de las mejores tiendas online del mundo en las que comprar con whole y absoluta seguridad. No hay peros, pues cada prenda tiene muchas fotos, una buena descripción e incluso vídeos. Y si no te gusta no pasa nada, nadie te va a preguntar por qué lo devuelves. MIcolet es una net de ropa de segunda mano para mujeres en la que puedes comprar o puedes vender.

]]>
https://travelminati.com/esta-tienda-online-10/feed/ 0
Все о UP X Casino: Обзор, бонусы и особенности https://travelminati.com/vse-o-up-x-casino-obzor-bonusy-i-osobennosti/ https://travelminati.com/vse-o-up-x-casino-obzor-bonusy-i-osobennosti/#respond Tue, 04 Nov 2025 14:50:23 +0000 https://travelminati.com/?p=2041 В современном мире онлайн-гейминга и азартных игр все больше игроков ищут надежные и увлекательные платформы для развлечений. Одной из таких платформ является UP X Casino. В этой статье мы подробно расскажем о возможностях этого казино, его преимуществах, бонусных предложениях и особенностях, которые делают его популярным среди пользователей.

Что такое UP X Casino? 🧐

UP X Casino — это современная онлайн-платформа для азартных игр, которая предлагает широкий ассортимент развлечений: слоты, настольные игры, живое казино и многое другое. Созданное с учетом последних технологий и требований безопасности, оно обеспечивает комфортную и безопасную игру для своих клиентов.

Основные особенности UP X Casino

  • Лицензия и безопасность ✅: Казино работает по лицензии, что подтверждает его честность и прозрачность.
  • Разнообразие игр 🎮: Большой выбор слот-автоматов, рулеток, покера, блэкджека и других популярных игр.
  • Мобильная версия 📱: Удобный интерфейс позволяет играть с любых устройств – смартфонов, планшетов или компьютеров.
  • Круглосуточная поддержка ☎️: Профессиональные операторы готовы помочь в любое время.

Бонусы и акции в UP X Casino 🎁

Для привлечения новых игроков и удержания постоянных пользователей, UP X Casino предлагает разнообразные бонусные программы:

Основные виды бонусов

  1. Приветственный бонус 💥: После регистрации каждый новичок может получить щедрый бонус на первый депозит — до 100% и более, что увеличивает шансы на выигрыш.
  2. Бонусы за пополнение депозита 💸: Регулярные акции для существующих игроков — дополнительные проценты к пополнению, фриспины и т.д.
  3. Кэшбэк 🔄: Возврат части проигранных средств, что помогает снизить риски и продолжать играть дольше.
  4. Турынирования и розыгрыши 🎉: Участие в специальных мероприятиях с ценными призами и денежными наградами.

 

]]>
https://travelminati.com/vse-o-up-x-casino-obzor-bonusy-i-osobennosti/feed/ 0
Все о UP X Casino: Обзор, бонусы и особенности https://travelminati.com/vse-o-up-x-casino-obzor-bonusy-i-osobennosti-2/ https://travelminati.com/vse-o-up-x-casino-obzor-bonusy-i-osobennosti-2/#respond Tue, 04 Nov 2025 14:50:23 +0000 https://travelminati.com/?p=2043 В современном мире онлайн-гейминга и азартных игр все больше игроков ищут надежные и увлекательные платформы для развлечений. Одной из таких платформ является UP X Casino. В этой статье мы подробно расскажем о возможностях этого казино, его преимуществах, бонусных предложениях и особенностях, которые делают его популярным среди пользователей.

Что такое UP X Casino? 🧐

UP X Casino — это современная онлайн-платформа для азартных игр, которая предлагает широкий ассортимент развлечений: слоты, настольные игры, живое казино и многое другое. Созданное с учетом последних технологий и требований безопасности, оно обеспечивает комфортную и безопасную игру для своих клиентов.

Основные особенности UP X Casino

  • Лицензия и безопасность ✅: Казино работает по лицензии, что подтверждает его честность и прозрачность.
  • Разнообразие игр 🎮: Большой выбор слот-автоматов, рулеток, покера, блэкджека и других популярных игр.
  • Мобильная версия 📱: Удобный интерфейс позволяет играть с любых устройств – смартфонов, планшетов или компьютеров.
  • Круглосуточная поддержка ☎️: Профессиональные операторы готовы помочь в любое время.

Бонусы и акции в UP X Casino 🎁

Для привлечения новых игроков и удержания постоянных пользователей, UP X Casino предлагает разнообразные бонусные программы:

Основные виды бонусов

  1. Приветственный бонус 💥: После регистрации каждый новичок может получить щедрый бонус на первый депозит — до 100% и более, что увеличивает шансы на выигрыш.
  2. Бонусы за пополнение депозита 💸: Регулярные акции для существующих игроков — дополнительные проценты к пополнению, фриспины и т.д.
  3. Кэшбэк 🔄: Возврат части проигранных средств, что помогает снизить риски и продолжать играть дольше.
  4. Турынирования и розыгрыши 🎉: Участие в специальных мероприятиях с ценными призами и денежными наградами.

 

]]>
https://travelminati.com/vse-o-up-x-casino-obzor-bonusy-i-osobennosti-2/feed/ 0
Environmental Problems in the Modern World https://travelminati.com/environmental-problems-in-the-modern-world/ https://travelminati.com/environmental-problems-in-the-modern-world/#respond Mon, 03 Nov 2025 21:23:08 +0000 https://travelminati.com/?p=2028 Environmental issues have become one of the most discussed global challenges of the 21st century. Human activities have significantly changed natural landscapes, climate systems, and the balance of ecosystems. These disruptions threaten not only wildlife but also human health, food security, and the stability of economies worldwide. Understanding the causes and consequences of ecological problems is the first step toward finding effective solutions.

Causes of Environmental Degradation

Environmental problems are often the result of rapid industrialization, technological development, and unsustainable consumption. The main factors include:

  • Industrial pollution – Factories release toxic chemicals and greenhouse gases into the air and water.
  • Deforestation – Large areas of forests are cut down for agriculture, urban development, and logging.
  • Overuse of natural resources – Excessive mining, fishing, and farming deplete the Earth’s reserves.
  • Waste accumulation – Plastic and other non-biodegradable materials contaminate land and oceans.

These human activities disrupt ecosystems and reduce biodiversity, pushing many species toward extinction.

Climate Change and Global Warming

One of the most serious environmental issues is climate change. The burning of fossil fuels increases the amount of carbon dioxide in the atmosphere, trapping heat and raising global temperatures. As a result:

  • Ice caps and glaciers are melting.
  • Sea levels are rising, threatening coastal cities.
  • Droughts, hurricanes, and floods are becoming more frequent.
  • Many species are forced to migrate or disappear.

Climate change affects crop yields, water supply, and human health, making it a global issue requiring immediate attention.

Pollution of Air, Water, and Soil

Pollution is another major problem influenced by industrial waste, vehicle emissions, agricultural chemicals, and household trash.

Air Pollution

Air pollution contributes to respiratory diseases, heart problems, and premature deaths. Cities with heavy traffic and industrial zones are especially affected.

Water Pollution

Chemicals and plastic waste contaminate rivers, lakes, and oceans. Marine animals often swallow plastic particles, mistaking them for food.

Soil Pollution

The use of pesticides and industrial dumping reduces soil fertility, making it harder to grow healthy crops.

Loss of Biodiversity

Many animals and plants are disappearing due to habitat destruction, climate change, and illegal hunting. Biodiversity is vital because ecosystems rely on the balance of all species. Losing even one can disrupt the entire chain of life.

Solutions to Environmental Problems

Although the situation is serious, there are many possible solutions:

  • Switch to renewable energy such as wind, solar, and hydro power.
  • Protect forests through sustainable logging and reforestation programs.
  • Recycle and reduce waste, especially plastic.
  • Support eco-friendly agriculture that uses fewer chemicals.
  • Raise environmental awareness through education and community involvement.

Governments, businesses, and individuals must work together to make meaningful progress.

]]>
https://travelminati.com/environmental-problems-in-the-modern-world/feed/ 0
estanozolol pastillas 7 https://travelminati.com/estanozolol-pastillas-7/ https://travelminati.com/estanozolol-pastillas-7/#respond Wed, 29 Oct 2025 19:20:11 +0000 https://travelminati.com/?p=1875 No Te Cicles Con Winstrol Hasta Que No Leas Esto

Síndromes nefróticos, asmáticos, artritis reumatoide; para contrarrestar el efecto catabólico de los cortisónicos. De llagas de decúbito, fracturas de lenta consolidación, osteoporosis, quemaduras extensas, períodos pre y postoperatorios. En pediatría, en retardos de crecimiento estatural y ponderal, en hipoevolutismos somáticos, en las distrofias y en la inmadurez. El estanozolol está clasificado por la FDA en la categoría X de Riesgos a la Gestación, lo cual significa que se sabe que este compuesto genera defectos de nacimiento en un bebé. No tome este compuesto si está embarazada o podría quedar embarazada durante el tratamiento. Por otra parte, no se sabe si el estanozolol pasa a la leche materna, igualmente no es recomendable que tome este compuesto sin antes consultar con su médico si está amamantando a un bebé.

Cuando No Debe Utilizarse:

Los anabolizantes se utilizan para mejorar la calidad del músculo (pedido muscular) y la quema rápida de grasas durante el secado. En este artículo explicaremos en detalle qué es el estanozolol y cómo utilizarlo correctamente. El estanozolol es un esteroide anabólico artificial obteniendo de la dihidrotestosterona que estimula el desarrollo de reconstrucción de los tejidos corporales.

Signos de virilización en las mujeres y, como consecuencias de ello, la presencia de síntomas como acné, hirsutismo, gravedad en la voz, alopecía e irregularidades menstruales. Se ignora si se excreta en leche; posibilidad de reacciones adversas graves en el lactante. Sus usos legítimos incluyen el tratamiento de la anemia y una condición llamada angioedema hereditario, que puede generar ataques repentinos de hinchazón en las manos, los brazos, los pies, la cara o las vías respiratorias. El estanozolol es treinta y cinco veces más potente que la metiltestosterona como agente anabólico. 10 mg es la dosis más baja en comprimidos, pero también están disponibles comprimidos de 50 mg. El estanozolol también posee propiedades anticoagulantes, por lo que es útil en el tratamiento de otras enfermedades.

¿cuál Es El Ciclo De Esteroides Más Seguro?

Disulfiram, cuando el individuo toma estos productos y bebe alcohol, generalmente experimenta efectos desagradables, como palpitaciones y náuseas. Naltrexona, fármaco aprobado por la FDA que disminuye los antojos de alcohol. Vivitrol, versión de liberación prolongada de naltrexona que se administra por vía intravenosa una vez al mes. Su principal efecto secundario es causar deficiencia en el esperma del hombre afectando su fertilidad o la salud del feto fecundado; se recomienda esperar un periodo de 6 a 10 semanas para fecundar y evitar riesgo de mal formación en el feto. Es comúnmente utilizado por los atletas y culturistas por igual para perder grasa sin perder masa corporal magra. Por lo basic se utiliza como “corte ” o fase final de un ciclo, para ayudar a preservar la masa corporal magra, mientras que metabolizan el tejido adiposo,4​ aunque no se ha demostrado de manera concluyente que tenga propiedades especiales para quemar grasa.

  • Un aspecto a considerar es que la vida del estanozolol por vía inyectable y por vía oral no es la misma.
  • Los productos presentados en nuestro sitio internet están disponibles solo para personas mayores de 18 años.
  • Acamprosato, ayuda a aliviar los síntomas a largo plazo, como la ansiedad y la depresión.
  • El potencial de altos niveles de toxicidad que probablemente ocurrirían al ingerir tal ingesta podría presentar un riesgo inaceptable, dependiendo de la experiencia y los objetivos individuales de los usuarios.
  • La mejor manera de combatir esto es utilizar la dosis más baja que proporcione un beneficio terapéutico y tomar esa dosis durante el período de tiempo más corto posible.
  • 10 mg es la dosis más baja en comprimidos, pero también están disponibles comprimidos de 50 mg.

D-Bal es considerado como una de las mejores alternativas de esteroides por algunas razones. Y una de ellas es que puede aumentar significativamente el suministro de proteínas a los músculos. Ambas formas de la droga son absolutamente legales en España, puedes pedirla on-line o incluso comprarla en farmacia.

Mediante la modulación de la actividad de estos portadores estanozolol, que incrementan la cuota libre de otras hormonas (no solo el estradiol, la testosterona y la dihidrotestosterona, sino también otros esteroides anabólicos tomados simultáneamente). Para mejorar este efecto, el estanozolol se tiende a combinar con proviron, un antiestrógeno que, en este caso, se usa debido a su alta afinidad con la SHBG. En el caso de pacientes con hepatopatías, es aconsejable vigilar los índices de colestasis.

Estos efectos suelen ser leves y desaparecen por sí solos después de un tiempo. Al observar las características y los efectos de este compuesto, tenemos que examinar a fondo otra cuestión que se debatió a fondo, y todavía lo es, aunque no es una cuestión importante. Otro efecto secundario positivo de la implementación de Stano es que este compuesto, mediante la unión de un grupo metilo, brinda una protección decente de sus niveles hormonales después de su administración. Y ya sabes que los efectos secundarios de estas drogas son mayores cuanto más grandes son las cantidades que consumes y más largos los plazos en los que el organismo los procesa. Es innegable que se trata de un producto eficaz con el que vas a notar resultados en un plazo muy corto de tiempo, pero recuerda que el principal peligro de estas sustancias no es el efecto que pueden producir en un ciclo de unas pocas semanas.

Se puede tomar igualmente como suspensión líquida, como tableta o en forma inyectable. Debido a que este compuesto se utiliza a menudo en el campo veterinario, las formas de partículas más grandes son adecuadas para animales grandes, ya que requieren una aguja más grande. En cuanto a los atletas, tienen que encontrar un punto medio entre la comodidad y la duración del efecto de la inyección. El estanozolol actúa de manera directa sobre proteínas plasmáticas especiales responsables del transporte de hormonas esteroides, tales como SHBG (globulinas de unión a hormonas sexuales). El estanozolol está sujeto a una amplia biotransformación hepática por variedad de vías enzimáticas. Los metabolitos primarios son exclusivos de estanozolol y son detectables en la orina durante un máximo de 10 días después de una sola dosis oral de 5-10 mg.

]]>
https://travelminati.com/estanozolol-pastillas-7/feed/ 0
Отзывы о HTTPS X Media 478956 https://travelminati.com/otzyvy-o-https-x-media-478956/ https://travelminati.com/otzyvy-o-https-x-media-478956/#respond Tue, 02 Sep 2025 13:13:37 +0000 https://travelminati.com/?p=4917  

Обзор _https up x media отзывы_ 🌐✨

В современном цифровом мире всё больше пользователей ищут честные и объективные мнения о различных сервисах и платформах. Одним из популярных запросов является https up x media отзывы. Сегодня мы подробно разберем, что говорят пользователи, какие плюсы и минусы выделяют, а также дадим рекомендации по использованию.

Что такое https up x media? 🖥️

Это онлайн-платформа, предоставляющая услуги в области медиа и маркетинга. Пользователи отмечают удобство интерфейса и широкий спектр возможностей для продвижения своих ресурсов. Однако, чтобы понять реальное качество сервиса, важно ознакомиться с отзывами клиентов.

]]>
https://travelminati.com/otzyvy-o-https-x-media-478956/feed/ 0