Skip to content

Commit

Permalink
Embeds: Replace Facebook embeds handler with oEmbeds
Browse files Browse the repository at this point in the history
  • Loading branch information
ockham committed Nov 20, 2020
1 parent b93c113 commit 6899cd7
Showing 1 changed file with 132 additions and 67 deletions.
199 changes: 132 additions & 67 deletions modules/shortcodes/facebook.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,94 +5,160 @@
* @package Jetpack
*/

use Automattic\Jetpack\Connection\Client;
use Automattic\Jetpack\Constants;

define( 'JETPACK_FACEBOOK_EMBED_REGEX', '#^https?://(www.)?facebook\.com/([^/]+)/(posts|photos)/([^/]+)?#' );
define( 'JETPACK_FACEBOOK_ALTERNATE_EMBED_REGEX', '#^https?://(www.)?facebook\.com/permalink.php\?([^\s]+)#' );
define( 'JETPACK_FACEBOOK_PHOTO_EMBED_REGEX', '#^https?://(www.)?facebook\.com/photo.php\?([^\s]+)#' );
define( 'JETPACK_FACEBOOK_PHOTO_ALTERNATE_EMBED_REGEX', '#^https?://(www.)?facebook\.com/([^/]+)/photos/([^/]+)?#' );
define( 'JETPACK_FACEBOOK_VIDEO_EMBED_REGEX', '#^https?://(www.)?facebook\.com/(?:video.php|watch\/?)\?([^\s]+)#' );
define( 'JETPACK_FACEBOOK_VIDEO_ALTERNATE_EMBED_REGEX', '#^https?://(www.)?facebook\.com/([^/]+)/videos/([^/]+)?#' );

/*
* Example URL: https://www.facebook.com/VenusWilliams/posts/10151647007373076
*/
wp_embed_register_handler( 'facebook', JETPACK_FACEBOOK_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
add_action( 'init', 'jetpack_facebook_enable_embeds' );
} else {
jetpack_facebook_enable_embeds();
}

/*
* Example URL: https://www.facebook.com/permalink.php?id=222622504529111&story_fbid=559431180743788
/**
* Register Facebook as oembed provider, and add required filters for the API request.
* Register [facebook] shortcode.
*
* @since 9.2.0
*/
wp_embed_register_handler( 'facebook-alternate', JETPACK_FACEBOOK_ALTERNATE_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
function jetpack_facebook_enable_embeds() {
$facebook_oembeds = array(
'#https?://www\.facebook\.com/.*/posts/.*#i' => array( 'https://graph.facebook.com/v9.0/oembed_post', true ),
'#https?://www\.facebook\.com/.*/activity/.*#i' => array( 'https://graph.facebook.com/v9.0/oembed_post', true ),
'#https?://www\.facebook\.com/.*/photos/.*#i' => array( 'https://graph.facebook.com/v9.0/oembed_post', true ),
'#https?://www\.facebook\.com/photo(s/|\.php).*#i' => array( 'https://graph.facebook.com/v9.0/oembed_post', true ),
'#https?://www\.facebook\.com/permalink\.php.*#i' => array( 'https://graph.facebook.com/v9.0/oembed_post', true ),
'#https?://www\.facebook\.com/media/.*#i' => array( 'https://graph.facebook.com/v9.0/oembed_post', true ),
'#https?://www\.facebook\.com/questions/.*#i' => array( 'https://graph.facebook.com/v9.0/oembed_post', true ),
'#https?://www\.facebook\.com/notes/.*#i' => array( 'https://graph.facebook.com/v9.0/oembed_post', true ),
'#https?://www\.facebook\.com/.*/videos/.*#i' => array( 'https://graph.facebook.com/v9.0/oembed_video', true ),
'#https?://www\.facebook\.com/video\.php.*#i' => array( 'https://graph.facebook.com/v9.0/oembed_video', true ),
);

foreach ( $facebook_oembeds as $pattern => $embed_data ) {
wp_oembed_remove_provider( $pattern ); // Remove Core's oEmbed handler, if present (WP <= 5.5.2).
wp_oembed_add_provider( $pattern, $embed_data[0], $embed_data[1] );
}

/*
* Photos are handled on a different endpoint; e.g. https://www.facebook.com/photo.php?fbid=10151609960150073&set=a.398410140072.163165.106666030072&type=1
*/
wp_embed_register_handler( 'facebook-photo', JETPACK_FACEBOOK_PHOTO_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
/**
* Add auth token required by Facebook's oEmbed REST API, or proxy through WP.com.
*/
add_filter( 'oembed_fetch_url', 'jetpack_facebook_oembed_fetch_url', 10, 2 );

/*
* Photos (from pages for example) can be at
*/
wp_embed_register_handler( 'facebook-alternate-photo', JETPACK_FACEBOOK_PHOTO_ALTERNATE_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
/**
* Add JP auth headers if we're proxying through WP.com.
*/
add_filter( 'oembed_remote_get_args', 'jetpack_facebook_oembed_remote_get_args', 10, 2 );

/**
* Add the shortcode.
*/
add_shortcode( 'facebook', 'jetpack_facebook_shortcode_handler' );
}

/*
* Videos
/**
* Add auth token required by Facebook's oEmbed REST API, or proxy through WP.com.
*
* @since 9.2.0
*
* Formats:
* https://www.facebook.com/video.php?v=2836814009877992
* https://www.facebook.com/watch/?v=2836814009877992
* @param string $provider URL of the oEmbed provider.
* @param string $url URL of the content to be embedded.
*
* @return string
*/
wp_embed_register_handler( 'facebook-video', JETPACK_FACEBOOK_VIDEO_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
function jetpack_facebook_oembed_fetch_url( $provider, $url ) {
if ( ! wp_startswith( $provider, 'https://graph.facebook.com/v9.0/oembed_' ) ) {
return $provider;
}

/*
* Videos https://www.facebook.com/WhiteHouse/videos/10153398464269238/
*/
wp_embed_register_handler( 'facebook-alternate-video', JETPACK_FACEBOOK_VIDEO_ALTERNATE_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
// Get a set of URL and parameters supported by Facebook.
$clean_parameters = array(); // jetpack_facebook_get_allowed_parameters( $url ); // FIXME!

// Replace existing URL by our clean version.
if ( ! empty( $clean_parameters['url'] ) ) {
$provider = add_query_arg( 'url', rawurlencode( $clean_parameters['url'] ), $provider );
}

// Our shortcode supports the width param, but the API expects maxwidth.
if ( ! empty( $clean_parameters['width'] ) ) {
$provider = add_query_arg( 'maxwidth', $clean_parameters['width'], $provider );
}

if ( ! empty( $clean_parameters['hidecaption'] ) ) {
$provider = add_query_arg( 'hidecaption', true, $provider );
}

$access_token = jetpack_facebook_get_access_token();

if ( ! empty( $access_token ) ) {
return add_query_arg( 'access_token', $access_token, $provider );
}

// If we don't have an access token, we go through the WP.com proxy instead.
// To that end, we need to make sure that we're connected to WP.com.
if ( ! Jetpack::is_active_and_not_offline_mode() ) {
return $provider;
}

$site_id = \Jetpack_Options::get_option( 'id' );
$wpcom_oembed_proxy = Constants::get_constant( 'JETPACK__WPCOM_JSON_API_BASE' ) . "/oembed/1.0/sites/$site_id/proxy";
return str_replace(
array(
'https://graph.facebook.com/v9.0/oembed_page',
'https://graph.facebook.com/v9.0/oembed_post',
'https://graph.facebook.com/v9.0/oembed_video',
),
$wpcom_oembed_proxy,
$provider
);
}

/**
* Callback to modify output of embedded Facebook posts.
* Add JP auth headers if we're proxying through WP.com.
*
* @since 9.2.0
*
* @param array $matches Regex partial matches against the URL passed.
* @param array $attr Attributes received in embed response.
* @param string $url Requested URL to be embedded.
* @return string Facebook embed markup.
* @param array $args oEmbed remote get arguments.
* @param string $url URL to be inspected.
*/
function jetpack_facebook_embed_handler( $matches, $attr, $url ) {
if (
false !== strpos( $url, 'video.php' )
|| false !== strpos( $url, '/videos/' )
|| false !== strpos( $url, '/watch' )
) {
$embed = sprintf( '<div class="fb-video" data-allowfullscreen="true" data-href="%s"></div>', esc_url( $url ) );
} else {
$width = 552; // As of 01/2017, the default width of Facebook embeds when no width attribute provided.

global $content_width;
if ( isset( $content_width ) ) {
$width = min( $width, $content_width );
}

$embed = sprintf( '<div class="fb-post" data-href="%s" data-width="%s"></div>', esc_url( $url ), esc_attr( $width ) );
function jetpack_facebook_oembed_remote_get_args( $args, $url ) {
if ( ! wp_startswith( $url, Constants::get_constant( 'JETPACK__WPCOM_JSON_API_BASE' ) . '/oembed/1.0/' ) ) {
return $args;
}

// Skip rendering scripts in an AMP context.
if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
return $embed;
}
$method = 'GET';
$signed_request = Client::build_signed_request(
compact( 'url', 'method' )
);

// since Facebook is a faux embed, we need to load the JS SDK in the wpview embed iframe.
if (
defined( 'DOING_AJAX' )
&& DOING_AJAX
// No need to check for a nonce here, that's already handled by Core further up.
&& ! empty( $_POST['action'] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
&& 'parse-embed' === $_POST['action'] // phpcs:ignore WordPress.Security.NonceVerification.Missing
) {
ob_start();
wp_scripts()->do_items( array( 'jetpack-facebook-embed' ) );
$scripts = ob_get_clean();
return $embed . $scripts;
} else {
wp_enqueue_script( 'jetpack-facebook-embed' );
return $embed;
}
return $signed_request['request'];
}

/**
* Fetches a Facebook API access token used for query for Facebook embed information, if one is set.
*
* @return string The access token or ''
*/
function jetpack_facebook_get_access_token() {
/**
* Filters the Facebook embed token that is used for querying the Facebook API.
*
* When this token is set, requests are not proxied through the WordPress.com API. Instead, a request is made directly to the
* Facebook API to query for information about the embed which should provide a performance benefit.
*
* @module shortcodes
*
* @since 9.2.0
*
* @param string string The access token set via the JETPACK_FACEBOOK_EMBED_TOKEN constant.
*/
return (string) apply_filters( 'jetpack_facebook_embed_token', (string) Constants::get_constant( 'JETPACK_FACEBOOK_EMBED_TOKEN' ) );
}

/**
Expand All @@ -116,4 +182,3 @@ function jetpack_facebook_shortcode_handler( $atts ) {

return $wp_embed->shortcode( $atts, $atts['url'] );
}
add_shortcode( 'facebook', 'jetpack_facebook_shortcode_handler' );

0 comments on commit 6899cd7

Please sign in to comment.