/**
* 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,
),
);
}
}Текста – Sanathan Dharm Veda
https://sanatandharmveda.com
Tue, 26 May 2026 14:39:28 +0000en-US
hourly
1 https://wordpress.org/?v=6.6.5https://sanatandharmveda.com/wp-content/uploads/2024/05/cropped-cropped-pexels-himeshmehtaa25-3519190-32x32.jpgТекста – Sanathan Dharm Veda
https://sanatandharmveda.com
3232Descubre la emoción de jugar con la pin up app en Honduras: ¡Una experiencia de casino en línea única y segura!
https://sanatandharmveda.com/descubre-la-emocion-de-jugar-con-la-pin-up-app-en-5/
https://sanatandharmveda.com/descubre-la-emocion-de-jugar-con-la-pin-up-app-en-5/#respondTue, 26 May 2026 14:31:16 +0000https://sanatandharmveda.com/?p=39782Descubre la emocionante experiencia de jugar con la pin up app en Honduras
Si eres amante de los juegos de casino en línea y te encuentras en Honduras, seguramente estarás buscando una plataforma segura y divertida para disfrutar de tus juegos favoritos. En este artículo te presentaremos la pin up app, una aplicación que te brinda la oportunidad de jugar a emocionantes tragamonedas, obtener increíbles bonos y giros gratis, y vivir una experiencia de juego única desde la comodidad de tu hogar.
¿Qué es la pin up app?
La pin up app es una aplicación de casino en línea que ofrece una amplia variedad de juegos de casino, incluyendo tragamonedas, ruleta, blackjack y muchos más. Con una interfaz fácil de usar y una gran variedad de opciones de entretenimiento, esta app se ha convertido en una de las favoritas de los jugadores en Honduras. Puedes descargar la hondubet app para acceder a la pin up app y comenzar a disfrutar de tus juegos de casino preferidos.
Regístrate y comienza a jugar con dinero real
Para comenzar a disfrutar de la pin up app y jugar con dinero real, primero necesitas registrarte en la plataforma. El proceso de registro es rápido y sencillo, y una vez completado, podrás realizar tu primer depósito y comenzar a apostar en tus juegos de casino favoritos. No olvides aprovechar los bonos de bienvenida y los giros gratis que la pin up app tiene preparados para sus nuevos usuarios.
Variedad de juegos en línea para todos los gustos
Una de las ventajas de la pin up app es la amplia variedad de juegos de casino que ofrece. Desde las clásicas tragamonedas de frutas hasta las emocionantes mesas de blackjack en vivo, en esta app encontrarás opciones para todos los gustos y preferencias. Además, la plataforma se actualiza constantemente con nuevos juegos, por lo que siempre tendrás algo nuevo por descubrir y disfrutar.
Disfruta de una experiencia de juego segura y emocionante
La pin up app se preocupa por la seguridad y la privacidad de sus usuarios, por lo que utiliza las últimas tecnologías de encriptación para garantizar que todas las transacciones y datos personales estén protegidos en todo momento. Además, el equipo de atención al cliente está disponible las 24 horas del día para resolver cualquier duda o problema que puedas tener durante tu experiencia de juego. Así que no esperes más y descarga la pin up app para vivir la emoción de los juegos de casino en línea desde Honduras.
Conclusión
En resumen, la pin up app es una excelente opción para los jugadores en línea en Honduras que buscan una plataforma segura, divertida y emocionante para disfrutar de sus juegos de casino favoritos. Con una amplia variedad de juegos, bonos, giros gratis y una experiencia de juego de alta calidad, esta app se ha convertido en una de las más populares en el país. Así que no pierdas más tiempo y descarga la app para comenzar a disfrutar de todo lo que tiene para ofrecer. ¡Buena suerte y que la diversión comience!
]]>https://sanatandharmveda.com/descubre-la-emocion-de-jugar-con-la-pin-up-app-en-5/feed/0Descubre la emoción de Pin Up: el casino en línea líder en Guatemala
https://sanatandharmveda.com/descubre-la-emocion-de-pin-up-el-casino-en-linea-7/
https://sanatandharmveda.com/descubre-la-emocion-de-pin-up-el-casino-en-linea-7/#respondTue, 26 May 2026 12:04:54 +0000https://sanatandharmveda.com/?p=39756
Descubre el mundo de Pin Up en Guatemala
Si eres un amante de los casinos en línea en Guatemala, seguramente has escuchado hablar de Pin Up. Este popular casino en línea ofrece una amplia variedad de juegos y promociones para que puedas disfrutar de una experiencia de juego emocionante y divertida. En https://pinup-casino.gt encontrarás todo lo que necesitas para jugar con dinero real y ganar grandes premios.
Tragamonedas y juegos de casino
Una de las principales atracciones de Pin Up son sus tragamonedas, que ofrecen una gran variedad de temas y funciones especiales para que puedas disfrutar de horas de diversión. Además, este casino en línea también cuenta con una amplia selección de juegos de casino clásicos como el blackjack, la ruleta y el póker, para que puedas probar tu suerte en diferentes modalidades.
Bonos y promociones
En Pin Up, los jugadores de Guatemala pueden disfrutar de generosos bonos y promociones que les permitirán aumentar sus ganancias y prolongar su tiempo de juego. Desde bonos de bienvenida hasta giros gratis en las tragamonedas, este casino en línea sabe cómo recompensar a sus jugadores y mantenerlos entretenidos en todo momento.
Registro y seguridad
El proceso de registro en Pin Up es rápido y sencillo, para que puedas comenzar a jugar en cuestión de minutos. Además, este casino en línea cuenta con las medidas de seguridad necesarias para proteger tus datos personales y financieros, garantizando una experiencia de juego segura y confiable para todos los jugadores de Guatemala.
Juegos en línea y diversión garantizada
Pin Up es el lugar ideal para los amantes de los juegos en línea, ya que ofrece una amplia variedad de opciones para todos los gustos. Ya sea que prefieras las tragamonedas con temáticas divertidas o los emocionantes juegos de mesa, en este casino en línea encontrarás todo lo que necesitas para disfrutar de una experiencia de juego inigualable.
Conclusión
En resumen, Pin Up es una excelente opción para los jugadores de casino en línea en Guatemala que buscan diversión y emoción. Con su amplia selección de juegos, generosos bonos y promociones, y medidas de seguridad confiables, este casino en línea se ha convertido en uno de los favoritos de los jugadores en todo el país. ¡No esperes más y únete a la diversión en https://pinup-casino.gt!
]]>https://sanatandharmveda.com/descubre-la-emocion-de-pin-up-el-casino-en-linea-7/feed/0Experience the Best Online Casino in Kyrgyzstan at Пинко казино!
https://sanatandharmveda.com/experience-the-best-online-casino-in-kyrgyzstan-at/
https://sanatandharmveda.com/experience-the-best-online-casino-in-kyrgyzstan-at/#respondTue, 26 May 2026 08:43:15 +0000https://sanatandharmveda.com/?p=39736Introduction
Welcome to the world of online casinos in Kyrgyzstan! In this article, we will explore the exciting Пинко казино and all it has to offer to players in the country. From thrilling slots to generous bonuses, Пинко казино provides a top-notch gaming experience for all who join.
Discover Пинко казино Кыргызстан
If you are looking for a reputable online casino in Kyrgyzstan, look no further than Пинко казино Кыргызстан. With a wide selection of casino games, including slots, table games, and live dealer options, players can enjoy endless entertainment and opportunities to win big.
Exciting Slots and Bonuses
One of the highlights of playing at Пинко казино is the impressive variety of slots available. From classic fruit machines to modern video slots, there is something for every type of player. Additionally, players can take advantage of generous bonuses, such as free spins and deposit matches, to enhance their gaming experience and increase their chances of winning.
Easy Registration and Secure Gameplay
Signing up for an account at Пинко казино is quick and easy, allowing players to start playing their favorite casino games in no time. With secure payment options and encryption technology, players can rest assured that their personal and financial information is safe and protected while they play for real money.
Wide Selection of Online Games
Whether you prefer classic casino games like blackjack and roulette or enjoy trying your luck at new and innovative titles, Пинко казино has something for everyone. With a user-friendly interface and seamless gameplay, players can immerse themselves in a world of excitement and entertainment right from their own homes.
Enhanced Gaming Experience
By choosing to play at Пинко казино, players can enjoy a truly immersive and enjoyable gaming experience. With high-quality graphics, smooth gameplay, and exciting features, every spin of the reels or hand of cards is sure to keep players on the edge of their seats. Whether you are a seasoned pro or new to online casinos, Пинко казино offers something for everyone.
Overall, Пинко казино is a top choice for players in Kyrgyzstan looking to enjoy a premium online gaming experience. With a wide selection of casino games, generous bonuses, and secure gameplay, players can feel confident and excited every time they log on to play. So why wait? Visit Пинко казино Кыргызстан today and start winning big!
]]>https://sanatandharmveda.com/experience-the-best-online-casino-in-kyrgyzstan-at/feed/0Découvrez Chicken Road : le nouveau jeu de casino en ligne passionnant en France
https://sanatandharmveda.com/decouvrez-chicken-road-le-nouveau-jeu-de-casino-en/
https://sanatandharmveda.com/decouvrez-chicken-road-le-nouveau-jeu-de-casino-en/#respondTue, 26 May 2026 06:52:32 +0000https://sanatandharmveda.com/?p=39730Introduction
En France, les amateurs de jeux en ligne ont découvert un nouveau jeu passionnant appelé “Chicken Road”. Ce jeu unique offre une expérience de jeu captivante et des opportunités passionnantes de gagner de l’argent réel. Dans cet article, nous explorerons en détail ce jeu innovant et les avantages qu’il offre aux joueurs français.
Qu’est-ce que Chicken Road?
Chicken Road est un jeu de casino en ligne qui offre une expérience de jeu immersive aux joueurs. Les joueurs peuvent profiter de graphismes époustouflants, de bonus excitants et de tours gratuits tout en naviguant sur le chemin du poulet. Pour jouer à Chicken Road et découvrir tous ses avantages, rendez-vous sur jeux-chicken-road.fr.
Avantages de jouer à Chicken Road
En choisissant de jouer à Chicken Road, les joueurs ont la possibilité de profiter de nombreux avantages, tels que des slots passionnants, des bonus généreux, des tours gratuits et une expérience de jeu immersive. De plus, les joueurs peuvent s’inscrire facilement et commencer à jouer pour de l’argent réel en quelques minutes seulement.
Conseils pour maximiser vos gains
Pour maximiser vos gains en jouant à Chicken Road, il est important de profiter des bonus et des tours gratuits offerts. En outre, en explorant les différentes options de jeux disponibles, les joueurs peuvent découvrir de nouvelles façons de gagner et améliorer leur expérience de jeu globale.
Jeux de casino en ligne
En plus de Chicken Road, les joueurs français peuvent profiter d’une large gamme de jeux de casino en ligne, tels que des machines à sous, des jeux de table et des jeux en direct. Ces jeux offrent aux joueurs une expérience de jeu variée et excitante, tout en leur permettant de jouer pour de l’argent réel et de gagner gros.
Conclusion
En conclusion, Chicken Road offre aux joueurs français une expérience de jeu unique et passionnante. En explorant ce jeu innovant et en profitant des nombreux avantages qu’il offre, les joueurs peuvent améliorer leur expérience de jeu en ligne et avoir la chance de gagner de l’argent réel. Ne manquez pas l’opportunité de jouer à Chicken Road sur jeux-chicken-road.fr et découvrez un monde de divertissement et de gains potentiels.
]]>https://sanatandharmveda.com/decouvrez-chicken-road-le-nouveau-jeu-de-casino-en/feed/0Take Your Gaming to the Next Level: Download the Betking App in Nigeria Today!
https://sanatandharmveda.com/take-your-gaming-to-the-next-level-download-the-5/
https://sanatandharmveda.com/take-your-gaming-to-the-next-level-download-the-5/#respondMon, 25 May 2026 08:55:10 +0000https://sanatandharmveda.com/?p=39658
Introduction
Are you an avid casino player in Nigeria looking to take your gaming experience to the next level? If so, downloading the Betking app could be the perfect solution for you. This app allows you to access a wide range of casino games, including slots, bonuses, free spins, and more, all from the convenience of your mobile device. In this article, we will explore how to download the Betking app in Nigeria and the benefits it can offer you.
Why Download the Betking App in Nigeria?
Downloading the Betking app in Nigeria opens up a world of opportunities for online gaming enthusiasts. With this app, you can access a variety of casino games, including slots, bonuses, free spins, and more, all with just a few taps on your mobile device. The app offers a seamless gaming experience, allowing you to play for real money and win big prizes from the comfort of your home.
To get started, simply visit https://betking-mobile.com.ng/ and follow the instructions to download the app to your device. Once installed, you can create an account and start enjoying all the exciting features Betking has to offer.
Exploring Casino Games on the Betking App
The Betking app provides a wide selection of casino games for players to enjoy. Whether you prefer slots, table games, or live dealer games, you can find it all on this platform. The app is constantly updated with new and exciting games, ensuring that you never run out of options to explore.
Benefits of Playing on the Betking App
One of the main benefits of playing on the Betking app is the convenience it offers. You can access your favorite casino games anytime, anywhere, without being tied to a desktop computer. Additionally, the app offers exclusive bonuses and promotions for players, including free spins and cash rewards.
Registration and Getting Started
To start playing on the Betking app, simply download the app to your device and create an account. Registration is quick and easy, requiring just a few personal details to get started. Once your account is set up, you can make a deposit and start playing your favorite casino games right away.
Tips for Maximizing Your Gaming Experience
To make the most of your time on the Betking app, be sure to take advantage of the various bonuses and promotions available. These can help boost your winnings and enhance your overall gaming experience. Additionally, try out different games to find your favorites and explore new ones to keep things exciting.
Overall, downloading the Betking app in Nigeria is a great way to enjoy a wide range of casino games, bonuses, and promotions on the go. Whether you’re a seasoned player or new to online gaming, this app has something for everyone. So why wait? Download the Betking app today and start playing for real money from the palm of your hand.
]]>https://sanatandharmveda.com/take-your-gaming-to-the-next-level-download-the-5/feed/0Descubre el emocionante mundo de Pin-Up Casino en Ecuador
https://sanatandharmveda.com/descubre-el-emocionante-mundo-de-pin-up-casino-en-2/
https://sanatandharmveda.com/descubre-el-emocionante-mundo-de-pin-up-casino-en-2/#respondSun, 24 May 2026 14:04:53 +0000https://sanatandharmveda.com/?p=39606
Pin-Up Casino en Ecuador
Introducción
Pin-Up Casino es una plataforma de juegos en línea que ha ganado popularidad en Ecuador por su amplia variedad de tragamonedas, bonos generosos y experiencia de juego emocionante. En este artículo, exploraremos todo lo que Pin-Up Casino tiene para ofrecer a los jugadores ecuatorianos.
Tragamonedas emocionantes
Una de las principales atracciones de Pin-Up Casino son sus emocionantes tragamonedas, que ofrecen una amplia variedad de temas y características. Desde tragamonedas clásicas hasta las últimas novedades, los jugadores en Ecuador encontrarán una gran selección de juegos para disfrutar. Además, con la opción de jugar con dinero real, la emoción está garantizada en cada giro.
Bonos y giros gratis
Pin-Up Casino no se queda atrás cuando se trata de recompensar a sus jugadores. Con generosos bonos de bienvenida y promociones regulares, los jugadores ecuatorianos pueden aumentar sus posibilidades de ganar y disfrutar de una experiencia aún más emocionante. Además, los giros gratis ofrecidos en ciertos juegos permiten a los jugadores probar suerte sin arriesgar su propio dinero.
Registro sencillo
Para empezar a disfrutar de todo lo que Pin-Up Casino tiene para ofrecer, los jugadores en Ecuador pueden registrarse de forma sencilla y rápida. Con unos pocos pasos, tendrán acceso a una amplia gama de juegos de casino en línea y podrán comenzar a jugar en cuestión de minutos.
Juegos en línea de calidad
Pin-Up Casino se enorgullece de ofrecer juegos de casino en línea de la más alta calidad, desarrollados por los mejores proveedores de la industria. Desde tragamonedas hasta juegos de mesa y póker, los jugadores en Ecuador encontrarán una amplia variedad de opciones para disfrutar y ganar premios emocionantes.
Experiencia de juego excepcional
En resumen, Pin-Up Casino brinda a los jugadores ecuatorianos una experiencia de juego excepcional, con una amplia variedad de juegos, bonos generosos y un servicio al cliente de primera clase. No pierdas la oportunidad de unirte a la diversión y emoción que ofrece Pin-Up Casino en Ecuador.
]]>
https://sanatandharmveda.com/descubre-el-emocionante-mundo-de-pin-up-casino-en-2/feed/0Discover the Excitement of Pinco: Your Ultimate Online Casino Destination!
https://sanatandharmveda.com/discover-the-excitement-of-pinco-your-ultimate/
https://sanatandharmveda.com/discover-the-excitement-of-pinco-your-ultimate/#respondFri, 22 May 2026 07:39:20 +0000https://sanatandharmveda.com/?p=39366
Introduction
Welcome to the world of online casinos in Canada, where gaming enthusiasts can enjoy a wide range of options right at their fingertips. In this article, we will delve into the exciting realm of Pinco App, App Pinco, Pinco Casino App, App Pinco Casino, Pinco Android, Pinco App Download for Android, and Pinco Apps. Whether you are a seasoned player or a newcomer to the online casino scene, Pinco has something for everyone.
Pinco Casino Canada: A Prime Destination for Online Gaming
When it comes to online casinos in Canada, Pinco Casino Canada stands out as a top choice for players looking for a premium gaming experience. With a user-friendly interface and a wide selection of games, Pinco Casino Canada offers a seamless gaming experience for players of all levels. Whether you prefer slots, bonuses, free spins, or classic casino games, Pinco Casino Canada has it all.
Pinco App: Your Gateway to Unlimited Fun
With the Pinco App, players can enjoy their favorite casino games anytime, anywhere. Whether you are on the go or relaxing at home, the Pinco App allows you to access a wide range of games with just a few taps on your smartphone or tablet. The convenience of the Pinco App makes it easy for players to dive into the world of online gaming and experience the thrill of playing for real money.
Enhance Your Gaming Experience with Pinco Android
For Android users, the Pinco Android app offers a seamless gaming experience with a user-friendly interface and smooth gameplay. Whether you are a fan of slots, bonuses, or free spins, the Pinco Android app has something for everyone. With just a few clicks, you can download the app and start playing your favorite casino games on your Android device.
Unlock Endless Entertainment with Pinco Apps
Pinco Apps bring a world of entertainment to your fingertips with a wide range of casino games to choose from. Whether you are a fan of slots, bonuses, or free spins, Pinco Apps have something for every player. With regular updates and new games added regularly, Pinco Apps ensure that players always have something fresh and exciting to look forward to.
Conclusion
In conclusion, Pinco App, App Pinco, Pinco Casino App, App Pinco Casino, Pinco Android, Pinco App Download for Android, and Pinco Apps offer a diverse and exciting gaming experience for players in Canada. With a focus on slots, bonuses, free spins, registration, and online games, Pinco provides endless opportunities for players to enjoy their favorite casino games and play for real money. Whether you are a seasoned player or a newcomer to the world of online gaming, Pinco has something for everyone. So why wait? Dive into the world of Pinco today and elevate your gaming experience to new heights!
]]>https://sanatandharmveda.com/discover-the-excitement-of-pinco-your-ultimate/feed/0Unwrap Santa’s Gifts and Win Big with Santa’s Gift Frenzy Burning Board Slot!
https://sanatandharmveda.com/unwrap-santa-s-gifts-and-win-big-with-santa-s-gift/
https://sanatandharmveda.com/unwrap-santa-s-gifts-and-win-big-with-santa-s-gift/#respondThu, 21 May 2026 11:34:15 +0000https://sanatandharmveda.com/?p=39198
Introduction
Welcome to the world of online slots, where excitement and thrill await you at every spin! In this article, we will delve into the thrilling Santa’s Gift Frenzy Burning Board slot, a game that promises an unforgettable gaming experience filled with bonuses, free spins, and the chance to play for real money. Get ready to embark on a journey to discover the magic of online slots!
Discover Santa’s Gift Frenzy Burning Board Slot
If you’re looking for a game that combines festive cheer with the excitement of online slots, look no further than Santa’s Gift Frenzy Burning Board slot. This slot game is designed to immerse players in a world of holiday magic, where Santa’s gifts are waiting to be unwrapped. With stunning graphics, engaging gameplay, and the chance to win big, this game is a must-try for all online slots enthusiasts.
Exciting Features and Bonuses
One of the highlights of Santa’s Gift Frenzy Burning Board slot is the array of bonuses and free spins it offers. From multiplier bonuses to free spin rounds, players have the opportunity to boost their winnings and extend their gameplay. By taking advantage of these bonuses, players can increase their chances of hitting the jackpot and walking away with a handsome reward.
Registration and Gameplay
Getting started with Santa’s Gift Frenzy Burning Board slot is quick and easy. Simply register at a reputable online casino that offers this game, make a deposit, and you’ll be ready to start spinning the reels. Whether you’re a seasoned player or new to online slots, the intuitive gameplay of this slot makes it easy to dive right in and start playing for real money.
Benefits of Playing Online Slots
Playing online slots like Santa’s Gift Frenzy Burning Board slot offers a host of benefits. Not only do you get to enjoy the convenience of playing from the comfort of your own home, but you also have access to a wide range of casino games at your fingertips. Additionally, online slots provide a social and interactive gaming experience, allowing you to connect with other players and share in the excitement of winning big.
Conclusion
In conclusion, Santa’s Gift Frenzy Burning Board slot is a must-play for anyone looking to experience the thrill of online slots. With its festive theme, exciting features, and generous bonuses, this game has something for every player to enjoy. So why wait? Head to your favorite online casino, register, and start spinning the reels to uncover Santa’s gifts and win big!
]]>https://sanatandharmveda.com/unwrap-santa-s-gifts-and-win-big-with-santa-s-gift/feed/0Unwrap Santa’s Gifts and Win Big with Santa’s Gift Frenzy Burning Board Slot!
https://sanatandharmveda.com/unwrap-santa-s-gifts-and-win-big-with-santa-s-gift-2/
https://sanatandharmveda.com/unwrap-santa-s-gifts-and-win-big-with-santa-s-gift-2/#respondThu, 21 May 2026 11:34:15 +0000https://sanatandharmveda.com/?p=39575
Introduction
Welcome to the world of online slots, where excitement and thrill await you at every spin! In this article, we will delve into the thrilling Santa’s Gift Frenzy Burning Board slot, a game that promises an unforgettable gaming experience filled with bonuses, free spins, and the chance to play for real money. Get ready to embark on a journey to discover the magic of online slots!
Discover Santa’s Gift Frenzy Burning Board Slot
If you’re looking for a game that combines festive cheer with the excitement of online slots, look no further than Santa’s Gift Frenzy Burning Board slot. This slot game is designed to immerse players in a world of holiday magic, where Santa’s gifts are waiting to be unwrapped. With stunning graphics, engaging gameplay, and the chance to win big, this game is a must-try for all online slots enthusiasts.
Exciting Features and Bonuses
One of the highlights of Santa’s Gift Frenzy Burning Board slot is the array of bonuses and free spins it offers. From multiplier bonuses to free spin rounds, players have the opportunity to boost their winnings and extend their gameplay. By taking advantage of these bonuses, players can increase their chances of hitting the jackpot and walking away with a handsome reward.
Registration and Gameplay
Getting started with Santa’s Gift Frenzy Burning Board slot is quick and easy. Simply register at a reputable online casino that offers this game, make a deposit, and you’ll be ready to start spinning the reels. Whether you’re a seasoned player or new to online slots, the intuitive gameplay of this slot makes it easy to dive right in and start playing for real money.
Benefits of Playing Online Slots
Playing online slots like Santa’s Gift Frenzy Burning Board slot offers a host of benefits. Not only do you get to enjoy the convenience of playing from the comfort of your own home, but you also have access to a wide range of casino games at your fingertips. Additionally, online slots provide a social and interactive gaming experience, allowing you to connect with other players and share in the excitement of winning big.
Conclusion
In conclusion, Santa’s Gift Frenzy Burning Board slot is a must-play for anyone looking to experience the thrill of online slots. With its festive theme, exciting features, and generous bonuses, this game has something for every player to enjoy. So why wait? Head to your favorite online casino, register, and start spinning the reels to uncover Santa’s gifts and win big!
]]>https://sanatandharmveda.com/unwrap-santa-s-gifts-and-win-big-with-santa-s-gift-2/feed/0Découvrez Chicken Road 2 : Le jeu de casino en ligne incontournable au Congo
https://sanatandharmveda.com/decouvrez-chicken-road-2-le-jeu-de-casino-en-ligne-60/
https://sanatandharmveda.com/decouvrez-chicken-road-2-le-jeu-de-casino-en-ligne-60/#respondThu, 21 May 2026 07:07:02 +0000https://sanatandharmveda.com/?p=39176
Jeu Chicken Road 2 : Une expérience de jeu passionnante au Congo
Les jeux de casino en ligne sont de plus en plus populaires au Congo, offrant aux joueurs locaux une expérience de jeu passionnante et divertissante. Parmi les nombreux jeux disponibles, le jeu Chicken Road 2 se démarque par son gameplay unique et ses nombreuses opportunités de gains.
Disponible sur https://chickenroad2-jeu.com/, Chicken Road 2 est une machine à sous en ligne qui offre des bonus généreux, des tours gratuits et la possibilité de jouer avec de l’argent réel. Les joueurs congolais peuvent s’inscrire facilement sur le site et commencer à profiter de leurs jeux de casino préférés en ligne.
Des bonus et des tours gratuits pour maximiser vos gains
En jouant à Chicken Road 2, les joueurs ont la possibilité de bénéficier de nombreux bonus et tours gratuits, ce qui augmente leurs chances de gagner gros. Ces offres promotionnelles sont un excellent moyen de maximiser vos gains tout en profitant de l’excitation des jeux de casino en ligne.
Inscription facile et jeux en ligne de haute qualité
L’inscription sur https://chickenroad2-jeu.com/ est rapide et simple, permettant aux joueurs congolais de commencer à jouer à leurs jeux préférés en quelques minutes seulement. De plus, le site propose une large sélection de jeux de casino de haute qualité, garantissant une expérience de jeu immersive et divertissante pour tous les joueurs.
Profitez de jeux de casino passionnants au Congo
Que vous soyez un joueur occasionnel ou un passionné de jeux de casino, Chicken Road 2 vous offre la possibilité de vivre une expérience de jeu inoubliable au Congo. Avec ses graphismes époustouflants, ses fonctionnalités uniques et ses opportunités de gains lucratives, ce jeu est un incontournable pour tous les amateurs de jeux en ligne.
N’attendez plus et rejoignez dès maintenant la communauté de joueurs congolais sur https://chickenroad2-jeu.com/ pour profiter de tout ce que Chicken Road 2 a à offrir. Que la chance soit de votre côté et que les gains soient au rendez-vous !