/** * REST API: WP_REST_Server class * * @package WordPress * @subpackage REST_API * @since 4.4.0 */ /** * Core class used to implement the WordPress REST API server. * * @since 4.4.0 */ #[AllowDynamicProperties] class WP_REST_Server { /** * Alias for GET transport method. * * @since 4.4.0 * @var string */ const READABLE = 'GET'; /** * Alias for POST transport method. * * @since 4.4.0 * @var string */ const CREATABLE = 'POST'; /** * Alias for POST, PUT, PATCH transport methods together. * * @since 4.4.0 * @var string */ const EDITABLE = 'POST, PUT, PATCH'; /** * Alias for DELETE transport method. * * @since 4.4.0 * @var string */ const DELETABLE = 'DELETE'; /** * Alias for GET, POST, PUT, PATCH & DELETE transport methods together. * * @since 4.4.0 * @var string */ const ALLMETHODS = 'GET, POST, PUT, PATCH, DELETE'; /** * Namespaces registered to the server. * * @since 4.4.0 * @var array */ protected $namespaces = array(); /** * Endpoints registered to the server. * * @since 4.4.0 * @var array */ protected $endpoints = array(); /** * Options defined for the routes. * * @since 4.4.0 * @var array */ protected $route_options = array(); /** * Caches embedded requests. * * @since 5.4.0 * @var array */ protected $embed_cache = array(); /** * Stores request objects that are currently being handled. * * @since 6.5.0 * @var array */ protected $dispatching_requests = array(); /** * Instantiates the REST server. * * @since 4.4.0 */ public function __construct() { $this->endpoints = array( // Meta endpoints. '/' => array( 'callback' => array( $this, 'get_index' ), 'methods' => 'GET', 'args' => array( 'context' => array( 'default' => 'view', ), ), ), '/batch/v1' => array( 'callback' => array( $this, 'serve_batch_request_v1' ), 'methods' => 'POST', 'args' => array( 'validation' => array( 'type' => 'string', 'enum' => array( 'require-all-validate', 'normal' ), 'default' => 'normal', ), 'requests' => array( 'required' => true, 'type' => 'array', 'maxItems' => $this->get_max_batch_size(), 'items' => array( 'type' => 'object', 'properties' => array( 'method' => array( 'type' => 'string', 'enum' => array( 'POST', 'PUT', 'PATCH', 'DELETE' ), 'default' => 'POST', ), 'path' => array( 'type' => 'string', 'required' => true, ), 'body' => array( 'type' => 'object', 'properties' => array(), 'additionalProperties' => true, ), 'headers' => array( 'type' => 'object', 'properties' => array(), 'additionalProperties' => array( 'type' => array( 'string', 'array' ), 'items' => array( 'type' => 'string', ), ), ), ), ), ), ), ), ); } /** * Checks the authentication headers if supplied. * * @since 4.4.0 * * @return WP_Error|null|true WP_Error if authentication error occurred, null if authentication * method wasn't used, true if authentication succeeded. */ public function check_authentication() { /** * Filters REST API authentication errors. * * This is used to pass a WP_Error from an authentication method back to * the API. * * Authentication methods should check first if they're being used, as * multiple authentication methods can be enabled on a site (cookies, * HTTP basic auth, OAuth). If the authentication method hooked in is * not actually being attempted, null should be returned to indicate * another authentication method should check instead. Similarly, * callbacks should ensure the value is `null` before checking for * errors. * * A WP_Error instance can be returned if an error occurs, and this should * match the format used by API methods internally (that is, the `status` * data should be used). A callback can return `true` to indicate that * the authentication method was used, and it succeeded. * * @since 4.4.0 * * @param WP_Error|null|true $errors WP_Error if authentication error occurred, null if authentication * method wasn't used, true if authentication succeeded. */ return apply_filters( 'rest_authentication_errors', null ); } /** * Converts an error to a response object. * * This iterates over all error codes and messages to change it into a flat * array. This enables simpler client behavior, as it is represented as a * list in JSON rather than an object/map. * * @since 4.4.0 * @since 5.7.0 Converted to a wrapper of {@see rest_convert_error_to_response()}. * * @param WP_Error $error WP_Error instance. * @return WP_REST_Response List of associative arrays with code and message keys. */ protected function error_to_response( $error ) { return rest_convert_error_to_response( $error ); } /** * Retrieves an appropriate error representation in JSON. * * Note: This should only be used in WP_REST_Server::serve_request(), as it * cannot handle WP_Error internally. All callbacks and other internal methods * should instead return a WP_Error with the data set to an array that includes * a 'status' key, with the value being the HTTP status to send. * * @since 4.4.0 * * @param string $code WP_Error-style code. * @param string $message Human-readable message. * @param int|null $status Optional. HTTP status code to send. Default null. * @return string JSON representation of the error. */ protected function json_error( $code, $message, $status = null ) { if ( $status ) { $this->set_status( $status ); } $error = compact( 'code', 'message' ); return wp_json_encode( $error ); } /** * Gets the encoding options passed to {@see wp_json_encode}. * * @since 6.1.0 * * @param \WP_REST_Request $request The current request object. * * @return int The JSON encode options. */ protected function get_json_encode_options( WP_REST_Request $request ) { $options = 0; if ( $request->has_param( '_pretty' ) ) { $options |= JSON_PRETTY_PRINT; } /** * Filters the JSON encoding options used to send the REST API response. * * @since 6.1.0 * * @param int $options JSON encoding options {@see json_encode()}. * @param WP_REST_Request $request Current request object. */ return apply_filters( 'rest_json_encode_options', $options, $request ); } /** * Handles serving a REST API request. * * Matches the current server URI to a route and runs the first matching * callback then outputs a JSON representation of the returned value. * * @since 4.4.0 * * @see WP_REST_Server::dispatch() * * @global WP_User $current_user The currently authenticated user. * * @param string|null $path Optional. The request route. If not set, `$_SERVER['PATH_INFO']` will be used. * Default null. * @return null|false Null if not served and a HEAD request, false otherwise. */ public function serve_request( $path = null ) { // Refuse to start a fresh top-level REST cycle while another dispatch // is already in flight. Internal sub-requests must use dispatch(). if ( $this->is_dispatching() ) { return false; } /* @var WP_User|null $current_user */ global $current_user; if ( $current_user instanceof WP_User && ! $current_user->exists() ) { /* * If there is no current user authenticated via other means, clear * the cached lack of user, so that an authenticate check can set it * properly. * * This is done because for authentications such as Application * Passwords, we don't want it to be accepted unless the current HTTP * request is a REST API request, which can't always be identified early * enough in evaluation. */ $current_user = null; } /** * Filters whether JSONP is enabled for the REST API. * * @since 4.4.0 * * @param bool $jsonp_enabled Whether JSONP is enabled. Default true. */ $jsonp_enabled = apply_filters( 'rest_jsonp_enabled', true ); $jsonp_callback = false; if ( isset( $_GET['_jsonp'] ) ) { $jsonp_callback = $_GET['_jsonp']; } $content_type = ( $jsonp_callback && $jsonp_enabled ) ? 'application/javascript' : 'application/json'; $this->send_header( 'Content-Type', $content_type . '; charset=' . get_option( 'blog_charset' ) ); $this->send_header( 'X-Robots-Tag', 'noindex' ); $api_root = get_rest_url(); if ( ! empty( $api_root ) ) { $this->send_header( 'Link', '<' . sanitize_url( $api_root ) . '>; rel="https://api.w.org/"' ); } /* * Mitigate possible JSONP Flash attacks. * * https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ */ $this->send_header( 'X-Content-Type-Options', 'nosniff' ); /** * Filters whether the REST API is enabled. * * @since 4.4.0 * @deprecated 4.7.0 Use the {@see 'rest_authentication_errors'} filter to * restrict access to the REST API. * * @param bool $rest_enabled Whether the REST API is enabled. Default true. */ apply_filters_deprecated( 'rest_enabled', array( true ), '4.7.0', 'rest_authentication_errors', sprintf( /* translators: %s: rest_authentication_errors */ __( 'The REST API can no longer be completely disabled, the %s filter can be used to restrict access to the API, instead.' ), 'rest_authentication_errors' ) ); if ( $jsonp_callback ) { if ( ! $jsonp_enabled ) { echo $this->json_error( 'rest_callback_disabled', __( 'JSONP support is disabled on this site.' ), 400 ); return false; } if ( ! wp_check_jsonp_callback( $jsonp_callback ) ) { echo $this->json_error( 'rest_callback_invalid', __( 'Invalid JSONP callback function.' ), 400 ); return false; } } if ( empty( $path ) ) { $path = $_SERVER['PATH_INFO'] ?? '/'; } $request = new WP_REST_Request( $_SERVER['REQUEST_METHOD'], $path ); $request->set_query_params( wp_unslash( $_GET ) ); $request->set_body_params( wp_unslash( $_POST ) ); $request->set_file_params( $_FILES ); $request->set_headers( $this->get_headers( wp_unslash( $_SERVER ) ) ); $request->set_body( self::get_raw_data() ); /* * HTTP method override for clients that can't use PUT/PATCH/DELETE. First, we check * $_GET['_method']. If that is not set, we check for the HTTP_X_HTTP_METHOD_OVERRIDE * header. */ $method_overridden = false; if ( isset( $_GET['_method'] ) ) { $request->set_method( $_GET['_method'] ); } elseif ( isset( $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ) ) { $request->set_method( $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ); $method_overridden = true; } $expose_headers = array( 'X-WP-Total', 'X-WP-TotalPages', 'Link' ); /** * Filters the list of response headers that are exposed to REST API CORS requests. * * @since 5.5.0 * @since 6.3.0 The `$request` parameter was added. * * @param string[] $expose_headers The list of response headers to expose. * @param WP_REST_Request $request The request in context. */ $expose_headers = apply_filters( 'rest_exposed_cors_headers', $expose_headers, $request ); $this->send_header( 'Access-Control-Expose-Headers', implode( ', ', $expose_headers ) ); $allow_headers = array( 'Authorization', 'X-WP-Nonce', 'Content-Disposition', 'Content-MD5', 'Content-Type', ); /** * Filters the list of request headers that are allowed for REST API CORS requests. * * The allowed headers are passed to the browser to specify which * headers can be passed to the REST API. By default, we allow the * Content-* headers needed to upload files to the media endpoints. * As well as the Authorization and Nonce headers for allowing authentication. * * @since 5.5.0 * @since 6.3.0 The `$request` parameter was added. * * @param string[] $allow_headers The list of request headers to allow. * @param WP_REST_Request $request The request in context. */ $allow_headers = apply_filters( 'rest_allowed_cors_headers', $allow_headers, $request ); $this->send_header( 'Access-Control-Allow-Headers', implode( ', ', $allow_headers ) ); $result = $this->check_authentication(); if ( ! is_wp_error( $result ) ) { $result = $this->dispatch( $request ); } // Normalize to either WP_Error or WP_REST_Response... $result = rest_ensure_response( $result ); // ...then convert WP_Error across. if ( is_wp_error( $result ) ) { $result = $this->error_to_response( $result ); } /** * Filters the REST API response. * * Allows modification of the response before returning. * * @since 4.4.0 * @since 4.5.0 Applied to embedded responses. * * @param WP_HTTP_Response $result Result to send to the client. Usually a `WP_REST_Response`. * @param WP_REST_Server $server Server instance. * @param WP_REST_Request $request Request used to generate the response. */ $result = apply_filters( 'rest_post_dispatch', rest_ensure_response( $result ), $this, $request ); // Wrap the response in an envelope if asked for. if ( isset( $_GET['_envelope'] ) ) { $embed = isset( $_GET['_embed'] ) ? rest_parse_embed_param( $_GET['_embed'] ) : false; $result = $this->envelope_response( $result, $embed ); } // Send extra data from response objects. $headers = $result->get_headers(); $this->send_headers( $headers ); $code = $result->get_status(); $this->set_status( $code ); /** * Filters whether to send no-cache headers on a REST API request. * * @since 4.4.0 * @since 6.3.2 Moved the block to catch the filter added on rest_cookie_check_errors() from wp-includes/rest-api.php. * * @param bool $rest_send_nocache_headers Whether to send no-cache headers. */ $send_no_cache_headers = apply_filters( 'rest_send_nocache_headers', is_user_logged_in() ); /* * Send no-cache headers if $send_no_cache_headers is true, * OR if the HTTP_X_HTTP_METHOD_OVERRIDE is used but resulted a 4xx response code. */ if ( $send_no_cache_headers || ( true === $method_overridden && str_starts_with( $code, '4' ) ) ) { foreach ( wp_get_nocache_headers() as $header => $header_value ) { if ( empty( $header_value ) ) { $this->remove_header( $header ); } else { $this->send_header( $header, $header_value ); } } } /** * Filters whether the REST API request has already been served. * * Allow sending the request manually - by returning true, the API result * will not be sent to the client. * * @since 4.4.0 * * @param bool $served Whether the request has already been served. Default false. * @param WP_HTTP_Response $result Result to send to the client. Usually a `WP_REST_Response`. * @param WP_REST_Request $request Request used to generate the response. * @param WP_REST_Server $server Server instance. */ $served = apply_filters( 'rest_pre_serve_request', false, $result, $request, $this ); if ( ! $served ) { if ( 'HEAD' === $request->get_method() ) { return null; } // Embed links inside the request. $embed = isset( $_GET['_embed'] ) ? rest_parse_embed_param( $_GET['_embed'] ) : false; $result = $this->response_to_data( $result, $embed ); /** * Filters the REST API response. * * Allows modification of the response data after inserting * embedded data (if any) and before echoing the response data. * * @since 4.8.1 * * @param array $result Response data to send to the client. * @param WP_REST_Server $server Server instance. * @param WP_REST_Request $request Request used to generate the response. */ $result = apply_filters( 'rest_pre_echo_response', $result, $this, $request ); // The 204 response shouldn't have a body. if ( 204 === $code || null === $result ) { return null; } $result = wp_json_encode( $result, $this->get_json_encode_options( $request ) ); $json_error_message = $this->get_json_last_error(); if ( $json_error_message ) { $this->set_status( 500 ); $json_error_obj = new WP_Error( 'rest_encode_error', $json_error_message, array( 'status' => 500 ) ); $result = $this->error_to_response( $json_error_obj ); $result = wp_json_encode( $result->data, $this->get_json_encode_options( $request ) ); } if ( $jsonp_callback ) { // Prepend '/**/' to mitigate possible JSONP Flash attacks. // https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ echo '/**/' . $jsonp_callback . '(' . $result . ')'; } else { echo $result; } } return null; } /** * Converts a response to data to send. * * @since 4.4.0 * @since 5.4.0 The `$embed` parameter can now contain a list of link relations to include. * * @param WP_REST_Response $response Response object. * @param bool|string[] $embed Whether to embed all links, a filtered list of link relations, or no links. * @return array { * Data with sub-requests embedded. * * @type array $_links Links. * @type array $_embedded Embedded objects. * } */ public function response_to_data( $response, $embed ) { $data = $response->get_data(); $links = self::get_compact_response_links( $response ); if ( ! empty( $links ) ) { // Convert links to part of the data. $data['_links'] = $links; } if ( $embed ) { $this->embed_cache = array(); // Determine if this is a numeric array. if ( wp_is_numeric_array( $data ) ) { foreach ( $data as $key => $item ) { $data[ $key ] = $this->embed_links( $item, $embed ); } } else { $data = $this->embed_links( $data, $embed ); } $this->embed_cache = array(); } return $data; } /** * Retrieves links from a response. * * Extracts the links from a response into a structured hash, suitable for * direct output. * * @since 4.4.0 * * @param WP_REST_Response $response Response to extract links from. * @return array Map of link relation to list of link hashes. */ public static function get_response_links( $response ) { $links = $response->get_links(); if ( empty( $links ) ) { return array(); } // Convert links to part of the data. $data = array(); foreach ( $links as $rel => $items ) { $data[ $rel ] = array(); foreach ( $items as $item ) { $attributes = $item['attributes']; $attributes['href'] = $item['href']; if ( 'self' !== $rel ) { $data[ $rel ][] = $attributes; continue; } $target_hints = self::get_target_hints_for_link( $attributes ); if ( $target_hints ) { $attributes['targetHints'] = $target_hints; } $data[ $rel ][] = $attributes; } } return $data; } /** * Gets the target hints for a REST API Link. * * @since 6.7.0 * * @param array $link The link to get target hints for. * @return array|null */ protected static function get_target_hints_for_link( $link ) { // Prefer targetHints that were specifically designated by the developer. if ( isset( $link['targetHints']['allow'] ) ) { return null; } $request = WP_REST_Request::from_url( $link['href'] ); if ( ! $request ) { return null; } $server = rest_get_server(); $match = $server->match_request_to_handler( $request ); if ( is_wp_error( $match ) ) { return null; } if ( is_wp_error( $request->has_valid_params() ) ) { return null; } if ( is_wp_error( $request->sanitize_params() ) ) { return null; } $target_hints = array(); $response = new WP_REST_Response(); $response->set_matched_route( $match[0] ); $response->set_matched_handler( $match[1] ); $headers = rest_send_allow_header( $response, $server, $request )->get_headers(); foreach ( $headers as $name => $value ) { $name = WP_REST_Request::canonicalize_header_name( $name ); $target_hints[ $name ] = array_map( 'trim', explode( ',', $value ) ); } return $target_hints; } /** * Retrieves the CURIEs (compact URIs) used for relations. * * Extracts the links from a response into a structured hash, suitable for * direct output. * * @since 4.5.0 * * @param WP_REST_Response $response Response to extract links from. * @return array Map of link relation to list of link hashes. */ public static function get_compact_response_links( $response ) { $links = self::get_response_links( $response ); if ( empty( $links ) ) { return array(); } $curies = $response->get_curies(); $used_curies = array(); foreach ( $links as $rel => $items ) { // Convert $rel URIs to their compact versions if they exist. foreach ( $curies as $curie ) { $href_prefix = substr( $curie['href'], 0, strpos( $curie['href'], '{rel}' ) ); if ( ! str_starts_with( $rel, $href_prefix ) ) { continue; } // Relation now changes from '$uri' to '$curie:$relation'. $rel_regex = str_replace( '\{rel\}', '(.+)', preg_quote( $curie['href'], '!' ) ); preg_match( '!' . $rel_regex . '!', $rel, $matches ); if ( $matches ) { $new_rel = $curie['name'] . ':' . $matches[1]; $used_curies[ $curie['name'] ] = $curie; $links[ $new_rel ] = $items; unset( $links[ $rel ] ); break; } } } // Push the curies onto the start of the links array. if ( $used_curies ) { $links['curies'] = array_values( $used_curies ); } return $links; } /** * Embeds the links from the data into the request. * * @since 4.4.0 * @since 5.4.0 The `$embed` parameter can now contain a list of link relations to include. * * @param array $data Data from the request. * @param bool|string[] $embed Whether to embed all links or a filtered list of link relations. * Default true. * @return array { * Data with sub-requests embedded. * * @type array $_links Links. * @type array $_embedded Embedded objects. * } */ protected function embed_links( $data, $embed = true ) { if ( empty( $data['_links'] ) ) { return $data; } $embedded = array(); foreach ( $data['_links'] as $rel => $links ) { /* * If a list of relations was specified, and the link relation * is not in the list of allowed relations, don't process the link. */ if ( is_array( $embed ) && ! in_array( $rel, $embed, true ) ) { continue; } $embeds = array(); foreach ( $links as $item ) { // Determine if the link is embeddable. if ( empty( $item['embeddable'] ) ) { // Ensure we keep the same order. $embeds[] = array(); continue; } if ( ! array_key_exists( $item['href'], $this->embed_cache ) ) { // Run through our internal routing and serve. $request = WP_REST_Request::from_url( $item['href'] ); if ( ! $request ) { $embeds[] = array(); continue; } // Embedded resources get passed context=embed. if ( empty( $request['context'] ) ) { $request['context'] = 'embed'; } if ( empty( $request['per_page'] ) ) { $matched = $this->match_request_to_handler( $request ); if ( ! is_wp_error( $matched ) && isset( $matched[1]['args']['per_page']['maximum'] ) ) { $request['per_page'] = (int) $matched[1]['args']['per_page']['maximum']; } } $response = $this->dispatch( $request ); /** This filter is documented in wp-includes/rest-api/class-wp-rest-server.php */ $response = apply_filters( 'rest_post_dispatch', rest_ensure_response( $response ), $this, $request ); $this->embed_cache[ $item['href'] ] = $this->response_to_data( $response, false ); } $embeds[] = $this->embed_cache[ $item['href'] ]; } // Determine if any real links were found. $has_links = count( array_filter( $embeds ) ); if ( $has_links ) { $embedded[ $rel ] = $embeds; } } if ( ! empty( $embedded ) ) { $data['_embedded'] = $embedded; } return $data; } /** * Wraps the response in an envelope. * * The enveloping technique is used to work around browser/client * compatibility issues. Essentially, it converts the full HTTP response to * data instead. * * @since 4.4.0 * @since 6.0.0 The `$embed` parameter can now contain a list of link relations to include. * * @param WP_REST_Response $response Response object. * @param bool|string[] $embed Whether to embed all links, a filtered list of link relations, or no links. * @return WP_REST_Response New response with wrapped data */ public function envelope_response( $response, $embed ) { $envelope = array( 'body' => $this->response_to_data( $response, $embed ), 'status' => $response->get_status(), 'headers' => $response->get_headers(), ); /** * Filters the enveloped form of a REST API response. * * @since 4.4.0 * * @param array $envelope { * Envelope data. * * @type array $body Response data. * @type int $status The 3-digit HTTP status code. * @type array $headers Map of header name to header value. * } * @param WP_REST_Response $response Original response data. */ $envelope = apply_filters( 'rest_envelope_response', $envelope, $response ); // Ensure it's still a response and return. return rest_ensure_response( $envelope ); } /** * Registers a route to the server. * * @since 4.4.0 * * @param string $route_namespace Namespace. * @param string $route The REST route. * @param array $route_args Route arguments. * @param bool $override Optional. Whether the route should be overridden if it already exists. * Default false. */ public function register_route( $route_namespace, $route, $route_args, $override = false ) { if ( ! isset( $this->namespaces[ $route_namespace ] ) ) { $this->namespaces[ $route_namespace ] = array(); $this->register_route( $route_namespace, '/' . $route_namespace, array( array( 'methods' => self::READABLE, 'callback' => array( $this, 'get_namespace_index' ), 'args' => array( 'namespace' => array( 'default' => $route_namespace, ), 'context' => array( 'default' => 'view', ), ), ), ) ); } // Associative to avoid double-registration. $this->namespaces[ $route_namespace ][ $route ] = true; $route_args['namespace'] = $route_namespace; if ( $override || empty( $this->endpoints[ $route ] ) ) { $this->endpoints[ $route ] = $route_args; } else { $this->endpoints[ $route ] = array_merge( $this->endpoints[ $route ], $route_args ); } } /** * Retrieves the route map. * * The route map is an associative array with path regexes as the keys. The * value is an indexed array with the callback function/method as the first * item, and a bitmask of HTTP methods as the second item (see the class * constants). * * Each route can be mapped to more than one callback by using an array of * the indexed arrays. This allows mapping e.g. GET requests to one callback * and POST requests to another. * * Note that the path regexes (array keys) must have @ escaped, as this is * used as the delimiter with preg_match() * * @since 4.4.0 * @since 5.4.0 Added `$route_namespace` parameter. * * @param string $route_namespace Optionally, only return routes in the given namespace. * @return array `'/path/regex' => array( $callback, $bitmask )` or * `'/path/regex' => array( array( $callback, $bitmask ), ...)`. */ public function get_routes( $route_namespace = '' ) { $endpoints = $this->endpoints; if ( $route_namespace ) { $endpoints = wp_list_filter( $endpoints, array( 'namespace' => $route_namespace ) ); } /** * Filters the array of available REST API endpoints. * * @since 4.4.0 * * @param array $endpoints The available endpoints. An array of matching regex patterns, each mapped * to an array of callbacks for the endpoint. These take the format * `'/path/regex' => array( $callback, $bitmask )` or * `'/path/regex' => array( array( $callback, $bitmask ). */ $endpoints = apply_filters( 'rest_endpoints', $endpoints ); // Normalize the endpoints. $defaults = array( 'methods' => '', 'accept_json' => false, 'accept_raw' => false, 'show_in_index' => true, 'args' => array(), ); foreach ( $endpoints as $route => &$handlers ) { if ( isset( $handlers['callback'] ) ) { // Single endpoint, add one deeper. $handlers = array( $handlers ); } if ( ! isset( $this->route_options[ $route ] ) ) { $this->route_options[ $route ] = array(); } foreach ( $handlers as $key => &$handler ) { if ( ! is_numeric( $key ) ) { // Route option, move it to the options. $this->route_options[ $route ][ $key ] = $handler; unset( $handlers[ $key ] ); continue; } $handler = wp_parse_args( $handler, $defaults ); // Allow comma-separated HTTP methods. if ( is_string( $handler['methods'] ) ) { $methods = explode( ',', $handler['methods'] ); } elseif ( is_array( $handler['methods'] ) ) { $methods = $handler['methods']; } else { $methods = array(); } $handler['methods'] = array(); foreach ( $methods as $method ) { $method = strtoupper( trim( $method ) ); $handler['methods'][ $method ] = true; } } } return $endpoints; } /** * Retrieves namespaces registered on the server. * * @since 4.4.0 * * @return string[] List of registered namespaces. */ public function get_namespaces() { return array_keys( $this->namespaces ); } /** * Retrieves specified options for a route. * * @since 4.4.0 * * @param string $route Route pattern to fetch options for. * @return array|null Data as an associative array if found, or null if not found. */ public function get_route_options( $route ) { if ( ! isset( $this->route_options[ $route ] ) ) { return null; } return $this->route_options[ $route ]; } /** * Matches the request to a callback and call it. * * @since 4.4.0 * * @param WP_REST_Request $request Request to attempt dispatching. * @return WP_REST_Response Response returned by the callback. */ public function dispatch( $request ) { $this->dispatching_requests[] = $request; /** * Filters the pre-calculated result of a REST API dispatch request. * * Allow hijacking the request before dispatching by returning a non-empty. The returned value * will be used to serve the request instead. * * @since 4.4.0 * * @param mixed $result Response to replace the requested version with. Can be anything * a normal endpoint can return, or null to not hijack the request. * @param WP_REST_Server $server Server instance. * @param WP_REST_Request $request Request used to generate the response. */ $result = apply_filters( 'rest_pre_dispatch', null, $this, $request ); if ( ! empty( $result ) ) { // Normalize to either WP_Error or WP_REST_Response... $result = rest_ensure_response( $result ); // ...then convert WP_Error across. if ( is_wp_error( $result ) ) { $result = $this->error_to_response( $result ); } array_pop( $this->dispatching_requests ); return $result; } $error = null; $matched = $this->match_request_to_handler( $request ); if ( is_wp_error( $matched ) ) { $response = $this->error_to_response( $matched ); array_pop( $this->dispatching_requests ); return $response; } list( $route, $handler ) = $matched; if ( ! is_callable( $handler['callback'] ) ) { $error = new WP_Error( 'rest_invalid_handler', __( 'The handler for the route is invalid.' ), array( 'status' => 500 ) ); } if ( ! is_wp_error( $error ) ) { $check_required = $request->has_valid_params(); if ( is_wp_error( $check_required ) ) { $error = $check_required; } else { $check_sanitized = $request->sanitize_params(); if ( is_wp_error( $check_sanitized ) ) { $error = $check_sanitized; } } } $response = $this->respond_to_request( $request, $route, $handler, $error ); array_pop( $this->dispatching_requests ); return $response; } /** * Returns whether the REST server is currently dispatching / responding to a request. * * This may be a standalone REST API request, or an internal request dispatched from within a regular page load. * * @since 6.5.0 * * @return bool Whether the REST server is currently handling a request. */ public function is_dispatching() { return (bool) $this->dispatching_requests; } /** * Matches a request object to its handler. * * @access private * @since 5.6.0 * * @param WP_REST_Request $request The request object. * @return array|WP_Error The route and request handler on success or a WP_Error instance if no handler was found. */ protected function match_request_to_handler( $request ) { $method = $request->get_method(); $path = $request->get_route(); $with_namespace = array(); foreach ( $this->get_namespaces() as $namespace ) { if ( str_starts_with( trailingslashit( ltrim( $path, '/' ) ), $namespace ) ) { $with_namespace[] = $this->get_routes( $namespace ); } } if ( $with_namespace ) { $routes = array_merge( ...$with_namespace ); } else { $routes = $this->get_routes(); } foreach ( $routes as $route => $handlers ) { $match = preg_match( '@^' . $route . '$@i', $path, $matches ); if ( ! $match ) { continue; } $args = array(); foreach ( $matches as $param => $value ) { if ( ! is_int( $param ) ) { $args[ $param ] = $value; } } foreach ( $handlers as $handler ) { $callback = $handler['callback']; // Fallback to GET method if no HEAD method is registered. $checked_method = $method; if ( 'HEAD' === $method && empty( $handler['methods']['HEAD'] ) ) { $checked_method = 'GET'; } if ( empty( $handler['methods'][ $checked_method ] ) ) { continue; } if ( ! is_callable( $callback ) ) { return array( $route, $handler ); } $request->set_url_params( $args ); $request->set_attributes( $handler ); $defaults = array(); foreach ( $handler['args'] as $arg => $options ) { if ( isset( $options['default'] ) ) { $defaults[ $arg ] = $options['default']; } } $request->set_default_params( $defaults ); return array( $route, $handler ); } } return new WP_Error( 'rest_no_route', __( 'No route was found matching the URL and request method.' ), array( 'status' => 404 ) ); } /** * Dispatches the request to the callback handler. * * @access private * @since 5.6.0 * * @param WP_REST_Request $request The request object. * @param string $route The matched route regex. * @param array $handler The matched route handler. * @param WP_Error|null $response The current error object if any. * @return WP_REST_Response */ protected function respond_to_request( $request, $route, $handler, $response ) { /** * Filters the response before executing any REST API callbacks. * * Allows plugins to perform additional validation after a * request is initialized and matched to a registered route, * but before it is executed. * * Note that this filter will not be called for requests that * fail to authenticate or match to a registered route. * * @since 4.7.0 * * @param WP_REST_Response|WP_HTTP_Response|WP_Error|mixed $response Result to send to the client. * Usually a WP_REST_Response or WP_Error. * @param array $handler Route handler used for the request. * @param WP_REST_Request $request Request used to generate the response. */ $response = apply_filters( 'rest_request_before_callbacks', $response, $handler, $request ); // Check permission specified on the route. if ( ! is_wp_error( $response ) && ! empty( $handler['permission_callback'] ) ) { $permission = call_user_func( $handler['permission_callback'], $request ); if ( is_wp_error( $permission ) ) { $response = $permission; } elseif ( false === $permission || null === $permission ) { $response = new WP_Error( 'rest_forbidden', __( 'Sorry, you are not allowed to do that.' ), array( 'status' => rest_authorization_required_code() ) ); } } if ( ! is_wp_error( $response ) ) { /** * Filters the REST API dispatch request result. * * Allow plugins to override dispatching the request. * * @since 4.4.0 * @since 4.5.0 Added `$route` and `$handler` parameters. * * @param mixed $dispatch_result Dispatch result, will be used if not empty. * @param WP_REST_Request $request Request used to generate the response. * @param string $route Route matched for the request. * @param array $handler Route handler used for the request. */ $dispatch_result = apply_filters( 'rest_dispatch_request', null, $request, $route, $handler ); // Allow plugins to halt the request via this filter. if ( null !== $dispatch_result ) { $response = $dispatch_result; } else { $response = call_user_func( $handler['callback'], $request ); } } /** * Filters the response immediately after executing any REST API * callbacks. * * Allows plugins to perform any needed cleanup, for example, * to undo changes made during the {@see 'rest_request_before_callbacks'} * filter. * * Note that this filter will not be called for requests that * fail to authenticate or match to a registered route. * * Note that an endpoint's `permission_callback` can still be * called after this filter - see `rest_send_allow_header()`. * * @since 4.7.0 * * @param WP_REST_Response|WP_HTTP_Response|WP_Error|mixed $response Result to send to the client. * Usually a WP_REST_Response or WP_Error. * @param array $handler Route handler used for the request. * @param WP_REST_Request $request Request used to generate the response. */ $response = apply_filters( 'rest_request_after_callbacks', $response, $handler, $request ); if ( is_wp_error( $response ) ) { $response = $this->error_to_response( $response ); } else { $response = rest_ensure_response( $response ); } $response->set_matched_route( $route ); $response->set_matched_handler( $handler ); return $response; } /** * Returns if an error occurred during most recent JSON encode/decode. * * Strings to be translated will be in format like * "Encoding error: Maximum stack depth exceeded". * * @since 4.4.0 * * @return false|string Boolean false or string error message. */ protected function get_json_last_error() { if ( JSON_ERROR_NONE === json_last_error() ) { return false; } return json_last_error_msg(); } /** * Retrieves the site index. * * This endpoint describes the capabilities of the site. * * @since 4.4.0 * * @param WP_REST_Request $request Request data. * @return WP_REST_Response The API root index data. */ public function get_index( $request ) { // General site data. $available = array( 'name' => get_option( 'blogname' ), 'description' => get_option( 'blogdescription' ), 'url' => get_option( 'siteurl' ), 'home' => home_url(), 'gmt_offset' => get_option( 'gmt_offset' ), 'timezone_string' => get_option( 'timezone_string' ), 'page_for_posts' => (int) get_option( 'page_for_posts' ), 'page_on_front' => (int) get_option( 'page_on_front' ), 'show_on_front' => get_option( 'show_on_front' ), 'namespaces' => array_keys( $this->namespaces ), 'authentication' => array(), 'routes' => $this->get_data_for_routes( $this->get_routes(), $request['context'] ), ); // Add media processing settings for users who can upload files. if ( wp_is_client_side_media_processing_enabled() && current_user_can( 'upload_files' ) ) { // Image sizes keyed by name for client-side media processing. $available['image_sizes'] = array(); foreach ( wp_get_registered_image_subsizes() as $name => $size ) { $available['image_sizes'][ $name ] = $size; } /** This filter is documented in wp-admin/includes/image.php */ $available['image_size_threshold'] = (int) apply_filters( 'big_image_size_threshold', 2560, array( 0, 0 ), '', 0 ); /** This filter is documented in wp-includes/class-wp-image-editor-imagick.php */ $available['image_strip_meta'] = (bool) apply_filters( 'image_strip_meta', true ); /* * On the server, this filter receives the decoded image's actual bit depth. * The client path never decodes the image on the server, so the filter is * applied with 16 (the maximum depth the client encoder can produce) as * both the value and the current depth. The client caps its output bit * depth at the filtered value, so a plugin lowering it (e.g. to 8) takes * effect on client-generated images too. */ /** This filter is documented in wp-includes/class-wp-image-editor-imagick.php */ $available['image_max_bit_depth'] = (int) apply_filters( 'image_max_bit_depth', 16, 16 ); } $response = new WP_REST_Response( $available ); $fields = $request['_fields'] ?? ''; $fields = wp_parse_list( $fields ); if ( empty( $fields ) ) { $fields[] = '_links'; } if ( $request->has_param( '_embed' ) ) { $fields[] = '_embedded'; } if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_link( 'help', 'https://developer.wordpress.org/rest-api/' ); $this->add_active_theme_link_to_index( $response ); $this->add_site_logo_to_index( $response ); $this->add_site_icon_to_index( $response ); } else { if ( rest_is_field_included( 'site_logo', $fields ) ) { $this->add_site_logo_to_index( $response ); } if ( rest_is_field_included( 'site_icon', $fields ) || rest_is_field_included( 'site_icon_url', $fields ) ) { $this->add_site_icon_to_index( $response ); } } /** * Filters the REST API root index data. * * This contains the data describing the API. This includes information * about supported authentication schemes, supported namespaces, routes * available on the API, and a small amount of data about the site. * * @since 4.4.0 * @since 6.0.0 Added `$request` parameter. * * @param WP_REST_Response $response Response data. * @param WP_REST_Request $request Request data. */ return apply_filters( 'rest_index', $response, $request ); } /** * Adds a link to the active theme for users who have proper permissions. * * @since 5.7.0 * * @param WP_REST_Response $response REST API response. */ protected function add_active_theme_link_to_index( WP_REST_Response $response ) { $should_add = current_user_can( 'switch_themes' ) || current_user_can( 'manage_network_themes' ); if ( ! $should_add && current_user_can( 'edit_posts' ) ) { $should_add = true; } if ( ! $should_add ) { foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { $should_add = true; break; } } } if ( $should_add ) { $theme = wp_get_theme(); $response->add_link( 'https://api.w.org/active-theme', rest_url( 'wp/v2/themes/' . $theme->get_stylesheet() ) ); } } /** * Exposes the site logo through the WordPress REST API. * * This is used for fetching this information when user has no rights * to update settings. * * @since 5.8.0 * * @param WP_REST_Response $response REST API response. */ protected function add_site_logo_to_index( WP_REST_Response $response ) { $site_logo_id = get_theme_mod( 'custom_logo', 0 ); $this->add_image_to_index( $response, $site_logo_id, 'site_logo' ); } /** * Exposes the site icon through the WordPress REST API. * * This is used for fetching this information when user has no rights * to update settings. * * @since 5.9.0 * * @param WP_REST_Response $response REST API response. */ protected function add_site_icon_to_index( WP_REST_Response $response ) { $site_icon_id = get_option( 'site_icon', 0 ); $this->add_image_to_index( $response, $site_icon_id, 'site_icon' ); $response->data['site_icon_url'] = get_site_icon_url(); } /** * Exposes an image through the WordPress REST API. * This is used for fetching this information when user has no rights * to update settings. * * @since 5.9.0 * * @param WP_REST_Response $response REST API response. * @param int $image_id Image attachment ID. * @param string $type Type of Image. */ protected function add_image_to_index( WP_REST_Response $response, $image_id, $type ) { $response->data[ $type ] = (int) $image_id; if ( $image_id ) { $response->add_link( 'https://api.w.org/featuredmedia', rest_url( rest_get_route_for_post( $image_id ) ), array( 'embeddable' => true, 'type' => $type, ) ); } } /** * Retrieves the index for a namespace. * * @since 4.4.0 * * @param WP_REST_Request $request REST request instance. * @return WP_REST_Response|WP_Error WP_REST_Response instance if the index was found, * WP_Error if the namespace isn't set. */ public function get_namespace_index( $request ) { $namespace = $request['namespace']; if ( ! isset( $this->namespaces[ $namespace ] ) ) { return new WP_Error( 'rest_invalid_namespace', __( 'The specified namespace could not be found.' ), array( 'status' => 404 ) ); } $routes = $this->namespaces[ $namespace ]; $endpoints = array_intersect_key( $this->get_routes(), $routes ); $data = array( 'namespace' => $namespace, 'routes' => $this->get_data_for_routes( $endpoints, $request['context'] ), ); $response = rest_ensure_response( $data ); // Link to the root index. $response->add_link( 'up', rest_url( '/' ) ); /** * Filters the REST API namespace index data. * * This typically is just the route data for the namespace, but you can * add any data you'd like here. * * @since 4.4.0 * * @param WP_REST_Response $response Response data. * @param WP_REST_Request $request Request data. The namespace is passed as the 'namespace' parameter. */ return apply_filters( 'rest_namespace_index', $response, $request ); } /** * Retrieves the publicly-visible data for routes. * * @since 4.4.0 * * @param array $routes Routes to get data for. * @param string $context Optional. Context for data. Accepts 'view' or 'help'. Default 'view'. * @return array[] Route data to expose in indexes, keyed by route. */ public function get_data_for_routes( $routes, $context = 'view' ) { $available = array(); // Find the available routes. foreach ( $routes as $route => $callbacks ) { $data = $this->get_data_for_route( $route, $callbacks, $context ); if ( empty( $data ) ) { continue; } /** * Filters the publicly-visible data for a single REST API route. * * @since 4.4.0 * * @param array $data Publicly-visible data for the route. */ $available[ $route ] = apply_filters( 'rest_endpoints_description', $data ); } /** * Filters the publicly-visible data for REST API routes. * * This data is exposed on indexes and can be used by clients or * developers to investigate the site and find out how to use it. It * acts as a form of self-documentation. * * @since 4.4.0 * * @param array[] $available Route data to expose in indexes, keyed by route. * @param array $routes Internal route data as an associative array. */ return apply_filters( 'rest_route_data', $available, $routes ); } /** * Retrieves publicly-visible data for the route. * * @since 4.4.0 * * @param string $route Route to get data for. * @param array $callbacks Callbacks to convert to data. * @param string $context Optional. Context for the data. Accepts 'view' or 'help'. Default 'view'. * @return array|null Data for the route, or null if no publicly-visible data. */ public function get_data_for_route( $route, $callbacks, $context = 'view' ) { $data = array( 'namespace' => '', 'methods' => array(), 'endpoints' => array(), ); $allow_batch = false; if ( isset( $this->route_options[ $route ] ) ) { $options = $this->route_options[ $route ]; if ( isset( $options['namespace'] ) ) { $data['namespace'] = $options['namespace']; } $allow_batch = $options['allow_batch'] ?? false; if ( isset( $options['schema'] ) && 'help' === $context ) { $data['schema'] = call_user_func( $options['schema'] ); } } $allowed_schema_keywords = array_flip( wp_get_json_schema_allowed_keywords( 'rest-api' ) ); $route = preg_replace( '#\(\?P<(\w+?)>.*?\)#', '{$1}', $route ); foreach ( $callbacks as $callback ) { // Skip to the next route if any callback is hidden. if ( empty( $callback['show_in_index'] ) ) { continue; } $data['methods'] = array_merge( $data['methods'], array_keys( $callback['methods'] ) ); $endpoint_data = array( 'methods' => array_keys( $callback['methods'] ), ); $callback_batch = $callback['allow_batch'] ?? $allow_batch; if ( $callback_batch ) { $endpoint_data['allow_batch'] = $callback_batch; } if ( isset( $callback['args'] ) ) { $endpoint_data['args'] = array(); foreach ( $callback['args'] as $key => $opts ) { if ( is_string( $opts ) ) { $opts = array( $opts => 0 ); } elseif ( ! is_array( $opts ) ) { $opts = array(); } $arg_data = array_intersect_key( $opts, $allowed_schema_keywords ); $arg_data['required'] = ! empty( $opts['required'] ); $endpoint_data['args'][ $key ] = $arg_data; } } $data['endpoints'][] = $endpoint_data; // For non-variable routes, generate links. if ( ! str_contains( $route, '{' ) ) { $data['_links'] = array( 'self' => array( array( 'href' => rest_url( $route ), ), ), ); } } if ( empty( $data['methods'] ) ) { // No methods supported, hide the route. return null; } return $data; } /** * Gets the maximum number of requests that can be included in a batch. * * @since 5.6.0 * * @return int The maximum requests. */ protected function get_max_batch_size() { /** * Filters the maximum number of REST API requests that can be included in a batch. * * @since 5.6.0 * * @param int $max_size The maximum size. */ return apply_filters( 'rest_get_max_batch_size', 25 ); } /** * Serves the batch/v1 request. * * @since 5.6.0 * * @param WP_REST_Request $batch_request The batch request object. * @return WP_REST_Response The generated response object. */ public function serve_batch_request_v1( WP_REST_Request $batch_request ) { $requests = array(); foreach ( $batch_request['requests'] as $args ) { $parsed_url = wp_parse_url( $args['path'] ); if ( false === $parsed_url ) { $requests[] = new WP_Error( 'parse_path_failed', __( 'Could not parse the path.' ), array( 'status' => 400 ) ); continue; } $single_request = new WP_REST_Request( $args['method'] ?? 'POST', $parsed_url['path'] ); if ( ! empty( $parsed_url['query'] ) ) { $query_args = array(); wp_parse_str( $parsed_url['query'], $query_args ); $single_request->set_query_params( $query_args ); } if ( ! empty( $args['body'] ) ) { $single_request->set_body_params( $args['body'] ); } if ( ! empty( $args['headers'] ) ) { $single_request->set_headers( $args['headers'] ); } $requests[] = $single_request; } $matches = array(); $validation = array(); $has_error = false; foreach ( $requests as $single_request ) { if ( is_wp_error( $single_request ) ) { $has_error = true; $matches[] = $single_request; $validation[] = $single_request; continue; } $match = $this->match_request_to_handler( $single_request ); $matches[] = $match; $error = null; if ( is_wp_error( $match ) ) { $error = $match; } if ( ! $error ) { list( $route, $handler ) = $match; if ( isset( $handler['allow_batch'] ) ) { $allow_batch = $handler['allow_batch']; } else { $route_options = $this->get_route_options( $route ); $allow_batch = $route_options['allow_batch'] ?? false; } if ( ! is_array( $allow_batch ) || empty( $allow_batch['v1'] ) ) { $error = new WP_Error( 'rest_batch_not_allowed', __( 'The requested route does not support batch requests.' ), array( 'status' => 400 ) ); } } if ( ! $error ) { $check_required = $single_request->has_valid_params(); if ( is_wp_error( $check_required ) ) { $error = $check_required; } } if ( ! $error ) { $check_sanitized = $single_request->sanitize_params(); if ( is_wp_error( $check_sanitized ) ) { $error = $check_sanitized; } } if ( $error ) { $has_error = true; $validation[] = $error; } else { $validation[] = true; } } $responses = array(); if ( $has_error && 'require-all-validate' === $batch_request['validation'] ) { foreach ( $validation as $valid ) { if ( is_wp_error( $valid ) ) { $responses[] = $this->envelope_response( $this->error_to_response( $valid ), false )->get_data(); } else { $responses[] = null; } } return new WP_REST_Response( array( 'failed' => 'validation', 'responses' => $responses, ), WP_Http::MULTI_STATUS ); } foreach ( $requests as $i => $single_request ) { if ( is_wp_error( $single_request ) ) { $result = $this->error_to_response( $single_request ); $responses[] = $this->envelope_response( $result, false )->get_data(); continue; } $clean_request = clone $single_request; $clean_request->set_url_params( array() ); $clean_request->set_attributes( array() ); $clean_request->set_default_params( array() ); /** This filter is documented in wp-includes/rest-api/class-wp-rest-server.php */ $result = apply_filters( 'rest_pre_dispatch', null, $this, $clean_request ); if ( empty( $result ) ) { $match = $matches[ $i ]; $error = null; if ( is_wp_error( $validation[ $i ] ) ) { $error = $validation[ $i ]; } if ( is_wp_error( $match ) ) { $result = $this->error_to_response( $match ); } else { list( $route, $handler ) = $match; if ( ! $error && ! is_callable( $handler['callback'] ) ) { $error = new WP_Error( 'rest_invalid_handler', __( 'The handler for the route is invalid' ), array( 'status' => 500 ) ); } $result = $this->respond_to_request( $single_request, $route, $handler, $error ); } } /** This filter is documented in wp-includes/rest-api/class-wp-rest-server.php */ $result = apply_filters( 'rest_post_dispatch', rest_ensure_response( $result ), $this, $single_request ); $responses[] = $this->envelope_response( $result, false )->get_data(); } return new WP_REST_Response( array( 'responses' => $responses ), WP_Http::MULTI_STATUS ); } /** * Sends an HTTP status code. * * @since 4.4.0 * * @param int $code HTTP status. */ protected function set_status( $code ) { status_header( $code ); } /** * Sends an HTTP header. * * @since 4.4.0 * * @param string $key Header key. * @param string $value Header value. */ public function send_header( $key, $value ) { /* * Sanitize as per RFC2616 (Section 4.2): * * Any LWS that occurs between field-content MAY be replaced with a * single SP before interpreting the field value or forwarding the * message downstream. */ $value = preg_replace( '/\s+/', ' ', $value ); header( sprintf( '%s: %s', $key, $value ) ); } /** * Sends multiple HTTP headers. * * @since 4.4.0 * * @param array $headers Map of header name to header value. */ public function send_headers( $headers ) { foreach ( $headers as $key => $value ) { $this->send_header( $key, $value ); } } /** * Removes an HTTP header from the current response. * * @since 4.8.0 * * @param string $key Header key. */ public function remove_header( $key ) { header_remove( $key ); } /** * Retrieves the raw request entity (body). * * @since 4.4.0 * * @global string $HTTP_RAW_POST_DATA Raw post data. * * @return string Raw request data. */ public static function get_raw_data() { // phpcs:disable PHPCompatibility.Variables.RemovedPredefinedGlobalVariables.http_raw_post_dataDeprecatedRemoved global $HTTP_RAW_POST_DATA; // $HTTP_RAW_POST_DATA was deprecated in PHP 5.6 and removed in PHP 7.0. if ( ! isset( $HTTP_RAW_POST_DATA ) ) { $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' ); } return $HTTP_RAW_POST_DATA; // phpcs:enable } /** * Extracts headers from a PHP-style $_SERVER array. * * @since 4.4.0 * * @param array $server Associative array similar to `$_SERVER`. * @return array Headers extracted from the input. */ public function get_headers( $server ) { $headers = array(); // CONTENT_* headers are not prefixed with HTTP_. $additional = array( 'CONTENT_LENGTH' => true, 'CONTENT_MD5' => true, 'CONTENT_TYPE' => true, ); foreach ( $server as $key => $value ) { if ( str_starts_with( $key, 'HTTP_' ) ) { $headers[ substr( $key, 5 ) ] = $value; } elseif ( 'REDIRECT_HTTP_AUTHORIZATION' === $key && empty( $server['HTTP_AUTHORIZATION'] ) ) { /* * In some server configurations, the authorization header is passed in this alternate location. * Since it would not be passed in both places we do not check for both headers and resolve. */ $headers['AUTHORIZATION'] = $value; } elseif ( isset( $additional[ $key ] ) ) { $headers[ $key ] = $value; } } return $headers; } } Quantic Dream | ZIRAN Comunicación https://www.ziran.es Comunicación Estratégica Thu, 26 Feb 2026 20:23:11 +0000 es hourly 1 https://wordpress.org/?v=7.1 https://www.ziran.es/wp-content/uploads/2020/07/favicon.svg Quantic Dream | ZIRAN Comunicación https://www.ziran.es 32 32 SPELLCASTERS CHRONICLES COMIENZA SU EARLY ACCESS, YA DISPONIBLE EN STEAM https://www.ziran.es/nota_prensa/spellcasters-chronicles-comienza-su-early-access-ya-disponible-en-steam/ Thu, 26 Feb 2026 20:23:11 +0000 https://www.ziran.es/?post_type=nota_prensa&p=62766 Quantic Dream ha presentado el Early Access Vision Roadmap, detallando nuevos contenidos y las próximas fases de desarrollo definidas junto a la comunidad. PARÍS – 26 DE FEBRERO DE 2026 – Quantic Dream abre hoy un nuevo capítulo con el lanzamiento del Early Access de Spellcasters Chronicles en Steam, ya disponible para los jugadores de todo […]

La entrada SPELLCASTERS CHRONICLES COMIENZA SU EARLY ACCESS, YA DISPONIBLE EN STEAM apareció primero en ZIRAN Comunicación.]]>

Quantic Dream ha presentado el Early Access Vision Roadmap, detallando nuevos contenidos y las próximas fases de desarrollo definidas junto a la comunidad.

PARÍS – 26 DE FEBRERO DE 2026 – Quantic Dream abre hoy un nuevo capítulo con el lanzamiento del Early Access de Spellcasters Chronicles en Steam, ya disponible para los jugadores de todo el mundo. Spellcasters Chronicles es un juego gratuito de acción y estrategia por equipos 3v3, fundamentado en el combate aéreo y la construcción estratégica de mazos. Los jugadores deberán surcar el campo de batalla, lanzar hechizos devastadores e invocar poderosas criaturas y Titanes para cambiar el rumbo de los encuentros.

El Early Access del juego se presenta como un Workshop abierto, un espacio colaborativo donde se invita a los jugadores a dar forma activamente a la evolución del juego junto al equipo de desarrollo en una experiencia viva y en constante evolución, moldeada por la retroalimentación de la comunidad. A diferencia de las anteriores pruebas de la Beta Cerrada, centradas en el rendimiento y la estabilidad técnica, esta fase traslada el foco hacia la profundidad del gameplay, la iteración del equilibrio, los sistemas de progresión y el desarrollo de características a largo plazo.

Visualiza el trailer de lanzamiento del Early Access de Spellcasters Chronicles:
“Desde el primer momento, concebimos Spellcasters Chronicles como un juego que crece a través de la experimentación y la iteración”, declaró Gregorie Diaconu, Game Director en Quantic Dream. “Con el Early Access, abrimos el Workshop a todo el mundo. No se trata de una fase de lanzamiento tradicional; es un espacio de colaboración activa. Estamos yendo más allá de la validación técnica para adentrarnos en capas más profundas de diseño: refinar el equilibrio, ampliar las mecánicas y probar nuevas ideas en estrecho diálogo con nuestros jugadores. Vuestros comentarios no solo ajustarán cifras, sino que influirán en las prioridades, darán forma a nuevos contenidos y ayudarán a guiar la dirección de la propia Chronicle. Esta fase es solo el comienzo de un viaje mucho más largo que estamos deseando construir juntos.”
DANDO FORMA A LA CHRONICLE
Visualiza un mensaje del Game Director  de Spellcasters Chronicles:
Junto con el lanzamiento del Early Access, Quantic Dream presenta la hoja de ruta de acceso anticipado estructurada en fases de desarrollo evolutivas. A lo largo de estas fases, el estudio implementará progresivamente las características fundamentales de un juego vivo y en evolución, incluyendo EL chat de voz, una personalización ampliada, un modo competitivo renovado, la progresión de desbloqueo de los hechizos, las misiones diarias y las actualizaciones de la tienda.
Entre los primeros avances de lo que está por llegar se encuentran una nueva Arena conocida como Kamazad y la llegada de un nuevo Spellcaster, el Technomancer, cuyos detalles se revelarán en las próximas semanas. Esta hoja de ruta representa los objetivos actuales de desarrollo del estudio y se mantendrá flexible. Las prioridades y los plazos podrán ajustarse a medida que el equipo analice los comentarios de los jugadores e identifique nuevas oportunidades durante el Early Access.
INTRODUCCIÓN DEL COMMUNITY VOTE WORKSHOP
Además, el estudio introducirá un nuevo método para facilitar la involucración de los jugadores en el desarrollo del juego, el Community Vote, un sistema que estará disponible muy pronto en SpellcastersChronicles.com. Se pedirá regularmente a los jugadores que voten sobre diversos temas que ayudarán al equipo de desarrollo a dar forma a la experiencia y al meta del juego. Todos aquellos que participen en estas votaciones recibirán recompensas.
NUEVAS CARACTERÍSTICAS DEL EARLY ACCESS
Como parte del lanzamiento del Early Access, se implementarán nuevos contenidos y sistemas que ampliarán la base establecida durante las fases de Beta Cerrada:
  • Tutorial final y Co-op VS CPU – Una experiencia de iniciación refinada diseñada para ayudar a los nuevos jugadores a aprender los fundamentos del lanzamiento de hechizos, la invocación y el trabajo en equipo.
  • Chat de voz – Permite la comunicación directa entre la actividad dentro del juego y la comunidad.
  • Integración del SDK de Discord – Refuerza la conexión entre la actividad dentro del juego y la comunidad.
  • Sistema de desbloqueo de hechizos – Introduce mecánicas de progresión que permiten a los jugadores ampliar su libro de hechizos a lo largo del tiempo.
  • Tienda dentro del juego – Sienta las bases para la personalización cosmética y futuros contenidos de temporada.

El Early Access también ampliará el contenido jugable con:

  • Nuevos hechizos – Los jugadores pueden incluir en sus mazos Ice Ray, Poison Breath, Metamorphosis y Holy Arrow.
  • Dos nuevas invocaciones – La Siren y el Rhino Rider se unen al campo de batalla.
  • Un nuevo edificio – The Rocket Soldier Factory.

Para acceder al desglose completo de los nuevos contenidos, ajustes de equilibrio, corrección de errores, problemas conocidos y mejoras técnicas en curso que llegan con el Early Access, los jugadores pueden consultar las notas completas del parche disponibles en el sitio web oficial.

INTEGRACIÓN DEL DISCORD SOCIAL SDK

El Early Access también integra el Discord Social SDK directamente en Spellcasters Chronicles, permitiendo a los jugadores conectarse sin problemas con sus amigos de Discord dentro del juego. Las funciones incluyen invitaciones multiplataforma desde Discord al juego, listas de amigos unificadas, salas de voz y chats dentro del juego, cuentas vinculadas y mensajería directa entre Discord y las sesiones del juego. Esta integración está diseñada para reforzar las funcionalidades sociales del juego manteniendo a los jugadores totalmente inmersos en el mundo de Ashkenon.

DESARROLLO Y OPTIMIZACIÓN CONTINUOS

Quantic Dream continúa trabajando en mejoras de rendimiento y optimización del sistema a medida que avanza el desarrollo. A continuación, se detallan las especificaciones mínimas y recomendadas de PC actualizadas para el Early Access:

Requisitos mínimos del sistema

• CPU: Intel Core i5-10400 o AMD Ryzen 5 2600 o equivalente (6 núcleos / 12 hilos).
• GPU: NVIDIA GeForce GTX 1660 o RTX 2060, o Radeon RX 5600 o equivalente con al menos 6 GB de VRAM.
• Memoria/RAM: 16 GB de RAM.
• Almacenamiento: SSD NVMe.
• Sistema operativo: Windows 11.

Requisitos recomendados del sistema

• CPU: Intel Core i7-10700K o AMD Ryzen 7 2700 o equivalente (8 núcleos / 16 hilos).
• GPU: NVIDIA GeForce RTX 3070 o Radeon RX 9060 XT o equivalente con al menos 8 GB de VRAM.
• Memoria/RAM: 16 GB de RAM.
• Almacenamiento: SSD NVMe.
• Sistema operativo: Windows 11.

Visita la página de Steam y la web oficial:

SOBRE QUANTIC DREAM 
Quantic Dream es un estudio de desarrollo de videojuegos fundado en 1997 por David Cage, con sedes en París (Francia) y Montreal (Canadá). Las experiencias únicas ofrecidas por Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™ han conmovido a millones de jugadores en todo el mundo y han ganado más de 250 premios internacionales, contribuyendo significativamente al reconocimiento de la narrativa interactiva en los videojuegos.
Desde 2019, Quantic Dream es su propia editora, habiendo lanzado en PC los títulos de su catálogo histórico: Fahrenheit™ (Indigo Prophecy), Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™. En 2022, Quantic Dream se unió a NetEase Games para potenciar su visión creativa y acelerar el desarrollo de títulos que redefinen la experiencia interactiva para jugadores de todo el mundo.
En 2025, Quantic Dream anunció Spellcasters Chronicles, su primer título original multijugador y un audaz paso creativo hacia el género de acción y estrategia. Esto brinda al estudio la oportunidad de explorar nuevos territorios creativos manteniéndose fiel a su legado de innovación narrativa.
Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™ ©Sony Interactive Entertainment Europe. Desarrollados por Quantic Dream. Heavy Rain™ es una marca comercial de Quantic Dream. Beyond: Two Souls™ y Detroit: Become Human™ son marcas comerciales o marcas registradas de Sony Interactive Entertainment Europe. Todos los derechos reservados.
Spellcasters Chronicles © 2025 Quantic Dream. Desarrollado y publicado por Quantic Dream. Spellcasters Chronicles, Quantic Dream y los logotipos de Quantic Dream son marcas comerciales de Quantic Dream.

La entrada SPELLCASTERS CHRONICLES COMIENZA SU EARLY ACCESS, YA DISPONIBLE EN STEAM apareció primero en ZIRAN Comunicación.]]>
SPELLCASTERS CHRONICLES REABRE EL PORTAL A ASHKENON CON LA BETA CERRADA 2, YA DISPONIBLE EN STEAM https://www.ziran.es/nota_prensa/spellcasters-chronicles-reabre-el-portal-a-ashkenon-con-la-beta-cerrada-2-ya-disponible-en-steam/ Fri, 30 Jan 2026 19:58:49 +0000 https://www.ziran.es/?post_type=nota_prensa&p=62045 Esta Segunda Beta desbloquea nuevas posibilidades con nuevos hechizos e invocaciones, funcionalidades adicionales y otras mejoras. Además, incluye la primera nueva arena desde la presentación de Spellcasters Chronicles. PARIS — 29 DE ENERO DE 2026 — Quantic Dream se enorgullece de anunciar que la segunda Beta Cerrada de Spellcasters Chronicles ya está disponible en PC a través de […]

La entrada SPELLCASTERS CHRONICLES REABRE EL PORTAL A ASHKENON CON LA BETA CERRADA 2, YA DISPONIBLE EN STEAM apareció primero en ZIRAN Comunicación.]]>

Esta Segunda Beta desbloquea nuevas posibilidades con nuevos hechizos e invocaciones, funcionalidades adicionales y otras mejoras. Además, incluye la primera nueva arena desde la presentación de Spellcasters Chronicles.

PARIS — 29 DE ENERO DE 2026 — Quantic Dream se enorgullece de anunciar que la segunda Beta Cerrada de Spellcasters Chronicles ya está disponible en PC a través de Steam. Los servidores abrieron hoy a las 16:00 CET y permanecerán accesibles hasta el 2 de febrero a las 10:00 CET. Esta nueva fase se fundamenta en las opiniones que los jugadores brindaron durante la primera Beta Cerrada, celebrada en diciembre de 2025, e introduce nuevos contenidos, funcionalidades que mejoran la experiencia de uso, así como mejoras técnicas en el camino hacia el lanzamiento del Early Access, programado para el 26 de febrero de 2026.
«La Beta Cerrada 2 marca un nuevo e importante capítulo para Spellcasters Chronicles», afirmó Gregorie Diaconu, Director de Juego en Quantic Dream. «Abrir el primer portal a Ashkenon nos enseñó mucho, no solo sobre nuestros sistemas, sino sobre cómo los jugadores se mueven, experimentan y se expresan dentro del juego. Esta segunda beta trata de interiorizar esas lecciones e integrarlas en la experiencia, reforzando el rendimiento, refinando la jugabilidad y expandiendo el caos mágico con nuevos hechizos, invocaciones y las Costas Nórdicas de Valm. Estamos entusiasmados de invitar de nuevo a los jugadores y de seguir dando forma a este viaje juntos a medida que nos acercamos al Early Access».

Visualiza el trailer de la Segunda Beta Cerrada de Spellcasters Chronicles aquí:
NUEVAS CARACTERÍSTICAS DE SPELLCASTERS CHORNICLES EN LA BETA CERRADA 2
La Beta Cerrada 2 incorpora una serie de nuevas características, entre las que se incluyen:
  • Introducción al juego y tutorial: una nueva experiencia de iniciación diseñada para ayudar a los nuevos jugadores a aprender los conceptos básicos.
  • Chat de texto de equipo dentro del juego: para que los jugadores se puedan comunicar entre sí durante las partidas.
  • Sistema de reporte de jugadores: para ayudar a abordar comportamientos tóxicos o inapropiados.
  • Personalización de Spellcasters y Lifestones: para que los jugadores prueben las funciones de personalización disponibles para los Spellcasters y las Lifestones.
  • Versión temprana del sistema de clasificación.

 

En esta segunda fase de pruebas también se expande el contenido jugable con:

  • La Costa nórdica de Valm: una nueva arena de 5 carriles que cuenta con líneas de visión abiertas, condiciones ambientales extremas un diseño distintivo.
  • Seis nuevos hechizos: los jugadores pueden incluir en sus mazos Lluvia de fuego (Fire Rain), Granada de veneno (Poison Grenade), Infusión de hielo (Ice Infusion), Infusión de fuego (Fire Infusion), Sacrificio (Sacrifice) y Resurrección ( Resurrection).
  • Cinco nuevas invocaciones: los jugadores pueden incluir en sus mazos a Stone Behemoth, Lich, Faery, Steam Tank y a Wolven Hunter.
  • Tres nuevos edificios: los jugadores pueden incluir en sus mazos el Nido de Arpías (Harpy’s Nest), el Baluarte (Rampart) y la Balista (Ballista).

Para obtener un desglose completo de los nuevos contenidos, los ajustes de equilibrio, las correcciones de errores, los problemas conocidos y las mejoras técnicas que llegan con la Beta Cerrada 2, los jugadores pueden consultar las notas del parche completas, disponibles junto con el lanzamiento de esta fase de pruebas.

Consulta las notas del parche de la Segunda Beta Cerrada aquí:
DESATA EL CAOS MÁGICO EN UNA NUEVA ARENA JUGABLE: LA COSTA NÓRDICA DE VALM
Visualiza el trailer de la nueva arena, la Costa nórdica:
La Beta Cerrada 2 introduce la Costa nórdica de Valm, la segunda arena jugable desde la presentación de Spellcasters Chronicles. Ambientada en una costa escarpada marcada por un antiguo enfrentamiento entre las fuerzas de Valmide y criaturas de los reinos exteriores, la Costa nórdica se extiende sobre los restos de una guerra olvidada: desde barcos destrozados y armas colosales hasta los restos de bestias abisales esparcidos por los acantilados.
Construida en torno a un diseño único de cinco carriles, la arena favorece los enfrentamientos a ras de suelo, mientras que cuevas serpenteantes, senderos estrechos y rutas costeras ofrecen múltiples oportunidades para flanqueos, retiradas y emboscadas.
CONSTRUYENDO UN CAMPO DE BATALLA MÁS FLUIDO PARA EL SEGUNDO FIN DE SEMANA DE LA BETA CERRADA
Además, esta segunda fase de la beta hace énfasis en el rendimiento, el uso de la memoria y la estabilidad general del juego, al tiempo que amplía la disponibilidad de los servidores con la incorporación de Asia junto a los ya existentes de Europa y Norteamérica. Como resultado de estas optimizaciones y mejoras de infraestructura, los requisitos del sistema también se han actualizado para la Beta Cerrada 2 con el fin de ofrecer una experiencia más fluida en una gama más amplia de configuraciones de hardware:
Requisitos mínimos del sistema
CPU: Intel Core i5-10400 o AMD Ryzen 5 2600 o equivalente (6 núcleos / 12 hilos).
GPU: NVIDIA GeForce RTX 2070 o Radeon RX 5700 o equivalente con al menos 8 GB de VRAM.
Memoria/RAM: 16 GB de RAM.
Almacenamiento: SSD NVMe.
Sistema operativo: Windows 11.
Requisitos del sistema recomendados
CPU: Intel Core i7-10700K o AMD Ryzen 7 2700 o equivalente (8 núcleos / 16 hilos).
GPU: NVIDIA GeForce RTX 3070 o Radeon RX 9060 XT o equivalente con al menos 10 GB de VRAM.
Memoria/RAM: 16 GB de RAM.
Almacenamiento: SSD NVMe.
Sistema operativo: Windows 11.
Los jugadores que deseen unirse a la Beta Cerrada pueden registrarse directamente a través de la página de Steam de Spellcasters Chronicles o mediante el sitio web oficial durante el fin de semana. El soporte técnico estará disponible durante toda la prueba en el servidor oficial de Discord del juego, donde los jugadores también podrán obtener directamente claves para la Beta Cerrada a través de funciones comunitarias dedicadas.
El Acceso Anticipado de Spellcasters Chronicles comenzará el 26 de febrero de 2026, con nuevos contenidos que incluyen nuevos hechizos, nuevas invocaciones y más.
Las Ediciones de Fundador, que incluyen una clave para la Beta Cerrada, títulos, estandartes y aspectos de personaje exclusivos, están disponibles en la página de Steam de Spellcasters Chronicles; se desbloquearán permanentemente en el Acceso Anticipado y estarán disponibles temporalmente durante la Beta Cerrada II.
Los jugadores pueden encontrar más información en SpellcastersChronicles.com/founder y a continuación:
Paquete de Arquitecto – Enlace
Paquete de Pionero – Enlace
Paquete de Fundador – Enlace
Paquete de Explorador – Enlace

SOBRE QUANTIC DREAM
Quantic Dream es un estudio de desarrollo de videojuegos fundado en 1997 por David Cage, con sedes en París (Francia) y Montreal (Canadá). Las experiencias únicas ofrecidas por Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™ han conmovido a millones de jugadores en todo el mundo y han ganado más de 250 premios internacionales, contribuyendo significativamente al reconocimiento de la narrativa interactiva en los videojuegos.
Desde 2019, Quantic Dream es su propia editora, habiendo lanzado en PC los títulos de su catálogo histórico: Fahrenheit™ (Indigo Prophecy), Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™. En 2022, Quantic Dream se unió a NetEase Games para potenciar su visión creativa y acelerar el desarrollo de títulos que redefinen la experiencia interactiva para jugadores de todo el mundo.
En 2025, Quantic Dream anunció Spellcasters Chronicles, su primer título original multijugador y un audaz paso creativo hacia el género de acción y estrategia. Esto brinda al estudio la oportunidad de explorar nuevos territorios creativos manteniéndose fiel a su legado de innovación narrativa.
Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™ ©Sony Interactive Entertainment Europe. Desarrollados por Quantic Dream. Heavy Rain™ es una marca comercial de Quantic Dream. Beyond: Two Souls™ y Detroit: Become Human™ son marcas comerciales o marcas registradas de Sony Interactive Entertainment Europe. Todos los derechos reservados.
Spellcasters Chronicles © 2025 Quantic Dream. Desarrollado y publicado por Quantic Dream. Spellcasters Chronicles, Quantic Dream y los logotipos de Quantic Dream son marcas comerciales de Quantic Dream.

 

La entrada SPELLCASTERS CHRONICLES REABRE EL PORTAL A ASHKENON CON LA BETA CERRADA 2, YA DISPONIBLE EN STEAM apareció primero en ZIRAN Comunicación.]]>
QUANTIC DREAM anuncia la segunda BETA de Spellcasters Chronicles y revela la fehca de inicio de la fase Early Access del juego https://www.ziran.es/nota_prensa/quantic-dream-announces-the-second-beta-of-spellcasters-chronicles-and-reveals-the-early-access-start-date-of-the-game/ Fri, 23 Jan 2026 09:46:50 +0000 https://www.ziran.es/?post_type=nota_prensa&p=61884 Descubre a Ozdam Devam, el Chronicler of Ashkenon, en el nuevo vídeo teaser. El Founders Pack ya está disponible en Steam, en el que se incluyen objetos cosméticos exclusivos así como acceso a la segunda Beta Cerrada, que dará comienzo el 29 de enero de 2026. PARÍS — 22 DE ENERO DE 2026 — Quantic Dream […]

La entrada QUANTIC DREAM anuncia la segunda BETA de Spellcasters Chronicles y revela la fehca de inicio de la fase Early Access del juego apareció primero en ZIRAN Comunicación.]]>

Descubre a Ozdam Devam, el Chronicler of Ashkenon, en el nuevo vídeo teaser.

El Founders Pack ya está disponible en Steam, en el que se incluyen objetos cosméticos exclusivos así como acceso a la segunda Beta Cerrada, que dará comienzo el 29 de enero de 2026.

PARÍS — 22 DE ENERO DE 2026 — Quantic Dream ha anunciado hoy la segunda Beta Cerrada de Spellcasters Chronicles, que comenzará el 29 de enero a las 16:00 CET y permanecerá accesible hasta el 2 de febrero a las 10:00 CET, así como el lanzamiento del Early Access del juego, que llegará el 26 de febrero de 2026. Este anuncio marca el inicio de la próxima fase de desarrollo del juego, en el que se están teniendo en cuenta las opiniones y sugerencias de la comunidad recopiladas durante las pruebas públicas inaugurales, realizadas en diciembre de 2025.

Ozdam Devam, el Chronicler de Ashkenon:  https://youtu.be/-MuC1YR8wzM

Para destacar el comienzo de esta nueva fase, Quantic Dream ha presentado un nuevo personaje no jugable: Ozdam Devam, conocido como el Chronicler de Ashkenon. Apasionado historiador del Tapestry y experto en el funcionamiento de la Source, se alza sobre los interminables conflictos de Ashkenon, registrando el auge y la caída de los imperios. Como misterioso narrador dentro de este mundo, Ozdam Devam actúa como intermediario entre la comunidad de Spellcasters y el mundo de los mortales, guiando a todos aquellos que están destinados a cambiar el futuro de Ashkenon.

SEGUNDA BETA CERRADA DE SPELLCASTERS CHRONICLES

Esta segunda Beta Cerrada incluirá una selección de nuevos contenidos y mejoras técnicas. Entre todos los contenidos añadidos, los jugadores podrán descubrir:

  • The Nordic Shore: una nueva arena de 5 carriles que presenta líneas de visión abiertas, condiciones ambientales extremas y un diseño único.
  • Introducción y tutorial del juego: una nueva introducción y un tutorial jugable para ayudar a los nuevos jugadores a aprender los conceptos básicos.
  • Chat de texto para el equipo: para que los jugadores se puedan comunicar directamente durante las partidas.
  • Sistema de reporte de jugadores: para ayudar a combatir el comportamiento tóxico o inapropiado.
  • Personalización de Spellcasters y Lifestones: para que los jugadores prueben las funciones de personalización disponibles para los personajes y las bases.
  • Versión temprana del sistema de Ranking.
  • Seis nuevos Spells: los jugadores podrán incluir en sus mazos Fire Rain, Poison Grenade, Ice Infusion, Fire Infusion, Sacrifice y Resurrection.
  • Cinco nuevas Summons: los jugadores podrán incluir en sus mazos a Stone Behemont, Lich, Faery, Steam Tank y Wolven Hunter.
  • Tres nuevos Buildings: los jugadores podrán incluir en sus mazos el Harpy’s Nest, el Rampart y la Ballista.
Además, estarán disponibles nuevos objetos de batalla junto con una gran variedad de actualizaciones de equilibrio que afectan a los Spellcasters, a las invocaciones, a los hechizos y a las reglas básicas del juego. Para consultar todos los detalles acerca de estos cambios los usuarios interesados pueden leer las notas oficiales sobre el parche en Discord y Steam.
OPTIMIZACIÓN Y MEJORAS DE RENDIMIENTO PARA LA SEGUNDA BETA CERRADA

Watch the Developer Update for Closed Beta 2 here: https://youtu.be/pTXdcnQYfAs

La segunda beta también añadirá una serie de optimizaciones con el objetivo de mejorar el rendimiento, el uso de la memoria y la estabilidad gráfica en general, proporcionando una experiencia más fluida en un espectro de configuraciones de hardware mayor. Como resultado, los requisitos del sistema han sido actualizados para la segunda Beta Cerrada. Los jugadores pueden consultar los requisitos mínimos y recomendados a continuación:
Requisitos del sistema mínimos:
  • CPU: Intel Core i5-10400 o AMD Ryzen 5 2600 o equivalente (6 núcleos / 12 hilos).
  • GPU: NVIDIA GeForce RTX 2070 o Radeon RX 5700 o equivalente con al menos 8 GB de VRAM
  • Memoria/RAM: 16 GB de RAM.
  • Disco duro: SSD NVMe
  • Sistema operativo: Windows 11
Requisitos del sistema recomendados:
  • CPU: Intel Core i7-10700K o AMD Ryzen 7 2700 o equivalente (8 núcleos / 16 hilos).
  • GPU: NVIDIA RTX 3070 o Radeon RX 9060 XT o equivalente con al menos 10 GB de VRAM
  • Memoria/RAM: 16 GB de RAM.
  • Disco duro: SSD NVMe
  • Sistema operativo: Windows 11
Además, para ofrecer soporte a la creciente base global de jugadores, la segunda Beta Cerrada expandirá la disponibilidad de servidores más allá de las áreas cubiertas durante el primer test. Sumándose a Europa y América del Norte, la segunda beta cerrada añadirá servidores regionales en Asia, mejorando la calidad del matchmaking, la estabilidad de las conexiones y la latencia para los jugadores de dicha región.
LOS FOUNDER’S PACK YA ESTÁN DISPONIBLES EN STEAM
Como parte de esta actualización, Quantic Dream también ha lanzado una serie de Founder’s Pack exclusivos en Steam, que incluyen lotes de cosméticos opcionales para aquellos jugadores que deseen personalizar sus Spellcasters desde el principio y disfrutar del acceso a la segunda Beta Cerrada. Cada tier ofrece niveles crecientes de cosméticos Founder y objetos prestigiosos que permitirán a los jugadores expresar su identidad en el mundo de Ashkenon.
Todos los packs incluyen una clave para la Beta Cerrada, títulos, banners y aspectos exclusivos para los personajes que permanecerán desbloqueados de forma permanente desde el Early Access, el 26 de febrero de 2026, así como disponibles de manera temporal durante la segunda Beta Cerrada:
  • Explorer Pack – 8.99€
    • 1 clave para la segunda Beta Cerrada
    • Founder Skins exclusiva para Swamp Witch
    • Founder Skins exclusiva para el catalyst de Swamp Witch
    • Título “Explorer of Ashkenon”
    • Founder Banner: “Witch”
    • Banner border: “Explorer”
  • Founder Pack – $19.99
    • 1 clave para la segunda Beta Cerrada
    • 2,400 Elder Gold, que se puede usar para adquirir más cosméticos in-game a partir del Early Access
    • Founder Skins exclusivas para Swamp Witch y Iron Sorcerer
    • Founder Skins exclusivas para los catalyst de Swamp Witch y Iron Sorcerer.
    • Títulos: “Explorer of Ashkenon,” “Founder of Ashkenon”
    • Founder banners: “Witch,” “Sorcerer”
    • Banner borders: “Explorer,” “Founder,”
  • Pioneer Pack – $39.99
    • 1 clave para la segunda Beta Cerrada
    • 4,820 Elder Gold, que se puede usar para adquirir más cosméticos in-game a partir del Early Access
    • Founder Skins exclusivas para Swamp Witch, Iron Sorcerer, Mystic Scribe y Fire Elementalist.
    • Founder Skins exclusivas para los catalyst de Swamp Witch, Iron Sorcerer, Mystic Scribe y Fire Elementalist catalysts.
    • Títulos: “Pioneer of Ashkenon,” “Explorer of Ashkenon,” “Founder of Ashkenon”
    • Founder banners: “Swamp Witch,” “Iron Sorcerer,” “Mystic Scribe,” and “Fire Elementalist.”
    • Banner borders: “Explorer”, “Founder”, “Pioneer”
  • Architect Pack – $69.99
    • 1 clave para la segunda Beta Cerrada
    • 8,700 Elder Gold, que se puede usar para adquirir más cosméticos in-game a partir del Early Access
    • Founder Skins exclusivas para Swamp Witch, Iron Sorcerer, Mystic Scribe, Fire Elementalist, Stone Shaman y Astral Monk.
    • Founder Skins exclusivas para los catalyst de Swamp Witch, Iron Sorcerer, Mystic Scribe, Fire Elementalist, Stone Shaman y Astral Monk.
    • Lifestone “Founder” Skin exclusiva.
    • Títulos: “Architect of Ashkenon,” “Pioneer of Ashkenon,” “Explorer of Ashkenon,” “Founder of Ashkenon”.
    • Founder banners: “Swamp Witch,” “Iron Sorcerer,” “Mystic Scribe,” “Fire Elementalist,” “Stone Shaman” and “Astral Monk”.
    • Banner borders: “Explorer,” “Founder,” “Pioneer,” “Architect”
    • Tu apodo en el juego quedará entretejido en el Tapestry, un lugar de honor dentro del lore del juego.
    • Un libro de arte digital de 78 páginas que incluye arte conceptual y comentarios del director de arte.

Para más información, se puede visitar SpellcastersChronicles.com/founder y:

  • Architect Pack – Link
  • Pioneer Pack – Link
  • Founder’s Pack – Link
  • Explorer Pack – Link

El Early Access de Spellcasters Chronicles comenzará el 26 de febrero de 2026 con nuevos contenidos, entre los que se incluirán nuevos hechizos, invocaciones y más.

Los usuarios interesados pueden visitar la web oficial aquí:

También pueden seguir las redes de Spellcasters Chronicles:

 


SOBRE QUANTIC DREAM
Quantic Dream es un estudio de desarrollo de videojuegos fundado en 1997 por David Cage, con sedes en París (Francia) y Montreal (Canadá). Las experiencias únicas ofrecidas por Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™ han conmovido a millones de jugadores en todo el mundo y han ganado más de 250 premios internacionales, contribuyendo significativamente al reconocimiento de la narrativa interactiva en los videojuegos.
Desde 2019, Quantic Dream es su propia editora, habiendo lanzado en PC los títulos de su catálogo histórico: Fahrenheit™ (Indigo Prophecy), Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™. En 2022, Quantic Dream se unió a NetEase Games para potenciar su visión creativa y acelerar el desarrollo de títulos que redefinen la experiencia interactiva para jugadores de todo el mundo.
En 2025, Quantic Dream anunció Spellcasters Chronicles, su primer título original multijugador y un audaz paso creativo hacia el género de acción y estrategia. Esto brinda al estudio la oportunidad de explorar nuevos territorios creativos manteniéndose fiel a su legado de innovación narrativa.
Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™ ©Sony Interactive Entertainment Europe. Desarrollados por Quantic Dream. Heavy Rain™ es una marca comercial de Quantic Dream. Beyond: Two Souls™ y Detroit: Become Human™ son marcas comerciales o marcas registradas de Sony Interactive Entertainment Europe. Todos los derechos reservados.
Spellcasters Chronicles © 2025 Quantic Dream. Desarrollado y publicado por Quantic Dream. Spellcasters Chronicles, Quantic Dream y los logotipos de Quantic Dream son marcas comerciales de Quantic Dream.
La entrada QUANTIC DREAM anuncia la segunda BETA de Spellcasters Chronicles y revela la fehca de inicio de la fase Early Access del juego apareció primero en ZIRAN Comunicación.]]>
SPELLCASTERS CHRONICLES COMENZARÁ SU PRIMER FIN DE SEMANA DE BETA CERRADA EL 4 DE DICIEMBRE DE 2025 https://www.ziran.es/nota_prensa/spellcasters-chronicles-comenzara-su-primer-fin-de-semana-de-beta-cerrada-el-4-de-diciembre-de-2025/ Mon, 01 Dec 2025 10:47:25 +0000 https://www.ziran.es/?post_type=nota_prensa&p=60602 La primera beta global jugable incluirá seis Spellcasters, la arena Mausoleum y las mecánicas de construcción de mazos mostradas en el debut del juego. PARÍS – 25 DE NOVIEMBRE DE 2025 – Quantic Dream ha anunciado hoy el primer Fin de Semana de Beta Cerrada de Spellcasters Chronicles, que comenzará el 4 de diciembre a […]

La entrada SPELLCASTERS CHRONICLES COMENZARÁ SU PRIMER FIN DE SEMANA DE BETA CERRADA EL 4 DE DICIEMBRE DE 2025 apareció primero en ZIRAN Comunicación.]]>
La primera beta global jugable incluirá seis Spellcasters, la arena Mausoleum y las mecánicas de construcción de mazos mostradas en el debut del juego.

PARÍS – 25 DE NOVIEMBRE DE 2025 – Quantic Dream ha anunciado hoy el primer Fin de Semana de Beta Cerrada de Spellcasters Chronicles, que comenzará el 4 de diciembre a las 16:00 CET y finalizará el 8 de diciembre a las 10:00 CET. Supone la primera oportunidad para que los jugadores de Europa y Norteamérica puedan probar en línea el primer juego multijugador, por equipos y gratuito del estudio. La Beta Cerrada tendrá lugar en Steam, con acceso concedido a los jugadores que se registren y sean seleccionados para unirse a esta primera fase de pruebas.

Tras la demo presentada en TwitchCon San Diego a principios de este año, esta Beta Cerrada trae una experiencia de juego ampliada, que incluye seis Spellcasters jugables, la arena Mausoleum y acceso a una primera selección de hechizos y criaturas para experimentar con el sistema de construcción de mazos. Con 11 criaturas, 8 conjuros y 2 titanes disponibles durante esta fase inicial, los jugadores podrán crear y poner a prueba estrategias únicas mientras exploran la experiencia de juego central de Spellcasters Chronicles.
Cada Spellcaster encarna un arquetipo distinto, definido por la forma en que interactúa con el sistema de construcción de mazos y modifica el flujo del combate. Estos arquetipos garantizan que cada composición de mazo resulte significativa, y que sus fortalezas pasivas guíen de forma natural a los jugadores hacia ciertos hechizos, criaturas y combinaciones de construcción, permitiendo que cada mazo exprese la identidad del Spellcaster elegido:
  • La Swamp Witch destaca gracias a sus mazos de enjambre basados en invocaciones sacrificables y que escalan en la fase final de la partida.
  • El Astral Monk prospera con daño explosivo y hechizos ofensivos.
  • El Iron Sorcerer es ideal para mazos centrados en estructuras que enfatizan el control de carriles y ejércitos duraderos.
  • El Fire Elementalist impulsa un estilo de juego agresivo, mazos de fuego de ciclo rápido y funciona mejor en manos de jugadores móviles.
  • El Mystic Scribe destaca en mazos de apoyo orientados a la supervivencia.
  • El Stone Shaman brilla en mazos de control defensivo que refuerzan los carriles y mantienen la posición.
Esta Beta Cerrada ayudará al estudio a refinar el juego a través de los comentarios de los jugadores. Una segunda Beta Cerrada, con más contenido, nuevos Spellcasters, arenas, encantamientos e invocaciones, tendrá lugar a principios del año que viene siguiendo el camino de Spellcasters Chronicles hacia su Early Access. Cada nueva fase incluirá nuevas características de la jugabilidad y desvelará más información acerca del universo y la narrativa, guiada por la comunidad, de Spellcasters Chronicles.
“Hemos construido Spellcasters Chronicles como un juego que prospera con la adaptación, la creatividad y la sinergia de equipo, y que solo cobra vida de verdad cuando los jugadores lo tienen entre manos”, dijo Gregorie Diaconu, Director del Juego de Spellcasters Chronicles. “Abrir los servidores por primera vez es un momento tan emocionante para el equipo. Es el inicio de un diálogo que llevamos tiempo deseando comenzar; queremos escuchar, iterar rápidamente y dar forma a la experiencia junto con nuestros jugadores. Spellcasters Chronicles representa un paso creativo audaz para el estudio, y esta fase de pruebas marca el comienzo de ese viaje compartido. Este primer fin de semana de Beta Cerrada es el capítulo inicial donde vuestros comentarios influirán directamente en el juego, desde el ritmo del combate y la estabilidad técnica del juego hasta el equilibrio de construcción de mazos y más allá. Invitamos a los jugadores a experimentar, sorprendernos y contarnos qué se siente correcto.”
Los jugadores que quieran unirse a la Beta Cerrada pueden registrarse directamente a través de la página de Steam de Spellcasters Chronicles o mediante el sitio web oficial. Si no reciben acceso para esta primera sesión, seguirán siendo elegibles para beta siguiente.
Para garantizar una experiencia óptima durante esta primera fase de prueba, se detallan a continuación las especificaciones mínimas y recomendadas de PC:
Requisitos mínimos del sistema
  • CPU: Intel Core i5-11400 o AMD Ryzen 5 5500 o equivalente (6 núcleos / 12 hilos).
  • GPU: NVIDIA GeForce RTX 2070 o Radeon RX 5700 o equivalente con al menos 8 GB de VRAM.
  • Memoria/RAM: 32 GB de RAM.
  • Almacenamiento: SSD NVMe
  • Sistema operativo: Windows 11
Requisitos recomendados del sistema
  • CPU: Intel Core i7-11700K o AMD Ryzen 7 3700X o equivalente (8 núcleos / 16 hilos).
  • NVIDIA GeForce RTX 3070 o Radeon RX 9060 XT o equivalente con al menos 10 GB de VRAM.
  • Memoria/RAM: 32 GB de RAM.
  • Almacenamiento: SSD NVMe
  • Sistema operativo: Windows 11
——

 

Los usuarios interesados pueden visitar la web oficial aquí:
También pueden seguir las redes de Spellcasters Chronicles:
Quantic Dream también puede encontrarse en:
X (Twitter): @Quantic_Dream
Instagram: SpellcastersGame
Twitch: quanticdream
Se puede visitar la tienda oficial en línea aquí: https://shop.quanticdream.com/ 
SOBRE QUANTIC DREAM 

Desde 2019, Quantic Dream autopublica sus títulos, llevando a nivel mundial su catálogo de clásicos para PC: Fahrenheit™ (Indigo Prophecy), Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™. En diciembre de 2021, el estudio anunció su colaboración con Lucasfilm para Star Wars Eclipse™, un juego de acción y aventuras AAA actualmente en desarrollo. En 2022, Quantic Dream se unió a NetEase Games para potenciar su visión creativa y acelerar el desarrollo de títulos destinados a redefinir la experiencia interactiva de los jugadores en todo el mundo.




En 2025, Quantic Dream anunció Spellcasters Chronicles, su primer título multijugador original y un audaz paso creativo hacia el género de acción y estrategia, que brinda al estudio la oportunidad de explorar nuevos territorios creativos manteniéndose fiel a su legado de innovación narrativa.




Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™ © Sony Interactive Entertainment Europe. Desarrollados por Quantic Dream. Heavy Rain™ es una marca comercial de Quantic Dream. Beyond: Two Souls™ y Detroit: Become Human™ son marcas comerciales o registradas de Sony Interactive Entertainment Europe. Todos los derechos reservados.


Spellcasters Chronicles © 2025 Quantic Dream. Desarrollado y publicado por Quantic Dream. Spellcasters Chronicles, Quantic Dream y los logotipos de Quantic Dream son marcas registradas de la compañía.


Lucasfilm, STAR WARS y las propiedades relacionadas son marcas comerciales y/o derechos de autor, en Estados Unidos y otros países, de Lucasfilm Ltd. y/o sus filiales.


La entrada SPELLCASTERS CHRONICLES COMENZARÁ SU PRIMER FIN DE SEMANA DE BETA CERRADA EL 4 DE DICIEMBRE DE 2025 apareció primero en ZIRAN Comunicación.]]>
QUANTIC DREAM PRESENTA SPELLCASTERS CHRONICLES, UN JUEGO BASADO EN EQUIPOS 3c3 DE ESTRATEGIA Y ACCIÓN QUE LANZARÁ SU BETA CERRADA ESTE AÑO https://www.ziran.es/nota_prensa/quantic-dream-presenta-spellcasters-chronicles-un-juego-basado-en-equipos-3c3-de-estrategia-y-accion-que-lanzara-su-beta-cerrada-este-ano/ Tue, 21 Oct 2025 15:32:40 +0000 https://www.ziran.es/?post_type=nota_prensa&p=59256 El juego será presentado en directo y podrá jugarse por primera vez el 17 de octubre de 2025, en el área LAN de TwitchCon San Diego, con conexiones en directo y entrevistas a los desarrolladores presentadas por TWITCH el mismo día a través de su canal oficial. PARIS & MONTREAL – 16 DE OCTUBRE DE […]

La entrada QUANTIC DREAM PRESENTA SPELLCASTERS CHRONICLES, UN JUEGO BASADO EN EQUIPOS 3c3 DE ESTRATEGIA Y ACCIÓN QUE LANZARÁ SU BETA CERRADA ESTE AÑO apareció primero en ZIRAN Comunicación.]]>
El juego será presentado en directo y podrá jugarse por primera vez el 17 de octubre de 2025, en el área LAN de TwitchCon San Diego, con conexiones en directo y entrevistas a los desarrolladores presentadas por TWITCH el mismo día a través de su canal oficial.

PARIS & MONTREAL – 16 DE OCTUBRE DE 2025 – Quantic Dream, el galardonado estudio responsable de Detroit: Become Human™, presenta Spellcasters Chronicles, su primer juego multijugador. Gratuito y por equipos, combina de forma única acción y estrategia, invitando a los jugadores a desatar el caos mágico en espectaculares batallas 3 contra 3. El juego debutará con una beta cerrada en PC (Steam) a finales de 2025.

Visualiza el tráiler de presentación aquí:
“Nos honra y entusiasma presentar hoy, a los amantes de los videojuegos, Spellcasters Chronicles, desarrollado en nuestros estudios de París y Montreal”, declaró David Cage, fundador y presidente de Quantic Dream. “Dar el salto a un nuevo género con un enfoque artístico renovado ha supuesto tanto un desafío como una fuente de crecimiento, que nos ha permitido evolucionar como equipo. Ahora, nos gustaría seguir dando forma al juego con los comentarios de los jugadores y perfeccionar así este viaje juntos.
Este proyecto refleja el espíritu creativo y las ambiciones técnicas que han guiado a Quantic Dream durante casi tres décadas. Con Spellcasters Chronicles, buscamos dar vida a una nueva forma de experiencia de juego que combine acción y estrategia, explorando al mismo tiempo una narrativa impulsada por la comunidad. Ha sido una exploración de ideas audaces, una oportunidad para expandirnos hacia experiencias sociales y multijugador, y una aventura compartida por un nuevo y talentoso equipo de expertos en nuestros estudios de París y Montreal, que ha dado vida a este universo original y que siguen desarrollando nuevas experiencias, entre las que se encuentran Star Wars Eclipse™”.
Con la primera beta cerrada prevista para finales de este año, el estudio invita con entusiasmo a los jugadores a participar en las pruebas iniciales, compartir sus impresiones y ayudar a definir la evolución del juego. Para acompañar este proceso, los jugadores ya pueden unirse al servidor oficial de Discord de Spellcasters Chronicles, un espacio dedicado al debate comunitario, y registrarse en la beta cerrada aquí:
UN COMBATE ÉPICO 3c3, CREADO CON VISIÓN Y PASIÓN
En una combinación única de acción en tercera persona y toma de decisiones estratégicas, Spellcasters Chronicles desafía a los jugadores a dominar tanto el movimiento como la magia para marcar el ritmo de la batalla. Cada partida se desarrolla en intensos enfrentamientos 3 contra 3 de 25 minutos, en arenas místicas de escala épica y gran verticalidad, donde los equipos deben capturar altares para ganar territorio y destruir las Lifestones de sus oponentes para alcanzar la victoria.
Los jugadores se adentrarán en el combate como Spellcasters, magos definidos por arquetipos con identidades, roles y habilidades distintivas, capaces de invocar hordas de criaturas y lanzar poderosos conjuros. Imbuido de magia, cada Spellcaster puede volar libremente durante el combate para dominar el campo de batalla, ofreciendo un nivel de libertad de movimiento pocas veces visto en el género.
FUSIONANDO TÁCTICA Y CREATIVIDAD A TRAVÉS DE TU LIBRO DE HECHIZOS
Spellcasters Chronicles destaca gracias a su sistema estratégico de construcción de mazos. Los jugadores, ya sea eligiendo un arquetipo de apoyo, de tanque o de atacante, podrán escoger entre más de 50 conjuros e invocaciones, aportando su creatividad y dotes tácticas a la arena. Además, deberán seleccionar una de las colosales invocaciones definitivas, los Titanes, criaturas descomunales capaces de cambiar el curso de la batalla.
Esta combinación de diseño basado en arquetipos y mazos personalizables convierte cada partida de Spellcasters Chronicles en un enfrentamiento estratégico que premia la experimentación y las sinergias con el resto de los integrantes del equipo.
LLEVANDO NUESTRA EXPERIENCIA NARRATIVA A UN NUEVO GÉNERO
Además de su núcleo competitivo, el juego incluirá un enfoque único a la hora de construir la historia dentro de una experiencia multijugador. Este componente narrativo comunitario se revelará en los próximos meses.
“Spellcasters Chronicles nació como un experimento creativo, una oportunidad para canalizar nuestra pasión por la narrativa dentro de un mundo compartido y vivo”, comenta Grégoire Diaconu, director del juego en Quantic Dream. “Aunque sea muy diferente a nuestros títulos anteriores, se basa en lo que siempre nos ha impulsado: dar a los jugadores el poder de moldear historias, esta vez de forma colectiva.
Tras años de desarrollo, estamos deseando compartir por fin el mundo de Spellcasters Chronicles con todos los jugadores. Iniciaremos nuestra fase de beta cerrada con el core loop centrado en las batallas de arena, e iremos incorporando la narrativa comunitaria y otros elementos de nuestro macro loop en los próximos meses. Éste es solo el comienzo del viaje, y tenemos muchas ganas de escuchar, aprender y crecer junto a la comunidad. Vuestros comentarios serán esenciales para dar forma y perfeccionar la experiencia, asegurando que el juego evolucione hacia algo verdaderamente especial, construido mano a mano con quienes lo jueguen”.
Los fans podrán descubrir más detalles a partir de mañana, 17 de octubre, durante la presentación especial en la que se sumergirán en la jugabilidad del título y podrán asistir a la presentación del equipo en directo desde el área LAN de la TwitchCon de San Diego, que será retransmitida globalmente desde el canal oficial de Twitch LAN de 20:30 del 17 de octubre a 3:30 del 18 de octubre CEST. Tanto los asistentes como los espectadores podrán ver el juego en acción por primera vez, con el caos mágico del campo de batalla y otros detalles exclusivos, así como con la oportunidad de conseguir una clave para acceder a la beta cerrada.
Durante la presentación, los espectadores podrán disfrutar de diferentes apartados:
  • Gameplay Deep Dive – Presentación en profundidad de las mecánicas principales de Spellcasters Chronicles.
  • Presentación del equipo – Perspectiva de los desarrolladores sobre la visión y el enfoque creativo del juego.
  • Sesión de preguntas y respuestas – Encuentro exclusivo con el equipo creativo, respondiendo preguntas de la comunidad y del público en directo.
  • Showmatches – Partidas competitivas en vivo con jugadores y creadores de contenido.
  • Revelación de cosplay – Presentación especial del Cosplayer oficial.
Los usuarios interesados pueden visitar la web oficial aquí:
También pueden seguir las redes de Spellcasters Chronicles:
Quantic Dream también puede encontrarse en:
X (Twitter): @Quantic_Dream
Instagram: SpellcastersGame
Twitch: quanticdream
Se puede visitar la tienda oficial en línea aquí: https://shop.quanticdream.com/ 
###
SOBRE QUANTIC DREAM 

Desde 2019, Quantic Dream autopublica sus títulos, llevando a nivel mundial su catálogo de clásicos para PC: Fahrenheit™ (Indigo Prophecy), Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™. En diciembre de 2021, el estudio anunció su colaboración con Lucasfilm para Star Wars Eclipse™, un juego de acción y aventuras AAA actualmente en desarrollo. En 2022, Quantic Dream se unió a NetEase Games para potenciar su visión creativa y acelerar el desarrollo de títulos destinados a redefinir la experiencia interactiva de los jugadores en todo el mundo.




En 2025, Quantic Dream anunció Spellcasters Chronicles, su primer título multijugador original y un audaz paso creativo hacia el género de acción y estrategia, que brinda al estudio la oportunidad de explorar nuevos territorios creativos manteniéndose fiel a su legado de innovación narrativa.




Heavy Rain™, Beyond: Two Souls™ y Detroit: Become Human™ © Sony Interactive Entertainment Europe. Desarrollados por Quantic Dream. Heavy Rain™ es una marca comercial de Quantic Dream. Beyond: Two Souls™ y Detroit: Become Human™ son marcas comerciales o registradas de Sony Interactive Entertainment Europe. Todos los derechos reservados.


Spellcasters Chronicles © 2025 Quantic Dream. Desarrollado y publicado por Quantic Dream. Spellcasters Chronicles, Quantic Dream y los logotipos de Quantic Dream son marcas registradas de la compañía.


Lucasfilm, STAR WARS y las propiedades relacionadas son marcas comerciales y/o derechos de autor, en Estados Unidos y otros países, de Lucasfilm Ltd. y/o sus filiales.

La entrada QUANTIC DREAM PRESENTA SPELLCASTERS CHRONICLES, UN JUEGO BASADO EN EQUIPOS 3c3 DE ESTRATEGIA Y ACCIÓN QUE LANZARÁ SU BETA CERRADA ESTE AÑO apareció primero en ZIRAN Comunicación.]]>
Under The Waves Celebra Sus Tres Meses De Vida Con Un Mensaje Del Director https://www.ziran.es/nota_prensa/under-the-waves-celebra-sus-tres-meses-de-vida-con-un-mensaje-del-director/ Mon, 04 Dec 2023 16:07:57 +0000 https://www.ziran.es/?post_type=nota_prensa&p=54191 Ya está disponible la última actualización del juego, que incluye un nuevo modo en el que se podrá controlar al león marino J0, así como mejoras en la interfaz y problemas menores solucionados La banda sonora de Under The Waves también se ha puesto a la venta en un innovador vinilo respetuoso con el medio […]

La entrada Under The Waves Celebra Sus Tres Meses De Vida Con Un Mensaje Del Director apareció primero en ZIRAN Comunicación.]]>
Ya está disponible la última actualización del juego, que incluye un nuevo modo en el que se podrá controlar al león marino J0, así como mejoras en la interfaz y problemas menores solucionados

La banda sonora de Under The Waves también se ha puesto a la venta en un innovador vinilo respetuoso con el medio ambiente que no contiene plásticos.

«Ha sido todo un viaje desde que se lanzó Under The Waves, el pasado 29 de agosto. No hemos tenido más que excelentes comentarios y reseñas, ¡y todo el equipo está más que agradecido! Siendo un estudio independiente de 19 personas, nos llevó casi 4 años dar vida a este juego, ¡y aquí estamos ahora!», dice Ronan Coiffec, director del juego y del estudio en Parallel Studio. «A nivel personal, me siento honrado, ya que este proyecto ha sido especialmente significativo. Necesitaba contar esta historia, que se remonta a mi infancia, pero también a lo que soy hoy y, realmente, he puesto todo mi corazón en ella. ¡Verlo en tus manos, saber que tiene un impacto en ti, es el regalo más increíble!».

El equipo ha mejorado la experiencia general en varios aspectos. Entre éstos, destaca la optimización de Under The Waves para Steam Deck y el soporte para Razer Chroma. Además, el último parche incluye nuevas opciones de accesibilidad deseadas por la comunidad:

  • Una nueva opción en la configuración gráfica para atenuar el Grano.
  • Una nueva opción en la configuración gráfica para desactivar la Aberración Cromática.
  • Una nueva opción en la configuración gráfica para desactivar el Letterboxing.
  • Una nueva opción en la configuración gráfica para desactivar la Suciedad en la Lente.
  • Soporte para pantallas anchas.

Se pueden consultar todos los detalles del parche en Steam: https://store.steampowered.com/news/app/1975440

Quantic Dream también se enorgullece de colaborar con Kid Katana Productions para llevar el mensaje ecológico del título más allá del medio de los videojuegos, lanzando la primera banda sonora de la historia de los videojuegos grabada en un vinilo libre de plásticos. Compuesta por Nicolas Bredin, la banda sonora de Under The Waves se erige como un reflejo fidedigno de la narrativa del juego, con influencias de compositores islandeses como Valgeir Sigurdsson y Ólafur Arnalds, además de bandas post-rock como Mogwai, Sigur Rós y Radiohead.

Para mantenerse fiel al mensaje ecológico presente en el juego y a la colaboración con Surfrider Foundation Europe, este vinilo OST será manufacturado en Alemania usando el nuevo proceso BioVynil, desarrollado por uno de los líderes europeos, Optimal Media.

El impacto ecológico de esta edición física se ha tenido muy en cuenta:

  • Una producción libre de plásticos, en la que todo el petróleo en S-PVC ha sido sustituido por aceite de cocina y gases residuales industriales reciclados. La certificación ISCC PLUS obtenida por el fabricante también garantiza una cadena de suministro sostenible.
  • Un packaging ecológico fabricado con papel y cartón 100% reciclado e impreso con tintas sostenibles elaboradas a partir de aceites vegetales.
  • Un diseño respetuoso con el medio ambiente, con Kid Katana Records estableciendo un enfoque minimalista en todo el diseño para ahorrar el uso de papel y tinta, sin folleto impreso, sin grandes superficies completas de color liso y solo 1 color utilizado.

 

 

Parallel Studio ha añadido el modo J0, un nuevo modo que permite controlar al león marino preferido de los fans en una parte dedicada del mapa. Con esta última incorporación, el equipo ha querido ofrecer a los amantes de la naturaleza y a los fotógrafos virtuales una nueva forma de experimentar el mundo de Under The Waves. Para acceder a este modo, los jugadores deberán teclear el código Morse «J0»: un punto, ocho rayas (pulsando brevemente el stick analógico derecho, seguido de ocho pulsaciones más largas).

Para saber más acerca de Under The Waves y los próximos lanzamientos de SPOTLIGHT by QUANTIC DREAM, los usuarios interesados pueden visitar QuanticDream.com y seguir los perfiles @Quantic_Dream y @FromParallel.

La entrada Under The Waves Celebra Sus Tres Meses De Vida Con Un Mensaje Del Director apareció primero en ZIRAN Comunicación.]]>
El Primer Parche De Under The Waves Llega A Consolas Y Pc https://www.ziran.es/nota_prensa/el-primer-parche-de-under-the-waves-llega-a-consolas-y-pc/ Mon, 11 Sep 2023 08:00:30 +0000 https://www.ziran.es/?post_type=nota_prensa&p=53683 El nuevo parche 1.02, que ya está disponible en Steam, Epic Games Store, PlayStation y Xbox, corrige numerosos errores visuales y problemas del juego. El parche 1.02 ya ha llegado a las consolas Xbox y PlayStation, tras haber aterrizado previamente en PC a través de Steam y Epic Games Store. El parche para consolas corrige […]

La entrada El Primer Parche De Under The Waves Llega A Consolas Y Pc apareció primero en ZIRAN Comunicación.]]>
El nuevo parche 1.02, que ya está disponible en Steam, Epic Games Store, PlayStation y Xbox, corrige numerosos errores visuales y problemas del juego.

El parche 1.02 ya ha llegado a las consolas Xbox y PlayStation, tras haber aterrizado previamente en PC a través de Steam y Epic Games Store. El parche para consolas corrige errores relacionados con la versión de consolas de Under The Waves, entre los que destacan:

  • En PS5
    • Se han corregido los problemas de tearing
  • En todas las consolas
    • Se ha arreglado el guardado de capturas realizadas con la Cámara
    • Se ha arreglado un error que permitía tener oxígeno ilimitado durante el día 14.
    • Se ha corregido un marcador de objetivo mal colocado durante el uso del taladro.
    • Se han corregido algunas interacciones que no se habilitaban después de terminar el juego (la cama y las medusas en la ventana).
    • Ahora se puede obtener el trofeo galeón.
    • Se ha arreglado la misión de los contenedores, que no se activaba tras reiniciar el juego durante el día 3.
    • Se ha arreglado un error que no permitía a Stan entrar en Moon durante la misión de los contenedores del día 3.
    • Se ha corregido un error que hacía que Moon quedase atrapado en un bucle de explosiones.
    • Se ha corregido un error que cerraba el juego al usar una mina en Transit Street.

Parallel Studio se centrará en corregir cualquier otro problema que pueda surgir, y seguirá actualizando el juego durante las próximas semanas para ofrecer la mejor experiencia posible a todos los jugadores.

Los jugadores que sufran algún fallo, pueden dirigirse a la página de soporte oficial para recibir asistencia: https://support.quanticdream.com/hc/en-us/categories/18545512054036-UNDER-THE-WAVES

 

La entrada El Primer Parche De Under The Waves Llega A Consolas Y Pc apareció primero en ZIRAN Comunicación.]]>
Under The Waves Lanza Su Primer Parche https://www.ziran.es/nota_prensa/under-the-waves-lanza-su-primer-parche/ Wed, 06 Sep 2023 15:27:12 +0000 https://www.ziran.es/?post_type=nota_prensa&p=53622 El nuevo parche 1.02, que ya está disponible en Steam y Epic Games Store, corrige numerosos errores visuales y problemas del juego. Pronto llegará a consolas. Parallel Studio ha puesto todo su corazón en el camino de Stan hacia la resiliencia y la preservación de los océanos. El estudio se muestra agradecido por las reacciones […]

La entrada Under The Waves Lanza Su Primer Parche apareció primero en ZIRAN Comunicación.]]>
El nuevo parche 1.02, que ya está disponible en Steam y Epic Games Store, corrige numerosos errores visuales y problemas del juego. Pronto llegará a consolas.

Parallel Studio ha puesto todo su corazón en el camino de Stan hacia la resiliencia y la preservación de los océanos. El estudio se muestra agradecido por las reacciones de todos los jugadores alrededor del mundo. Para mejorar la aventura, Parallel Studio ha estado trabajando en un nuevo parche, que tiene como cometido satisfacer las demandas de la comunidad y los medios.

En el parche 1.02, que ya está disponible en PC a través de Steam y Epic Games Store, destacan las siguientes mejoras:

  • Se han arreglado cortes abruptos de la música
  • Se ha arreglado un error que permitía tener oxígeno ilimitado durante el día 14.
  • Se ha corregido un marcador de objetivo mal colocado durante el uso del taladro.
  • Se han corregido algunas interacciones que no se habilitaban después de terminar el juego (la cama y las medusas en la ventana).
  • Ahora se puede obtener el trofeo galeón.
  • Se ha arreglado la misión de los contenedores, que no se activaba tras reiniciar el juego durante el día 3.
  • Se ha arreglado un error que no permitía a Stan entrar en Moon durante la misión de los contenedores del día 3.
  • Se ha corregido un error que hacía que Moon quedase atrapado en un bucle de explosiones.
  • Se ha corregido un error que cerraba el juego al usar una mina en Transit Street.

Este parche llegará a consolas pronto y resolverá los problemas previamente comentados, así como otros específicos de cada plataforma. Ente los fallos adicionales que serán solventados, se incluyen problemas de tearing en la pantalla, errores de guardado automático en PlayStation 5 y capturas de pantalla que no se guardan en Xbox Series X. Parallel Studio se centrará en corregir cualquier otro problema que pueda surgir, y seguirá actualizando el juego durante las próximas semanas para ofrecer la mejor experiencia posible a todos los jugadores.

 

La entrada Under The Waves Lanza Su Primer Parche apareció primero en ZIRAN Comunicación.]]>
Under The Waves, El Cuento Melancólico Imaginado Por Parallel Studio, Ya Está Disponible En Pc Y Consolas Playstation Y Xbox https://www.ziran.es/nota_prensa/under-the-waves-el-cuento-melancolico-imaginado-por-parallel-studio-ya-esta-disponible-en-pc-y-consolas-playstation-y-xbox/ Tue, 29 Aug 2023 14:22:52 +0000 https://www.ziran.es/?post_type=nota_prensa&p=53424 Esta aventura submarina sumerge a los jugadores en una historia poética sobre el absorbente poder del dolor. El juego también intenta concienciar sobre el impacto de los humanos en los océanos, a través de una colaboración única con Surfrider Foundation Europe.   París, Francia, 29 de agosto de 2023 – Quantic Dream y Parallel Studio […]

La entrada Under The Waves, El Cuento Melancólico Imaginado Por Parallel Studio, Ya Está Disponible En Pc Y Consolas Playstation Y Xbox apareció primero en ZIRAN Comunicación.]]>
  • Esta aventura submarina sumerge a los jugadores en una historia poética sobre el absorbente poder del dolor.
  • El juego también intenta concienciar sobre el impacto de los humanos en los océanos, a través de una colaboración única con Surfrider Foundation Europe.
  •  

    París, Francia, 29 de agosto de 2023 – Quantic Dream y Parallel Studio se enorgullecen de anunciar el lanzamiento de Under The Waves, la nueva aventura narrativa publicada por el sello SPOTLIGHT by QUANTIC DREAM, y disponible en PC, PlayStation 5, PlayStation 4, Xbox Series S|X y Xbox One.

    Ambientado en una versión alternativa y retrofuturista de 1979, Under The Waves se desarrolla en las profundidades del Mar del Norte y sigue la vida cotidiana de Stan, un buzo profesional que trabaja para una compañía petrolera llevando a cabo trabajos de mantenimiento. Escondido de su pasado, Stan encuentra la paz bajo el agua, lejos de la vida cotidiana, envuelto en la reconfortante monotonía del aislamiento. La confrontación con eventos extraños lo llevará lentamente a cuestionar su propia realidad.

    En un mundo semiabierto, Under The Waves revela su narrativa sutil y poética a través de las misiones diarias de Stan, ya sea a bordo de su submarino o en su traje autónomo. Los jugadores pueden explorar libremente las profundidades del mar, visitar naufragios y recolectar materiales para reciclar en el módulo de vida, para crear nuevos elementos que se utilizarán en las diversas misiones principales y secundarias.

    Ronan Coiffec, cofundador y director de juego de Parallel Studio, repasa los orígenes del proyecto:

    «Hace casi 20 años, sin saberlo, estaba creando los primeros esbozos de un proyecto que se convertiría en Under The Waves, a la luz de mi pequeña lámpara de noche en la escuela de arte. El fin de semana jugaba, maravillado, al juego que me hizo querer hacer lo que hago hoy: Omikron The Nomad Soul. Siento que he cumplido varios sueños a través de Under The Waves, trabajando en un juego significativo con un equipo talentoso, en colaboración con Surfrider Foundation Europe en particular, y trabajando con Quantic Dream.
    Estos 3 años de producción han sido increíbles y emocionalmente enriquecedores. Desde el nacimiento del proyecto, pasando por el período COVID, aislados en nuestros apartamentos, las reuniones remotas con el escritor / director de Quantic Dream, David Cage, para discutir nuestra narrativa, las reuniones con Surfrider para definir los mensajes clave de nuestra historia, hasta las fases de captura de movimiento, grabación de voz y ajustes de iluminación bajo el ojo experto de los equipos de Quantic Dream. Hemos experimentado y aprendido infinidad de aspectos que han nutrido este proyecto, que hoy es Under The Waves, un juego de aventura narrativa, fruto del duro trabajo de un equipo de desarrolladores independientes que estaban dispuestos a crear una experiencia original, significativa y atractiva. Esperamos que los jugadores se sientan conmovidos por la experiencia que hemos creado con pasión, generosidad y sinceridad».

    Detrás de la fuerza melancólica de la historia de Stan en su camino hacia la resiliencia, Under The Waves también abre una reflexión sobre el impacto de los humanos en el planeta y los seres vivos. Para apoyar su mensaje ecológico, sutilmente destilado a lo largo de la aventura, Parallel Studio ha trabajado con Surfrider Foundation Europe en varias etapas de desarrollo. Esta colaboración única tiene como objetivo transmitir un mensaje de esperanza a los jugadores sobre la conservación de los océanos, a través de mensajes contextuales, recursos visuales con los colores de la Fundación y trofeos / logros dedicados.

    «Después de más de un año de estrecha colaboración, estamos muy orgullosos de ver que Under The Waves llega a buen término», dijo Rémi Touja, director de marketing digital en Surfrider Foundation Europe. «Como ávido jugador, con un gran interés en contar historias, estaba encantado de participar en esta asociación, con el fin de transmitir los mensajes de la Surfrider Foundation Europe a una nueva audiencia. El juego nos brinda una oportunidad única de hablar sobre los problemas oceánicos de una manera completamente nueva, integrándolos sutil y naturalmente en la aventura de Stan y la jugabilidad, sin ser moralistas ni forzar el mensaje. Estamos convencidos de que, con este enfoque, los jugadores serán más sensibles a nuestros mensajes y, quién sabe, tal vez los inspire a tomar alguna acción inicial, como recoger un pedazo de basura la próxima vez que vayan a la playa. ¡Todo el equipo está ansioso por ver esta colaboración llegar a buen término y descubrir el impacto que Under The Waves tendrá en los jugadores!»

    Under The Waves es la última incorporación al catálogo SPOTLIGHT by QUANTIC DREAM, el sello editorial del estudio francés. Para Guillaume de Fondaumière, CEO y Jefe de Publicaciones de Quantic Dream: «Este es un proyecto del que nos enamoramos inmediatamente cuando comenzamos a construir nuestro catálogo editorial. Ya sea a través de su narración, su dirección artística o, más en general, la dedicación de su equipo de desarrollo, Under The Waves representa lo que creemos en Quantic Dream: una experiencia interactiva única y memorable que tocará emocionalmente a quienes la jueguen, creada por un equipo apasionado. También estamos muy orgullosos de haber podido apoyar a Surfrider Foundation Europe y contribuir a dar a conocer sus importantes acciones hacia la preservación del océano a un público más amplio».

    Under The Waves está disponible digitalmente en PC, PlayStation 5, PlayStation 4, Xbox Series S/X y Xbox One, por 29,99 €. La edición física deluxe, que incluye un libro de arte y un conjunto exclusivo de pegatinas, también está disponible en PlayStation 5, PlayStation 4, Xbox Series S / X y Xbox One, a un precio de € 39.99.

    Kid Katana Records se asocia con Quantic Dream y Parallel Studio para ofrecer a los jugadores de todo el mundo la banda sonora inmersiva y minimalista de Under The Waves. Compuesta por Nicolas Bredin, la banda sonora de Under The Waves se erige como una encarnación profunda de la narrativa del juego, influenciada por compositores islandeses como Valgeir Sigurdsson y Ólafur Arnalds, así como bandas de post-rock como Mogwai, Sigur Ros y Radiohead.

    La banda sonora de Under The Waves ya está disponible en todas las plataformas.

    Para obtener más información sobre Under The Waves  y los próximos lanzamientos de SPOTLIGHT by QUANTIC DREAM, visita QuanticDream.com y sigue @Quantic_Dream y @FromParallel.

     

    La entrada Under The Waves, El Cuento Melancólico Imaginado Por Parallel Studio, Ya Está Disponible En Pc Y Consolas Playstation Y Xbox apareció primero en ZIRAN Comunicación.]]>
    SPOTLIGHT by QUANTIC DREAM muestra sus juegos en Gamescom 2023 https://www.ziran.es/nota_prensa/spotlight-by-quantic-dream-muestra-sus-juegos-en-gamescom-2023/ Tue, 22 Aug 2023 20:10:49 +0000 https://www.ziran.es/?post_type=nota_prensa&p=53323 El sello dedicado al apoyo y a la publicación de juegos indie ha aprovechado su presencia en Gamescom 2023 para mostrar Under the Waves, Lysfanga: The Time Shift Warrior y Dustborn SPOTLIGHT by QUANTIC DREAM, el sello del estudio y editor francés Quantic Dream dedicado al apoyo, publicación y promoción de juegos indie, ha mostrado […]

    La entrada SPOTLIGHT by QUANTIC DREAM muestra sus juegos en Gamescom 2023 apareció primero en ZIRAN Comunicación.]]>
    El sello dedicado al apoyo y a la publicación de juegos indie ha aprovechado su presencia en Gamescom 2023 para mostrar Under the Waves, Lysfanga: The Time Shift Warrior y Dustborn

    SPOTLIGHT by QUANTIC DREAM, el sello del estudio y editor francés Quantic Dream dedicado al apoyo, publicación y promoción de juegos indie, ha mostrado tres nuevos tráileres en Gamescom 2023.

    UNDER THE WAVES

    Tras casi cuatro años de desarrollo, Parallel Studio lanzará Under The Waves el martes, 29 de agosto, en versión digital para PC, PlayStation 5, PlayStation 4, Xbox Series S|X y Xbox One. Para celebrar su llegada, el estudio ha mostrado un tráiler de lanzamiento.

    El juego también tendrá una versión física deluxe, disponible a partir del 29 de agosto para PlayStation 5, PlayStation 4, Xbox Series S|X y Xbox One, que incluirá un libro de arte y un conjunto de pegatinas exclusivas.

    Para más información acerca de Under The Waves, los usuarios interesados pueden visitar la página oficial UnderTheWavesGame.com y la cuenta de X de Parallel Studio.

    LYSFANGA: THE TIME SHIFT WARRIOR

    La primera creación de Sand Door Studio, Lysfanga: The Time Shift Warrior, llegará a PC a principios de 2024. El juego le da un giro táctico al concepto básico de hack’n’slash: los usuarios controlarán a Imë, una poderosa heroína que puede invocar clones de su pasado para ayudarla a luchar contra hordas de enemigos en una gran variedad de arenas. El juego también ha sido diseñado pensando en el speedrunning y ofrecerá una experiencia de acción única.

    Los usuarios que lo deseen, ya pueden añadir Lysfanga: The Time Shift Warrior a su lista de deseos. Para obtener más información acerca del juego, están disponibles la página oficial de Sand Door Studio y su cuenta de X.

    DUSTBORN

    Dustborn, creado y desarrollado por el equipo de Red Thread Games en Oslo, Noruega, ofrece una sorprendente experiencia que mezcla la acción y la aventura con un alto contenido narrativo, reforzado por su arte, que se inspira en el estilo de los cómic. Con su lanzamiento programado para 2024 en PC, PlayStation 5, PlayStation 4, Xbox Series S|X y Xbox One, en Dustborn los jugadores se pondrán en la piel de Pax y su equipo en un viaje salvaje a través de los distópicos Estados Divididos de América.

    Los usuarios que lo deseen, ya pueden añadir Dustborn a su lista de deseos tanto en PC como en consolas. Para seguir las novedades acerca del juego, los usuarios interesados pueden visitar la página oficial https://www.wearedustborn.com y la cuenta de X.

     

    La entrada SPOTLIGHT by QUANTIC DREAM muestra sus juegos en Gamescom 2023 apareció primero en ZIRAN Comunicación.]]>