[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-core/classes/ -> class-bp-core-oembed-extension.php (source)

   1  <?php
   2  /**
   3   * Core component classes.
   4   *
   5   * @package BuddyPress
   6   * @subpackage Core
   7   * @since 2.6.0
   8   */
   9  
  10  // Exit if accessed directly.
  11  defined( 'ABSPATH' ) || exit;
  12  
  13  /**
  14   * API for responding and returning a custom oEmbed request.
  15   *
  16   * @since 2.6.0
  17   */
  18  abstract class BP_Core_oEmbed_Extension {
  19  
  20      /** START PROPERTIES ****************************************************/
  21  
  22      /**
  23       * (required) The slug endpoint.
  24       *
  25       * Should be your component id.
  26       *
  27       * @since 2.6.0
  28       *
  29       * @var string
  30       */
  31      public $slug_endpoint = '';
  32  
  33      /** END PROPERTIES ******************************************************/
  34  
  35      /**
  36       * Constructor.
  37       */
  38  	final public function __construct() {
  39          $this->setup_properties();
  40  
  41          // Some rudimentary logic checking.
  42          if ( empty( $this->slug_endpoint ) ) {
  43              return;
  44          }
  45  
  46          $this->setup_hooks();
  47          $this->custom_hooks();
  48      }
  49  
  50      /** REQUIRED METHODS ****************************************************/
  51  
  52      /**
  53       * Add content for your oEmbed response here.
  54       *
  55       * @since 2.6.0
  56       *
  57       * @return null
  58       */
  59      abstract protected function content();
  60  
  61      /**
  62       * Add a check for when you are on the page you want to oEmbed.
  63       *
  64       * You'll want to return a boolean here. eg. bp_is_single_activity().
  65       *
  66       * @since 2.6.0
  67       *
  68       * @return bool
  69       */
  70      abstract protected function is_page();
  71  
  72      /**
  73       * Validate the URL to see if it matches your item ID.
  74       *
  75       * @since 2.6.0
  76       *
  77       * @param string $url URL to validate.
  78       * @return int Your item ID
  79       */
  80      abstract protected function validate_url_to_item_id( $url );
  81  
  82      /**
  83       * Set the oEmbed response data.
  84       *
  85       * @since 2.6.0
  86       *
  87       * @param int $item_id Your item ID to do checks against.
  88       * @return array Should contain 'content', 'title', 'author_url', 'author_name' as array
  89       *               keys. 'author_url' and 'author_name' is optional; the rest are required.
  90       */
  91      abstract protected function set_oembed_response_data( $item_id );
  92  
  93      /**
  94       * Sets the fallback HTML for the oEmbed response.
  95       *
  96       * In a WordPress oEmbed item, the fallback HTML is a <blockquote>.  This is
  97       * usually hidden after the <iframe> is loaded.
  98       *
  99       * @since 2.6.0
 100       *
 101       * @param int $item_id Your item ID to do checks against.
 102       * @return string Fallback HTML you want to output.
 103       */
 104      abstract protected function set_fallback_html( $item_id );
 105  
 106      /** OPTIONAL METHODS ****************************************************/
 107  
 108      /**
 109       * If your oEmbed endpoint requires additional arguments, set them here.
 110       *
 111       * @see register_rest_route() View the $args parameter for more info.
 112       *
 113       * @since 2.6.0
 114       *
 115       * @return array
 116       */
 117  	protected function set_route_args() {
 118          return array();
 119      }
 120  
 121      /**
 122       * Set the iframe title.
 123       *
 124       * If not set, this will fallback to WP's 'Embedded WordPress Post'.
 125       *
 126       * @since 2.6.0
 127       *
 128       * @param int $item_id The item ID to do checks for.
 129       */
 130  	protected function set_iframe_title( $item_id ) {}
 131  
 132      /**
 133       * Do what you need to do here to initialize any custom hooks.
 134       *
 135       * @since 2.6.0
 136       */
 137  	protected function custom_hooks() {}
 138  
 139      /**
 140       * Set permalink for oEmbed link discovery.
 141       *
 142       * This method will be called on the page we want to oEmbed.  In most cases,
 143       * you will not need to override this method.  However, if you need to, do
 144       * override in your extended class.
 145       *
 146       * @since 2.6.0
 147       */
 148  	protected function set_permalink() {
 149          $url = bp_get_requested_url();
 150  
 151          // Remove querystring from bp_get_requested_url().
 152          if ( false !== strpos( bp_get_requested_url(), '?' ) ) {
 153              $url = substr( bp_get_requested_url(), 0, strpos( bp_get_requested_url(), '?' ) );
 154          }
 155  
 156          return $url;
 157      }
 158  
 159      /** HELPERS *************************************************************/
 160  
 161      /**
 162       * Get the item ID when filtering the oEmbed HTML.
 163       *
 164       * Should only be used during the 'embed_html' hook.
 165       *
 166       * @since 2.6.0
 167       */
 168  	protected function get_item_id() {
 169          return $this->is_page() ? $this->validate_url_to_item_id( $this->set_permalink() ) : buddypress()->{$this->slug_endpoint}->embedid_in_progress;
 170      }
 171  
 172      /** SET UP **************************************************************/
 173  
 174      /**
 175       * Set up properties.
 176       *
 177       * @since 2.6.0
 178       */
 179  	protected function setup_properties() {
 180          $this->slug_endpoint = sanitize_title( $this->slug_endpoint );
 181      }
 182  
 183      /**
 184       * Hooks! We do the dirty work here, so you don't have to! :)
 185       *
 186       * More hooks are available in the setup_template_parts() method.
 187       *
 188       * @since 2.6.0
 189       */
 190  	protected function setup_hooks() {
 191          add_action( 'rest_api_init',    array( $this, 'register_route' ) );
 192          add_action( 'bp_embed_content', array( $this, 'inject_content' ) );
 193  
 194          add_filter( 'embed_template', array( $this, 'setup_template_parts' ) );
 195          add_filter( 'post_embed_url', array( $this, 'filter_embed_url' ) );
 196          add_filter( 'embed_html',     array( $this, 'filter_embed_html' ) );
 197          add_filter( 'oembed_discovery_links', array( $this, 'add_oembed_discovery_links' ) );
 198          add_filter( 'rest_pre_serve_request', array( $this, 'oembed_xml_request' ), 20, 4 );
 199      }
 200  
 201      /** HOOKS ***************************************************************/
 202  
 203      /**
 204       * Register the oEmbed REST API route.
 205       *
 206       * @since 2.6.0
 207       */
 208  	public function register_route() {
 209          /** This filter is documented in wp-includes/class-wp-oembed-controller.php */
 210          $maxwidth = apply_filters( 'oembed_default_width', 600 );
 211  
 212          // Required arguments.
 213          $args = array(
 214              'url'      => array(
 215                  'required'          => true,
 216                  'sanitize_callback' => 'esc_url_raw',
 217              ),
 218              'format'   => array(
 219                  'default'           => 'json',
 220                  'sanitize_callback' => 'wp_oembed_ensure_format',
 221              ),
 222              'maxwidth' => array(
 223                  'default'           => $maxwidth,
 224                  'sanitize_callback' => 'absint',
 225              )
 226          );
 227  
 228          // Merge custom arguments here.
 229          $args = $args + (array) $this->set_route_args();
 230  
 231          register_rest_route( 'oembed/1.0', "/embed/{$this->slug_endpoint}", array(
 232              array(
 233                  'methods'             => WP_REST_Server::READABLE,
 234                  'callback'            => array( $this, 'get_item' ),
 235                  'permission_callback' => '__return_true',
 236                  'args'                => $args
 237              ),
 238          ) );
 239      }
 240  
 241      /**
 242       * Set up custom embed template parts for BuddyPress use.
 243       *
 244       * @since 2.6.0
 245       *
 246       * @param string $template File path to current embed template.
 247       * @return string
 248       */
 249  	public function setup_template_parts( $template ) {
 250          // Determine if we're on our BP page.
 251          if ( ! $this->is_page() || is_404() ) {
 252              return $template;
 253          }
 254  
 255          // Set up some BP-specific embed template overrides.
 256          add_action( 'get_template_part_embed', array( $this, 'content_buffer_start' ), -999, 2 );
 257          add_action( 'get_footer',              array( $this, 'content_buffer_end' ), -999 );
 258  
 259          // Return the original WP embed template.
 260          return $template;
 261      }
 262  
 263      /**
 264       * Start object buffer.
 265       *
 266       * We're going to override WP's get_template_part( 'embed, 'content' ) call
 267       * and inject our own template for BuddyPress use.
 268       *
 269       * @since 2.6.0
 270       *
 271       * @param string $slug Template slug.
 272       * @param string $name Template name.
 273       */
 274  	public function content_buffer_start( $slug, $name ) {
 275          if ( 'embed' !== $slug || 'content' !== $name ) {
 276              return;
 277          }
 278  
 279          // Start the buffer to wipe out get_template_part( 'embed, 'content' ).
 280          ob_start();
 281      }
 282  
 283      /**
 284       * End object buffer.
 285       *
 286       * We're going to override WP's get_template_part( 'embed, 'content' ) call
 287       * and inject our own template for BuddyPress use.
 288       *
 289       * @since 2.6.0
 290       *
 291       * @param string $name Template name.
 292       */
 293  	public function content_buffer_end( $name ) {
 294          if ( 'embed' !== $name || is_404() ) {
 295              return;
 296          }
 297  
 298          // Wipe out get_template_part( 'embed, 'content' ).
 299          ob_end_clean();
 300  
 301          // Start our custom BuddyPress embed template!
 302          echo '<div ';
 303          post_class( 'wp-embed' );
 304          echo '>';
 305  
 306          // Template part for our embed header.
 307          bp_get_asset_template_part( 'embeds/header', bp_current_component() );
 308  
 309          /**
 310           * Inject BuddyPress embed content on this hook.
 311           *
 312           * You shouldn't really need to use this if you extend the
 313           * {@link BP_oEmbed_Component} class.
 314           *
 315           * @since 2.6.0
 316           */
 317          do_action( 'bp_embed_content' );
 318  
 319          // Template part for our embed footer.
 320          bp_get_asset_template_part( 'embeds/footer', bp_current_component() );
 321  
 322          echo '</div>';
 323      }
 324  
 325      /**
 326       * Adds oEmbed discovery links on single activity pages.
 327       *
 328       * @since 2.6.0
 329       *
 330       * @param string $retval Current discovery links.
 331       * @return string
 332       */
 333  	public function add_oembed_discovery_links( $retval ) {
 334          if ( ! $this->is_page() ) {
 335              return $retval;
 336          }
 337  
 338          $permalink = $this->set_permalink();
 339          if ( empty( $permalink ) ) {
 340              return $retval;
 341          }
 342  
 343          add_filter( 'rest_url' , array( $this, 'filter_rest_url' ) );
 344  
 345          $retval = '<link rel="alternate" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( $permalink ) ) . '" />' . "\n";
 346  
 347          if ( class_exists( 'SimpleXMLElement' ) ) {
 348              $retval .= '<link rel="alternate" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( $permalink, 'xml' ) ) . '" />' . "\n";
 349          }
 350  
 351          remove_filter( 'rest_url' , array( $this, 'filter_rest_url' ) );
 352  
 353          return $retval;
 354      }
 355  
 356      /**
 357       * Fetch our oEmbed response data to return.
 358       *
 359       * A simplified version of {@link get_oembed_response_data()}.
 360       *
 361       * @since 2.6.0
 362       *
 363       * @link http://oembed.com/ View the 'Response parameters' section for more details.
 364       *
 365       * @param array $item  Custom oEmbed response data.
 366       * @param int   $width The requested width.
 367       * @return array
 368       */
 369  	protected function get_oembed_response_data( $item, $width ) {
 370          $data = wp_parse_args( $item, array(
 371              'version'       => '1.0',
 372              'provider_name' => get_bloginfo( 'name' ),
 373              'provider_url'  => get_home_url(),
 374              'author_name'   => get_bloginfo( 'name' ),
 375              'author_url'    => get_home_url(),
 376              'title'         => ucfirst( $this->slug_endpoint ),
 377              'type'          => 'rich',
 378          ) );
 379  
 380          /** This filter is documented in /wp-includes/embed.php */
 381          $min_max_width = apply_filters( 'oembed_min_max_width', array(
 382              'min' => 200,
 383              'max' => 600
 384          ) );
 385  
 386          $width  = min( max( $min_max_width['min'], $width ), $min_max_width['max'] );
 387          $height = max( ceil( $width / 16 * 9 ), 200 );
 388  
 389          $data['width']  = absint( $width );
 390          $data['height'] = absint( $height );
 391  
 392          // Set 'html' parameter.
 393          if ( 'video' === $data['type'] || 'rich' === $data['type'] ) {
 394              // Fake a WP post so we can use get_post_embed_html().
 395              $post = new stdClass;
 396              $post->post_content = $data['content'];
 397              $post->post_title   = $data['title'];
 398  
 399              $data['html'] = get_post_embed_html( $data['width'], $data['height'], $post );
 400          }
 401  
 402          // Remove temporary parameters.
 403          unset( $data['content'] );
 404  
 405          return $data;
 406      }
 407  
 408      /**
 409       * Callback for the API endpoint.
 410       *
 411       * Returns the JSON object for the item.
 412       *
 413       * @since 2.6.0
 414       *
 415       * @param WP_REST_Request $request Full data about the request.
 416       * @return WP_Error|array oEmbed response data or WP_Error on failure.
 417       */
 418  	public function get_item( $request ) {
 419          $url = $request['url'];
 420  
 421          $data = false;
 422  
 423          $item_id = (int) $this->validate_url_to_item_id( $url );
 424  
 425          if ( ! empty( $item_id ) ) {
 426              // Add markers to tell that we're embedding a single activity.
 427              // This is needed for various oEmbed response data filtering.
 428              if ( ! isset( buddypress()->{$this->slug_endpoint} ) || ! buddypress()->{$this->slug_endpoint} ) {
 429                  buddypress()->{$this->slug_endpoint} = new stdClass;
 430              }
 431              buddypress()->{$this->slug_endpoint}->embedurl_in_progress = $url;
 432              buddypress()->{$this->slug_endpoint}->embedid_in_progress  = $item_id;
 433  
 434              // Save custom route args as well.
 435              $custom_args = array_keys( (array) $this->set_route_args() );
 436              if ( ! empty( $custom_args ) ) {
 437                  buddypress()->{$this->slug_endpoint}->embedargs_in_progress = array();
 438  
 439                  foreach( $custom_args as $arg ) {
 440                      if ( isset( $request[ $arg ] ) ) {
 441                          buddypress()->{$this->slug_endpoint}->embedargs_in_progress[ $arg ] = $request[ $arg ];
 442                      }
 443                  }
 444              }
 445  
 446              // Grab custom oEmbed response data.
 447              $item = $this->set_oembed_response_data( $item_id );
 448  
 449              // Set oEmbed response data.
 450              $data = $this->get_oembed_response_data( $item, $request['maxwidth'] );
 451          }
 452  
 453          if ( ! $data ) {
 454              return new WP_Error( 'oembed_invalid_url', get_status_header_desc( 404 ), array( 'status' => 404 ) );
 455          }
 456  
 457          return $data;
 458      }
 459  
 460      /**
 461       * If oEmbed request wants XML, return XML instead of JSON.
 462       *
 463       * Basically a copy of {@link _oembed_rest_pre_serve_request()}. Unfortunate
 464       * that we have to duplicate this just for a URL check.
 465       *
 466       * @since 2.6.0
 467       *
 468       * @param bool                      $served  Whether the request has already been served.
 469       * @param WP_HTTP_ResponseInterface $result  Result to send to the client. Usually a WP_REST_Response.
 470       * @param WP_REST_Request           $request Request used to generate the response.
 471       * @param WP_REST_Server            $server  Server instance.
 472       * @return bool
 473       */
 474  	public function oembed_xml_request( $served, $result, $request, $server ) {
 475          $params = $request->get_params();
 476  
 477          if ( ! isset( $params['format'] ) || 'xml' !== $params['format'] ) {
 478              return $served;
 479          }
 480  
 481          // Validate URL against our oEmbed endpoint. If not valid, bail.
 482          // This is our mod to _oembed_rest_pre_serve_request().
 483          $query_params = $request->get_query_params();
 484          if ( false === $this->validate_url_to_item_id( $query_params['url'] ) ) {
 485              return $served;
 486          }
 487  
 488          // Embed links inside the request.
 489          $data = $server->response_to_data( $result, false );
 490  
 491          if ( ! class_exists( 'SimpleXMLElement' ) ) {
 492              status_header( 501 );
 493              die( get_status_header_desc( 501 ) );
 494          }
 495  
 496          $result = _oembed_create_xml( $data );
 497  
 498          // Bail if there's no XML.
 499          if ( ! $result ) {
 500              status_header( 501 );
 501              return get_status_header_desc( 501 );
 502          }
 503  
 504          if ( ! headers_sent() ) {
 505              $server->send_header( 'Content-Type', 'text/xml; charset=' . get_option( 'blog_charset' ) );
 506          }
 507  
 508          echo $result;
 509  
 510          return true;
 511      }
 512  
 513      /**
 514       * Pass our BuddyPress activity permalink for embedding.
 515       *
 516       * @since 2.6.0
 517       *
 518       * @see bp_activity_embed_rest_route_callback()
 519       *
 520       * @param string $retval Current embed URL.
 521       * @return string
 522       */
 523  	public function filter_embed_url( $retval ) {
 524          if ( false === isset( buddypress()->{$this->slug_endpoint}->embedurl_in_progress ) && ! $this->is_page() ) {
 525              return $retval;
 526          }
 527  
 528          $url = $this->is_page() ? $this->set_permalink() : buddypress()->{$this->slug_endpoint}->embedurl_in_progress;
 529          $url = trailingslashit( $url );
 530  
 531          // This is for the 'WordPress Embed' block
 532          // @see bp_activity_embed_comments_button().
 533          if ( 'the_permalink' !== current_filter() ) {
 534              $url = add_query_arg( 'embed', 'true', trailingslashit( $url ) );
 535  
 536              // Add custom route args to iframe.
 537              if ( isset( buddypress()->{$this->slug_endpoint}->embedargs_in_progress ) && buddypress()->{$this->slug_endpoint}->embedargs_in_progress ) {
 538                  foreach( buddypress()->{$this->slug_endpoint}->embedargs_in_progress as $key => $value ) {
 539                      $url = add_query_arg( $key, $value, $url );
 540                  }
 541              }
 542          }
 543  
 544          return $url;
 545      }
 546  
 547      /**
 548       * Filters the embed HTML for our BP oEmbed endpoint.
 549       *
 550       * @since 2.6.0
 551       *
 552       * @param string $retval Current embed HTML.
 553       * @return string
 554       */
 555  	public function filter_embed_html( $retval ) {
 556          if ( false === isset( buddypress()->{$this->slug_endpoint}->embedurl_in_progress ) && ! $this->is_page() ) {
 557              return $retval;
 558          }
 559  
 560          $url = $this->set_permalink();
 561  
 562          $item_id = $this->is_page() ? $this->validate_url_to_item_id( $url ) : buddypress()->{$this->slug_endpoint}->embedid_in_progress;
 563  
 564          // Change 'Embedded WordPress Post' to custom title.
 565          $custom_title = $this->set_iframe_title( $item_id );
 566          if ( ! empty( $custom_title ) ) {
 567              $title_pos = strpos( $retval, 'title=' ) + 7;
 568              $title_end_pos = strpos( $retval, '"', $title_pos );
 569  
 570              $retval = substr_replace( $retval, esc_attr( $custom_title ), $title_pos, $title_end_pos - $title_pos );
 571          }
 572  
 573          // Add 'max-width' CSS attribute to IFRAME.
 574          // This will make our oEmbeds responsive.
 575          if ( false === strpos( $retval, 'style="max-width' ) ) {
 576              $retval = str_replace( '<iframe', '<iframe style="max-width:100%"', $retval );
 577          }
 578  
 579          // Remove default <blockquote>.
 580          $retval = substr( $retval, strpos( $retval, '</blockquote>' ) + 13 );
 581  
 582          // Set up new fallback HTML
 583          // @todo Maybe use KSES?
 584          $fallback_html = $this->set_fallback_html( $item_id );
 585  
 586          /**
 587           * Dynamic filter to return BP oEmbed HTML.
 588           *
 589           * @since 2.6.0
 590           *
 591           * @var string $retval
 592           */
 593          return apply_filters( "bp_{$this->slug_endpoint}_embed_html", $fallback_html . $retval );
 594      }
 595  
 596      /**
 597       * Append our custom slug endpoint to oEmbed endpoint URL.
 598       *
 599       * Meant to be used as a filter on 'rest_url' before any call to
 600       * {@link get_oembed_endpoint_url()} is used.
 601       *
 602       * @since 2.6.0
 603       *
 604       * @see add_oembed_discovery_links()
 605       *
 606       * @param string $retval Current oEmbed endpoint URL.
 607       * @return string
 608       */
 609  	public function filter_rest_url( $retval = '' ) {
 610          return $retval . "/{$this->slug_endpoint}";
 611      }
 612  
 613      /**
 614       * Inject content into the embed template.
 615       *
 616       * @since 2.6.0
 617       */
 618  	public function inject_content() {
 619          if ( ! $this->is_page() ) {
 620              return;
 621          }
 622  
 623          $this->content();
 624      }
 625  }


Generated: Tue Sep 29 01:01:36 2020 Cross-referenced by PHPXref 0.7.1