Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/features/field/oembed/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ The oEmbed field allows embedding external content from various providers like Y

## Availability

The live URL preview and search (which resolves a pasted URL into embed HTML on the fly) is reserved for authenticated users with the standard WordPress content-authoring capability (`edit_posts`) — typically Authors, Editors, and Administrators. Anonymous and front-end visitors do not see the live preview populate when typing a URL into an oEmbed input. Already-stored oEmbed values continue to render normally for all viewers regardless of login state.
The live URL preview and search (which resolves a pasted URL into embed HTML on the fly) uses WordPress's registered oEmbed provider allowlist for anonymous visitors and users without the standard WordPress content-authoring capability (`edit_posts`). Users with content-authoring capability can also use WordPress oEmbed discovery. Already-stored oEmbed values continue to render normally for all viewers regardless of login state.
58 changes: 43 additions & 15 deletions includes/fields/class-acf-field-oembed.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function initialize() {
* @since ACF 5.5.8.5.8
*
* @param $field (array)
* @return (int)
* @return array
*/
function prepare_field( $field ) {

Expand All @@ -86,13 +86,17 @@ function prepare_field( $field ) {
* @param string $url The URL that should be embedded.
* @param integer|string $width Optional maxwidth value passed to the provider URL.
* @param integer|string $height Optional maxheight value passed to the provider URL.
* @param array $args Optional. Additional arguments merged into the oEmbed request.
* @return string|false The embedded HTML on success, false on failure.
*/
function wp_oembed_get( $url = '', $width = 0, $height = 0 ) {
public function wp_oembed_get( $url = '', $width = 0, $height = 0, $args = array() ) {
$embed = false;
$res = array(
'width' => $width,
'height' => $height,
$res = array_merge(
array(
'width' => $width,
'height' => $height,
),
$args
);

if ( function_exists( 'wp_oembed_get' ) ) {
Expand All @@ -102,7 +106,18 @@ function wp_oembed_get( $url = '', $width = 0, $height = 0 ) {
// try shortcode
if ( ! $embed ) {
global $wp_embed;

// WP_Embed::shortcode() otherwise forces discovery on through this filter.
$force_discover_off = isset( $args['discover'] ) && false === $args['discover'];
if ( $force_discover_off ) {
add_filter( 'embed_oembed_discover', '__return_false', PHP_INT_MAX );
}

$embed = $wp_embed->shortcode( $res, $url );

if ( $force_discover_off ) {
remove_filter( 'embed_oembed_discover', '__return_false', PHP_INT_MAX );
}
}

return $embed;
Expand All @@ -123,15 +138,13 @@ public function ajax_query() {
)
);

if ( ! acf_verify_ajax( $args['nonce'], $args['field_key'], true ) || ! current_user_can( 'edit_posts' ) ) {
if ( ! is_user_logged_in() ) {
_doing_it_wrong(
__METHOD__,
esc_html__( 'The oEmbed AJAX search endpoint now requires an authenticated user with the edit_posts capability. Unauthenticated access via wp_ajax_nopriv_acf/fields/oembed/search is deprecated and will be removed in a future release.', 'secure-custom-fields' ),
'6.8.5'
);
}
wp_send_json_error();
if ( ! acf_verify_ajax( $args['nonce'], $args['field_key'], true ) ) {
die();
}

$field = acf_get_field( $args['field_key'] );
if ( ! $field || 'oembed' !== ( $field['type'] ?? '' ) ) {
die();
}

wp_send_json( $this->get_ajax_query( $_POST ) );
Expand Down Expand Up @@ -167,10 +180,25 @@ function get_ajax_query( $args = array() ) {
// prepare field to correct width and height
$field = $this->prepare_field( $field );

/**
* Filters whether URL discovery is permitted on the AJAX oEmbed preview path.
*
* Discovery is restricted by default to users with the edit_posts capability,
* limiting unauthenticated and subscriber-tier callers to WordPress's
* registered oEmbed provider allowlist. Saved values and admin save-time
* rendering are unaffected.
*
* @since SCF 6.8.6
*
* @param bool $allow_discovery Whether discovery is permitted.
* @param array $field The oEmbed field array.
*/
$allow_discovery = (bool) apply_filters( 'acf/fields/oembed/allow_discovery', current_user_can( 'edit_posts' ), $field );

// vars
$response = array(
'url' => $args['s'],
'html' => $this->wp_oembed_get( $args['s'], $field['width'], $field['height'] ),
'html' => $this->wp_oembed_get( $args['s'], $field['width'], $field['height'], array( 'discover' => $allow_discovery ) ),
);

// return
Expand Down
2 changes: 1 addition & 1 deletion readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ This plugin builds upon and is a fork of the previous work done by the contribut

*Security*

- Hardened authorization on the oEmbed field's AJAX search endpoint. The endpoint now requires an authenticated user with content-authoring capability; the legacy unauthenticated entry point is deprecated and will be removed in a future release.
- Hardened the oEmbed field's AJAX preview handling by restricting provider discovery for visitors and users without content-authoring capability while preserving previews from WordPress's registered oEmbed providers.
- Hardened front-end `acf_form()` submission processing so the `post_title` and `post_content` form options are respected on save, and the save pipeline only accepts values for fields the rendered form exposed. A new `acf/form/allowed_field_keys` filter is available for sites that legitimately extend a form at runtime.

= 6.8.5 =
Expand Down
Loading
Loading