/** * 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 – Sanathan Dharm Veda https://sanatandharmveda.com Mon, 01 Jun 2026 20:03:28 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.5 https://sanatandharmveda.com/wp-content/uploads/2024/05/cropped-cropped-pexels-himeshmehtaa25-3519190-32x32.jpg casino – Sanathan Dharm Veda https://sanatandharmveda.com 32 32 Пинко Казахстан: Лучший выбор игровых слотов и бонусов для игроков! https://sanatandharmveda.com/pinko-kazahstan-luchshij-vybor-igrovyh-slotov-i/ https://sanatandharmveda.com/pinko-kazahstan-luchshij-vybor-igrovyh-slotov-i/#respond Mon, 01 Jun 2026 18:45:15 +0000 https://sanatandharmveda.com/?p=40715 Онлайн-казино Пинко Казахстан — это популярный игровой портал, который предлагает широкий выбор слотов, бонусов и фриспинов для игроков из Казахстана. Регистрация на сайте занимает всего несколько минут, после чего вы сможете насладиться увлекательными онлайн-играми и играть на реальные деньги.

Слоты

На сайте Пинко Казахстан представлены разнообразные игровые автоматы, которые понравятся как новичкам, так и опытным игрокам. Вы можете выбирать из сотен различных игр, каждая из которых обещает захватывающий игровой опыт.

Бонусы и фриспины

Пинко Казахстан радует своих игроков различными бонусами и акциями. Новые игроки могут рассчитывать на приветственный бонус при регистрации, а постоянные клиенты участвуют в различных акциях и получают фриспины на популярные слоты.

Регистрация

Чтобы начать играть на реальные деньги на сайте Пинко Казахстан, вам необходимо пройти быструю и простую процедуру регистрации. Заполните несколько обязательных полей, подтвердите свой аккаунт и начните наслаждаться азартом.

Онлайн-игры

Помимо слотов, на сайте Пинко Казахстан представлены и другие популярные игры казино, такие как рулетка, блэкджек, покер и многое другое. Выбирайте любимую игру и наслаждайтесь азартом в уютной обстановке вашего дома.

Игровой опыт

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

Посетите Пинко казахстан сегодня и начните свое приключение в мире азарта и адреналина!

]]>
https://sanatandharmveda.com/pinko-kazahstan-luchshij-vybor-igrovyh-slotov-i/feed/ 0
Пинко Казахстан: Лучший выбор игровых слотов и бонусов для игроков! https://sanatandharmveda.com/pinko-kazahstan-luchshij-vybor-igrovyh-slotov-i-2/ https://sanatandharmveda.com/pinko-kazahstan-luchshij-vybor-igrovyh-slotov-i-2/#respond Mon, 01 Jun 2026 18:45:15 +0000 https://sanatandharmveda.com/?p=40723 Онлайн-казино Пинко Казахстан — это популярный игровой портал, который предлагает широкий выбор слотов, бонусов и фриспинов для игроков из Казахстана. Регистрация на сайте занимает всего несколько минут, после чего вы сможете насладиться увлекательными онлайн-играми и играть на реальные деньги.

Слоты

На сайте Пинко Казахстан представлены разнообразные игровые автоматы, которые понравятся как новичкам, так и опытным игрокам. Вы можете выбирать из сотен различных игр, каждая из которых обещает захватывающий игровой опыт.

Бонусы и фриспины

Пинко Казахстан радует своих игроков различными бонусами и акциями. Новые игроки могут рассчитывать на приветственный бонус при регистрации, а постоянные клиенты участвуют в различных акциях и получают фриспины на популярные слоты.

Регистрация

Чтобы начать играть на реальные деньги на сайте Пинко Казахстан, вам необходимо пройти быструю и простую процедуру регистрации. Заполните несколько обязательных полей, подтвердите свой аккаунт и начните наслаждаться азартом.

Онлайн-игры

Помимо слотов, на сайте Пинко Казахстан представлены и другие популярные игры казино, такие как рулетка, блэкджек, покер и многое другое. Выбирайте любимую игру и наслаждайтесь азартом в уютной обстановке вашего дома.

Игровой опыт

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

Посетите Пинко казахстан сегодня и начните свое приключение в мире азарта и адреналина!

]]>
https://sanatandharmveda.com/pinko-kazahstan-luchshij-vybor-igrovyh-slotov-i-2/feed/ 0
Experience the Thrills of Online Gaming at Pin-Up Bet in India! https://sanatandharmveda.com/experience-the-thrills-of-online-gaming-at-pin-up-35/ https://sanatandharmveda.com/experience-the-thrills-of-online-gaming-at-pin-up-35/#respond Mon, 01 Jun 2026 11:47:23 +0000 https://sanatandharmveda.com/?p=40682 Introduction

Welcome to the exciting world of online casinos in India! If you are looking for a thrilling gaming experience, look no further than pin-up bet. This popular online casino offers a wide range of casino games, slots, bonuses, and free spins to keep you entertained for hours on end. Whether you are a seasoned player or just starting out, pin-up bet has something for everyone.

Slots Galore

One of the highlights of pin-up bet is its impressive collection of slots. From classic fruit machines to modern video slots, you will find a variety of games to suit your preferences. With high-quality graphics and exciting gameplay, the slots at pin-up bet are sure to keep you entertained for hours on end. Plus, with the chance to win big jackpots, playing slots at pin-up bet is not only fun but also rewarding.

Exciting Bonuses and Free Spins

At pin-up bet, players are treated to a range of bonuses and free spins to enhance their gaming experience. From welcome bonuses for new players to loyalty rewards for regulars, there are plenty of opportunities to boost your bankroll. Additionally, free spins on selected slots give you the chance to win without risking your own money. Keep an eye out for the latest promotions to make the most of your time at pin-up bet.

Easy Registration and Play for Real Money

Getting started at pin-up bet is quick and easy. Simply complete the registration process and you will be ready to start playing your favorite casino games in no time. Whether you prefer slots, table games, or live dealer games, pin-up bet has it all. Plus, with the option to play for real money, you have the chance to win big from the comfort of your own home. Sign up today and start your online casino journey with pin-up bet.

Diverse Selection of Online Games

In addition to slots, pin-up bet offers a diverse selection of online games to cater to all preferences. From classic casino games like blackjack and roulette to innovative titles that push the boundaries of online gaming, there is something for everyone at pin-up bet. With high-quality graphics, immersive sound effects, and seamless gameplay, the online games at pin-up bet provide an unparalleled gaming experience.

Conclusion

In conclusion, pin-up bet is a top choice for online casino enthusiasts in India. With a wide range of casino games, slots, bonuses, and free spins, there is never a dull moment at pin-up bet. Whether you are looking to play for real money or simply enjoy the thrill of online gaming, pin-up bet has you covered. Sign up today and experience the excitement of online casino gaming with pin-up bet.

]]>
https://sanatandharmveda.com/experience-the-thrills-of-online-gaming-at-pin-up-35/feed/ 0
Experience the Thrills of Online Gaming with Pin Up Bet in India https://sanatandharmveda.com/experience-the-thrills-of-online-gaming-with-pin-30/ https://sanatandharmveda.com/experience-the-thrills-of-online-gaming-with-pin-30/#respond Mon, 01 Jun 2026 11:47:16 +0000 https://sanatandharmveda.com/?p=40674 casino online game betting

Welcome to the world of online casinos in India, where players can enjoy a wide range of exciting games and opportunities to win big. In this article, we will explore the popular online casino ‘pin up bet’ and delve into the thrilling world of online gaming.

What is Pin Up Bet?

pin up bet is a reputable online casino that offers a variety of casino games, including slots, table games, and live dealer games. With a user-friendly interface and a wide selection of games, Pin Up Bet provides players with a top-notch gaming experience.

Slots and Bonuses

One of the main attractions of Pin Up Bet is its wide range of slot games. Players can choose from classic slots, video slots, and progressive jackpot slots, offering endless entertainment and opportunities to win big. Additionally, Pin Up Bet offers generous bonuses and free spins to new and existing players, enhancing the gaming experience and increasing the chances of winning.

Registration and Online Games

Signing up at Pin Up Bet is quick and easy, allowing players to start enjoying their favorite casino games in no time. Whether you prefer slots, table games, or live dealer games, Pin Up Bet has something for everyone. The online games are designed to provide a realistic and immersive gaming experience, making players feel like they are in a real casino.

Play for Real Money

For those looking to take their gaming experience to the next level, Pin Up Bet offers the option to play for real money. Players can deposit funds securely and start playing their favorite casino games for a chance to win real cash prizes. With a variety of payment options available, players can easily deposit and withdraw their winnings.

Casino Games and Gaming Experience

Whether you enjoy classic casino games like blackjack and roulette, or prefer the thrill of video slots and live dealer games, Pin Up Bet has it all. The casino games are designed to provide a seamless and enjoyable gaming experience, with stunning graphics and realistic sound effects. Players can immerse themselves in the world of online gaming and have a chance to win big.

In conclusion, Pin Up Bet is a top online casino in India that offers a wide range of games, generous bonuses, and a thrilling gaming experience. Whether you are a seasoned player or new to online gaming, Pin Up Bet has something for everyone. So why wait? Sign up today and start playing your favorite casino games at Pin Up Bet!

]]>
https://sanatandharmveda.com/experience-the-thrills-of-online-gaming-with-pin-30/feed/ 0
Experience the Thrill of Pin Up Aviator: India’s Premier Online Casino https://sanatandharmveda.com/experience-the-thrill-of-pin-up-aviator-india-s/ https://sanatandharmveda.com/experience-the-thrill-of-pin-up-aviator-india-s/#respond Mon, 01 Jun 2026 11:46:49 +0000 https://sanatandharmveda.com/?p=40658 Exploring Pin Up Aviator in India

India is a country known for its love of casino games and online gambling. One popular online casino that has caught the attention of Indian players is pin up aviator. This casino offers a wide range of slots, bonuses, and free spins to enhance the gaming experience for players in India.

Registration Process

Signing up at Pin Up Aviator is a simple and straightforward process. Players can easily create an account by providing some basic information such as their name, email address, and desired currency. Once registered, players can start exploring the exciting world of online games offered by the casino.

Playing for Real Money

One of the main attractions of Pin Up Aviator is the opportunity to play for real money. Players can enjoy a wide variety of casino games and have the chance to win big prizes. With secure payment options available, players in India can easily deposit and withdraw their winnings without any hassle.

Exciting Casino Games

Pin Up Aviator offers a diverse selection of casino games to cater to the preferences of all players. From classic slots to table games and live dealer options, there is something for everyone at this online casino. Players can enjoy a realistic gaming experience from the comfort of their own homes.

Benefits of Playing at Pin Up Aviator

There are numerous benefits to playing at Pin Up Aviator in India. Some of these include:

  • Generous bonuses and promotions to boost your winnings
  • Regular free spins to keep the excitement going
  • 24/7 customer support for any queries or concerns
  • Secure and fair gaming environment

Overall, Pin Up Aviator provides a top-notch gaming experience for players in India, with a wide range of games and exciting rewards to enjoy.

]]>
https://sanatandharmveda.com/experience-the-thrill-of-pin-up-aviator-india-s/feed/ 0
Descubre la emoción del casino en línea con Pin Up Chile: juegos, bonos y seguridad garantizada. https://sanatandharmveda.com/descubre-la-emocion-del-casino-en-linea-con-pin-up-4/ https://sanatandharmveda.com/descubre-la-emocion-del-casino-en-linea-con-pin-up-4/#respond Sun, 31 May 2026 20:35:02 +0000 https://sanatandharmveda.com/?p=40356 Introducción

En Chile, los casinos en línea han ganado una gran popularidad en los últimos años. Entre ellos, destaca el casino Pin Up Chile, una plataforma que ofrece una amplia variedad de juegos de casino, bonificaciones atractivas y una experiencia de juego única. En este artículo, exploraremos todo lo que este casino tiene para ofrecer a los jugadores chilenos.

Tragamonedas y juegos de casino

Una de las principales atracciones de Pin Up Chile son sus emocionantes tragamonedas y juegos de casino. Con una amplia selección de títulos de diferentes proveedores, los jugadores pueden disfrutar de la emoción de jugar con dinero real desde la comodidad de sus hogares. Ya sea que prefieras las tragamonedas clásicas o los juegos de mesa como el blackjack o la ruleta, en Pin Up Chile encontrarás algo que se adapte a tus gustos.

Bonos y giros gratis

Al registrarte en Pin Up Chile, tendrás acceso a una variedad de bonos y promociones. Desde bonificaciones de bienvenida hasta giros gratis en tus juegos favoritos, este casino se esfuerza por recompensar a sus jugadores. Estos bonos no solo te permiten prolongar tu experiencia de juego, sino que también aumentan tus posibilidades de ganar premios increíbles.

Registro y seguridad

El proceso de registro en Pin Up Chile es rápido y sencillo. Simplemente completa el formulario de inscripción en la página web oficial del casino y estarás listo para comenzar a jugar. Además, este casino en línea cuenta con las medidas de seguridad necesarias para proteger la información personal y financiera de sus jugadores, brindándoles tranquilidad y confianza mientras disfrutan de sus juegos favoritos.

Juegos en línea y experiencia de juego

Pin Up Chile ofrece una experiencia de juego inmersiva y emocionante, gracias a su plataforma de juegos en línea de última generación. Con gráficos de alta calidad, sonido envolvente y una interfaz fácil de usar, este casino te transportará a la atmósfera de un casino real desde cualquier lugar. Ya sea que juegues en tu computadora, tablet o teléfono móvil, la diversión está garantizada en Pin Up Chile.

Conclusión

En resumen, Pin Up Chile es una excelente opción para los jugadores chilenos que buscan disfrutar de juegos de casino de calidad, bonificaciones atractivas y una experiencia de juego inigualable. Con una amplia selección de tragamonedas, juegos de mesa y mucho más, este casino en línea tiene todo lo que necesitas para vivir emocionantes momentos de entretenimiento. ¡Regístrate hoy en https://chilepinup.cl/ y comienza a disfrutar de todo lo que Pin Up Chile tiene para ofrecer!

]]>
https://sanatandharmveda.com/descubre-la-emocion-del-casino-en-linea-con-pin-up-4/feed/ 0
Descubre la emoción de Casino Pin Up Chile: ¡Juega y gana ahora! https://sanatandharmveda.com/descubre-la-emocion-de-casino-pin-up-chile-juega-y-2/ https://sanatandharmveda.com/descubre-la-emocion-de-casino-pin-up-chile-juega-y-2/#respond Sun, 31 May 2026 20:35:02 +0000 https://sanatandharmveda.com/?p=40374 casino online game

Descubre el emocionante mundo de Casino Pin Up Chile

Si estás buscando una experiencia de juego única y emocionante, Casino Pin Up Chile es la opción perfecta para ti. Con una amplia selección de tragamonedas, bonos generosos, giros gratis y la posibilidad de jugar con dinero real, este casino en línea te ofrece todo lo que necesitas para disfrutar al máximo.

Tragamonedas: diversión sin límites

En Casino Pin Up Chile encontrarás una gran variedad de tragamonedas con temas emocionantes y gráficos de alta calidad. Desde tragamonedas clásicas hasta las últimas novedades, aquí podrás disfrutar de horas de diversión y emoción.

Bonos y giros gratis: aumenta tus ganancias

Para hacer tu experiencia aún más emocionante, Casino Pin Up Chile ofrece increíbles bonos de bienvenida y giros gratis a sus jugadores. Estas promociones te permitirán aumentar tus ganancias y disfrutar al máximo de tus juegos favoritos.

Registro fácil y rápido

Registrarte en Casino Pin Up Chile es muy sencillo. Solo necesitas completar un formulario con tus datos personales y en pocos minutos podrás empezar a disfrutar de todos los juegos que este casino en línea tiene para ofrecerte.

Juegos en línea: diversión garantizada

Con una amplia variedad de juegos de casino, como la ruleta, el blackjack, el póker y las tragamonedas, en Casino Pin Up Chile nunca te aburrirás. Además, podrás jugar con dinero real y vivir la emoción de apostar y ganar grandes premios.

Conclusión: vive una experiencia de juego inigualable en Casino Pin Up Chile

En resumen, si estás buscando un casino en línea que te ofrezca una experiencia de juego emocionante y segura, no busques más. Casino Pin Up Chile es la opción ideal para disfrutar de los mejores juegos de casino, bonos increíbles y la posibilidad de ganar grandes premios. ¡Regístrate ahora y comienza a disfrutar de todo lo que este fantástico casino tiene para ofrecerte!

]]>
https://sanatandharmveda.com/descubre-la-emocion-de-casino-pin-up-chile-juega-y-2/feed/ 0
Descubre la emoción de Fruit Cocktail 2: ¡Juega gratis en línea ahora! https://sanatandharmveda.com/descubre-la-emocion-de-fruit-cocktail-2-juega/ https://sanatandharmveda.com/descubre-la-emocion-de-fruit-cocktail-2-juega/#respond Sun, 31 May 2026 09:05:19 +0000 https://sanatandharmveda.com/?p=40299 bettimg slots casino


¿Qué es Fruit Cocktail 2?

Fruit Cocktail 2 es una popular tragamonedas en línea que ofrece a los jugadores una experiencia de juego emocionante y colorida. Con símbolos de frutas, bonos y giros gratis, este juego es perfecto para aquellos que buscan diversión y premios.

Opciones de Demo y Cómo Acceder

Si estás interesado en jugar a Fruit Cocktail 2 gratis y sin registro, puedes acceder a la versión de demostración del juego a través de este enlace: https://www.tuvozenpinares.com/articulo/comunicados/fruit-cocktail-2-jugar-gratis-registro-opciones-demo-como-acceder/20260430095229090655.html. Una vez en la página, podrás disfrutar de la tragamonedas sin la necesidad de registrarte.

Beneficios de la Versión Demo

La opción de jugar a Fruit Cocktail 2 en modo demo te permite familiarizarte con el juego antes de apostar con dinero real. Podrás probar diferentes estrategias, entender las reglas y disfrutar de la emoción de las tragamonedas sin arriesgar tu dinero.

Registro y Juegos en Línea

Si decides jugar con dinero real, deberás realizar un registro en el casino en línea de tu elección. Una vez completado el proceso de registro, podrás acceder a una amplia variedad de juegos de casino, incluyendo Fruit Cocktail 2, y disfrutar de la emoción de jugar por premios reales.

Bonos y Giros Gratis

Al registrarte en un casino en línea para jugar a Fruit Cocktail 2 con dinero real, es posible que tengas acceso a bonos de bienvenida y giros gratis. Estas promociones te permitirán aumentar tus posibilidades de ganar y prolongar tu experiencia de juego de forma gratuita.

Conclusión

En resumen, Fruit Cocktail 2 es una emocionante tragamonedas en línea que ofrece la opción de jugar gratis sin registro a través de su versión demo. Ya sea que prefieras jugar por diversión o por dinero real, este juego te brinda una experiencia de juego colorida y llena de premios. ¡No esperes más para disfrutar de la emoción de los juegos de casino en línea!

]]>
https://sanatandharmveda.com/descubre-la-emocion-de-fruit-cocktail-2-juega/feed/ 0
Is Ferrari Gearing Up for a New Formula 1 Star? https://sanatandharmveda.com/is-ferrari-gearing-up-for-a-new-formula-1-star/ https://sanatandharmveda.com/is-ferrari-gearing-up-for-a-new-formula-1-star/#respond Fri, 29 May 2026 10:46:15 +0000 https://sanatandharmveda.com/?p=40148 casino online slots betting

Is Ferrari Preparing a Seat for a New Formula 1 Golden Boy? This question has been circulating in the world of motorsports, sparking excitement and speculation among fans and experts alike. With the upcoming Formula 1 season just around the corner, all eyes are on Ferrari and the potential changes they might make to their driver lineup.

The Current Scenario

As we approach the new Formula 1 season, the rumors surrounding Ferrari’s driver lineup continue to grow. The team’s current drivers, Charles Leclerc and Carlos Sainz, have been performing well on the track, but there are whispers that Ferrari might be looking to shake things up. Could a new golden boy be on the horizon?

https://www.grandprix247.com/f1-teams-news/is-ferrari-preparing-a-seat-for-a-new-formula-1-golden-boy

The Speculation

One name that has been making the rounds in the Formula 1 paddock is that of a young and talented driver who has been turning heads in the lower series. With Ferrari known for nurturing young talent, could they be preparing a seat for this rising star? Only time will tell, but the excitement is palpable.

Potential Benefits

If Ferrari does decide to bring in a new golden boy, it could inject a fresh energy into the team and provide a new perspective on the track. This move could also attract a younger audience to the sport, increasing viewership and engagement with Formula 1. Additionally, a new driver could bring in new sponsorships and opportunities for the team, further strengthening their position in the sport.

Engaging the Fans

For fans of Formula 1, the prospect of a new golden boy at Ferrari is an exciting one. It opens up endless possibilities for the team and adds an element of unpredictability to the upcoming season. Whether you are a die-hard Ferrari supporter or simply a motorsports enthusiast, the potential changes at Ferrari are sure to keep you on the edge of your seat.

Conclusion

As we eagerly await the start of the new Formula 1 season, the question of whether Ferrari is preparing a seat for a new golden boy remains unanswered. The speculations and rumors only add to the anticipation and excitement surrounding the sport. Whatever the outcome may be, one thing is for sure – Formula 1 fans are in for a thrilling ride.

]]>
https://sanatandharmveda.com/is-ferrari-gearing-up-for-a-new-formula-1-star/feed/ 0
Descubre doradobet apuestas: la mejor experiencia de juego en línea en Nicaragua https://sanatandharmveda.com/descubre-doradobet-apuestas-la-mejor-experiencia-2/ https://sanatandharmveda.com/descubre-doradobet-apuestas-la-mejor-experiencia-2/#respond Fri, 29 May 2026 07:19:30 +0000 https://sanatandharmveda.com/?p=40128 casino online game

Descubre todo sobre doradobet apuestas en Nicaragua

En Nicaragua, los amantes de los juegos de azar tienen la oportunidad de disfrutar de una experiencia única en línea gracias a doradobet apuestas. Esta plataforma de juegos en línea ofrece una amplia variedad de opciones para aquellos que buscan emoción y diversión desde la comodidad de su hogar.

Si estás buscando un sitio confiable y seguro para disfrutar de tus juegos favoritos, doradobet apuestas es la opción ideal para ti. Con una amplia selección de tragamonedas, juegos de mesa y opciones de apuestas deportivas, este casino en línea tiene todo lo que necesitas para vivir una experiencia de juego inolvidable.

Tragamonedas: diversión sin límites

Una de las principales atracciones de doradobet apuestas son sus emocionantes tragamonedas. Con una gran variedad de temas y estilos, los jugadores pueden disfrutar de giros emocionantes y la posibilidad de ganar increíbles premios. Desde clásicos juegos de frutas hasta modernas tragamonedas con gráficos de última generación, hay opciones para todos los gustos.

Bonos y giros gratis: aumenta tus ganancias

En doradobet apuestas, los jugadores pueden aprovechar una amplia variedad de bonos y promociones que les ayudarán a aumentar sus ganancias y prolongar su tiempo de juego. Desde bonos de bienvenida hasta giros gratis en tragamonedas populares, siempre hay algo emocionante esperando a los jugadores en este casino en línea.

Registro fácil y rápido

Para comenzar a disfrutar de todo lo que doradobet apuestas tiene para ofrecer, simplemente debes completar un rápido proceso de registro. Con unos pocos pasos sencillos, estarás listo para sumergirte en el apasionante mundo de los juegos de casino en línea y jugar con dinero real en tus juegos favoritos.

Variedad de juegos en línea

Además de las tragamonedas, doradobet apuestas ofrece una amplia selección de juegos de mesa clásicos como el blackjack, la ruleta y el póker. Los jugadores pueden disfrutar de la emoción de competir contra la casa y otros jugadores en tiempo real, creando una experiencia de juego inmersiva y emocionante.

Conclusión: vive la mejor experiencia de juego en doradobet apuestas

En resumen, doradobet apuestas es la opción perfecta para aquellos que buscan disfrutar de juegos de casino en línea de calidad, seguridad y diversión. Con una amplia variedad de opciones, bonos y promociones emocionantes, este casino en línea ofrece todo lo que necesitas para vivir una experiencia de juego inolvidable en Nicaragua. ¡Regístrate hoy y comienza a disfrutar de todo lo que doradobet apuestas tiene para ofrecer!

  • doradobet apuestas
  • tragamonedas
  • bonos
  • giros gratis
  • registro
  • juegos en línea
  • jugar con dinero real
  • juegos de casino
  • experiencia de juego
]]>
https://sanatandharmveda.com/descubre-doradobet-apuestas-la-mejor-experiencia-2/feed/ 0