GravityView  1.22.6
The best, easiest way to display Gravity Forms entries on your website.
class-oembed.php
Go to the documentation of this file.
1 <?php
2 /**
3  * GravityView oEmbed handling
4  *
5  * @package GravityView
6  * @license GPL2+
7  * @author Katz Web Services, Inc.
8  * @link http://gravityview.co
9  * @copyright Copyright 2014, Katz Web Services, Inc.
10  * @since 1.6
11  */
12 
13 if ( ! defined( 'ABSPATH' ) ) {
14  die;
15 }
16 
17 /**
18  * Register oEmbed handlers for embedding GravityView data and render that data
19  *
20  * @since 1.6
21  */
23 
24  protected $output = array();
25  protected $entry_id = NULL;
26  protected $view_id = NULL;
27  protected $is_full_oembed_preview = false;
28 
29  static $instance = NULL;
30 
31  private function __construct() {}
32 
33  private function initialize() {
34 
35  add_action( 'init', array( $this, 'register_handler' ) );
36  add_action( 'init', array( $this, 'add_provider' ) );
37 
38  if ( ! empty( $_GET['gv_oembed_provider'] ) && ! empty( $_GET['url'] ) ) {
39  add_action( 'template_redirect', array( $this, 'render_provider_request' ) );
40  }
41  }
42 
43  /**
44  * @return GravityView_oEmbed
45  * @since 1.6
46  */
47  static function getInstance() {
48 
49  if( empty( self::$instance ) ) {
50  self::$instance = new self;
51 
52  self::$instance->initialize();
53  }
54 
55  return self::$instance;
56  }
57 
58  /**
59  * Register the oEmbed handler
60  *
61  * @since 1.6
62  * @uses get_handler_regex
63  */
64  function register_handler() {
65 
66  wp_embed_register_handler( 'gravityview_entry', $this->get_handler_regex(), array( $this, 'render_handler' ), 20000 );
67 
68  }
69 
70  /**
71  * Become an oEmbed provider for GravityView.
72  *
73  * @since 1.21.5.3
74  *
75  * @return void
76  */
77  function add_provider() {
78  wp_oembed_add_provider( $this->get_handler_regex(), add_query_arg( 'gv_oembed_provider', '1', site_url() ), true );
79  }
80 
81  /**
82  * Output a response as a provider for an entry oEmbed URL.
83  *
84  * For now we only output the JSON format and don't care about the size (width, height).
85  * Our only current use-case is for it to provide output to the Add Media / From URL box
86  * in WordPress 4.8.
87  *
88  * @since 1.21.5.3
89  *
90  * @return void
91  */
93  if ( ! empty( $_GET['url'] ) ) {
94  $url = $_GET['url'];
95  } else {
96  header( 'HTTP/1.0 404 Not Found' );
97  exit;
98  }
99 
100  preg_match( $this->get_handler_regex(), $url, $matches );
101 
102  // If not using permalinks, re-assign values for matching groups
103  if ( ! empty( $matches['entry_slug2'] ) ) {
104  $matches['is_cpt'] = $matches['is_cpt2'];
105  $matches['slug'] = $matches['slug2'];
106  $matches['entry_slug'] = $matches['entry_slug2'];
107  unset( $matches['is_cpt2'], $matches['slug2'], $matches['entry_slug2'] );
108  }
109 
110  // No Entry was found
111  if ( empty( $matches['entry_slug'] ) ) {
112  do_action('gravityview_log_error', 'GravityView_oEmbed[render_handler] $entry_slug not parsed by regex.', $matches );
113  header( 'HTTP/1.0 404 Not Found' );
114  exit;
115  }
116 
117  // Setup the data used
118  $this->set_vars( $matches, null, $url, null );
119 
120  echo json_encode( array(
121  'version' => '1.0',
122  'provider_name' => 'gravityview',
123  'provider_url' => add_query_arg( 'gv_oembed_provider', '1', site_url() ),
124  'html' => $this->generate_preview_notice() . $this->render_frontend( null, null, null, null ),
125  ) );
126  exit;
127  }
128 
129  /**
130  * Generate the Regular expression that matches embedded entries.
131  *
132  * Generates different regex if using permalinks and if not using permalinks
133  *
134  * @since 1.6
135  *
136  * @return string Regex code
137  */
138  private function get_handler_regex() {
139 
140  if ( defined( 'GRAVITYVIEW_FUTURE_CORE_LOADED' ) ) {
141  $entry_var_name = \GV\Entry::get_endpoint_name();
142  } else {
143  /** Deprecated. Use \GV\Entry::get_endpoint_name instead. */
144  $entry_var_name = GravityView_Post_Types::get_entry_var_name();
145  }
146 
147  /**
148  * @filter `gravityview_slug` Modify the url part for a View. [Read the doc](http://docs.gravityview.co/article/62-changing-the-view-slug)
149  * @param string $rewrite_slug The slug shown in the URL
150  */
151  $rewrite_slug = apply_filters( 'gravityview_slug', 'view' );
152 
153  // Only support embeds for current site
154  $prefix = trailingslashit( home_url() );
155 
156  // Using permalinks
157  $using_permalinks = $prefix . "(?P<is_cpt>{$rewrite_slug})?/?(?P<slug>.+?)/{$entry_var_name}/(?P<entry_slug>.+?)/?\$";
158 
159  // Not using permalinks
160  $not_using_permalinks = $prefix . "(?:index.php)?\?(?P<is_cpt2>[^=]+)=(?P<slug2>[^&]+)&entry=(?P<entry_slug2>[^&]+)\$";
161 
162  // Catch either
163  $match_regex = "(?:{$using_permalinks}|{$not_using_permalinks})";
164 
165  return '#'.$match_regex.'#i';
166  }
167 
168  /**
169  * Get the post ID from an URL
170  *
171  * This is necessary because url_to_postid() doesn't work with permalinks off for custom post types
172  *
173  * @uses url_to_postid()
174  * @since 1.6
175  *
176  * @param string $url URL to get the post ID from
177  * @param string $slug The name of a post, used as backup way of checking for post ID
178  * @return int 0 if not found; int of URL post ID otherwise
179  */
180  private function get_postid_from_url_and_slug( $url = '', $slug = '' ) {
181 
182  $post_id = url_to_postid( $url );
183 
184  $page_on_front = get_option( 'page_on_front' );
185 
186  if( (int) $post_id === (int) $page_on_front || empty( $post_id ) ) {
187 
188  $args = array(
189  'post_status' => 'publish',
190  'name' => $slug,
191  'post_type' => array('any', 'gravityview'),
192  );
193 
194  $posts = get_posts( $args );
195 
196  if( !empty( $posts ) ) {
197  $post_id = $posts[0]->ID;
198  }
199  }
200 
201  return $post_id;
202  }
203 
204  /**
205  * Get the entry id for the current oEmbedded entry
206  *
207  * @since 1.6
208  *
209  * @return int|null
210  */
211  public function get_entry_id() {
212  return $this->entry_id;
213  }
214 
215  /**
216  *
217  *
218  * @since 1.6
219  * @see GravityView_oEmbed::add_providers() for the regex
220  *
221  * @param array $matches The regex matches from the provided regex when calling wp_embed_register_handler()
222  * @param array $attr Embed attributes.
223  * @param string $url The original URL that was matched by the regex.
224  * @param array $rawattr The original unmodified attributes.
225  * @return string The embed HTML.
226  */
227  public function render_handler( $matches, $attr, $url, $rawattr ) {
228 
229  // If not using permalinks, re-assign values for matching groups
230  if( !empty( $matches['entry_slug2'] ) ) {
231  $matches['is_cpt'] = $matches['is_cpt2'];
232  $matches['slug'] = $matches['slug2'];
233  $matches['entry_slug'] = $matches['entry_slug2'];
234  unset( $matches['is_cpt2'], $matches['slug2'], $matches['entry_slug2'] );
235  }
236 
237  // No Entry was found
238  if( empty( $matches['entry_slug'] ) ) {
239 
240  do_action('gravityview_log_error', 'GravityView_oEmbed[render_handler] $entry_slug not parsed by regex.', $matches );
241 
242  return '';
243  }
244 
245  $return = '';
246 
247  // Setup the data used
248  $this->set_vars( $matches, $attr, $url, $rawattr );
249 
250  if( is_admin() && !$this->is_full_oembed_preview ) {
251  $return = $this->render_admin( $matches, $attr, $url, $rawattr );
252  } else {
253 
254  if( $this->is_full_oembed_preview ) {
255  $return .= $this->generate_preview_notice();
256  }
257 
258  $return .= $this->render_frontend( $matches, $attr, $url, $rawattr );
259  }
260 
261  return $return;
262  }
263 
264 
265  /**
266  * Generate a warning to users when previewing oEmbed in the Add Media modal
267  *
268  * @return string HTML notice
269  */
270  private function generate_preview_notice() {
271  $floaty = GravityView_Admin::get_floaty();
272  $title = esc_html__( 'This will look better when it is embedded.', 'gravityview' );
273  $message = esc_html__('Styles don\'t get loaded when being previewed, so the content below will look strange. Don\'t be concerned!', 'gravityview');
274  return '<div class="updated notice">'. $floaty. '<h3>'.$title.'</h3><p>'.$message.'</p><br style="clear:both;" /></div>';
275  }
276 
277  /**
278  * Set entry_id and view_id from the data sent to render_handler
279  *
280  * @var $entry_id
281  * @var $view_id
282  *
283  * @see render_handler
284  */
285  private function set_vars( $matches, $attr, $url, $rawattr ) {
286 
287  $this->entry_id = $matches['entry_slug'];
288 
289  $post_id = $this->get_postid_from_url_and_slug( $url, $matches['slug'] );
290 
291  // The URL didn't have the View Custom Post Type structure.
292  if( empty( $matches['is_cpt'] ) || $matches['is_cpt'] !== 'gravityview' ) {
293 
294  do_action('gravityview_log_debug', 'GravityView_oEmbed[render_handler] Embedding an entry inside a post or page', $matches );
295 
296  if ( defined( 'GRAVITYVIEW_FUTURE_CORE_LOADED' ) && $post = get_post( $post_id ) ) {
298  $views = $views->all();
299  if ( ! empty( $views ) ) {
300  /** maybe_get_view_id has a side-effect that adds retrieved views to the global scope */
301  foreach ( $views as $view ) {
302  if ( \GV\View::exists( $view->ID ) && ! gravityview()->views->contains( $view->ID ) ) {
303  gravityview()->views->add( $view );
304  }
305  }
306 
307  $this->view_id = $views[0]->ID;
308  }
309  } else {
310  /** Deprecated. */
311  $this->view_id = GravityView_View_Data::getInstance()->maybe_get_view_id( $post_id );
312  }
313 
314  } else {
315 
316  $this->view_id = $post_id;
317 
318  }
319 
320  // The inline content has $_POST['type'] set to "embed", while the "Add Media" modal doesn't set that.
321  $this->is_full_oembed_preview = ( isset( $_POST['action'] ) && $_POST['action'] === 'parse-embed' && !isset( $_POST['type'] ) );
322  }
323 
324  /**
325  * Display a nice placeholder in the admin for the entry
326  *
327  * @param array $matches The regex matches from the provided regex when calling wp_embed_register_handler()
328  * @param array $attr Embed attributes.
329  * @param string $url The original URL that was matched by the regex.
330  * @param array $rawattr The original unmodified attributes.
331  * @return string The embed HTML.
332  */
333  private function render_admin( $matches, $attr, $url, $rawattr ) {
334  global $wp_version;
335 
336  // Floaty the astronaut
338 
339  $embed_heading = sprintf( esc_html__('Embed Entry %d', 'gravityview'), $this->entry_id );
340 
341  $embed_text = sprintf( esc_html__('This entry will be displayed as it is configured in View %d', 'gravityview'), $this->view_id );
342 
343  return '
344  <div class="loading-placeholder" style="background-color:#e6f0f5;">
345  <h3 style="margin:0; padding:0; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Oxygen-Sans, Ubuntu, Cantarell, \'Helvetica Neue\', sans-serif;">'.$image.$embed_heading.'</h3>
346  <p style="margin:0; padding:0; font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Oxygen-Sans, Ubuntu, Cantarell, \'Helvetica Neue\', sans-serif;">
347  '.$embed_text.'
348  </p>
349  <br style="clear: both;">
350  </div>';
351 
352  }
353 
354  private function generate_entry_output() {
355 
356  // Tell get_gravityview() to display a single entry
357  add_filter( 'gravityview/is_single_entry', array( $this, 'set_single_entry_id' ) );
358 
359  ob_start();
360 
361  // Print the entry as configured in View
362  the_gravityview( $this->view_id );
363 
364  $view_html = ob_get_clean();
365 
366  // Clean up the filter
367  remove_filter( 'gravityview/is_single_entry', array( $this, 'set_single_entry_id' ) );
368 
369  // Strip the new lines that are generated--when editing an entry in particular, scripts are printed that
370  // then are passed through wpautop() and everything looks terrible.
371  $view_html = str_replace( "\n", ' ', $view_html );
372 
373  return $view_html;
374  }
375 
376  /**
377  * Tell get_gravityview() to display a single entry
378  *
379  * REQUIRED FOR THE VIEW TO OUTPUT A SINGLE ENTRY
380  *
381  * @param bool|int $is_single_entry Existing single entry. False, because GV thinks we're in a post or page.
382  *
383  * @return int The current entry ID
384  */
385  public function set_single_entry_id( $is_single_entry = false ) {
386 
387  return $this->entry_id;
388  }
389 
390  /**
391  * GravityView embed entry handler
392  *
393  * @param array $matches The regex matches from the provided regex when calling {@link wp_embed_register_handler()}.
394  * @param array $attr Embed attributes.
395  * @param string $url The original URL that was matched by the regex.
396  * @param array $rawattr The original unmodified attributes.
397  * @return string The embed HTML.
398  */
399  private function render_frontend( $matches, $attr, $url, $rawattr ) {
400 
401  // If it's already been parsed, don't re-output it.
402  if( !empty( $this->output[ $this->entry_id ] ) ) {
403  return $this->output[ $this->entry_id ];
404  }
405 
406  $entry_output = $this->generate_entry_output();
407 
408  // Wrap a container div around the output to allow for custom styling
409  $output = sprintf('<div class="gravityview-oembed gravityview-oembed-entry gravityview-oembed-entry-'.$this->entry_id.'">%s</div>', $entry_output );
410 
411  /**
412  * @filter `gravityview/oembed/entry` Filter the output of the oEmbed entry embed
413  * @param string $output HTML of the embedded entry, with wrapper div
414  * @param GravityView_oEmbed $object The current GravityView_oEmbed instance
415  * @param array $atts Other passed parameters and info. \n
416  * @var string $entry_output HTML of just the View output, without the wrapper \n
417  * @var array $matches Capture group matches from the regex \n
418  * @var array $attr Embed attributes. \n
419  * @var string $url The original URL that was matched by the regex. \n
420  * @var array $rawattr The original unmodified attributes.
421  */
422  $output = apply_filters('gravityview/oembed/entry', $output, $this, compact( $entry_output, $matches, $attr, $url, $rawattr ) );
423 
424  unset( $entry_output );
425 
426  $this->output[ $this->entry_id ] = $output;
427 
428  return $this->output[ $this->entry_id ];
429 
430  }
431 
432 }
433 
$url
Definition: post_image.php:25
$image
Definition: post_image.php:98
set_vars( $matches, $attr, $url, $rawattr)
Register oEmbed handlers for embedding GravityView data and render that data.
static get_entry_var_name()
Return the query var / end point name for the entry.
static getInstance( $passed_post=NULL)
Definition: class-data.php:164
render_admin( $matches, $attr, $url, $rawattr)
Display a nice placeholder in the admin for the entry.
register_handler()
Register the oEmbed handler.
generate_preview_notice()
Generate a warning to users when previewing oEmbed in the Add Media modal.
$entry_id
Set entry_id and view_id from the data sent to render_handler.
static from_post(\WP_Post $post)
Get a list of objects inside the supplied .
the_gravityview( $view_id='', $atts=array())
Theme function to render a GravityView view.
static get_endpoint_name()
Return the endpoint name for a single Entry.
get_entry_id()
Get the entry id for the current oEmbedded entry.
set_single_entry_id( $is_single_entry=false)
Tell get_gravityview() to display a single entry.
add_provider()
Become an oEmbed provider for GravityView.
get_postid_from_url_and_slug( $url='', $slug='')
Get the post ID from an URL.
static get_floaty()
Get an image of our intrepid explorer friend.
global $post
gravityview()
The main GravityView wrapper function.
get_handler_regex()
Generate the Regular expression that matches embedded entries.
render_provider_request()
Output a response as a provider for an entry oEmbed URL.
render_handler( $matches, $attr, $url, $rawattr)
$title