/** * 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() ) ); } 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' ); $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. counter clockwise. $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 sub-directory 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( $type, $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, ), ); } } casino online game – Sanathan Dharm Veda https://sanatandharmveda.com Fri, 04 Sep 2026 15:27:59 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.7 https://sanatandharmveda.com/wp-content/uploads/2024/05/cropped-cropped-pexels-himeshmehtaa25-3519190-32x32.jpg casino online game – Sanathan Dharm Veda https://sanatandharmveda.com 32 32 Pin Up Az: Azərbaycanın Ən Populyar Onlayn Kazinosu https://sanatandharmveda.com/pin-up-az-azrbaycann-n-populyar-onlayn-kazinosu-22/ https://sanatandharmveda.com/pin-up-az-azrbaycann-n-populyar-onlayn-kazinosu-22/#respond Fri, 04 Sep 2026 12:36:28 +0000 https://sanatandharmveda.com/?p=216837 casino online game

Pin Up Az Kazino

Pin Up Az, Azərbaycan ərazisində ən populyar onlayn kazino platformalarından biridir. Bu saytda slot oyunları, bonuslar, pulsuz fırlanmalar və daha bir çoxunu tapa bilərsiniz.

pinup saytına daxil olaraq, qeydiyyatdan keçin və onlayn oyunlar dünyasına daxil olun. Real pul ilə oynamağın keyfini çıxarın və əyləncəli kazino oyunları təcrübəsi yaşayın.

Pin Up Az, oyun seçimləri, bonuslar və müştəri xidmətləri ilə diqqət çəkir və real pula oynamaq istəyənlər üçün mükəmməl bir seçimdir.

Pin Up Az, onlayn kazino oyunlarında keyfiyyət və əyləncəni bir araya gətirir. Slotlar, bonuslar, pulsuz fırlanmalar və daha bir çoxunu əldə etmək üçün hər gün sayta daxil olun.

Pin Up Az, onlayn kazino oyunlarında ən yaxşı təcrübəni təqdim edir. Hesabınızı qeydiyyatdan keçirin və oyunlarınızı başlayın!

]]>
https://sanatandharmveda.com/pin-up-az-azrbaycann-n-populyar-onlayn-kazinosu-22/feed/ 0
Descubre Chicken Road: Tu destino de entretenimiento en línea en Chile https://sanatandharmveda.com/descubre-chicken-road-tu-destino-de/ https://sanatandharmveda.com/descubre-chicken-road-tu-destino-de/#respond Wed, 26 Aug 2026 10:50:13 +0000 https://sanatandharmveda.com/?p=196240 casino online game

Descubre Chicken Road, tu destino de entretenimiento en línea en Chile

En el mundo de los casinos en línea, Chicken Road destaca como una opción popular entre los jugadores chilenos. Con una amplia variedad de tragamonedas, bonos atractivos y giros gratis, este sitio se ha convertido en el favorito de muchos entusiastas de los juegos de azar en el país. Si estás buscando una experiencia emocionante y segura, te invitamos a visitar https://chickenroad-cl.co.com/ y descubrir todo lo que tiene para ofrecerte.

Tragamonedas emocionantes para todos los gustos

Una de las principales atracciones de Chicken Road son sus tragamonedas, que ofrecen una amplia variedad de temas y estilos para satisfacer los gustos de todos los jugadores. Desde clásicos juegos de frutas hasta emocionantes tragamonedas con gráficos de última generación, aquí encontrarás opciones para todos los gustos. Además, con la posibilidad de ganar bonos y giros gratis, la emoción nunca termina.

Regístrate y disfruta de increíbles bonos y promociones

Al unirte a Chicken Road, tendrás la oportunidad de acceder a increíbles bonos de bienvenida y promociones exclusivas que te permitirán maximizar tu experiencia de juego. Ya sea que estés buscando jugar con dinero real o simplemente quieras disfrutar de algunos giros gratis, este sitio tiene algo para todos. No te pierdas la oportunidad de aprovechar al máximo tu registro y disfrutar de todo lo que Chicken Road tiene para ofrecer.

Explora una amplia selección de juegos de casino en línea

Además de las tragamonedas, Chicken Road también ofrece una amplia variedad de juegos de casino en línea, que van desde el blackjack y la ruleta hasta el póker y el baccarat. Con opciones para jugadores de todos los niveles, este sitio es el destino perfecto para aquellos que buscan una experiencia de juego completa y emocionante. ¿Estás listo para sumergirte en la diversión?

Disfruta de una experiencia de juego segura y emocionante

En Chicken Road, la seguridad de los jugadores es una prioridad. Con medidas de protección de datos y transacciones seguras, puedes disfrutar de tus juegos favoritos con total tranquilidad. Además, con un equipo de atención al cliente disponible las 24 horas del día, los 7 días de la semana, cualquier duda o problema que tengas será resuelto de manera rápida y eficiente. Jugar en línea nunca había sido tan seguro y conveniente.

Únete a la diversión en Chicken Road y vive la emoción de los juegos de casino en línea

Ya sea que seas un jugador experimentado o estés recién comenzando en el mundo de los casinos en línea, Chicken Road es el lugar perfecto para disfrutar de una experiencia de juego inigualable. Regístrate hoy mismo, explora la amplia selección de juegos disponibles y descubre por qué este sitio se ha convertido en el favorito de tantos jugadores chilenos. ¡No esperes más y comienza a disfrutar de la emoción de jugar en línea!

]]>
https://sanatandharmveda.com/descubre-chicken-road-tu-destino-de/feed/ 0
¡Descubre Pin Up Casino y disfruta de la mejor experiencia de juego en Ecuador! https://sanatandharmveda.com/descubre-pin-up-casino-y-disfruta-de-la-mejor-3/ https://sanatandharmveda.com/descubre-pin-up-casino-y-disfruta-de-la-mejor-3/#respond Wed, 26 Aug 2026 08:07:28 +0000 https://sanatandharmveda.com/?p=196138 casino online game

Descubre Pin Up Casino en Ecuador

Si estás buscando una experiencia emocionante de juegos de casino en línea en Ecuador, no puedes dejar de visitar el casino Pin-Up Ecuador. Con una amplia selección de tragamonedas, bonos tentadores y la posibilidad de ganar giros gratis, este casino en línea te garantiza horas de diversión y emoción.

Tragamonedas de Última Generación

Pin Up Casino ofrece una variedad de tragamonedas de última generación con gráficos impresionantes y funciones especiales que te mantendrán entretenido durante horas. Desde los clásicos de 3 carretes hasta los video slots más innovadores, encontrarás opciones para todos los gustos.

Bonos y Promociones Exclusivas

Al registrarte en Pin Up Casino en Ecuador, podrás disfrutar de increíbles bonos de bienvenida y promociones exclusivas que te permitirán aumentar tus posibilidades de ganar. Además, podrás obtener giros gratis en tus juegos favoritos y participar en emocionantes torneos.

Registro Sencillo y Seguro

El proceso de registro en Pin Up Casino es rápido y sencillo, y garantiza la seguridad de tus datos personales y financieros. Solo necesitas completar unos pocos pasos para comenzar a disfrutar de todos los juegos en línea que este casino tiene para ofrecerte.

Juegos de Casino para Todos los Gustos

Ya sea que prefieras las tragamonedas, la ruleta, el blackjack o el póker, en Pin Up Casino encontrarás una amplia variedad de juegos de casino para satisfacer tus gustos y preferencias. Podrás jugar con dinero real y vivir la emoción de la experiencia de juego en línea.

Disfruta de la Mejor Experiencia de Juego en Ecuador

En resumen, Pin Up Casino es el destino perfecto para los amantes de los juegos de casino en línea en Ecuador. Con su amplia variedad de juegos, bonos generosos y atención al cliente de primera clase, este casino te garantiza una experiencia de juego inigualable. ¡No esperes más y únete a la diversión en Pin Up Casino hoy mismo!

]]>
https://sanatandharmveda.com/descubre-pin-up-casino-y-disfruta-de-la-mejor-3/feed/ 0
¡Disfruta de la emoción del casino en línea con Pin Up Casino en Ecuador! https://sanatandharmveda.com/disfruta-de-la-emocion-del-casino-en-linea-con-pin-3/ https://sanatandharmveda.com/disfruta-de-la-emocion-del-casino-en-linea-con-pin-3/#respond Wed, 26 Aug 2026 08:07:15 +0000 https://sanatandharmveda.com/?p=196136 casino online game

Introducción

Pin Up Casino es una plataforma de juegos en línea que ha ganado popularidad en todo el mundo, incluido Ecuador. Con una amplia variedad de juegos de casino, bonos atractivos y la posibilidad de jugar con dinero real, Pin Up Casino ofrece una experiencia de juego emocionante y segura para sus usuarios ecuatorianos.

Registro en Pin Up Casino

Para comenzar a disfrutar de la amplia gama de juegos que ofrece Pin Up Casino, es necesario registrarse en la plataforma. El proceso de registro es sencillo y rápido, y una vez completado, los jugadores ecuatorianos pueden acceder a tragamonedas, juegos de mesa y mucho más. Además, al registrarse, los nuevos usuarios pueden aprovechar bonos de bienvenida y giros gratis para aumentar sus posibilidades de ganar.

Descargar Pin Up APK

Si prefieres jugar en tu dispositivo móvil, puedes descargar Pin Up APK desde descargar Pin Up APK para acceder a la plataforma en cualquier momento y lugar. Con la aplicación móvil de Pin Up Casino, los jugadores ecuatorianos pueden disfrutar de sus juegos favoritos desde sus teléfonos o tabletas de forma conveniente.

Variedad de juegos en línea

Pin Up Casino ofrece una amplia variedad de juegos en línea para satisfacer todos los gustos. Desde tragamonedas clásicas hasta juegos de mesa como el blackjack y la ruleta, los jugadores ecuatorianos encontrarán opciones emocionantes para disfrutar. Además, la plataforma actualiza regularmente su catálogo de juegos para ofrecer nuevas experiencias a sus usuarios.

Bonos y promociones

Una de las ventajas de jugar en Pin Up Casino son los generosos bonos y promociones que ofrece. Los jugadores ecuatorianos pueden aprovechar bonos de recarga, giros gratis y otras ofertas especiales que aumentan sus posibilidades de ganar grandes premios. Además, el programa de fidelidad recompensa a los jugadores más activos con beneficios exclusivos.

Jugar con dinero real en Pin Up Casino

Para aquellos que buscan emociones reales, Pin Up Casino permite a los jugadores ecuatorianos jugar con dinero real y competir por premios en efectivo. Con métodos de pago seguros y una plataforma confiable, los usuarios pueden disfrutar de la emoción de los juegos de casino desde la comodidad de sus hogares. ¡No esperes más para unirte a la diversión en Pin Up Casino!

]]>
https://sanatandharmveda.com/disfruta-de-la-emocion-del-casino-en-linea-con-pin-3/feed/ 0
Découvrez le jeu Aviator en ligne en République Démocratique du Congo! https://sanatandharmveda.com/decouvrez-le-jeu-aviator-en-ligne-en-republique-134/ https://sanatandharmveda.com/decouvrez-le-jeu-aviator-en-ligne-en-republique-134/#respond Tue, 25 Aug 2026 10:59:57 +0000 https://sanatandharmveda.com/?p=195901 casino online game

Jeu Aviator en ligne en République Démocratique du Congo

Les jeux de casino en ligne sont de plus en plus populaires en République Démocratique du Congo. Parmi les jeux les plus appréciés, on retrouve le jeu Aviator, qui offre une expérience de jeu passionnante pour les amateurs de machines à sous.

Si vous cherchez à jouer au jeu Aviator en ligne, vous pouvez vous rendre sur https://aviator-rdc.com/ pour découvrir une sélection de jeux de casino en ligne, y compris le jeu Aviator. L’inscription est rapide et facile, et vous pourrez profiter de bonus, de tours gratuits et de la possibilité de jouer avec de l’argent réel.

Les avantages de jouer au jeu Aviator en ligne en République Démocratique du Congo

En optant pour les jeux de casino en ligne, vous avez la possibilité de jouer à tout moment et de n’importe où, tant que vous disposez d’une connexion internet. Vous pouvez profiter d’une large gamme de jeux de casino, y compris le jeu Aviator, sans avoir à vous déplacer dans un casino physique.

Les jeux de casino en ligne offrent également des bonus attractifs, tels que des tours gratuits et des promotions spéciales pour les nouveaux joueurs. En jouant au jeu Aviator en ligne, vous pouvez bénéficier de ces offres pour augmenter vos chances de gagner et prolonger votre expérience de jeu.

En plus de l’aspect divertissant, jouer au jeu Aviator en ligne en République Démocratique du Congo vous permet de découvrir de nouvelles sensations et de vivre des moments palpitants. Que vous soyez un novice ou un joueur expérimenté, les jeux de casino en ligne offrent une expérience de jeu immersive et captivante.

Conclusion

En résumé, le jeu Aviator en ligne est une option idéale pour les passionnés de jeux de casino en République Démocratique du Congo. Avec la possibilité de jouer à tout moment, de bénéficier de bonus et de tours gratuits, et de découvrir une large sélection de jeux de casino, l’expérience de jeu en ligne est incomparable. N’attendez plus pour vous inscrire sur https://aviator-rdc.com/ et commencer à profiter de tout ce que le jeu Aviator a à offrir.

]]>
https://sanatandharmveda.com/decouvrez-le-jeu-aviator-en-ligne-en-republique-134/feed/ 0
Les jeux de casino en ligne, y compris le jeu Plinko, gagnent en popularité en République Démocratique du Congo https://sanatandharmveda.com/les-jeux-de-casino-en-ligne-y-compris-le-jeu-2/ https://sanatandharmveda.com/les-jeux-de-casino-en-ligne-y-compris-le-jeu-2/#respond Tue, 25 Aug 2026 10:59:49 +0000 https://sanatandharmveda.com/?p=195903 casino online game

Les jeux de casino en ligne sont de plus en plus populaires en République Démocratique du Congo, offrant aux joueurs une expérience de jeu passionnante et divertissante. Parmi les nombreux jeux disponibles, le jeu Plinko se démarque comme l’un des favoris des amateurs de casinos en ligne.

Qu’est-ce que le jeu Plinko?

Le jeu Plinko est un jeu de casino en ligne inspiré du célèbre jeu télévisé. Les joueurs peuvent profiter de l’excitation du jeu en ligne depuis le confort de leur foyer en jouant sur des sites comme Plinko. Ce jeu offre une expérience unique et divertissante, avec des graphismes attrayants et des possibilités de gains intéressantes.

Machines à sous et bonus

En plus du jeu Plinko, les casinos en ligne proposent une large sélection de machines à sous aux thèmes variés. Les joueurs peuvent profiter de bonus généreux, de tours gratuits et d’autres promotions pour maximiser leur expérience de jeu. L’inscription sur ces sites est simple et rapide, permettant aux joueurs de commencer à jouer en ligne en un rien de temps.

Jouer avec de l’argent réel

Les jeux de casino en ligne offrent aux joueurs la possibilité de jouer avec de l’argent réel, ajoutant une dimension supplémentaire d’excitation. Les joueurs peuvent placer des mises et tenter leur chance pour remporter des gains en argent réel. Avec une variété de jeux de casino disponibles, il y en a pour tous les goûts et préférences de jeu.

Jeux en ligne et expérience de jeu

Les jeux de casino en ligne offrent une expérience de jeu immersive et captivante, avec des animations et des effets sonores de qualité. Les joueurs peuvent profiter de jeux de table classiques, de machines à sous modernes et de jeux en direct avec de vrais croupiers. L’expérience de jeu est fluide et interactive, garantissant un divertissement sans fin pour les joueurs en ligne.

Conclusion

En conclusion, le jeu Plinko et les casinos en ligne offrent aux joueurs de la République Démocratique du Congo une expérience de jeu passionnante et variée. Avec une sélection de jeux de casino populaires, des bonus attractifs et la possibilité de jouer avec de l’argent réel, les casinos en ligne sont une option de divertissement idéale pour les amateurs de jeux de hasard. Ne manquez pas l’occasion de découvrir l’univers des jeux en ligne et de profiter de moments de jeu palpitants depuis chez vous.

]]>
https://sanatandharmveda.com/les-jeux-de-casino-en-ligne-y-compris-le-jeu-2/feed/ 0
Azərbaycanda Pinco Casino ilə Onlayn Oyunların Keyfini Çıxarın! https://sanatandharmveda.com/azrbaycanda-pinco-casino-il-onlayn-oyunlarn/ https://sanatandharmveda.com/azrbaycanda-pinco-casino-il-onlayn-oyunlarn/#respond Tue, 25 Aug 2026 07:31:12 +0000 https://sanatandharmveda.com/?p=195841 Pinco Casino: Azərbaycanda Onlayn Oyunlar

Azərbaycanda onlayn oyunlar dünyası hər gün daha da populyar olur. Pinco casino Azərbaycanlı oyunçulara slotlar, bonuslar, pulsuz fırlanmalar və daha bir çoxunu təqdim edir.

Pinco casino saytında qeydiyyatdan keçin və onlayn oyunların dünyasına daxil olun. Real pul ilə oynamaq üçün əyləncəli kazino oyunlarını burada tapa bilərsiniz.

Pinco casino oyunları ilə ən yaxşı oyun təcrübəsini yaşayın. Slotlar, bonuslar və pulsuz fırlanmalar ilə şansınızı sınayın və qazanın!

]]>
https://sanatandharmveda.com/azrbaycanda-pinco-casino-il-onlayn-oyunlarn/feed/ 0
Azərbaycan Üçün Pinco – Onlayn Kazino Oyunlarında Qeydiyyatdan Keçin! https://sanatandharmveda.com/azrbaycan-ucun-pinco-onlayn-kazino-oyunlarnda/ https://sanatandharmveda.com/azrbaycan-ucun-pinco-onlayn-kazino-oyunlarnda/#respond Tue, 25 Aug 2026 07:31:05 +0000 https://sanatandharmveda.com/?p=195851 casino online game

Pinco Giriş

Azərbaycan üçün Pinco giriş fəaliyyətinə xoş gəlmisiniz! Onlayn kazinolar arasında Pinco, slotlar, bonuslar və pulsuz fırlanmaları ilə məşhurdur. Qeydiyyatdan keçin və onlayn oyunlar dünyasına daxil olun!

Pinko ilə Pinco giriş edin və real pula oynayın. Kazino oyunları ilə dolu olan bu platformda unikal oyun təcrübəsini yaşayın!

Pinco giriş səhifəsində slotlar, bonuslar, pulsuz fırlanmalar və real pula oynamaq imkanı sizi gözləyir. Qeydiyyatdan keçin və onlayn kazino oyunlarının keyfini çıxarın!

]]>
https://sanatandharmveda.com/azrbaycan-ucun-pinco-onlayn-kazino-oyunlarnda/feed/ 0
¡Descubre Pin Up Bet Online en Guatemala y disfruta de una experiencia de juego emocionante y segura! https://sanatandharmveda.com/descubre-pin-up-bet-online-en-guatemala-y-disfruta-2/ https://sanatandharmveda.com/descubre-pin-up-bet-online-en-guatemala-y-disfruta-2/#respond Fri, 21 Aug 2026 10:39:53 +0000 https://sanatandharmveda.com/?p=190117 casino online game

Pin Up Bet Online en Guatemala

En Guatemala, los aficionados a los juegos de casino en línea buscan constantemente nuevas opciones para disfrutar de una experiencia de juego emocionante y segura. Una de las plataformas más populares en la actualidad es Pin Up Bet Online.

¿Qué ofrece Pin Up Bet Online?

Pin Up Bet Online es un casino en línea que brinda a los jugadores guatemaltecos la oportunidad de disfrutar de una amplia variedad de juegos de casino, incluyendo tragamonedas, ruleta, blackjack, poker y muchos más. Además, ofrece bonos y promociones exclusivas para sus usuarios.

Tragamonedas y Bonos

Una de las atracciones principales de Pin Up Bet Online son las tragamonedas, que son juegos de casino muy populares entre los jugadores guatemaltecos. Estas máquinas ofrecen la posibilidad de ganar grandes premios con tan solo un giro. Además, el casino ofrece bonos de bienvenida, giros gratis y promociones especiales para los amantes de las tragamonedas.

Registro y Juegos en Línea

Registrarse en Pin Up Bet Online es rápido y sencillo. Con tan solo unos pocos pasos, los jugadores guatemaltecos pueden crear su cuenta y comenzar a disfrutar de todos los juegos disponibles en la plataforma. Desde tragamonedas hasta mesas de blackjack en vivo, hay opciones para todos los gustos.

Jugar con Dinero Real y Seguridad

Para aquellos que deseen jugar con dinero real, Pin Up Bet Online ofrece diversas opciones de pago seguras y confiables. Los jugadores guatemaltecos pueden realizar depósitos y retiros de forma rápida y segura, garantizando una experiencia de juego sin preocupaciones. Además, el casino cuenta con medidas de seguridad para proteger la información personal y financiera de sus usuarios.

Experiencia de Juego en Pin Up Bet Online

En resumen, Pin Up Bet Online es la opción ideal para los jugadores guatemaltecos que buscan una experiencia de juego emocionante y segura. Con una amplia variedad de juegos de casino, bonos atractivos y un entorno de juego confiable, este casino en línea se ha ganado la confianza de los aficionados a los juegos de azar en Guatemala. ¡Regístrate hoy en https://pinupcasino.gt y comienza a disfrutar de todo lo que Pin Up Bet Online tiene para ofrecer!

]]>
https://sanatandharmveda.com/descubre-pin-up-bet-online-en-guatemala-y-disfruta-2/feed/ 0
Pin-Up Online: El Mejor Casino en Línea de Guatemala https://sanatandharmveda.com/pin-up-online-el-mejor-casino-en-linea-de/ https://sanatandharmveda.com/pin-up-online-el-mejor-casino-en-linea-de/#respond Fri, 21 Aug 2026 10:39:42 +0000 https://sanatandharmveda.com/?p=190119 casino online game

Pin-Up Online: La Mejor Experiencia de Juegos de Casino en Línea en Guatemala

En la actualidad, el mundo de los casinos en línea ha tomado gran relevancia en Guatemala, ofreciendo a los jugadores la oportunidad de disfrutar de una amplia variedad de juegos desde la comodidad de sus hogares. Entre las opciones más populares se encuentra Pin-Up Online, un casino virtual que ha ganado gran reconocimiento por su excelente oferta de juegos y atractivos bonos.

Tragamonedas: La Estrella de Pin-Up Online

Las tragamonedas son uno de los juegos más populares en los casinos en línea, y en Pin-Up Online no podía ser la excepción. Con una amplia selección de tragamonedas de alta calidad y con temáticas variadas, este casino brinda a sus jugadores una experiencia de juego única y emocionante. Para disfrutar de las mejores tragamonedas, no dudes en visitar https://pinup.gt.

Bonos y Giros Gratis: Aumenta tus Posibilidades de Ganar

Uno de los atractivos principales de Pin-Up Online son sus generosos bonos y giros gratis. Al registrarte en este casino, podrás acceder a interesantes bonificaciones que te permitirán jugar por más tiempo y aumentar tus posibilidades de ganar. Además, los giros gratis te brindarán la oportunidad de probar suerte en tus tragamonedas favoritas sin arriesgar tu propio dinero.

Registro en Pin-Up Online: Rápido y Sencillo

El proceso de registro en Pin-Up Online es rápido y sencillo, simplemente tendrás que completar un formulario con tus datos personales y crear una cuenta de usuario. Una vez registrado, podrás acceder a la amplia selección de juegos en línea que ofrece este casino y comenzar a jugar con dinero real en cuestión de minutos.

Juegos en Línea: Diversión Garantizada en Pin-Up Online

Pin-Up Online cuenta con una amplia variedad de juegos de casino, que van desde las clásicas tragamonedas hasta emocionantes mesas de blackjack y ruleta. Con gráficos de alta calidad y un diseño intuitivo, la experiencia de juego en este casino es incomparable. No pierdas la oportunidad de disfrutar de la emoción de jugar en línea en Pin-Up Online.

Jugar con Dinero Real en Pin-Up Online: Seguro y Confiable

Si estás buscando un casino en línea seguro y confiable para jugar con dinero real, Pin-Up Online es la opción ideal. Con métodos de pago seguros y una plataforma de juego certificada, podrás disfrutar de tus juegos de casino favoritos con total tranquilidad. ¡Regístrate hoy en Pin-Up Online y vive la emoción de jugar por premios reales!

]]>
https://sanatandharmveda.com/pin-up-online-el-mejor-casino-en-linea-de/feed/ 0