Filtering WordPress oEmbed provider list

2019-08-13 10:30发布

问题:

How would I filter the WordPress oEmbed provider list? My aim is to allow just Twitter and Youtube.

EDIT: Could I do something like this?

function filter_oembed_provider_list( $array ) {
    $array = array( 'http://youtu.be/*' => array( 'http://www.youtube.com/oembed',                     false ) );
    return $array;
}
add_filter( 'oembed_providers', 'filter_oembed_provider_list' );

But this doesn't seem to work.

Please see the relevant code in class-oembed.php:

apply_filters( 'oembed_providers', array(
        '#https?://(www\.)?youtube\.com/watch.*#i'           => array( 'http://www.youtube.com/oembed',                     true  ),
        'http://youtu.be/*'                                  => array( 'http://www.youtube.com/oembed',                     false ),
        'http://blip.tv/*'                                   => array( 'http://blip.tv/oembed/',                            false ),
        '#https?://(www\.)?vimeo\.com/.*#i'                  => array( 'http://vimeo.com/api/oembed.{format}',              true  ),
        '#https?://(www\.)?dailymotion\.com/.*#i'            => array( 'http://www.dailymotion.com/services/oembed',        true  ),
        'http://dai.ly/*'                                    => array( 'http://www.dailymotion.com/services/oembed',        false ),
        '#https?://(www\.)?flickr\.com/.*#i'                 => array( 'http://www.flickr.com/services/oembed/',            true  ),
        'http://flic.kr/*'                                   => array( 'http://www.flickr.com/services/oembed/',            false ),
        '#https?://(.+\.)?smugmug\.com/.*#i'                 => array( 'http://api.smugmug.com/services/oembed/',           true  ),
        '#https?://(www\.)?hulu\.com/watch/.*#i'             => array( 'http://www.hulu.com/api/oembed.{format}',           true  ),
        '#https?://(www\.)?viddler\.com/.*#i'                => array( 'http://lab.viddler.com/services/oembed/',           true  ),
        'http://qik.com/*'                                   => array( 'http://qik.com/api/oembed.{format}',                false ),
        'http://revision3.com/*'                             => array( 'http://revision3.com/api/oembed/',                  false ),
        'http://i*.photobucket.com/albums/*'                 => array( 'http://photobucket.com/oembed',                     false ),
        'http://gi*.photobucket.com/groups/*'                => array( 'http://photobucket.com/oembed',                     false ),
        '#https?://(www\.)?scribd\.com/.*#i'                 => array( 'http://www.scribd.com/services/oembed',             true  ),
        'http://wordpress.tv/*'                              => array( 'http://wordpress.tv/oembed/',                       false ),
        '#https?://(.+\.)?polldaddy\.com/.*#i'               => array( 'http://polldaddy.com/oembed/',                      true  ),
        '#https?://(www\.)?funnyordie\.com/videos/.*#i'      => array( 'http://www.funnyordie.com/oembed',                  true  ),
        '#https?://(www\.)?twitter\.com/.+?/status(es)?/.*#i'=> array( 'http://api.twitter.com/1/statuses/oembed.{format}', true  ),
        '#https?://(www\.)?soundcloud\.com/.*#i'             => array( 'http://soundcloud.com/oembed',                      true  ),
        '#https?://(www\.)?slideshare\.net/*#'               => array( 'http://www.slideshare.net/api/oembed/2',            true  ),
        '#http://instagr(\.am|am\.com)/p/.*#i'               => array( 'http://api.instagram.com/oembed',                   true  ),
        '#https?://(www\.)?rdio\.com/.*#i'                   => array( 'http://www.rdio.com/api/oembed/',                   true  ),
        '#https?://rd\.io/x/.*#i'                            => array( 'http://www.rdio.com/api/oembed/',                   true  ),
        '#https?://(open|play)\.spotify\.com/.*#i'           => array( 'https://embed.spotify.com/oembed/',                 true  ),
    ) );

回答1:

There is a built-in function wp_oembed_remove_provider, respectively wp_oembed_add_provider.

EDIT

add to functions.php file

function customize_oembed() {

    //load oembed class
    require_once ABSPATH . DIRECTORY_SEPARATOR . 'wp-includes' . DIRECTORY_SEPARATOR . 'class-oembed.php';

    //get a singleton object
    $oembed = _wp_oembed_get_object();

    /**
     * Forget about those lines
     *
       //empty the providers list
       $oembed->providers = array();

       //add what you want
       wp_oembed_add_provider( 'http://site.com/watchvideo/*', 'http://site.com/oembedprovider' );  
    */

    //use applying a filter
    $providers = array(
        'youtube' => array( 'http://www.youtube.com/oembed', false), 
        'twitter'=> array( 'http://api.twitter.com/1/statuses/oembed.{format}', true  )
    );
    $oembed->providers = apply_filters('oembed_providers', $providers);
}
add_action('init', 'customize_oembed');

EDIT 2

I looked into it, and I found out, that you can use a filter oembed_providers exactly in the same way, as it is used in a constructor of the class. Therefore using additional wordpress functions, which would again try to require the class file and instantiate a singleton object, is useless, when you can do it in one function.

(Despite of the fact, that it works, i still do not get a usage of this filter :-D)

EDIT 3

Finally, I got it working.

It is really similar code to yours, though the argument in the function is basically useless. It only gives you original providers, which you want to override, so you are not using it and you can return an array directly.

Maybe the important thing to remember is, after editing your list, you need to update your posts, since wordpress is saving some data into table *_postmeta under key _oembed_…

function filter_oembed_provider_list( ) {
    return array( 'http://youtu.be/*' => array( 'http://www.youtube.com/oembed', false ) );
}
add_filter( 'oembed_providers', 'filter_oembed_provider_list' );


回答2:

If the filter you provided (oembed_providers) is working for you, then you might try something like this:

/**
 * Filter the oembed providers through a whitelist
 *
 * @param array $providers
 * @return array $providers
 */
function filter_oembed_provider_list( $providers )
{
    // edit the whitelist to your needs
    $whitelist = array( 'youtu', 'twitter' );

    $output = array();

    foreach( $providers as $key => $provider )
    {
        foreach( $whitelist as $allowed )
        {
            if( stristr( $key, $allowed ) )
                $output[$key] = $provider;

        }
    }
    return $output; 
}

add_filter( 'oembed_providers' , 'filter_oembed_provider_list', 99 );

where you must edit the $whitelist to your needs.

Update:

Thanks to @Ivan Hanák, for suggesting the post saving part ;-)

This snippet should now work, after you update the oEmbed cache, by saving the post ;-)



回答3:

I had the same need, as instagram Oembeds are broken in Wordpress before 4.4. what I realized is that the filter for the providers run before your Theme is initialized, so if you want to add this filter, you have to use a plugin.This is what I used

<?php
/**
 * Plugin Name: Fix Instagram oEmbed
 * Plugin URI: https://10up.com
 * Description: Fix Instagram oEmbed.
 * Author: 10up
 * Version: 1.0.0
 * Author URI: https://10up.com
 * License: GPL2
 */

namespace TenUp\Plugin\InstagramFix;
add_filter( 'oembed_providers', __NAMESPACE__ . '\\oembed_providers' );


function oembed_providers( $providers ) {
    if ( ! isset( $providers['#https?://(www\.)?instagr(\.am|am\.com)/p/.*#i'] ) ) {
        $providers['#https?://(www\.)?instagr(\.am|am\.com)/p/.*#i'] = array(
            'https://api.instagram.com/oembed',
            true
        );
    }
    return $providers;
}

so you must

1) create a folder like instagram-oembed-fix in the plugin folder
2) create a file named instagram-oembed-fix.php
3) copy over the php code above
4) activate your plugin ( network activate in a network )
5) regenerate oEmbed cache by going to any post and presing "Save"