init
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
/**
|
||||
* Archive.org Shortcode
|
||||
*
|
||||
* Usage:
|
||||
* [archiveorg-book goodytwoshoes00newyiala]
|
||||
* [archiveorg-book https://www.archive.org/stream/goodytwoshoes00newyiala]
|
||||
* [archiveorg id=goodytwoshoes00newyiala width=480 height=430]
|
||||
|
||||
* <iframe src="https://www.archive.org/stream/goodytwoshoes00newyiala?ui=embed#mode/1up" width="480px" height="430px" frameborder="0" ></iframe>
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get ID of requested archive.org book embed.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*
|
||||
* @return int|string
|
||||
*/
|
||||
function jetpack_shortcode_get_archiveorg_book_id( $atts ) {
|
||||
if ( isset( $atts[0] ) ) {
|
||||
$atts[0] = trim( $atts[0], '=' );
|
||||
if ( preg_match( '#archive.org/stream/(.+)/?$#i', $atts[0], $match ) ) {
|
||||
$id = $match[1];
|
||||
} else {
|
||||
$id = $atts[0];
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an archive.org book shortcode into an embed code.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts An array of shortcode attributes.
|
||||
* @return string The embed code for the Archive.org book
|
||||
*/
|
||||
function jetpack_archiveorg_book_shortcode( $atts ) {
|
||||
global $content_width;
|
||||
|
||||
if ( isset( $atts[0] ) && empty( $atts['id'] ) ) {
|
||||
$atts['id'] = jetpack_shortcode_get_archiveorg_book_id( $atts );
|
||||
}
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => '',
|
||||
'width' => 480,
|
||||
'height' => 430,
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
if ( ! $atts['id'] ) {
|
||||
return '<!-- error: missing archive.org book ID -->';
|
||||
}
|
||||
|
||||
$id = $atts['id'];
|
||||
|
||||
if ( ! $atts['width'] ) {
|
||||
$width = absint( $content_width );
|
||||
} else {
|
||||
$width = (int) $atts['width'];
|
||||
}
|
||||
|
||||
if ( ! $atts['height'] ) {
|
||||
$height = round( ( $width / 640 ) * 360 );
|
||||
} else {
|
||||
$height = (int) $atts['height'];
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<div class="embed-archiveorg-book" style="text-align:center;"><iframe title="%s" src="%s" width="%s" height="%s" style="border:0;" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen></iframe></div>',
|
||||
esc_attr__( 'Archive.org Book', 'jetpack' ),
|
||||
esc_url( "https://archive.org/stream/{$id}?ui=embed#mode/1up" ),
|
||||
esc_attr( $width ),
|
||||
esc_attr( $height )
|
||||
);
|
||||
}
|
||||
|
||||
add_shortcode( 'archiveorg-book', 'jetpack_archiveorg_book_shortcode' );
|
||||
|
||||
/**
|
||||
* Compose shortcode from archive.org book iframe.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function jetpack_archiveorg_book_embed_to_shortcode( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'archive.org/stream/' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$regexp = '!<iframe\s+src=[\'"](http|https)://(www.archive|archive)\.org/stream/([^\'"]+)[\'"]((?:\s+\w+(=[\'"][^\'"]*[\'"])?)*)\s></iframe>!i';
|
||||
|
||||
if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
$url = explode( '?', $match[3] );
|
||||
$id = $url[0];
|
||||
|
||||
$params = $match[4];
|
||||
|
||||
$params = wp_kses_hair( $params, array( 'http' ) );
|
||||
|
||||
$width = isset( $params['width'] ) ? absint( $params['width']['value'] ) : 0;
|
||||
$height = isset( $params['height'] ) ? absint( $params['height']['value'] ) : 0;
|
||||
|
||||
$wh = '';
|
||||
if ( $width && $height ) {
|
||||
$wh = ' width=' . $width . ' height=' . $height;
|
||||
}
|
||||
|
||||
$shortcode = '[archiveorg-book ' . $id . $wh . ']';
|
||||
$content = str_replace( $match[0], $shortcode, $content );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
add_filter( 'pre_kses', 'jetpack_archiveorg_book_embed_to_shortcode' );
|
||||
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
/**
|
||||
* Archive.org book shortcode.
|
||||
*
|
||||
* Usage:
|
||||
* [archiveorg Experime1940]
|
||||
* [archiveorg http://archive.org/details/Experime1940 poster=http://archive.org/images/map.png]
|
||||
* [archiveorg id=Experime1940 width=640 height=480 autoplay=1]
|
||||
|
||||
* <iframe src="http://archive.org/embed/Experime1940&autoplay=1&poster=http://archive.org/images/map.png" width="640" height="480" frameborder="0" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen></iframe>
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get ID of requested archive.org embed.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*
|
||||
* @return int|string
|
||||
*/
|
||||
function jetpack_shortcode_get_archiveorg_id( $atts ) {
|
||||
if ( isset( $atts[0] ) ) {
|
||||
$atts[0] = trim( $atts[0], '=' );
|
||||
if ( preg_match( '#archive.org/(details|embed)/(.+)/?$#i', $atts[0], $match ) ) {
|
||||
$id = $match[2];
|
||||
} else {
|
||||
$id = $atts[0];
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an archive.org shortcode into an embed code.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts An array of shortcode attributes.
|
||||
* @return string The embed code for the archive.org video.
|
||||
*/
|
||||
function jetpack_archiveorg_shortcode( $atts ) {
|
||||
global $content_width;
|
||||
|
||||
if ( isset( $atts[0] ) && empty( $atts['id'] ) ) {
|
||||
$atts['id'] = jetpack_shortcode_get_archiveorg_id( $atts );
|
||||
}
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => '',
|
||||
'width' => 640,
|
||||
'height' => 480,
|
||||
'autoplay' => 0,
|
||||
'poster' => '',
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
if ( ! $atts['id'] ) {
|
||||
return '<!-- error: missing archive.org ID -->';
|
||||
}
|
||||
|
||||
$id = $atts['id'];
|
||||
|
||||
if ( ! $atts['width'] ) {
|
||||
$width = absint( $content_width );
|
||||
} else {
|
||||
$width = (int) $atts['width'];
|
||||
}
|
||||
|
||||
if ( ! $atts['height'] ) {
|
||||
$height = round( ( $width / 640 ) * 360 );
|
||||
} else {
|
||||
$height = (int) $atts['height'];
|
||||
}
|
||||
|
||||
if ( $atts['autoplay'] ) {
|
||||
$autoplay = '&autoplay=1';
|
||||
} else {
|
||||
$autoplay = '';
|
||||
}
|
||||
|
||||
if ( $atts['poster'] ) {
|
||||
$poster = '&poster=' . $atts['poster'];
|
||||
} else {
|
||||
$poster = '';
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<div class="embed-archiveorg" style="text-align:center;"><iframe title="%s" src="%s" width="%s" height="%s" style="border:0;" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen></iframe></div>',
|
||||
esc_attr__( 'Archive.org', 'jetpack' ),
|
||||
esc_url( "https://archive.org/embed/{$id}{$autoplay}{$poster}" ),
|
||||
esc_attr( $width ),
|
||||
esc_attr( $height )
|
||||
);
|
||||
}
|
||||
|
||||
add_shortcode( 'archiveorg', 'jetpack_archiveorg_shortcode' );
|
||||
|
||||
/**
|
||||
* Compose shortcode from archive.org iframe.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function jetpack_archiveorg_embed_to_shortcode( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'archive.org/embed/' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$regexp = '!<iframe\s+src=[\'"]https?://archive\.org/embed/([^\'"]+)[\'"]((?:\s+\w+(=[\'"][^\'"]*[\'"])?)*)></iframe>!i';
|
||||
|
||||
if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
$url = explode( '&', $match[1] );
|
||||
$id = 'id=' . $url[0];
|
||||
|
||||
$autoplay = '';
|
||||
$poster = '';
|
||||
$url_count = count( $url );
|
||||
|
||||
for ( $ii = 1; $ii < $url_count; $ii++ ) {
|
||||
if ( 'autoplay=1' === $url[ $ii ] ) {
|
||||
$autoplay = ' autoplay="1"';
|
||||
}
|
||||
|
||||
$map_matches = array();
|
||||
if ( preg_match( '/^poster=(.+)$/', $url[ $ii ], $map_matches ) ) {
|
||||
$poster = " poster=\"{$map_matches[1]}\"";
|
||||
}
|
||||
}
|
||||
|
||||
$params = $match[2];
|
||||
|
||||
$params = wp_kses_hair( $params, array( 'http' ) );
|
||||
|
||||
$width = isset( $params['width'] ) ? (int) $params['width']['value'] : 0;
|
||||
$height = isset( $params['height'] ) ? (int) $params['height']['value'] : 0;
|
||||
|
||||
$wh = '';
|
||||
if ( $width && $height ) {
|
||||
$wh = ' width=' . $width . ' height=' . $height;
|
||||
}
|
||||
|
||||
$shortcode = '[archiveorg ' . $id . $wh . $autoplay . $poster . ']';
|
||||
$content = str_replace( $match[0], $shortcode, $content );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
add_filter( 'pre_kses', 'jetpack_archiveorg_embed_to_shortcode' );
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* Archives shortcode
|
||||
*
|
||||
* @author bubel & nickmomrik
|
||||
* [archives limit=10]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
add_shortcode( 'archives', 'archives_shortcode' );
|
||||
|
||||
/**
|
||||
* Display Archives shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function archives_shortcode( $atts ) {
|
||||
if ( is_feed() ) {
|
||||
return '[archives]';
|
||||
}
|
||||
|
||||
global $allowedposttags;
|
||||
|
||||
$default_atts = array(
|
||||
'type' => 'postbypost',
|
||||
'limit' => '',
|
||||
'format' => 'html',
|
||||
'showcount' => false,
|
||||
'before' => '',
|
||||
'after' => '',
|
||||
'order' => 'desc',
|
||||
);
|
||||
|
||||
$attr = shortcode_atts( $default_atts, $atts, 'archives' );
|
||||
|
||||
if ( ! in_array( $attr['type'], array( 'yearly', 'monthly', 'daily', 'weekly', 'postbypost' ), true ) ) {
|
||||
$attr['type'] = 'postbypost';
|
||||
}
|
||||
|
||||
if ( ! in_array( $attr['format'], array( 'html', 'option', 'custom' ), true ) ) {
|
||||
$attr['format'] = 'html';
|
||||
}
|
||||
|
||||
$limit = (int) $attr['limit'];
|
||||
// A Limit of 0 makes no sense so revert back to the default.
|
||||
if ( empty( $limit ) ) {
|
||||
$limit = '';
|
||||
}
|
||||
|
||||
$showcount = ( false !== $attr['showcount'] && 'false' !== $attr['showcount'] ) ? true : false;
|
||||
$before = wp_kses( $attr['before'], $allowedposttags );
|
||||
$after = wp_kses( $attr['after'], $allowedposttags );
|
||||
|
||||
// Get the archives.
|
||||
$archives = wp_get_archives(
|
||||
array(
|
||||
'type' => $attr['type'],
|
||||
'limit' => $limit,
|
||||
'format' => $attr['format'],
|
||||
'echo' => false,
|
||||
'show_post_count' => $showcount,
|
||||
'before' => $before,
|
||||
'after' => $after,
|
||||
)
|
||||
);
|
||||
|
||||
if ( 'asc' === $attr['order'] ) {
|
||||
$archives = implode( "\n", array_reverse( explode( "\n", $archives ) ) );
|
||||
}
|
||||
|
||||
// Check to see if there are any archives.
|
||||
if ( empty( $archives ) ) {
|
||||
$archives = '<p>' . __( 'Your blog does not currently have any published posts.', 'jetpack' ) . '</p>';
|
||||
} elseif ( 'option' === $attr['format'] ) {
|
||||
$is_amp = class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request();
|
||||
$change_attribute = $is_amp ? 'on="change:AMP.navigateTo(url=event.value)"' : 'onchange="document.location.href=this.options[this.selectedIndex].value;"';
|
||||
$archives = '<select name="archive-dropdown" ' . $change_attribute . '><option value="' . get_permalink() . '">--</option>' . $archives . '</select>';
|
||||
} elseif ( 'html' === $attr['format'] ) {
|
||||
$archives = '<ul>' . $archives . '</ul>';
|
||||
}
|
||||
|
||||
return $archives;
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
/**
|
||||
* Shortcode handler for [bandcamp], which inserts a bandcamp.com
|
||||
* music player (iframe, html5)
|
||||
*
|
||||
* [bandcamp album=119385304]
|
||||
* [bandcamp album=3462839126 bgcol=FFFFFF linkcol=4285BB size=venti]
|
||||
* [bandcamp track=2446959313]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Display the Bandcamp shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function shortcode_handler_bandcamp( $atts ) {
|
||||
$csswidth = null;
|
||||
$cssheight = null;
|
||||
// there are no default values, but specify here anyway to explicitly list supported atts.
|
||||
$attributes = shortcode_atts(
|
||||
array(
|
||||
'album' => null, // integer album id.
|
||||
'track' => null, // integer track id.
|
||||
'video' => null, // integer track id for video player.
|
||||
'size' => 'venti', // one of the supported sizes.
|
||||
'bgcol' => 'FFFFFF', // hex, no '#' prefix.
|
||||
'linkcol' => null, // hex, no '#' prefix.
|
||||
'layout' => null, // encoded layout url.
|
||||
'width' => null, // integer with optional "%".
|
||||
'height' => null, // integer with optional "%".
|
||||
'notracklist' => null, // may be string "true" (defaults false).
|
||||
'tracklist' => null, // may be string "false" (defaults true).
|
||||
// phpcs:ignore Squiz.PHP.CommentedOutCode.Found -- false positive
|
||||
'artwork' => null, // may be string "false" (alternately: "none") or "small" (default is large).
|
||||
'minimal' => null, // may be string "true" (defaults false).
|
||||
'theme' => null, // may be theme identifier string ("light"|"dark" so far).
|
||||
'package' => null, // integer package id.
|
||||
't' => null, // integer track number.
|
||||
'tracks' => null, // comma separated list of allowed tracks.
|
||||
'esig' => null, // hex, no '#' prefix.
|
||||
),
|
||||
$atts,
|
||||
'bandcamp'
|
||||
);
|
||||
|
||||
$sizes = array(
|
||||
'venti' => array(
|
||||
'width' => 400,
|
||||
'height' => 100,
|
||||
),
|
||||
'grande' => array(
|
||||
'width' => 300,
|
||||
'height' => 100,
|
||||
),
|
||||
'grande2' => array(
|
||||
'width' => 300,
|
||||
'height' => 355,
|
||||
),
|
||||
'grande3' => array(
|
||||
'width' => 300,
|
||||
'height' => 415,
|
||||
),
|
||||
'tall_album' => array(
|
||||
'width' => 150,
|
||||
'height' => 295,
|
||||
),
|
||||
'tall_track' => array(
|
||||
'width' => 150,
|
||||
'height' => 270,
|
||||
),
|
||||
'tall2' => array(
|
||||
'width' => 150,
|
||||
'height' => 450,
|
||||
),
|
||||
'short' => array(
|
||||
'width' => 46,
|
||||
'height' => 23,
|
||||
),
|
||||
'large' => array(
|
||||
'width' => 350,
|
||||
'height' => 470,
|
||||
),
|
||||
'medium' => array(
|
||||
'width' => 450,
|
||||
'height' => 120,
|
||||
),
|
||||
'small' => array(
|
||||
'width' => 350,
|
||||
'height' => 42,
|
||||
),
|
||||
);
|
||||
|
||||
$sizekey = $attributes['size'];
|
||||
$height = null;
|
||||
$width = null;
|
||||
|
||||
$is_video = false;
|
||||
|
||||
/*
|
||||
* Build iframe url. For audio players, args are appended as
|
||||
* extra path segments for historical reasons having to
|
||||
* do with an IE-only flash bug which required this URL
|
||||
* to contain no querystring. Delay the actual joining
|
||||
* of args into a string until after we decide if it's
|
||||
* a video player or an audio player
|
||||
*/
|
||||
$argparts = array();
|
||||
|
||||
if ( ! isset( $attributes['album'] ) && ! isset( $attributes['track'] ) && ! isset( $attributes['video'] ) ) {
|
||||
return "[bandcamp: shortcode must include 'track', 'album', or 'video' param]";
|
||||
}
|
||||
|
||||
if ( isset( $attributes['track'] ) && is_numeric( $attributes['track'] ) ) {
|
||||
$track = esc_attr( $attributes['track'] );
|
||||
array_push( $argparts, "track={$track}" );
|
||||
} elseif ( isset( $attributes['video'] ) && is_numeric( $attributes['video'] ) ) {
|
||||
$track = esc_attr( $attributes['video'] ); // videos are referenced by track id.
|
||||
$url = '//bandcamp.com/EmbeddedPlayer/v=2';
|
||||
$is_video = true;
|
||||
array_push( $argparts, "track={$track}" );
|
||||
}
|
||||
if ( isset( $attributes['album'] ) && is_numeric( $attributes['album'] ) ) {
|
||||
$album = esc_attr( $attributes['album'] );
|
||||
array_push( $argparts, "album={$album}" );
|
||||
}
|
||||
|
||||
if ( 'tall' === $sizekey ) {
|
||||
if ( isset( $attributes['album'] ) ) {
|
||||
$sizekey .= '_album';
|
||||
} else {
|
||||
$sizekey .= '_track';
|
||||
}
|
||||
}
|
||||
|
||||
// if size specified that we don't recognize, fall back on venti.
|
||||
if ( empty( $sizes[ $sizekey ] ) ) {
|
||||
$sizekey = 'venti';
|
||||
$attributes['size'] = 'venti';
|
||||
}
|
||||
|
||||
/*
|
||||
* use strict regex for digits + optional % instead of absint for height/width
|
||||
* 'width' and 'height' params in the iframe url get the exact string from the shortcode
|
||||
* args, whereas the inline style attribute must have "px" added to it if it has no "%"
|
||||
*/
|
||||
if ( isset( $attributes['width'] ) && preg_match( '|^([0-9]+)(%)?$|', $attributes['width'], $matches ) ) {
|
||||
$width = $attributes['width'];
|
||||
$csswidth = $attributes['width'];
|
||||
if ( count( $matches ) < 3 ) {
|
||||
$csswidth .= 'px';
|
||||
}
|
||||
}
|
||||
if ( isset( $attributes['height'] ) && preg_match( '|^([0-9]+)(%)?$|', $attributes['height'], $matches ) ) {
|
||||
$height = $attributes['height'];
|
||||
$cssheight = $attributes['height'];
|
||||
if ( count( $matches ) < 3 ) {
|
||||
$cssheight .= 'px';
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $height ) {
|
||||
$height = $sizes[ $sizekey ]['height'];
|
||||
$cssheight = $height . 'px';
|
||||
}
|
||||
|
||||
if ( ! $width ) {
|
||||
$width = $sizes[ $sizekey ]['width'];
|
||||
$csswidth = $width . 'px';
|
||||
}
|
||||
|
||||
if ( isset( $attributes['layout'] ) ) {
|
||||
array_push( $argparts, "layout={$attributes['layout']}" );
|
||||
} elseif ( isset( $attributes['size'] ) && preg_match( '|^[a-zA-Z0-9]+$|', $attributes['size'] ) ) {
|
||||
array_push( $argparts, "size={$attributes['size']}" );
|
||||
}
|
||||
|
||||
if ( isset( $attributes['bgcol'] ) && preg_match( '|^[0-9A-Fa-f]+$|', $attributes['bgcol'] ) ) {
|
||||
array_push( $argparts, "bgcol={$attributes['bgcol']}" );
|
||||
}
|
||||
|
||||
if ( isset( $attributes['linkcol'] ) && preg_match( '|^[0-9A-Fa-f]+$|', $attributes['linkcol'] ) ) {
|
||||
array_push( $argparts, "linkcol={$attributes['linkcol']}" );
|
||||
}
|
||||
|
||||
if ( isset( $attributes['package'] ) && preg_match( '|^[0-9]+$|', $attributes['package'] ) ) {
|
||||
array_push( $argparts, "package={$attributes['package']}" );
|
||||
}
|
||||
|
||||
if ( isset( $attributes['t'] ) && preg_match( '|^[0-9]+$|', $attributes['t'] ) ) {
|
||||
array_push( $argparts, "t={$attributes['t']}" );
|
||||
}
|
||||
|
||||
if ( 'true' === $attributes['notracklist'] ) {
|
||||
array_push( $argparts, 'notracklist=true' );
|
||||
}
|
||||
|
||||
// 'tracklist' arg deprecates 'notracklist=true' to be less weird. note, behavior
|
||||
// if both are specified is undefined
|
||||
switch ( $attributes['tracklist'] ) {
|
||||
case 'false':
|
||||
case 'none':
|
||||
array_push( $argparts, 'tracklist=false' );
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( $attributes['artwork'] ) {
|
||||
case 'false':
|
||||
case 'none':
|
||||
case 'small':
|
||||
array_push( $argparts, 'artwork=' . $attributes['artwork'] );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( 'true' === $attributes['minimal'] ) {
|
||||
array_push( $argparts, 'minimal=true' );
|
||||
}
|
||||
|
||||
if ( isset( $attributes['theme'] ) && preg_match( '|^[a-zA-Z_]+$|', $attributes['theme'] ) ) {
|
||||
array_push( $argparts, "theme={$attributes['theme']}" );
|
||||
}
|
||||
|
||||
// param 'tracks' is signed digest param 'esig'.
|
||||
if ( isset( $attributes['tracks'] ) && preg_match( '|^[0-9\,]+$|', $attributes['tracks'] ) ) {
|
||||
if ( isset( $attributes['esig'] ) && preg_match( '|^[0-9A-Fa-f]+$|', $attributes['esig'] ) ) {
|
||||
array_push( $argparts, "tracks={$attributes['tracks']}" );
|
||||
array_push( $argparts, "esig={$attributes['esig']}" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $is_video ) {
|
||||
$url = '//bandcamp.com/VideoEmbed?' . implode( '&', $argparts );
|
||||
$extra_attrs = " mozallowfullscreen='1' webkitallowfullscreen='1' allowfullscreen='1'";
|
||||
} else {
|
||||
$url = '//bandcamp.com/EmbeddedPlayer/v=2/' . implode( '/', $argparts ) . '/';
|
||||
$extra_attrs = '';
|
||||
}
|
||||
|
||||
$iframe = '<iframe width="%s" height="%s" style="position: relative; display: block; width: %s; height: %s;" src="%s" allowtransparency="true" frameborder="0"%s></iframe>';
|
||||
$iframe = sprintf( $iframe, esc_attr( $width ), esc_attr( $height ), esc_attr( $csswidth ), esc_attr( $cssheight ), esc_url( $url ), $extra_attrs );
|
||||
|
||||
return $iframe;
|
||||
}
|
||||
|
||||
add_shortcode( 'bandcamp', 'shortcode_handler_bandcamp' );
|
||||
@@ -0,0 +1,297 @@
|
||||
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
|
||||
use Automattic\Jetpack\Assets;
|
||||
|
||||
/**
|
||||
* Brightcove shortcode.
|
||||
*
|
||||
* Brighcove had renovated their video player embedding code since they introduced their "new studio".
|
||||
* See https://support.brightcove.com/en/video-cloud/docs.
|
||||
* The new code is not 100% backward compatible, as long as a customized player is used.
|
||||
* By the time I wrote this, there were about 150000+ posts embedded legacy players, so it would be a bad
|
||||
* idea either to introduce a new brightcove shortcode, or to break those posts completely.
|
||||
*
|
||||
* That's why we introduce a less aggressive way: leaving the old embedding code untouched, and
|
||||
* introduce a new set of shortcode parameters which are translated to the latest Brightcove embedding code.
|
||||
*
|
||||
* e.g.
|
||||
* [brightcove video_id="12345" account_id="99999"] will be translated to the latest embedding code.
|
||||
* [brightcove exp=627045696&vid=1415670151] or [brightcove exp=1463233149&vref=1601200825] will be translated
|
||||
* to the legacy code.
|
||||
*/
|
||||
class Jetpack_Brightcove_Shortcode {
|
||||
/**
|
||||
* Shortcode name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $shortcode = 'brightcove';
|
||||
|
||||
/**
|
||||
* Parse shortcode arguments and render its output.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function convert( $atts ) {
|
||||
$normalized_atts = self::normalize_attributes( $atts );
|
||||
|
||||
if ( empty( $atts ) ) {
|
||||
return '<!-- Missing Brightcove parameters -->';
|
||||
}
|
||||
|
||||
return self::has_legacy_atts( $normalized_atts )
|
||||
? self::convert_to_legacy_studio( $normalized_atts )
|
||||
: self::convert_to_new_studio( $normalized_atts );
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to take care of two kinds of shortcode format here.
|
||||
* The latest: [shortcode a=1 b=2] and the legacy: [shortcode a=1&b=2]
|
||||
* For an old shortcode: [shortcode a=1&b=2&c=3], it would be parsed into array( 'a' => 1&b=2&c=3' ), which is useless.
|
||||
* However, since we want to determine whether to call convert_to_legacy_studio() or convert_to_new_studio() via passed parameters, we still need to parse the two properly.
|
||||
* See https://jetpack.wp-a2z.org/oik_api/shortcode_new_to_old_params/
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function normalize_attributes( $atts ) {
|
||||
if ( is_array( $atts ) && 1 === count( $atts ) ) { // this is the case we need to take care of.
|
||||
$parsed_atts = array();
|
||||
$params = shortcode_new_to_old_params( $atts );
|
||||
|
||||
/**
|
||||
* Filter the Brightcove shortcode parameters.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $params String of shortcode parameters.
|
||||
*/
|
||||
$params = apply_filters( 'brightcove_dimensions', $params );
|
||||
parse_str( $params, $parsed_atts );
|
||||
|
||||
return $parsed_atts;
|
||||
} else {
|
||||
return $atts;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that it has legacy attributes.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_legacy_atts( $atts ) {
|
||||
return ( isset( $atts['vid'] ) || isset( $atts['vref'] ) )
|
||||
&& ( isset( $atts['exp'] ) || isset( $atts['exp3'] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to latest player format.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function convert_to_new_studio( $atts ) {
|
||||
$defaults = array(
|
||||
'account_id' => '',
|
||||
'video_id' => '',
|
||||
'player_id' => 'default',
|
||||
'width' => '100%',
|
||||
'height' => '100%',
|
||||
);
|
||||
|
||||
$atts_applied = shortcode_atts( $defaults, $atts, self::$shortcode );
|
||||
|
||||
$player_url = sprintf(
|
||||
'//players.brightcove.net/%s/%s_default/index.html?videoId=%s',
|
||||
esc_attr( $atts_applied['account_id'] ),
|
||||
esc_attr( $atts_applied['player_id'] ),
|
||||
esc_attr( $atts_applied['video_id'] )
|
||||
);
|
||||
|
||||
$output_html = sprintf(
|
||||
'<iframe src="' . esc_url( $player_url ) . '" allowfullscreen webkitallowfullscreen mozallowfullscreen style="width: %spx; height: %spx;"></iframe>',
|
||||
esc_attr( $atts_applied['width'] ),
|
||||
esc_attr( $atts_applied['height'] )
|
||||
);
|
||||
|
||||
return $output_html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to legacy player format.
|
||||
*
|
||||
* [brightcove exp=627045696&vid=1415670151] for the older player and backward compatibility
|
||||
* [brightcove exp=1463233149&vref=1601200825] for the new player
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function convert_to_legacy_studio( $atts ) {
|
||||
$attr = shortcode_atts(
|
||||
array(
|
||||
'bg' => '',
|
||||
'exp' => '',
|
||||
'exp3' => '',
|
||||
'h' => '',
|
||||
'lbu' => '',
|
||||
'pk' => '',
|
||||
'pubid' => '',
|
||||
's' => '',
|
||||
'surl' => '',
|
||||
'vid' => '',
|
||||
'vref' => '',
|
||||
'w' => '',
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
if ( isset( $attr['pk'] ) ) {
|
||||
$attr['pk'] = rawurlencode( preg_replace( '/[^a-zA-Z0-9!*\'();:@&=+$,\/?#\[\]\-_.~ ]/', '', $attr['pk'] ) );
|
||||
}
|
||||
|
||||
if ( isset( $attr['bg'] ) ) {
|
||||
$attr['bg'] = preg_replace( '![^-a-zA-Z0-9#]!', '', $attr['bg'] );
|
||||
}
|
||||
|
||||
$fv = array(
|
||||
'viewerSecureGatewayURL' => 'https://services.brightcove.com/services/amfgateway',
|
||||
'servicesURL' => 'http://services.brightcove.com/services',
|
||||
'cdnURL' => 'http://admin.brightcove.com',
|
||||
'autoStart' => 'false',
|
||||
);
|
||||
|
||||
$js_tld = 'com';
|
||||
$src = '';
|
||||
$name = 'flashObj';
|
||||
$html5 = false;
|
||||
|
||||
if ( isset( $attr['exp3'] ) ) {
|
||||
if ( isset( $attr['surl'] ) && strpos( $attr['surl'], 'brightcove.co.jp' ) ) {
|
||||
$js_tld = 'co.jp';
|
||||
}
|
||||
if ( ! isset( $attr['surl'] ) || ! preg_match( '#^https?://(?:[a-z\d-]+\.)*brightcove\.(?:com|co\.jp)/#', $attr['surl'] ) ) {
|
||||
$attr['surl'] = 'http://c.brightcove.com/services';
|
||||
}
|
||||
|
||||
$attr['exp3'] = (int) $attr['exp3'];
|
||||
$attr['pubid'] = (int) $attr['pubid'];
|
||||
$attr['vid'] = (int) $attr['vid'];
|
||||
|
||||
$fv['servicesURL'] = $attr['surl'];
|
||||
$fv['playerID'] = $attr['exp3'];
|
||||
$fv['domain'] = 'embed';
|
||||
$fv['videoID'] = (int) $attr['vid'];
|
||||
|
||||
$src = sprintf(
|
||||
'%s/viewer/federated_f9/%s?isVid=1&isUI=1&publisherID=%s',
|
||||
$attr['surl'],
|
||||
$attr['exp3'],
|
||||
$attr['pubid']
|
||||
);
|
||||
$html5 = true;
|
||||
} elseif ( isset( $attr['exp'] ) ) {
|
||||
$attr['exp'] = (int) $attr['exp'];
|
||||
$src = 'http://services.brightcove.com/services/viewer/federated_f8/' . $attr['exp'];
|
||||
if ( $attr['vid'] ) {
|
||||
$fv['videoId'] = $attr['vid'];
|
||||
} elseif ( $attr['vref'] ) {
|
||||
$fv['videoRef'] = $attr['vref'];
|
||||
}
|
||||
|
||||
$fv['playerId'] = $attr['exp'];
|
||||
$fv['domain'] = 'embed';
|
||||
} else {
|
||||
return '<small>brightcove error: missing required parameter exp or exp3</small>';
|
||||
}
|
||||
|
||||
if ( ! empty( $attr['lbu'] ) ) {
|
||||
$fv['linkBaseURL'] = $attr['lbu'];
|
||||
}
|
||||
|
||||
$flashvars = trim( add_query_arg( array_map( 'urlencode', $fv ), '' ), '?' );
|
||||
|
||||
$width = null;
|
||||
$height = null;
|
||||
|
||||
if ( ! empty( $attr['w'] ) && ! empty( $attr['h'] ) ) {
|
||||
$w = abs( (int) $attr['w'] );
|
||||
$h = abs( (int) $attr['h'] );
|
||||
if ( $w && $h ) {
|
||||
$width = $w;
|
||||
$height = $h;
|
||||
}
|
||||
} elseif ( empty( $attr['s'] ) || 'l' === $attr['s'] ) {
|
||||
$width = '480';
|
||||
$height = '360';
|
||||
}
|
||||
|
||||
if ( empty( $width ) || empty( $height ) ) {
|
||||
$width = '280';
|
||||
$height = '210';
|
||||
}
|
||||
|
||||
if ( $html5 ) {
|
||||
wp_enqueue_script(
|
||||
'brightcove-loader',
|
||||
Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/brightcove.min.js', 'modules/shortcodes/js/brightcove.js' ),
|
||||
array( 'jquery' ),
|
||||
20121127,
|
||||
false
|
||||
);
|
||||
wp_localize_script(
|
||||
'brightcove-loader',
|
||||
'brightcoveData',
|
||||
array(
|
||||
'tld' => esc_js( $js_tld ),
|
||||
)
|
||||
);
|
||||
|
||||
return '
|
||||
<object id="myExperience" class="BrightcoveExperience">
|
||||
<param name="bgcolor" value="' . esc_attr( $attr['bg'] ) . '" />
|
||||
<param name="width" value="' . esc_attr( $width ) . '" />
|
||||
<param name="height" value="' . esc_attr( $height ) . '" />
|
||||
<param name="playerID" value="' . esc_attr( $attr['exp3'] ) . '" />
|
||||
<param name="@videoPlayer" value="' . esc_attr( $attr['vid'] ) . '" />
|
||||
<param name="playerKey" value="' . esc_attr( $attr['pk'] ) . '" />
|
||||
<param name="isVid" value="1" />
|
||||
<param name="isUI" value="1" />
|
||||
<param name="dynamicStreaming" value="true" />
|
||||
<param name="autoStart" value="false" />
|
||||
<param name="secureConnections" value="true" />
|
||||
<param name="secureHTMLConnections" value="true" />
|
||||
</object>';
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<embed src="%s" bgcolor="#FFFFFF" flashvars="%s" base="http://admin.brightcove.com" name="%s" width="%s" height="%s" allowFullScreen="true" seamlesstabbing="false" type="application/x-shockwave-flash" swLiveConnect="true" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" />',
|
||||
esc_url( $src ),
|
||||
$flashvars,
|
||||
esc_attr( $name ),
|
||||
esc_attr( $width ),
|
||||
esc_attr( $height )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
add_shortcode( Jetpack_Brightcove_Shortcode::$shortcode, array( 'Jetpack_Brightcove_Shortcode', 'convert' ) );
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* Carto (formerly CartoDB)
|
||||
*
|
||||
* Example URL: http://osm2.carto.com/viz/08aef918-94da-11e4-ad83-0e0c41326911/public_map
|
||||
*
|
||||
* possible patterns:
|
||||
* [username].carto.com/viz/[map-id]/public_map
|
||||
* [username].carto.com/viz/[map-id]/embed_map
|
||||
* [username].carto.com/viz/[map-id]/map
|
||||
* [organization].carto.com/u/[username]/viz/[map-id]/public_map
|
||||
* [organization].carto.com/u/[username]/viz/[map-id]/embed_map
|
||||
* [organization].carto.com/u/[username]/viz/[map-id]/map
|
||||
*
|
||||
* On July 8th, 2016 CartoDB changed its primary domain from cartodb.com to carto.com
|
||||
* So this shortcode still supports the cartodb.com domain for oembeds.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
wp_oembed_add_provider( '#https?://(?:www\.)?[^/^\.]+\.carto(db)?\.com/\S+#i', 'https://services.carto.com/oembed', true );
|
||||
@@ -0,0 +1,403 @@
|
||||
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
/**
|
||||
* The companion file to shortcodes.php
|
||||
*
|
||||
* This file contains the code that converts HTML embeds into shortcodes
|
||||
* for when the user copy/pastes in HTML.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
add_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'filter' ), 11 );
|
||||
add_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'maybe_create_links' ), 100 ); // See WPCom_Embed_Stats::init().
|
||||
|
||||
/**
|
||||
* Helper class for identifying and parsing known HTML embeds (iframe, object, embed, etc. elements), then converting them to shortcodes.
|
||||
* For unknown HTML embeds, the class still tries to convert them to plain links so that at least something is preserved instead of having the entire element stripped by KSES.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
class Filter_Embedded_HTML_Objects {
|
||||
/**
|
||||
* Array of patterns to search for via strpos().
|
||||
* Keys are patterns, values are callback functions that implement the HTML -> shortcode replacement.
|
||||
* Patterns are matched against URLs (src or movie HTML attributes).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $strpos_filters = array();
|
||||
/**
|
||||
* Array of patterns to search for via preg_match().
|
||||
* Keys are patterns, values are callback functions that implement the HTML -> shortcode replacement.
|
||||
* Patterns are matched against URLs (src or movie HTML attributes).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $regexp_filters = array();
|
||||
/**
|
||||
* HTML element being processed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $current_element = false;
|
||||
/**
|
||||
* Array of patterns to search for via strpos().
|
||||
* Keys are patterns, values are callback functions that implement the HTML -> shortcode replacement.
|
||||
* Patterns are matched against full HTML elements.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $html_strpos_filters = array();
|
||||
/**
|
||||
* Array of patterns to search for via preg_match().
|
||||
* Keys are patterns, values are callback functions that implement the HTML -> shortcode replacement.
|
||||
* Patterns are matched against full HTML elements.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $html_regexp_filters = array();
|
||||
/**
|
||||
* Failed embeds (stripped)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $failed_embeds = array();
|
||||
|
||||
/**
|
||||
* Store tokens found in Syntax Highlighter.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $sh_unfiltered_content_tokens;
|
||||
|
||||
/**
|
||||
* Capture tokens found in Syntax Highlighter and collect them in self::$sh_unfiltered_content_tokens.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $match Array of Syntax Highlighter matches.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function sh_regexp_callback( $match ) {
|
||||
$token = sprintf(
|
||||
'[prekses-filter-token-%1$d-%2$s-%1$d]',
|
||||
wp_rand(),
|
||||
md5( $match[0] )
|
||||
);
|
||||
self::$sh_unfiltered_content_tokens[ $token ] = $match[0];
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for HTML elements that match the registered patterns.
|
||||
* Replace them with the HTML generated by the registered replacement callbacks.
|
||||
*
|
||||
* @param string $html Post content.
|
||||
*/
|
||||
public static function filter( $html ) {
|
||||
if ( ! $html || ! is_string( $html ) ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$regexps = array(
|
||||
'object' => '%<object[^>]*+>(?>[^<]*+(?><(?!/object>)[^<]*+)*)</object>%i',
|
||||
'embed' => '%<embed[^>]*+>(?:\s*</embed>)?%i',
|
||||
'iframe' => '%<iframe[^>]*+>(?>[^<]*+(?><(?!/iframe>)[^<]*+)*)</iframe>%i',
|
||||
'div' => '%<div[^>]*+>(?>[^<]*+(?><(?!/div>)[^<]*+)*+)(?:</div>)+%i',
|
||||
'script' => '%<script[^>]*+>(?>[^<]*+(?><(?!/script>)[^<]*+)*)</script>%i',
|
||||
);
|
||||
|
||||
$unfiltered_content_tokens = array();
|
||||
self::$sh_unfiltered_content_tokens = array();
|
||||
|
||||
// Check here to make sure that SyntaxHighlighter is still used. (Just a little future proofing).
|
||||
if ( class_exists( 'SyntaxHighlighter' ) ) {
|
||||
/*
|
||||
* Replace any "code" shortcode blocks with a token that we'll later replace with its original text.
|
||||
* This will keep the contents of the shortcode from being filtered.
|
||||
*/
|
||||
global $SyntaxHighlighter; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
|
||||
|
||||
// Check to see if the $syntax_highlighter object has been created and is ready for use.
|
||||
if ( isset( $SyntaxHighlighter ) && is_array( $SyntaxHighlighter->shortcodes ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
|
||||
$shortcode_regex = implode( '|', array_map( 'preg_quote', $SyntaxHighlighter->shortcodes ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
|
||||
$html = preg_replace_callback(
|
||||
'/\[(' . $shortcode_regex . ')(\s[^\]]*)?\][\s\S]*?\[\/\1\]/m',
|
||||
array( __CLASS__, 'sh_regexp_callback' ),
|
||||
$html
|
||||
);
|
||||
$unfiltered_content_tokens = self::$sh_unfiltered_content_tokens;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $regexps as $element => $regexp ) {
|
||||
self::$current_element = $element;
|
||||
|
||||
if ( false !== stripos( $html, "<$element" ) ) {
|
||||
$new_html = preg_replace_callback( $regexp, array( __CLASS__, 'dispatch' ), $html );
|
||||
if ( $new_html ) {
|
||||
$html = $new_html;
|
||||
}
|
||||
}
|
||||
|
||||
if ( false !== stripos( $html, "<$element" ) ) {
|
||||
$regexp_entities = self::regexp_entities( $regexp );
|
||||
$new_html = preg_replace_callback( $regexp_entities, array( __CLASS__, 'dispatch_entities' ), $html );
|
||||
if ( $new_html ) {
|
||||
$html = $new_html;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $unfiltered_content_tokens !== array() ) {
|
||||
// Replace any tokens generated earlier with their original unfiltered text.
|
||||
$html = str_replace( array_keys( $unfiltered_content_tokens ), $unfiltered_content_tokens, $html );
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace HTML entities in current HTML element regexp.
|
||||
* This is useful when the content is HTML encoded by TinyMCE.
|
||||
*
|
||||
* @param string $regexp Selected regexp.
|
||||
*/
|
||||
public static function regexp_entities( $regexp ) {
|
||||
return preg_replace(
|
||||
'/\[\^&([^\]]+)\]\*\+/',
|
||||
'(?>[^&]*+(?>&(?!\1)[^&])*+)*+',
|
||||
str_replace( '?>', '?' . '>', htmlspecialchars( $regexp, ENT_NOQUOTES ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a filter to convert a matching HTML element to a shortcode.
|
||||
*
|
||||
* We can match the provided pattern against the source URL of the HTML element
|
||||
* (generally the value of the src attribute of the HTML element), or against the full HTML element.
|
||||
*
|
||||
* The callback is passed an array containing the raw HTML of the element as well as pre-parsed attribute name/values.
|
||||
*
|
||||
* @param string $match Pattern to search for: either a regular expression to use with preg_match() or a search string to use with strpos().
|
||||
* @param string $callback Function used to convert embed into shortcode.
|
||||
* @param bool $is_regexp Is $match a regular expression? If true, match using preg_match(). If not, match using strpos(). Default false.
|
||||
* @param bool $is_html_filter Match the pattern against the full HTML (true) or just the source URL (false)? Default false.
|
||||
*/
|
||||
public static function register( $match, $callback, $is_regexp = false, $is_html_filter = false ) {
|
||||
if ( $is_html_filter ) {
|
||||
if ( $is_regexp ) {
|
||||
self::$html_regexp_filters[ $match ] = $callback;
|
||||
} else {
|
||||
self::$html_strpos_filters[ $match ] = $callback;
|
||||
}
|
||||
} elseif ( $is_regexp ) {
|
||||
self::$regexp_filters[ $match ] = $callback;
|
||||
} else {
|
||||
self::$strpos_filters[ $match ] = $callback;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing registered pattern/replacement filter.
|
||||
*
|
||||
* @param string $match Embed regexp.
|
||||
*/
|
||||
public static function unregister( $match ) {
|
||||
// Allow themes/plugins to remove registered embeds.
|
||||
unset( self::$regexp_filters[ $match ] );
|
||||
unset( self::$strpos_filters[ $match ] );
|
||||
unset( self::$html_regexp_filters[ $match ] );
|
||||
unset( self::$html_strpos_filters[ $match ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter and replace HTML element entity.
|
||||
*
|
||||
* @param array $matches Array of matches.
|
||||
*/
|
||||
private static function dispatch_entities( $matches ) {
|
||||
$orig_html = $matches[0];
|
||||
$decoded_matches = array( html_entity_decode( $matches[0], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ) );
|
||||
|
||||
return self::dispatch( $decoded_matches, $orig_html );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter and replace HTML element.
|
||||
*
|
||||
* @param array $matches Array of matches.
|
||||
* @param string $orig_html Original html. Returned if no results are found via $matches processing.
|
||||
*/
|
||||
private static function dispatch( $matches, $orig_html = null ) {
|
||||
if ( null === $orig_html ) {
|
||||
$orig_html = $matches[0];
|
||||
}
|
||||
$html = preg_replace( '%�*58;//%', '://', $matches[0] );
|
||||
$attrs = self::get_attrs( $html );
|
||||
if ( isset( $attrs['src'] ) ) {
|
||||
$src = $attrs['src'];
|
||||
} elseif ( isset( $attrs['movie'] ) ) {
|
||||
$src = $attrs['movie'];
|
||||
} else {
|
||||
// no src found, search html.
|
||||
foreach ( self::$html_strpos_filters as $match => $callback ) {
|
||||
if ( str_contains( $html, $match ) ) {
|
||||
return call_user_func( $callback, $attrs );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( self::$html_regexp_filters as $match => $callback ) {
|
||||
if ( preg_match( $match, $html ) ) {
|
||||
return call_user_func( $callback, $attrs );
|
||||
}
|
||||
}
|
||||
|
||||
return $orig_html;
|
||||
}
|
||||
|
||||
$src = trim( $src );
|
||||
|
||||
// check source filter.
|
||||
foreach ( self::$strpos_filters as $match => $callback ) {
|
||||
if ( str_contains( $src, $match ) ) {
|
||||
return call_user_func( $callback, $attrs );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( self::$regexp_filters as $match => $callback ) {
|
||||
if ( preg_match( $match, $src ) ) {
|
||||
return call_user_func( $callback, $attrs );
|
||||
}
|
||||
}
|
||||
|
||||
// check html filters.
|
||||
foreach ( self::$html_strpos_filters as $match => $callback ) {
|
||||
if ( str_contains( $html, $match ) ) {
|
||||
return call_user_func( $callback, $attrs );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( self::$html_regexp_filters as $match => $callback ) {
|
||||
if ( preg_match( $match, $html ) ) {
|
||||
return call_user_func( $callback, $attrs );
|
||||
}
|
||||
}
|
||||
|
||||
// Log the strip.
|
||||
if ( function_exists( 'wp_kses_reject' ) ) {
|
||||
wp_kses_reject(
|
||||
sprintf(
|
||||
/* translators: placeholder is an HTML tag. */
|
||||
__( '<code>%s</code> HTML tag removed as it is not allowed', 'jetpack' ),
|
||||
'<' . self::$current_element . '>'
|
||||
),
|
||||
array( self::$current_element => $attrs )
|
||||
);
|
||||
}
|
||||
|
||||
// Keep the failed match so we can later replace it with a link,
|
||||
// but return the original content to give others a chance too.
|
||||
self::$failed_embeds[] = array(
|
||||
'match' => $orig_html,
|
||||
'src' => esc_url( $src ),
|
||||
);
|
||||
|
||||
return $orig_html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Failed embeds are stripped, so let's convert them to links at least.
|
||||
*
|
||||
* @param string $string Failed embed string.
|
||||
*
|
||||
* @return string $string Linkified string.
|
||||
*/
|
||||
public static function maybe_create_links( $string ) {
|
||||
if ( empty( self::$failed_embeds ) ) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
foreach ( self::$failed_embeds as $entry ) {
|
||||
$html = sprintf( '<a href="%s">%s</a>', esc_url( $entry['src'] ), esc_url( $entry['src'] ) );
|
||||
// Check if the string doesn't contain iframe, before replace.
|
||||
if ( ! preg_match( '/<iframe /', $string ) ) {
|
||||
$string = str_replace( $entry['match'], $html, $string );
|
||||
}
|
||||
}
|
||||
|
||||
self::$failed_embeds = array();
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse post HTML for HTML tags.
|
||||
*
|
||||
* @param string $html Post HTML.
|
||||
*/
|
||||
public static function get_attrs( $html ) {
|
||||
if (
|
||||
! ( class_exists( 'DOMDocument' ) && function_exists( 'simplexml_load_string' ) ) ) {
|
||||
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
|
||||
esc_html__( 'PHP’s XML extension is not available. Please contact your hosting provider to enable PHP’s XML extension.', 'jetpack' )
|
||||
);
|
||||
return array();
|
||||
}
|
||||
// We have to go through DOM, since it can load non-well-formed XML (i.e. HTML). SimpleXML cannot.
|
||||
$dom = new DOMDocument();
|
||||
// The @ is not enough to suppress errors when dealing with libxml,
|
||||
// we have to tell it directly how we want to handle errors.
|
||||
libxml_use_internal_errors( true );
|
||||
// Suppress parser warnings.
|
||||
@$dom->loadHTML( $html ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
|
||||
libxml_use_internal_errors( false );
|
||||
$xml = false;
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
foreach ( $dom->childNodes as $node ) {
|
||||
// find the root node (html).
|
||||
if ( XML_ELEMENT_NODE === $node->nodeType ) {
|
||||
/*
|
||||
* Use simplexml_load_string rather than simplexml_import_dom
|
||||
* as the later doesn't cope well if the XML is malformmed in the DOM
|
||||
* See #1688-wpcom.
|
||||
*/
|
||||
libxml_use_internal_errors( true );
|
||||
// html->body->object.
|
||||
$xml = simplexml_load_string( $dom->saveXML( $node->firstChild->firstChild ) );
|
||||
libxml_clear_errors();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
|
||||
if ( ! $xml ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$attrs = array();
|
||||
$attrs['_raw_html'] = $html;
|
||||
|
||||
// <param> elements
|
||||
foreach ( $xml->param as $param ) {
|
||||
$attrs[ (string) $param['name'] ] = (string) $param['value'];
|
||||
}
|
||||
|
||||
// <object> attributes
|
||||
foreach ( $xml->attributes() as $name => $attr ) {
|
||||
$attrs[ $name ] = (string) $attr;
|
||||
}
|
||||
|
||||
// <embed> attributes
|
||||
if ( $xml->embed ) {
|
||||
foreach ( $xml->embed->attributes() as $name => $attr ) {
|
||||
$attrs[ $name ] = (string) $attr;
|
||||
}
|
||||
}
|
||||
|
||||
return $attrs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* CodePen embed
|
||||
*
|
||||
* Example URL: http://codepen.io/css-tricks/pen/wFeaG
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
// Register oEmbed provider.
|
||||
wp_oembed_add_provider( '#https?://codepen.io/([^/]+)/pen/([^/]+)/?#', 'https://codepen.io/api/oembed', true );
|
||||
@@ -0,0 +1,760 @@
|
||||
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
/**
|
||||
* Crowdsignal (PollDaddy) shortcode.
|
||||
*
|
||||
* Formats:
|
||||
* [polldaddy type="iframe" survey="EB151947E5950FCF" height="auto" domain="jeherve" id="a-survey-with-branches"]
|
||||
* [crowdsignal type="iframe" survey="EB151947E5950FCF" height="auto" domain="jeherve" id="a-survey-with-branches"]
|
||||
* https://polldaddy.com/poll/7910844/
|
||||
* https://jeherve.survey.fm/a-survey
|
||||
* https://jeherve.survey.fm/a-survey-with-branches
|
||||
* [crowdsignal type="iframe" survey="7676FB1FF2B56CE9" height="auto" domain="jeherve" id="a-survey"]
|
||||
* [crowdsignal survey="7676FB1FF2B56CE9"]
|
||||
* [polldaddy survey="7676FB1FF2B56CE9"]
|
||||
* [crowdsignal poll=9541291]
|
||||
* [crowdsignal poll=9541291 type=slider]
|
||||
* [crowdsignal rating=8755352]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
// phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
|
||||
|
||||
use Automattic\Jetpack\Assets;
|
||||
use Automattic\Jetpack\Constants;
|
||||
|
||||
// Keep compatibility with the PollDaddy plugin.
|
||||
if (
|
||||
! class_exists( 'CrowdsignalShortcode' )
|
||||
&& ! class_exists( 'PolldaddyShortcode' )
|
||||
) {
|
||||
/**
|
||||
* Class wrapper for Crowdsignal shortcodes
|
||||
*/
|
||||
class CrowdsignalShortcode {
|
||||
|
||||
/**
|
||||
* Should the Crowdsignal JavaScript be added to the page?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $add_script = false;
|
||||
|
||||
/**
|
||||
* Array of Polls / Surveys present on the page, and that need to be added.
|
||||
*
|
||||
* @var bool|array
|
||||
*/
|
||||
private static $scripts = false;
|
||||
|
||||
/**
|
||||
* Add all the actions & register the shortcode.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'register_scripts' ) );
|
||||
|
||||
add_shortcode( 'crowdsignal', array( $this, 'crowdsignal_shortcode' ) );
|
||||
add_shortcode( 'polldaddy', array( $this, 'polldaddy_shortcode' ) );
|
||||
|
||||
add_filter( 'pre_kses', array( $this, 'crowdsignal_embed_to_shortcode' ) );
|
||||
add_action( 'infinite_scroll_render', array( $this, 'crowdsignal_shortcode_infinite' ), 11 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register scripts that may be enqueued later on by the shortcode.
|
||||
*/
|
||||
public static function register_scripts() {
|
||||
wp_register_script(
|
||||
'crowdsignal-shortcode',
|
||||
Assets::get_file_url_for_environment( '_inc/build/crowdsignal-shortcode.min.js', '_inc/crowdsignal-shortcode.js' ),
|
||||
array(),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
wp_register_script(
|
||||
'crowdsignal-survey',
|
||||
Assets::get_file_url_for_environment( '_inc/build/crowdsignal-survey.min.js', '_inc/crowdsignal-survey.js' ),
|
||||
array(),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
wp_register_script(
|
||||
'crowdsignal-rating',
|
||||
'https://polldaddy.com/js/rating/rating.js',
|
||||
array(),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript code for a specific survey / poll.
|
||||
*
|
||||
* @param array $settings Array of information about a survey / poll.
|
||||
* @param string $survey_link HTML link tag for a specific survey or poll.
|
||||
* @param string $survey_url Link to the survey or poll.
|
||||
*/
|
||||
private function get_async_code( array $settings, $survey_link, $survey_url ) {
|
||||
wp_enqueue_script( 'crowdsignal-survey' );
|
||||
|
||||
if ( 'button' === $settings['type'] ) {
|
||||
$placeholder = sprintf(
|
||||
'<a class="cs-embed pd-embed" href="%1$s" data-settings="%2$s">%3$s</a>',
|
||||
esc_url( $survey_url ),
|
||||
esc_attr( wp_json_encode( $settings ) ),
|
||||
esc_html( $settings['title'] )
|
||||
);
|
||||
} else {
|
||||
$placeholder = sprintf(
|
||||
'<div class="cs-embed pd-embed" data-settings="%1$s"></div><noscript>%2$s</noscript>',
|
||||
esc_attr( wp_json_encode( $settings ) ),
|
||||
$survey_link
|
||||
);
|
||||
}
|
||||
|
||||
return $placeholder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crowdsignal Poll Embed script - transforms code that looks like that:
|
||||
* <script type="text/javascript" charset="utf-8" async src="http://static.polldaddy.com/p/123456.js"></script>
|
||||
* <noscript><a href="http://polldaddy.com/poll/123456/">What is your favourite color?</a></noscript>
|
||||
* into the [crowdsignal poll=...] shortcode format
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*/
|
||||
public function crowdsignal_embed_to_shortcode( $content ) {
|
||||
|
||||
if ( ! is_string( $content ) || ! str_contains( $content, 'polldaddy.com/p/' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$regexes = array();
|
||||
|
||||
$regexes[] = '#<script[^>]+?src="https?://(secure|static)\.polldaddy\.com/p/([0-9]+)\.js"[^>]*+>\s*?</script>\r?\n?(<noscript>.*?</noscript>)?#i';
|
||||
|
||||
$regexes[] = '#<script(?:[^&]|&(?!gt;))+?src="https?://(secure|static)\.polldaddy\.com/p/([0-9]+)\.js"(?:[^&]|&(?!gt;))*+>\s*?</script>\r?\n?(<noscript>.*?</noscript>)?#i';
|
||||
|
||||
foreach ( $regexes as $regex ) {
|
||||
if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
if ( ! isset( $match[2] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$id = (int) $match[2];
|
||||
|
||||
if ( $id > 0 ) {
|
||||
$content = str_replace( $match[0], " [crowdsignal poll=$id]", $content );
|
||||
/** This action is documented in modules/shortcodes/youtube.php */
|
||||
do_action( 'jetpack_embed_to_shortcode', 'crowdsignal', $id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for legacy Polldaddy shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
public function polldaddy_shortcode( $atts ) {
|
||||
if ( ! is_array( $atts ) ) {
|
||||
return '<!-- Polldaddy shortcode passed invalid attributes -->';
|
||||
}
|
||||
|
||||
$atts['site'] = 'polldaddy.com';
|
||||
return $this->crowdsignal_shortcode( $atts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcode for Crowdsignal
|
||||
* [crowdsignal poll|survey|rating="123456"]
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
public function crowdsignal_shortcode( $atts ) {
|
||||
global $post;
|
||||
global $content_width;
|
||||
|
||||
if ( ! is_array( $atts ) ) {
|
||||
return '<!-- Crowdsignal shortcode passed invalid attributes -->';
|
||||
}
|
||||
|
||||
$attributes = shortcode_atts(
|
||||
array(
|
||||
'survey' => null,
|
||||
'link_text' => esc_html__( 'Take Our Survey', 'jetpack' ),
|
||||
'poll' => 'empty',
|
||||
'rating' => 'empty',
|
||||
'unique_id' => null,
|
||||
'item_id' => null,
|
||||
'title' => null,
|
||||
'permalink' => null,
|
||||
'cb' => 0, // cache buster. Helps with testing.
|
||||
'type' => 'button',
|
||||
'body' => '',
|
||||
'button' => '',
|
||||
'text_color' => '000000',
|
||||
'back_color' => 'FFFFFF',
|
||||
'align' => '',
|
||||
'style' => '',
|
||||
'width' => $content_width,
|
||||
'height' => floor( $content_width * 3 / 4 ),
|
||||
'delay' => 100,
|
||||
'visit' => 'single',
|
||||
'domain' => '',
|
||||
'id' => '',
|
||||
'site' => 'crowdsignal.com',
|
||||
),
|
||||
$atts,
|
||||
'crowdsignal'
|
||||
);
|
||||
|
||||
$inline = ! in_the_loop()
|
||||
&& ! Constants::is_defined( 'TESTING_IN_JETPACK' );
|
||||
|
||||
$no_script = false;
|
||||
$infinite_scroll = false;
|
||||
|
||||
if ( is_home() && current_theme_supports( 'infinite-scroll' ) ) {
|
||||
$infinite_scroll = true;
|
||||
}
|
||||
|
||||
if ( function_exists( 'get_option' ) && get_option( 'polldaddy_load_poll_inline' ) ) {
|
||||
$inline = true;
|
||||
}
|
||||
|
||||
if ( is_feed() || ( defined( 'DOING_AJAX' ) && ! $infinite_scroll ) ) {
|
||||
$no_script = false;
|
||||
}
|
||||
|
||||
self::$add_script = $infinite_scroll;
|
||||
|
||||
/*
|
||||
* Rating embed.
|
||||
*/
|
||||
if ( (int) $attributes['rating'] > 0 && ! $no_script ) {
|
||||
|
||||
if ( empty( $attributes['unique_id'] ) ) {
|
||||
$attributes['unique_id'] = is_page() ? 'wp-page-' . $post->ID : 'wp-post-' . $post->ID;
|
||||
}
|
||||
|
||||
if ( empty( $attributes['item_id'] ) ) {
|
||||
$attributes['item_id'] = is_page() ? '_page_' . $post->ID : '_post_' . $post->ID;
|
||||
}
|
||||
|
||||
if ( empty( $attributes['title'] ) ) {
|
||||
/** This filter is documented in core/src/wp-includes/general-template.php */
|
||||
$attributes['title'] = apply_filters( 'wp_title', $post->post_title, '', '' );
|
||||
}
|
||||
|
||||
if ( empty( $attributes['permalink'] ) ) {
|
||||
$attributes['permalink'] = get_permalink( $post->ID );
|
||||
}
|
||||
|
||||
$rating = (int) $attributes['rating'];
|
||||
$unique_id = sanitize_key( wp_strip_all_tags( $attributes['unique_id'] ) );
|
||||
$item_id = wp_strip_all_tags( $attributes['item_id'] );
|
||||
$item_id = preg_replace( '/[^_a-z0-9]/i', '', $item_id );
|
||||
|
||||
$settings = wp_json_encode(
|
||||
array(
|
||||
'id' => $rating,
|
||||
'unique_id' => $unique_id,
|
||||
'title' => rawurlencode( trim( $attributes['title'] ) ),
|
||||
'permalink' => esc_url( $attributes['permalink'] ),
|
||||
'item_id' => $item_id,
|
||||
)
|
||||
);
|
||||
|
||||
$item_id = esc_js( $item_id );
|
||||
|
||||
if (
|
||||
class_exists( 'Jetpack_AMP_Support' )
|
||||
&& Jetpack_AMP_Support::is_amp_request()
|
||||
) {
|
||||
return sprintf(
|
||||
'<a href="%s" target="_blank">%s</a>',
|
||||
esc_url( $attributes['permalink'] ),
|
||||
esc_html( trim( $attributes['title'] ) )
|
||||
);
|
||||
} elseif ( $inline ) {
|
||||
$rating_js = "<!--//--><![CDATA[//><!--\n";
|
||||
$rating_js .= "PDRTJS_settings_{$rating}{$item_id}={$settings};";
|
||||
$rating_js .= "\n//--><!]]>";
|
||||
|
||||
wp_enqueue_script( 'crowdsignal-rating' );
|
||||
wp_add_inline_script(
|
||||
'crowdsignal-rating',
|
||||
$rating_js,
|
||||
'before'
|
||||
);
|
||||
|
||||
return sprintf(
|
||||
'<div class="cs-rating pd-rating" id="pd_rating_holder_%1$d%2$s"></div>',
|
||||
absint( $rating ),
|
||||
esc_attr( $item_id )
|
||||
);
|
||||
} else {
|
||||
if ( false === self::$scripts ) {
|
||||
self::$scripts = array();
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'id' => $rating,
|
||||
'item_id' => $item_id,
|
||||
'settings' => $settings,
|
||||
);
|
||||
|
||||
self::$scripts['rating'][] = $data;
|
||||
|
||||
add_action( 'wp_footer', array( $this, 'generate_scripts' ) );
|
||||
|
||||
if ( $infinite_scroll ) {
|
||||
return sprintf(
|
||||
'<div class="cs-rating pd-rating" id="pd_rating_holder_%1$d%2$s" data-settings="%3$s"></div>',
|
||||
absint( $rating ),
|
||||
esc_attr( $item_id ),
|
||||
esc_attr( wp_json_encode( $data ) )
|
||||
);
|
||||
} else {
|
||||
return sprintf(
|
||||
'<div class="cs-rating pd-rating" id="pd_rating_holder_%1$d%2$s"></div>',
|
||||
absint( $rating ),
|
||||
esc_attr( $item_id )
|
||||
);
|
||||
}
|
||||
}
|
||||
} elseif ( (int) $attributes['poll'] > 0 ) {
|
||||
/*
|
||||
* Poll embed.
|
||||
*/
|
||||
|
||||
if ( empty( $attributes['title'] ) ) {
|
||||
$attributes['title'] = esc_html__( 'Take Our Poll', 'jetpack' );
|
||||
}
|
||||
|
||||
$poll = (int) $attributes['poll'];
|
||||
|
||||
if ( 'crowdsignal.com' === $attributes['site'] ) {
|
||||
$poll_url = sprintf( 'https://poll.fm/%d', $poll );
|
||||
} else {
|
||||
$poll_url = sprintf( 'https://polldaddy.com/p/%d', $poll );
|
||||
}
|
||||
|
||||
$poll_js = sprintf( 'https://secure.polldaddy.com/p/%d.js', $poll );
|
||||
$poll_link = sprintf(
|
||||
'<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
|
||||
esc_url( $poll_url ),
|
||||
esc_html( $attributes['title'] )
|
||||
);
|
||||
|
||||
if (
|
||||
$no_script
|
||||
|| ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() )
|
||||
) {
|
||||
return $poll_link;
|
||||
} elseif ( 'slider' === $attributes['type'] && ! $inline ) { // Slider poll.
|
||||
if ( ! in_array(
|
||||
$attributes['visit'],
|
||||
array( 'single', 'multiple' ),
|
||||
true
|
||||
) ) {
|
||||
$attributes['visit'] = 'single';
|
||||
}
|
||||
|
||||
$settings = array(
|
||||
'type' => 'slider',
|
||||
'embed' => 'poll',
|
||||
'delay' => (int) $attributes['delay'],
|
||||
'visit' => $attributes['visit'],
|
||||
'id' => (int) $poll,
|
||||
'site' => $attributes['site'],
|
||||
);
|
||||
|
||||
return $this->get_async_code( $settings, $poll_link, $poll_url );
|
||||
} else {
|
||||
if ( 1 === $attributes['cb'] ) {
|
||||
$attributes['cb'] = '?cb=' . time();
|
||||
} else {
|
||||
$attributes['cb'] = false;
|
||||
}
|
||||
$margins = '';
|
||||
$float = '';
|
||||
|
||||
if ( in_array(
|
||||
$attributes['align'],
|
||||
array( 'right', 'left' ),
|
||||
true
|
||||
) ) {
|
||||
$float = sprintf( 'float: %s;', $attributes['align'] );
|
||||
|
||||
if ( 'left' === $attributes['align'] ) {
|
||||
$margins = 'margin: 0px 10px 0px 0px;';
|
||||
} elseif ( 'right' === $attributes['align'] ) {
|
||||
$margins = 'margin: 0px 0px 0px 10px';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the normal style embed on single posts/pages
|
||||
* otherwise it's not rendered on infinite scroll themed blogs
|
||||
* ('infinite_scroll_render' isn't fired)
|
||||
*/
|
||||
if ( is_singular() ) {
|
||||
$inline = true;
|
||||
}
|
||||
|
||||
if ( false === $attributes['cb'] && ! $inline ) {
|
||||
if ( false === self::$scripts ) {
|
||||
self::$scripts = array();
|
||||
}
|
||||
|
||||
$data = array( 'url' => $poll_js );
|
||||
|
||||
self::$scripts['poll'][ (int) $poll ] = $data;
|
||||
|
||||
add_action( 'wp_footer', array( $this, 'generate_scripts' ) );
|
||||
|
||||
wp_enqueue_script( 'crowdsignal-shortcode' );
|
||||
wp_localize_script(
|
||||
'crowdsignal-shortcode',
|
||||
'crowdsignal_shortcode_options',
|
||||
array(
|
||||
'script_url' => esc_url_raw(
|
||||
Assets::get_file_url_for_environment(
|
||||
'_inc/build/polldaddy-shortcode.min.js',
|
||||
'_inc/polldaddy-shortcode.js'
|
||||
)
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Hook into the Crowdsignal shortcode before rendering.
|
||||
*
|
||||
* @since 8.4.0
|
||||
*
|
||||
* @param int $poll Poll ID.
|
||||
*/
|
||||
do_action( 'crowdsignal_shortcode_before', (int) $poll );
|
||||
|
||||
return sprintf(
|
||||
'<a name="pd_a_%1$d"></a><div class="CSS_Poll PDS_Poll" id="PDI_container%1$d" data-settings="%2$s" style="%3$s%4$s"></div><div id="PD_superContainer"></div><noscript>%5$s</noscript>',
|
||||
absint( $poll ),
|
||||
esc_attr( wp_json_encode( $data ) ),
|
||||
$float,
|
||||
$margins,
|
||||
$poll_link
|
||||
);
|
||||
} else {
|
||||
if ( $inline ) {
|
||||
$attributes['cb'] = '';
|
||||
}
|
||||
|
||||
wp_enqueue_script(
|
||||
'crowdsignal-' . absint( $poll ),
|
||||
esc_url( $poll_js . $attributes['cb'] ),
|
||||
array(),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
/** This action is already documented in modules/shortcodes/crowdsignal.php */
|
||||
do_action( 'crowdsignal_shortcode_before', (int) $poll );
|
||||
|
||||
return sprintf(
|
||||
'<a id="pd_a_%1$s"></a><div class="CSS_Poll PDS_Poll" id="PDI_container%1$s" style="%2$s%3$s"></div><div id="PD_superContainer"></div><noscript>%4$s</noscript>',
|
||||
absint( $poll ),
|
||||
$float,
|
||||
$margins,
|
||||
$poll_link
|
||||
);
|
||||
}
|
||||
}
|
||||
} elseif ( ! empty( $attributes['survey'] ) ) {
|
||||
/*
|
||||
* Survey embed.
|
||||
*/
|
||||
|
||||
if ( in_array(
|
||||
$attributes['type'],
|
||||
array( 'iframe', 'button', 'banner', 'slider' ),
|
||||
true
|
||||
) ) {
|
||||
|
||||
if ( empty( $attributes['title'] ) ) {
|
||||
$attributes['title'] = esc_html__( 'Take Our Survey', 'jetpack' );
|
||||
if ( ! empty( $attributes['link_text'] ) ) {
|
||||
$attributes['title'] = $attributes['link_text'];
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
'banner' === $attributes['type']
|
||||
|| 'slider' === $attributes['type']
|
||||
) {
|
||||
$inline = false;
|
||||
}
|
||||
|
||||
$survey_url = '';
|
||||
|
||||
if ( 'true' !== $attributes['survey'] ) {
|
||||
$survey = preg_replace( '/[^a-f0-9]/i', '', $attributes['survey'] );
|
||||
|
||||
if ( 'crowdsignal.com' === $attributes['site'] ) {
|
||||
$survey_url = 'https://survey.fm/' . $survey;
|
||||
} else {
|
||||
$survey_url = 'https://polldaddy.com/s/' . $survey;
|
||||
}
|
||||
} elseif ( isset( $attributes['domain'] ) && isset( $attributes['id'] ) ) {
|
||||
$survey_domain = preg_replace( '/[^a-z0-9\-]/i', '', $attributes['domain'] );
|
||||
$survey_id = preg_replace( '/[\/\?&\{\}]/', '', $attributes['id'] );
|
||||
$survey_url = sprintf(
|
||||
'https://%1$s.survey.fm/%2$s',
|
||||
$survey_domain,
|
||||
$survey_id
|
||||
);
|
||||
}
|
||||
|
||||
$survey_link = sprintf(
|
||||
'<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
|
||||
esc_url( $survey_url ),
|
||||
esc_html( $attributes['title'] )
|
||||
);
|
||||
|
||||
$settings = array();
|
||||
|
||||
if ( 'iframe' === $attributes['type'] ) {
|
||||
if ( 'auto' !== $attributes['height'] ) {
|
||||
if (
|
||||
is_numeric( $content_width )
|
||||
&& $content_width > 0
|
||||
&& is_numeric( $attributes['width'] )
|
||||
&& $attributes['width'] > $content_width
|
||||
) {
|
||||
$attributes['width'] = $content_width;
|
||||
}
|
||||
|
||||
if ( ! $attributes['width'] ) {
|
||||
$attributes['width'] = '100%';
|
||||
} else {
|
||||
$attributes['width'] = (int) $attributes['width'];
|
||||
}
|
||||
|
||||
if ( ! $attributes['height'] ) {
|
||||
$attributes['height'] = '600';
|
||||
} else {
|
||||
$attributes['height'] = (int) $attributes['height'];
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<iframe src="%1$s?iframe=1" frameborder="0" width="%2$d" height="%3$d" scrolling="auto" allowtransparency="true" marginheight="0" marginwidth="0">%4$s</iframe>',
|
||||
esc_url( $survey_url ),
|
||||
absint( $attributes['width'] ),
|
||||
absint( $attributes['height'] ),
|
||||
$survey_link
|
||||
);
|
||||
} elseif (
|
||||
! empty( $attributes['domain'] )
|
||||
&& ! empty( $attributes['id'] )
|
||||
) {
|
||||
$domain = preg_replace( '/[^a-z0-9\-]/i', '', $attributes['domain'] );
|
||||
$id = preg_replace( '/[\/\?&\{\}]/', '', $attributes['id'] );
|
||||
|
||||
$auto_src = esc_url( "https://{$domain}.survey.fm/{$id}" );
|
||||
$auto_src = wp_parse_url( $auto_src );
|
||||
|
||||
if ( ! is_array( $auto_src ) || array() === $auto_src ) {
|
||||
return '<!-- no crowdsignal output -->';
|
||||
}
|
||||
|
||||
if ( ! isset( $auto_src['host'] ) || ! isset( $auto_src['path'] ) ) {
|
||||
return '<!-- no crowdsignal output -->';
|
||||
}
|
||||
|
||||
$domain = $auto_src['host'] . '/';
|
||||
$id = ltrim( $auto_src['path'], '/' );
|
||||
|
||||
$settings = array(
|
||||
'type' => $attributes['type'],
|
||||
'auto' => true,
|
||||
'domain' => $domain,
|
||||
'id' => $id,
|
||||
'site' => $attributes['site'],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$text_color = sanitize_hex_color_no_hash( $attributes['text_color'] );
|
||||
$back_color = sanitize_hex_color_no_hash( $attributes['back_color'] );
|
||||
|
||||
if (
|
||||
! in_array(
|
||||
$attributes['align'],
|
||||
array(
|
||||
'right',
|
||||
'left',
|
||||
'top-left',
|
||||
'top-right',
|
||||
'middle-left',
|
||||
'middle-right',
|
||||
'bottom-left',
|
||||
'bottom-right',
|
||||
),
|
||||
true
|
||||
)
|
||||
) {
|
||||
$attributes['align'] = '';
|
||||
}
|
||||
|
||||
if (
|
||||
! in_array(
|
||||
$attributes['style'],
|
||||
array(
|
||||
'inline',
|
||||
'side',
|
||||
'corner',
|
||||
'rounded',
|
||||
'square',
|
||||
),
|
||||
true
|
||||
)
|
||||
) {
|
||||
$attributes['style'] = '';
|
||||
}
|
||||
|
||||
$settings = array_filter(
|
||||
array(
|
||||
'title' => wp_strip_all_tags( $attributes['title'] ),
|
||||
'type' => $attributes['type'],
|
||||
'body' => wp_strip_all_tags( $attributes['body'] ),
|
||||
'button' => wp_strip_all_tags( $attributes['button'] ),
|
||||
'text_color' => $text_color,
|
||||
'back_color' => $back_color,
|
||||
'align' => $attributes['align'],
|
||||
'style' => $attributes['style'],
|
||||
'id' => $survey,
|
||||
'site' => $attributes['site'],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( empty( $settings ) ) {
|
||||
return '<!-- no crowdsignal output -->';
|
||||
}
|
||||
|
||||
return $this->get_async_code( $settings, $survey_link, $survey_url );
|
||||
}
|
||||
} else {
|
||||
return '<!-- no crowdsignal output -->';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue JavaScript containing all ratings / polls on the page.
|
||||
* Hooked into wp_footer
|
||||
*/
|
||||
public function generate_scripts() {
|
||||
if ( is_array( self::$scripts ) ) {
|
||||
if ( isset( self::$scripts['rating'] ) ) {
|
||||
$script = "<!--//--><![CDATA[//><!--\n";
|
||||
foreach ( self::$scripts['rating'] as $rating ) {
|
||||
$script .= "PDRTJS_settings_{$rating['id']}{$rating['item_id']}={$rating['settings']}; if ( typeof PDRTJS_RATING !== 'undefined' ){if ( typeof PDRTJS_{$rating['id']}{$rating['item_id']} == 'undefined' ){PDRTJS_{$rating['id']}{$rating['item_id']} = new PDRTJS_RATING( PDRTJS_settings_{$rating['id']}{$rating['item_id']} );}}";
|
||||
}
|
||||
$script .= "\n//--><!]]>";
|
||||
|
||||
wp_enqueue_script( 'crowdsignal-rating' );
|
||||
wp_add_inline_script(
|
||||
'crowdsignal-rating',
|
||||
$script,
|
||||
'before'
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset( self::$scripts['poll'] ) ) {
|
||||
foreach ( self::$scripts['poll'] as $poll_id => $poll ) {
|
||||
wp_enqueue_script(
|
||||
'crowdsignal-' . absint( $poll_id ),
|
||||
esc_url( $poll['url'] ),
|
||||
array(),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
self::$scripts = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically load the .js, if needed
|
||||
*
|
||||
* This hooks in late (priority 11) to infinite_scroll_render to determine
|
||||
* a posteriori if a shortcode has been called.
|
||||
*/
|
||||
public function crowdsignal_shortcode_infinite() {
|
||||
// only try to load if a shortcode has been called and theme supports infinite scroll.
|
||||
if ( self::$add_script ) {
|
||||
wp_enqueue_script( 'crowdsignal-shortcode' );
|
||||
wp_localize_script(
|
||||
'crowdsignal-shortcode',
|
||||
'crowdsignal_shortcode_options',
|
||||
array(
|
||||
'script_url' => esc_url_raw(
|
||||
Assets::get_file_url_for_environment(
|
||||
'_inc/build/polldaddy-shortcode.min.js',
|
||||
'_inc/polldaddy-shortcode.js'
|
||||
)
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kick it all off.
|
||||
new CrowdsignalShortcode();
|
||||
|
||||
if ( ! function_exists( 'crowdsignal_link' ) ) {
|
||||
/**
|
||||
* Replace link with shortcode.
|
||||
* Examples: https://poll.fm/10499328 | https://7iger.survey.fm/test-embed
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*/
|
||||
function crowdsignal_link( $content ) {
|
||||
if (
|
||||
class_exists( 'Jetpack_AMP_Support' )
|
||||
&& Jetpack_AMP_Support::is_amp_request()
|
||||
) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
// Replace poll links.
|
||||
$content = jetpack_preg_replace_outside_tags(
|
||||
'!(?:\n|\A)https?://(polldaddy\.com/poll|poll\.fm)/([0-9]+?)(/.*)?(?:\n|\Z)!i',
|
||||
'[crowdsignal poll=$2]',
|
||||
$content
|
||||
);
|
||||
|
||||
// Replace survey.fm links.
|
||||
$content = preg_replace(
|
||||
'!(?:\n|\A)https?://(.*).survey.fm/(.*)(/.*)?(?:\n|\Z)!i',
|
||||
'[crowdsignal type="iframe" survey="true" height="auto" domain="$1" id="$2"]',
|
||||
$content
|
||||
);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
// higher priority because we need it before auto-link and autop get to it.
|
||||
add_filter( 'the_content', 'crowdsignal_link', 1 );
|
||||
add_filter( 'the_content_rss', 'crowdsignal_link', 1 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Styles for the [gravatar_profile] shortcode when it is called from an AMP context
|
||||
*/
|
||||
.grofile-wrap {
|
||||
border: solid 1px #f0f0f1;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.grofile {
|
||||
padding: 0 0 5px 0;
|
||||
}
|
||||
|
||||
.grofile-left {
|
||||
float: left;
|
||||
display: block;
|
||||
width: 96px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.grofile .gravatar {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.grofile-clear {
|
||||
clear: left;
|
||||
font-size: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.grofile ul li a {
|
||||
text-indent: -99999px;
|
||||
}
|
||||
|
||||
.grofile .grofile-left a:hover {
|
||||
text-decoration: none !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.grofile-name {
|
||||
margin-top: 0;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
div.jetpack-quiz {
|
||||
border: 1px solid #deede3;
|
||||
background-color: #f3f3f3;
|
||||
padding: 1em;
|
||||
line-height: 1.3em;
|
||||
margin-bottom: 2em;
|
||||
border-radius: .2em;
|
||||
}
|
||||
|
||||
div.jetpack-quiz div.jetpack-quiz-question {
|
||||
margin-bottom: .5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.jetpack-quiz div.jetpack-quiz-answer {
|
||||
cursor: pointer;
|
||||
margin-bottom: .5em;
|
||||
padding: 1em 0 1em 1em;
|
||||
border-bottom: 1px dotted #999;
|
||||
}
|
||||
div.jetpack-quiz div.jetpack-quiz-answer.last {
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
div.jetpack-quiz div.jetpack-quiz-answer.correct {
|
||||
color: green;
|
||||
}
|
||||
|
||||
div.jetpack-quiz div.jetpack-quiz-answer.wrong {
|
||||
color: red;
|
||||
}
|
||||
|
||||
div.jetpack-quiz div.jetpack-quiz-answer div.jetpack-quiz-explanation {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.jetpack-quiz div.jetpack-quiz-answer.correct div.jetpack-quiz-explanation, div.jetpack-quiz div.jetpack-quiz-answer.wrong div.jetpack-quiz-explanation {
|
||||
display: block;
|
||||
color: black;
|
||||
font-size: 90%;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
div.jetpack-quiz div.jetpack-quiz-answer.correct div.jetpack-quiz-explanation tt, div.jetpack-quiz div.jetpack-quiz-answer.wrong div.jetpack-quiz-explanation tt {
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
div.jetpack-quiz pre {
|
||||
font: 15px Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace;
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.jetpack-quiz-options {
|
||||
margin-top: 12px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.jetpack-quiz-count {
|
||||
color: #646970;
|
||||
float: left;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.jetpack-quiz-option-button {
|
||||
cursor: pointer;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.jetpack-quiz-option-button:hover svg {
|
||||
background: #3c434a;
|
||||
}
|
||||
|
||||
.jetpack-quiz-option-button svg {
|
||||
background: #000;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
fill: #fff;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.jetpack-quiz-wrapper .jetpack-quiz:first-of-type .jetpack-quiz-option-button:first-of-type,
|
||||
.jetpack-quiz-wrapper .jetpack-quiz:last-of-type .jetpack-quiz-option-button:last-of-type {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
.jetpack-recipe-meta li.jetpack-recipe-print{display:none}.jetpack-recipe-title{font-size:16pt}.jetpack-recipe-content img{display:inline-block!important;max-width:100%}.jetpack-recipe-image{display:none!important}.jetpack-recipe-content .aligncenter{display:block!important;margin:0 auto 1em!important;text-align:center!important}.jetpack-recipe-content .alignright{float:left!important;margin:0 1em .5em 0!important}.jetpack-recipe-content .alignleft{float:right!important;margin:0 0 .5em 1em!important}.jetpack-recipe-content .alignnone{display:inline-block}
|
||||
@@ -0,0 +1 @@
|
||||
.jetpack-recipe-meta li.jetpack-recipe-print{display:none}.jetpack-recipe-title{font-size:16pt}.jetpack-recipe-content img{display:inline-block!important;max-width:100%}.jetpack-recipe-image{display:none!important}.jetpack-recipe-content .aligncenter{display:block!important;margin:0 auto 1em!important;text-align:center!important}.jetpack-recipe-content .alignright{float:left!important;margin:0 1em .5em 0!important}.jetpack-recipe-content .alignleft{float:right!important;margin:0 0 .5em 1em!important}.jetpack-recipe-content .alignnone{display:inline-block}
|
||||
@@ -0,0 +1,36 @@
|
||||
.jetpack-recipe-meta li.jetpack-recipe-print {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.jetpack-recipe-title {
|
||||
font-size: 16pt;
|
||||
}
|
||||
|
||||
.jetpack-recipe-content img {
|
||||
display: inline-block !important;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.jetpack-recipe-image {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.jetpack-recipe-content .aligncenter {
|
||||
display: block !important;
|
||||
margin: 0 auto 1em !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.jetpack-recipe-content .alignright {
|
||||
float: right !important;
|
||||
margin: 0 0 .5em 1em !important;
|
||||
}
|
||||
|
||||
.jetpack-recipe-content .alignleft {
|
||||
float: left !important;
|
||||
margin: 0 1em .5em 0 !important;
|
||||
}
|
||||
|
||||
.jetpack-recipe-content .alignnone {
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
.jetpack-recipe-meta li.jetpack-recipe-print{display:none}.jetpack-recipe-title{font-size:16pt}.jetpack-recipe-content img{display:inline-block!important;max-width:100%}.jetpack-recipe-image{display:none!important}.jetpack-recipe-content .aligncenter{display:block!important;margin:0 auto 1em!important;text-align:center!important}.jetpack-recipe-content .alignright{float:right!important;margin:0 0 .5em 1em!important}.jetpack-recipe-content .alignleft{float:left!important;margin:0 1em .5em 0!important}.jetpack-recipe-content .alignnone{display:inline-block}
|
||||
@@ -0,0 +1 @@
|
||||
.jetpack-recipe{border:1px solid #f2f2f2;border-radius:1px;clear:both;margin:1.5em 1%;padding:1% 2%}.jetpack-recipe-title{border-bottom:1px solid #ccc;margin:.25em 0;padding:.25em 0}.jetpack-recipe .jetpack-recipe-meta{display:block;font-size:.9em;list-style-type:none;margin-left:0;margin-right:0;overflow:hidden;padding:0;width:100%}.jetpack-recipe .jetpack-recipe-meta li{float:right;list-style-type:none;margin:0;padding:0 0 0 5%}.jetpack-recipe-meta li.jetpack-recipe-print{float:left;padding-left:0;text-align:left}.jetpack-recipe-notes{font-style:italic}
|
||||
@@ -0,0 +1 @@
|
||||
.jetpack-recipe{border:1px solid #f2f2f2;border-radius:1px;clear:both;margin:1.5em 1%;padding:1% 2%}.jetpack-recipe-title{border-bottom:1px solid #ccc;margin:.25em 0;padding:.25em 0}.jetpack-recipe .jetpack-recipe-meta{display:block;font-size:.9em;list-style-type:none;margin-left:0;margin-right:0;overflow:hidden;padding:0;width:100%}.jetpack-recipe .jetpack-recipe-meta li{float:right;list-style-type:none;margin:0;padding:0 0 0 5%}.jetpack-recipe-meta li.jetpack-recipe-print{float:left;padding-left:0;text-align:left}.jetpack-recipe-notes{font-style:italic}
|
||||
@@ -0,0 +1,36 @@
|
||||
.jetpack-recipe {
|
||||
border: 1px solid #f2f2f2;
|
||||
border-radius: 1px;
|
||||
clear: both;
|
||||
margin: 1.5em 1%;
|
||||
padding: 1% 2%;
|
||||
}
|
||||
.jetpack-recipe-title {
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin: .25em 0;
|
||||
padding: .25em 0;
|
||||
}
|
||||
.jetpack-recipe .jetpack-recipe-meta {
|
||||
display: block;
|
||||
font-size: .9em;
|
||||
list-style-type: none;
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
.jetpack-recipe .jetpack-recipe-meta li {
|
||||
float: left;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0 5% 0 0;
|
||||
}
|
||||
.jetpack-recipe-meta li.jetpack-recipe-print {
|
||||
float: right;
|
||||
padding-right: 0;
|
||||
text-align: right;
|
||||
}
|
||||
.jetpack-recipe-notes {
|
||||
font-style: italic;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
.jetpack-recipe{border:1px solid #f2f2f2;border-radius:1px;clear:both;margin:1.5em 1%;padding:1% 2%}.jetpack-recipe-title{border-bottom:1px solid #ccc;margin:.25em 0;padding:.25em 0}.jetpack-recipe .jetpack-recipe-meta{display:block;font-size:.9em;list-style-type:none;margin-left:0;margin-right:0;overflow:hidden;padding:0;width:100%}.jetpack-recipe .jetpack-recipe-meta li{float:left;list-style-type:none;margin:0;padding:0 5% 0 0}.jetpack-recipe-meta li.jetpack-recipe-print{float:right;padding-right:0;text-align:right}.jetpack-recipe-notes{font-style:italic}
|
||||
@@ -0,0 +1,158 @@
|
||||
.jetpack-slideshow-window {
|
||||
background-color: #222;
|
||||
border: 20px solid #222;
|
||||
border-radius: 10px;
|
||||
height: 0;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
padding-top: 30px !important;
|
||||
padding-bottom: 56.25% !important;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-window.jetpack-slideshow-white {
|
||||
background-color: #fff;
|
||||
border-color: #fff;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-window, .jetpack-slideshow-window * {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-loading {
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
body div.jetpack-slideshow-window * img {
|
||||
/* Override any styles that might be present in the page stylesheet */
|
||||
background-color: transparent !important;
|
||||
background-image: none !important;
|
||||
border-width: 0 !important;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
padding: 0 !important;
|
||||
position: relative;
|
||||
transform: translateY(-50%);
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-loading img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-slide {
|
||||
display: none;
|
||||
height: 100% !important;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-slide img {
|
||||
vertical-align: middle;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-line-height-hack {
|
||||
overflow: hidden;
|
||||
width: 0px;
|
||||
font-size: 0px;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-slide-caption {
|
||||
font-size: 13px;
|
||||
font-family: "Helvetica Neue", sans-serif;
|
||||
color: #f6f7f7;
|
||||
text-shadow: #222 -1px 1px 2px;
|
||||
line-height: 25px;
|
||||
height: 25px;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-controls {
|
||||
z-index: 1000;
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
|
||||
opacity: 0.5;
|
||||
direction: ltr;
|
||||
transition: 300ms opacity ease-out;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-window:hover .jetpack-slideshow-controls {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
body div div.jetpack-slideshow-controls a,
|
||||
body div div.jetpack-slideshow-controls a:hover {
|
||||
border: 2px solid rgba(255, 255, 255, 0.1) !important;
|
||||
background-color: #000 !important;
|
||||
background-color: rgba(0, 0, 0, 0.6) !important;
|
||||
background-image: url(../../../modules/shortcodes/img/slideshow-controls.png) !important;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 142px 16px !important;
|
||||
background-position: -34px 8px !important;
|
||||
color: #222 !important;
|
||||
margin: 0 5px !important;
|
||||
padding: 0 !important;
|
||||
display: inline-block !important;
|
||||
*display: inline;
|
||||
zoom: 1;
|
||||
height: 32px !important;
|
||||
width: 32px !important;
|
||||
line-height: 32px !important;
|
||||
text-align: center !important;
|
||||
border-radius: 10em !important;
|
||||
transition: 300ms border-color ease-out;
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 1.5) {
|
||||
body div div.jetpack-slideshow-controls a,
|
||||
body div div.jetpack-slideshow-controls a:hover {
|
||||
background-image: url(../../../modules/shortcodes/img/slideshow-controls-2x.png) !important;
|
||||
}
|
||||
}
|
||||
body div div.jetpack-slideshow-controls a:hover {
|
||||
border-color: rgb(255, 255, 255) !important;
|
||||
}
|
||||
|
||||
body div div.jetpack-slideshow-controls a:first-child {
|
||||
background-position: -76px 8px !important;
|
||||
}
|
||||
|
||||
body div div.jetpack-slideshow-controls a:last-child {
|
||||
background-position: -117px 8px !important;
|
||||
}
|
||||
|
||||
body div div.jetpack-slideshow-controls a:nth-child(2) {
|
||||
background-position: -34px 8px !important;
|
||||
}
|
||||
|
||||
body div div.jetpack-slideshow-controls a.running {
|
||||
background-position: -34px 8px !important;
|
||||
}
|
||||
|
||||
body div div.jetpack-slideshow-controls a.paused {
|
||||
background-position: 9px 8px !important;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-controls a img {
|
||||
border: 50px dotted fuchsia;
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
.jetpack-slideshow-window{background-color:#222;border:20px solid #222;border-radius:10px;height:0;margin-bottom:20px;overflow:hidden;padding-bottom:56.25%!important;padding-top:30px!important;position:relative;z-index:1}.jetpack-slideshow-window.jetpack-slideshow-white{background-color:#fff;border-color:#fff}.jetpack-slideshow-window,.jetpack-slideshow-window *{box-sizing:initial}.jetpack-slideshow-loading{height:100%;margin:auto;text-align:center}body div.jetpack-slideshow-window * img{background-color:initial!important;background-image:none!important;border-width:0!important;display:block;margin:0 auto;max-height:100%;max-width:100%;padding:0!important;position:relative;top:50%;transform:translateY(-50%)}.jetpack-slideshow-loading img{vertical-align:middle}.jetpack-slideshow-slide{display:none;height:100%!important;margin:auto;position:absolute;right:0;text-align:center;top:0;width:100%!important}.jetpack-slideshow-slide img{margin:0 auto;vertical-align:middle}.jetpack-slideshow-line-height-hack{font-size:0;overflow:hidden;width:0}.jetpack-slideshow-slide-caption{bottom:5px;color:#f6f7f7;font-family:Helvetica Neue,sans-serif;font-size:13px;height:25px;line-height:25px;position:absolute;right:0;text-align:center;text-shadow:#222 -1px 1px 2px;width:100%;z-index:100}.jetpack-slideshow-controls{bottom:30px;direction:ltr;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";margin:auto;opacity:.5;position:absolute;text-align:center;transition:opacity .3s ease-out;width:100%;z-index:1000}.jetpack-slideshow-window:hover .jetpack-slideshow-controls{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";opacity:1}body div div.jetpack-slideshow-controls a,body div div.jetpack-slideshow-controls a:hover{background-color:#000!important;background-color:#0009!important;background-image:url(../../../modules/shortcodes/img/slideshow-controls.png)!important;background-position:-34px 8px!important;background-repeat:no-repeat;background-size:142px 16px!important;border:2px solid #ffffff1a!important;color:#222!important;display:inline-block!important;*display:inline;margin:0 5px!important;padding:0!important;zoom:1;border-radius:10em!important;height:32px!important;line-height:32px!important;text-align:center!important;transition:border-color .3s ease-out;width:32px!important}@media only screen and (-webkit-min-device-pixel-ratio:1.5){body div div.jetpack-slideshow-controls a,body div div.jetpack-slideshow-controls a:hover{background-image:url(../../../modules/shortcodes/img/slideshow-controls-2x.png)!important}}body div div.jetpack-slideshow-controls a:hover{border-color:#fff!important}body div div.jetpack-slideshow-controls a:first-child{background-position:-76px 8px!important}body div div.jetpack-slideshow-controls a:last-child{background-position:-117px 8px!important}body div div.jetpack-slideshow-controls a.running,body div div.jetpack-slideshow-controls a:nth-child(2){background-position:-34px 8px!important}body div div.jetpack-slideshow-controls a.paused{background-position:9px 8px!important}.jetpack-slideshow-controls a img{border:50px dotted #f0f}
|
||||
@@ -0,0 +1,158 @@
|
||||
.jetpack-slideshow-window {
|
||||
background-color: #222;
|
||||
border: 20px solid #222;
|
||||
border-radius: 10px;
|
||||
height: 0;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
padding-top: 30px !important;
|
||||
padding-bottom: 56.25% !important;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-window.jetpack-slideshow-white {
|
||||
background-color: #fff;
|
||||
border-color: #fff;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-window, .jetpack-slideshow-window * {
|
||||
-moz-box-sizing: content-box;
|
||||
-webkit-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-loading {
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
body div.jetpack-slideshow-window * img {
|
||||
/* Override any styles that might be present in the page stylesheet */
|
||||
background-color: transparent !important;
|
||||
background-image: none !important;
|
||||
border-width: 0 !important;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
padding: 0 !important;
|
||||
position: relative;
|
||||
-webkit-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-loading img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-slide {
|
||||
display: none;
|
||||
height: 100% !important;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-slide img {
|
||||
vertical-align: middle;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-line-height-hack {
|
||||
overflow: hidden;
|
||||
width: 0px;
|
||||
font-size: 0px;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-slide-caption {
|
||||
font-size: 13px;
|
||||
font-family: "Helvetica Neue", sans-serif;
|
||||
color: #f6f7f7;
|
||||
text-shadow: #222 1px 1px 2px;
|
||||
line-height: 25px;
|
||||
height: 25px;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-controls {
|
||||
z-index: 1000;
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
|
||||
opacity: 0.5;
|
||||
/*rtl:ignore*/
|
||||
direction:ltr;
|
||||
-webkit-transition: 300ms opacity ease-out;
|
||||
-moz-transition: 300ms opacity ease-out;
|
||||
transition: 300ms opacity ease-out;
|
||||
}
|
||||
|
||||
.jetpack-slideshow-window:hover .jetpack-slideshow-controls {
|
||||
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
body div div.jetpack-slideshow-controls a,
|
||||
body div div.jetpack-slideshow-controls a:hover {
|
||||
border:2px solid rgba(255,255,255,0.1) !important;
|
||||
background-color: #000 !important;
|
||||
background-color: rgba(0,0,0,0.6) !important;
|
||||
background-image: url('../img/slideshow-controls.png') !important;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 142px 16px !important;
|
||||
background-position: -34px 8px !important;
|
||||
color: #222 !important;
|
||||
margin: 0 5px !important;
|
||||
padding: 0 !important;
|
||||
display: inline-block !important;
|
||||
*display: inline;
|
||||
zoom: 1;
|
||||
height: 32px !important;
|
||||
width: 32px !important;
|
||||
line-height: 32px !important;
|
||||
text-align: center !important;
|
||||
-khtml-border-radius: 10em !important;
|
||||
-webkit-border-radius: 10em !important;
|
||||
-moz-border-radius: 10em !important;
|
||||
border-radius: 10em !important;
|
||||
-webkit-transition: 300ms border-color ease-out;
|
||||
-moz-transition: 300ms border-color ease-out;
|
||||
-o-transition: 300ms border-color ease-out;
|
||||
transition: 300ms border-color ease-out;
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 1.5) {
|
||||
body div div.jetpack-slideshow-controls a,
|
||||
body div div.jetpack-slideshow-controls a:hover {
|
||||
background-image: url('../img/slideshow-controls-2x.png') !important;
|
||||
}
|
||||
}
|
||||
|
||||
body div div.jetpack-slideshow-controls a:hover {
|
||||
border-color: rgba(255,255,255,1) !important;
|
||||
}
|
||||
|
||||
body div div.jetpack-slideshow-controls a:first-child { background-position: -76px 8px !important;}
|
||||
body div div.jetpack-slideshow-controls a:last-child { background-position: -117px 8px !important;}
|
||||
body div div.jetpack-slideshow-controls a:nth-child(2) { background-position: -34px 8px !important;}
|
||||
body div div.jetpack-slideshow-controls a.running { background-position: -34px 8px !important;}
|
||||
body div div.jetpack-slideshow-controls a.paused { background-position: 9px 8px !important;}
|
||||
|
||||
.jetpack-slideshow-controls a img {
|
||||
border: 50px dotted fuchsia;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
.jetpack-slideshow-window{background-color:#222;border:20px solid #222;border-radius:10px;height:0;margin-bottom:20px;overflow:hidden;padding-bottom:56.25%!important;padding-top:30px!important;position:relative;z-index:1}.jetpack-slideshow-window.jetpack-slideshow-white{background-color:#fff;border-color:#fff}.jetpack-slideshow-window,.jetpack-slideshow-window *{box-sizing:initial}.jetpack-slideshow-loading{height:100%;margin:auto;text-align:center}body div.jetpack-slideshow-window * img{background-color:initial!important;background-image:none!important;border-width:0!important;display:block;margin:0 auto;max-height:100%;max-width:100%;padding:0!important;position:relative;top:50%;transform:translateY(-50%)}.jetpack-slideshow-loading img{vertical-align:middle}.jetpack-slideshow-slide{display:none;height:100%!important;left:0;margin:auto;position:absolute;text-align:center;top:0;width:100%!important}.jetpack-slideshow-slide img{margin:0 auto;vertical-align:middle}.jetpack-slideshow-line-height-hack{font-size:0;overflow:hidden;width:0}.jetpack-slideshow-slide-caption{bottom:5px;color:#f6f7f7;font-family:Helvetica Neue,sans-serif;font-size:13px;height:25px;left:0;line-height:25px;position:absolute;text-align:center;text-shadow:#222 1px 1px 2px;width:100%;z-index:100}.jetpack-slideshow-controls{bottom:30px;direction:ltr;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";margin:auto;opacity:.5;position:absolute;text-align:center;transition:opacity .3s ease-out;width:100%;z-index:1000}.jetpack-slideshow-window:hover .jetpack-slideshow-controls{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";opacity:1}body div div.jetpack-slideshow-controls a,body div div.jetpack-slideshow-controls a:hover{background-color:#000!important;background-color:#0009!important;background-image:url(../../../modules/shortcodes/img/slideshow-controls.png)!important;background-position:-34px 8px!important;background-repeat:no-repeat;background-size:142px 16px!important;border:2px solid #ffffff1a!important;color:#222!important;display:inline-block!important;*display:inline;margin:0 5px!important;padding:0!important;zoom:1;border-radius:10em!important;height:32px!important;line-height:32px!important;text-align:center!important;transition:border-color .3s ease-out;width:32px!important}@media only screen and (-webkit-min-device-pixel-ratio:1.5){body div div.jetpack-slideshow-controls a,body div div.jetpack-slideshow-controls a:hover{background-image:url(../../../modules/shortcodes/img/slideshow-controls-2x.png)!important}}body div div.jetpack-slideshow-controls a:hover{border-color:#fff!important}body div div.jetpack-slideshow-controls a:first-child{background-position:-76px 8px!important}body div div.jetpack-slideshow-controls a:last-child{background-position:-117px 8px!important}body div div.jetpack-slideshow-controls a.running,body div div.jetpack-slideshow-controls a:nth-child(2){background-position:-34px 8px!important}body div div.jetpack-slideshow-controls a.paused{background-position:9px 8px!important}.jetpack-slideshow-controls a img{border:50px dotted #f0f}
|
||||
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* 1. Fullscreen styles
|
||||
*/
|
||||
html.presentation-wrapper-fullscreen-parent,
|
||||
body.presentation-wrapper-fullscreen-parent {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.presentation-wrapper-fullscreen-parent #wpadminbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.presentation-wrapper-fullscreen,
|
||||
.presentation-wrapper-fullscreen-parent {
|
||||
min-width: 100% !important;
|
||||
min-height: 100% !important;
|
||||
position: absolute !important;
|
||||
top: 0 !important;
|
||||
right: 0 !important;
|
||||
bottom: 0 !important;
|
||||
left: 0 !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
z-index: 10000 !important;
|
||||
}
|
||||
|
||||
.presentation-wrapper-fullscreen {
|
||||
background-color: #808080;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.presentation-wrapper-fullscreen .nav-arrow-left,
|
||||
.presentation-wrapper-fullscreen .nav-arrow-right {
|
||||
z-index: 20001;
|
||||
}
|
||||
|
||||
.presentation-wrapper-fullscreen .nav-fullscreen-button {
|
||||
z-index: 20002;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 2. General presentation styles
|
||||
*/
|
||||
.presentation-wrapper {
|
||||
margin: 20px auto;
|
||||
border: 1px solid #dcdcde;
|
||||
overflow: hidden;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.presentation {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* jmpress requires that step sizes are explicitly defined
|
||||
* as it inserts sizeless divs before the steps. These
|
||||
* dimensions are set by the js code on initialization
|
||||
*/
|
||||
.presentation,
|
||||
.presentation .step {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opacity transition durations are set by the js code
|
||||
* so they match the presentation animation durations
|
||||
*/
|
||||
.presentation .step.fade:not(.active) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.presentation .slide-content {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 3. Styles for the navigation arrows
|
||||
*/
|
||||
.presentation .nav-arrow-left,
|
||||
.presentation .nav-arrow-right,
|
||||
.presentation .nav-fullscreen-button {
|
||||
position: absolute;
|
||||
width: 34px;
|
||||
background-repeat: no-repeat;
|
||||
z-index: 2;
|
||||
opacity: 0;
|
||||
|
||||
-webkit-transition : opacity .25s;
|
||||
-moz-transition : opacity .25s;
|
||||
-ms-transition : opacity .25s;
|
||||
-o-transition : opacity .25s;
|
||||
transition : opacity .25s;
|
||||
}
|
||||
|
||||
.presentation .nav-arrow-left,
|
||||
.presentation .nav-arrow-right {
|
||||
height: 100%;
|
||||
background-image: url(../images/slide-nav.png);
|
||||
background-size: 450% 61px;
|
||||
}
|
||||
|
||||
.presentation .nav-arrow-left {
|
||||
left: 0;
|
||||
background-position: 4px 50%;
|
||||
}
|
||||
|
||||
.presentation .nav-arrow-right {
|
||||
right: 0;
|
||||
background-position: -120px 50%;
|
||||
}
|
||||
|
||||
.presentation .nav-fullscreen-button {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 4px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 3;
|
||||
background-image: url(../images/expand.png);
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.presentation:hover .nav-arrow-left,
|
||||
.presentation:hover .nav-arrow-right {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.presentation:hover .nav-fullscreen-button {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.presentation-wrapper-fullscreen .nav-fullscreen-button {
|
||||
background-image: url(../images/collapse.png);
|
||||
}
|
||||
|
||||
/**
|
||||
* 4. Styles for the autoplay overlay
|
||||
*/
|
||||
.presentation .autoplay-overlay {
|
||||
height: 15%;
|
||||
width: 80%;
|
||||
margin: 30% 10%;
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
display: table;
|
||||
border-radius: 50px;
|
||||
background-color: #dcdcde;
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
|
||||
-webkit-transition : opacity .5s;
|
||||
-moz-transition : opacity .5s;
|
||||
-ms-transition : opacity .5s;
|
||||
-o-transition : opacity .5s;
|
||||
transition : opacity .5s;
|
||||
}
|
||||
|
||||
.presentation .autoplay-overlay .overlay-msg {
|
||||
position: relative;
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/**
|
||||
* 5. Styles for fading steps
|
||||
*/
|
||||
.presentation .will-fade {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.presentation .do-fade {
|
||||
opacity: 1;
|
||||
|
||||
-webkit-transition : opacity .5s;
|
||||
-moz-transition : opacity .5s;
|
||||
-ms-transition : opacity .5s;
|
||||
-o-transition : opacity .5s;
|
||||
transition : opacity .5s;
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
<?php
|
||||
/**
|
||||
* Dailymotion code
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Original codes:
|
||||
*
|
||||
* <embed height="270" type="application/x-shockwave-flash" width="480" src="http://www.dailymotion.com/swf/video/xekmrq?additionalInfos=0" wmode="opaque" pluginspage="http://www.macromedia.com/go/getflashplayer" allowscriptaccess="never" allownetworking="internal" />
|
||||
*
|
||||
* <object width="480" height="240"><param name="movie" value="http://www.dailymotion.com/swf/video/xen4ms_ghinzu-cold-love-mirror-mirror_music?additionalInfos=0"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param>
|
||||
* <embed type="application/x-shockwave-flash" src="http://www.dailymotion.com/swf/video/xen4ms_ghinzu-cold-love-mirror-mirror_music?additionalInfos=0" width="480" height="240" allowfullscreen="true" allowscriptaccess="always"></embed>
|
||||
* </object><br /><b><a href="http://www.dailymotion.com/video/xen4ms_ghinzu-cold-love-mirror-mirror_music">Ghinzu - Cold Love (Mirror Mirror)</a></b><br /><i>Uploaded by <a href="http://www.dailymotion.com/GhinzuTV">GhinzuTV</a>. - <a href="http://www.dailymotion.com/us/channel/music">Watch more music videos, in HD!</a></i>
|
||||
*
|
||||
* Code as of 01.01.11:
|
||||
* <object width="560" height="421"><param name="movie" value="http://www.dailymotion.com/swf/video/xaose5?width=560&theme=denim&foreground=%2392ADE0&highlight=%23A2ACBF&background=%23202226&start=&animatedTitle=&iframe=0&additionalInfos=0&autoPlay=0&hideInfos=0"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed type="application/x-shockwave-flash" src="http://www.dailymotion.com/swf/video/xaose5?width=560&theme=denim&foreground=%2392ADE0&highlight=%23A2ACBF&background=%23202226&start=&animatedTitle=&iframe=0&additionalInfos=0&autoPlay=0&hideInfos=0" width="560" height="421" allowfullscreen="true" allowscriptaccess="always"></embed></object><br /><b><a href="http://www.dailymotion.com/video/x29zm17_funny-videos-of-cats-and-babies-compilation-2015_fun">Funny cats and babies!</a></b><br /><i>Uploaded by <a href="http://www.dailymotion.com/GilLavie">GilLavie</a>. - <a target="_self" href="http://www.dailymotion.com/channel/funny/featured/1">Find more funny videos.</a></i>
|
||||
* movie param enforces anti-xss protection
|
||||
*
|
||||
* Scroll down for the new <iframe> embed code handler.
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*/
|
||||
function dailymotion_embed_to_shortcode( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'www.dailymotion.com/swf/' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$regexp = '!<object.*>\s*(<param.*></param>\s*)*<embed((?:\s+\w+="[^"]*")*)\s+src="http(?:\:|�*58;)//(www\.dailymotion\.com/swf/[^"]*)"((?:\s+\w+="[^"]*")*)\s*(?:/>|>\s*</embed>)\s*</object><br /><b><a .*>.*</a></b><br /><i>.*</i>!';
|
||||
$regexp_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );
|
||||
|
||||
foreach ( compact( 'regexp', 'regexp_ent' ) as $reg => $regexp ) {
|
||||
if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
$src = html_entity_decode( $match[3], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
|
||||
$params = $match[2] . $match[4];
|
||||
|
||||
if ( 'regexp_ent' === $reg ) {
|
||||
$src = html_entity_decode( $src, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
|
||||
$params = html_entity_decode( $params, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
|
||||
}
|
||||
|
||||
$params = wp_kses_hair( $params, array( 'http' ) );
|
||||
|
||||
if ( ! isset( $params['type'] ) || 'application/x-shockwave-flash' !== $params['type']['value'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$id = basename( substr( $src, strlen( 'www.dailymotion.com/swf' ) ) );
|
||||
$id = preg_replace( '/[^a-z0-9].*$/is', '', $id );
|
||||
|
||||
$content = str_replace( $match[0], "[dailymotion id=$id]", $content );
|
||||
/** This action is documented in modules/shortcodes/youtube.php */
|
||||
do_action( 'jetpack_embed_to_shortcode', 'dailymotion', $id );
|
||||
}
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
add_filter( 'pre_kses', 'dailymotion_embed_to_shortcode' );
|
||||
|
||||
/**
|
||||
* DailyMotion shortcode
|
||||
*
|
||||
* The documented shortcode is:
|
||||
* [dailymotion id=x8oma9]
|
||||
*
|
||||
* Possibilities, according to the old parsing regexp:
|
||||
* [dailymotion x8oma9]
|
||||
* [dailymotion=x8oma9]
|
||||
*
|
||||
* Hypothetical option, according to the old shortcode function is
|
||||
* [dailymotion id=1&title=2&user=3&video=4]
|
||||
*
|
||||
* The new style is now:
|
||||
* [dailymotion id=x8oma9 title=2 user=3 video=4]
|
||||
*
|
||||
* Supported parameters for player customization: width, height,
|
||||
* autoplay, endscreen-enable, mute, sharing-enabled, start, subtitles-default,
|
||||
* ui-highlight, ui-logo, ui-start-screen-info, ui-theme
|
||||
* see https://developer.dailymotion.com/player#player-parameters
|
||||
*
|
||||
* @todo: Update code to sniff for iframe embeds and convert those to shortcodes.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*
|
||||
* @return string html
|
||||
*/
|
||||
function dailymotion_shortcode( $atts ) {
|
||||
global $content_width;
|
||||
|
||||
if ( isset( $atts[0] ) ) {
|
||||
$id = ltrim( $atts[0], '=' );
|
||||
$atts['id'] = $id;
|
||||
|
||||
} else {
|
||||
$params = shortcode_new_to_old_params( $atts );
|
||||
parse_str( $params, $atts_new );
|
||||
|
||||
foreach ( $atts_new as $k => $v ) {
|
||||
$atts[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => '', // string.
|
||||
'width' => '', // int.
|
||||
'height' => '', // int.
|
||||
'title' => '', // string.
|
||||
'user' => '', // string.
|
||||
'video' => '', // string.
|
||||
'autoplay' => 0, // int.
|
||||
'endscreen-enable' => 1, // int.
|
||||
'mute' => 0, // int.
|
||||
'sharing-enable' => 1, // int.
|
||||
'start' => '', // int.
|
||||
'subtitles-default' => '', // string.
|
||||
'ui-highlight' => '', // string.
|
||||
'ui-logo' => 1, // int.
|
||||
'ui-start-screen-info' => 0, // int.
|
||||
'ui-theme' => '', // string.
|
||||
),
|
||||
$atts,
|
||||
'dailymotion'
|
||||
);
|
||||
|
||||
if ( isset( $atts['id'] ) && ! empty( $atts['id'] ) ) {
|
||||
$id = rawurlencode( $atts['id'] );
|
||||
} else {
|
||||
return '<!--Dailymotion error: bad or missing ID-->';
|
||||
}
|
||||
|
||||
/*set width and height using provided parameters if any */
|
||||
$width = isset( $atts['width'] ) ? (int) $atts['width'] : 0;
|
||||
$height = isset( $atts['height'] ) ? (int) $atts['height'] : 0;
|
||||
|
||||
if ( ! $width && ! $height ) {
|
||||
if ( ! empty( $content_width ) ) {
|
||||
$width = absint( $content_width );
|
||||
} else {
|
||||
$width = 425;
|
||||
}
|
||||
$height = $width / 425 * 334;
|
||||
} elseif ( ! $height ) {
|
||||
$height = $width / 425 * 334;
|
||||
} elseif ( ! $width ) {
|
||||
$width = $height / 334 * 425;
|
||||
}
|
||||
|
||||
if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
|
||||
return sprintf(
|
||||
'<amp-dailymotion data-videoid="%1$s" layout="responsive" width="%2$d" height="%3$d"></amp-dailymotion>',
|
||||
esc_attr( $id ),
|
||||
absint( $width ),
|
||||
absint( $height )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Let's add parameters if needed.
|
||||
*
|
||||
* @see https://developer.dailymotion.com/player
|
||||
*/
|
||||
$player_params = array();
|
||||
|
||||
if ( isset( $atts['autoplay'] ) && '1' === $atts['autoplay'] ) {
|
||||
$player_params['autoplay'] = '1';
|
||||
}
|
||||
if ( isset( $atts['endscreen-enable'] ) && '0' === $atts['endscreen-enable'] ) {
|
||||
$player_params['endscreen-enable'] = '0';
|
||||
}
|
||||
if ( isset( $atts['mute'] ) && '1' === $atts['mute'] ) {
|
||||
$player_params['mute'] = '1';
|
||||
}
|
||||
if ( isset( $atts['sharing-enable'] ) && '0' === $atts['sharing-enable'] ) {
|
||||
$player_params['sharing-enable'] = '0';
|
||||
}
|
||||
if ( isset( $atts['start'] ) && ! empty( $atts['start'] ) ) {
|
||||
$player_params['start'] = abs( (int) $atts['start'] );
|
||||
}
|
||||
if ( isset( $atts['subtitles-default'] ) && ! empty( $atts['subtitles-default'] ) ) {
|
||||
$player_params['subtitles-default'] = esc_attr( $atts['subtitles-default'] );
|
||||
}
|
||||
if ( isset( $atts['ui-highlight'] ) && ! empty( $atts['ui-highlight'] ) ) {
|
||||
$player_params['ui-highlight'] = esc_attr( $atts['ui-highlight'] );
|
||||
}
|
||||
if ( isset( $atts['ui-logo'] ) && '0' === $atts['ui-logo'] ) {
|
||||
$player_params['ui-logo'] = '0';
|
||||
}
|
||||
if ( isset( $atts['ui-start-screen-info'] ) && '0' === $atts['ui-start-screen-info'] ) {
|
||||
$player_params['ui-start-screen-info'] = '0';
|
||||
}
|
||||
if ( isset( $atts['ui-theme'] ) && in_array( strtolower( $atts['ui-theme'] ), array( 'dark', 'light' ), true ) ) {
|
||||
$player_params['ui-theme'] = esc_attr( $atts['ui-theme'] );
|
||||
}
|
||||
|
||||
// Add those parameters to the Video URL.
|
||||
$video_url = add_query_arg(
|
||||
$player_params,
|
||||
'https://www.dailymotion.com/embed/video/' . $id
|
||||
);
|
||||
|
||||
$output = '';
|
||||
|
||||
if ( preg_match( '/^[A-Za-z0-9]+$/', $id ) ) {
|
||||
$output .= '<iframe width="' . esc_attr( $width ) . '" height="' . esc_attr( $height ) . '" src="' . esc_url( $video_url ) . '" style="border:0;" allowfullscreen></iframe>';
|
||||
|
||||
$video = preg_replace( '/[^-a-z0-9_]/i', '', $atts['video'] );
|
||||
$title = wp_kses( $atts['title'], array() );
|
||||
if (
|
||||
array_key_exists( 'video', $atts )
|
||||
&& $video
|
||||
&& array_key_exists( 'title', $atts )
|
||||
&& $title
|
||||
) {
|
||||
$output .= '<br /><strong><a href="' . esc_url( 'https://www.dailymotion.com/video/' . $video ) . '" target="_blank">' . esc_html( $title ) . '</a></strong>';
|
||||
}
|
||||
|
||||
$user = preg_replace( '/[^-a-z0-9_]/i', '', $atts['user'] );
|
||||
if ( array_key_exists( 'user', $atts ) && $user ) {
|
||||
/* translators: %s is a Dailymotion user name */
|
||||
$output .= '<br /><em>' . wp_kses(
|
||||
sprintf(
|
||||
/* Translators: placeholder is a Dailymotion username, linking to a Dailymotion profile page. */
|
||||
__( 'Uploaded by %s', 'jetpack' ),
|
||||
'<a href="' . esc_url( 'https://www.dailymotion.com/' . $user ) . '" target="_blank">' . esc_html( $user ) . '</a>'
|
||||
),
|
||||
array(
|
||||
'a' => array(
|
||||
'href' => true,
|
||||
'target' => true,
|
||||
),
|
||||
)
|
||||
) . '</em>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calypso Helper
|
||||
*
|
||||
* Makes shortcode output responsive to the location it is loaded:
|
||||
* Notifications, Reader, Email
|
||||
*/
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
require_once WP_CONTENT_DIR . '/lib/display-context.php';
|
||||
$context = A8C\Display_Context\get_current_context();
|
||||
|
||||
// Notifications.
|
||||
if ( A8C\Display_Context\NOTIFICATIONS === $context ) {
|
||||
return sprintf(
|
||||
'<a href="%1$s" target="_blank" rel="noopener noreferrer">%1$s</a>',
|
||||
esc_url( 'https://www.dailymotion.com/video/' . $id )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
add_shortcode( 'dailymotion', 'dailymotion_shortcode' );
|
||||
|
||||
/**
|
||||
* DailyMotion Channel Shortcode
|
||||
*
|
||||
* Examples:
|
||||
* [dailymotion-channel user=MatthewDominick]
|
||||
* [dailymotion-channel user=MatthewDominick type=grid] (supports grid, carousel, badge/default)
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function dailymotion_channel_shortcode( $atts ) {
|
||||
$username = $atts['user'];
|
||||
|
||||
switch ( $atts['type'] ) {
|
||||
case 'grid':
|
||||
$channel_iframe = '<iframe sandbox="allow-popups allow-scripts allow-same-origin allow-presentation" width="300px" height="264px" scrolling="no" style="border:0;" src="' . esc_url( '//www.dailymotion.com/badge/user/' . $username . '?type=grid' ) . '"></iframe>';
|
||||
break;
|
||||
case 'carousel':
|
||||
$channel_iframe = '<iframe sandbox="allow-popups allow-scripts allow-same-origin allow-presentation" width="300px" height="360px" scrolling="no" style="border:0;" src="' . esc_url( '//www.dailymotion.com/badge/user/' . $username . '?type=carousel' ) . '"></iframe>';
|
||||
break;
|
||||
default:
|
||||
$channel_iframe = '<iframe sandbox="allow-popups allow-scripts allow-same-origin allow-presentation" width="300px" height="78px" scrolling="no" style="border:0;" src="' . esc_url( '//www.dailymotion.com/badge/user/' . $username ) . '"></iframe>';
|
||||
}
|
||||
|
||||
return $channel_iframe;
|
||||
}
|
||||
add_shortcode( 'dailymotion-channel', 'dailymotion_channel_shortcode' );
|
||||
|
||||
/**
|
||||
* Embed Reversal for Badge/Channel
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*/
|
||||
function dailymotion_channel_reversal( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'dailymotion.com/badge/' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample embed code:
|
||||
* <iframe width="300px" height="360px" scrolling="no" frameborder="0" src="http://www.dailymotion.com/badge/user/Dailymotion?type=carousel"></iframe>
|
||||
*/
|
||||
|
||||
$regexes = array();
|
||||
|
||||
$regexes[] = '#<iframe[^>]+?src=" (?:https?:)?//(?:www\.)?dailymotion\.com/badge/user/([^"\'/]++) "[^>]*+></iframe>#ix';
|
||||
|
||||
// Let's play nice with the visual editor too.
|
||||
$regexes[] = '#<iframe(?:[^&]|&(?!gt;))+?src=" (?:https?:)?//(?:www\.)?dailymotion\.com/badge/user/([^"\'/]++) "(?:[^&]|&(?!gt;))*+></iframe>#ix';
|
||||
|
||||
foreach ( $regexes as $regex ) {
|
||||
if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
$url_pieces = wp_parse_url( $match[1] );
|
||||
|
||||
if ( 'type=carousel' === $url_pieces['query'] ) {
|
||||
$type = 'carousel';
|
||||
} elseif ( 'type=grid' === $url_pieces['query'] ) {
|
||||
$type = 'grid';
|
||||
} else {
|
||||
$type = 'badge';
|
||||
}
|
||||
|
||||
$shortcode = '[dailymotion-channel user=' . esc_attr( $url_pieces['path'] ) . ' type=' . esc_attr( $type ) . ']';
|
||||
$replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $match[0], '#' ) );
|
||||
$content = preg_replace( $replace_regex, sprintf( "\n\n%s\n\n", $shortcode ), $content );
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
add_filter( 'pre_kses', 'dailymotion_channel_reversal' );
|
||||
|
||||
/**
|
||||
* Dailymotion Embed Reversal (with new iframe code as of 17.09.2014)
|
||||
*
|
||||
* Converts a generic HTML embed code from Dailymotion into an
|
||||
* oEmbeddable URL.
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*/
|
||||
function jetpack_dailymotion_embed_reversal( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'dailymotion.com/embed' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample embed code as of Sep 17th 2014:
|
||||
* <iframe frameborder="0" width="480" height="270" src="//www.dailymotion.com/embed/video/x25x71x" allowfullscreen></iframe><br /><a href="http://www.dailymotion.com/video/x25x71x_dog-with-legs-in-casts-learns-how-to-enter-the-front-door_animals" target="_blank">Dog with legs in casts learns how to enter the...</a> <i>by <a href="http://www.dailymotion.com/videobash" target="_blank">videobash</a></i>
|
||||
*/
|
||||
$regexes = array();
|
||||
|
||||
// I'm Konstantin and I love regex.
|
||||
$regexes[] = '#<iframe[^>]+?src=" (?:https?:)?//(?:www\.)?dailymotion\.com/embed/video/([^"\'/]++) "[^>]*+>\s*+</iframe>\s*+(?:<br\s*+/>)?\s*+
|
||||
(?: <a[^>]+?href=" (?:https?:)?//(?:www\.)?dailymotion\.com/[^"\']++ "[^>]*+>.+?</a>\s*+ )?
|
||||
(?: <i>.*?<a[^>]+?href=" (?:https?:)?//(?:www\.)?dailymotion\.com/[^"\']++ "[^>]*+>.+?</a>\s*+</i> )?#ix';
|
||||
|
||||
$regexes[] = '#<iframe(?:[^&]|&(?!gt;))+?src=" (?:https?:)?//(?:www\.)?dailymotion\.com/embed/video/([^"\'/]++) "(?:[^&]|&(?!gt;))*+>\s*+</iframe>\s*+(?:<br\s*+/>)?\s*+
|
||||
(?: <a(?:[^&]|&(?!gt;))+?href=" (?:https?:)?//(?:www\.)?dailymotion\.com/[^"\']++ "(?:[^&]|&(?!gt;))*+>.+?</a>\s*+ )?
|
||||
(?: <i>.*?<a(?:[^&]|&(?!gt;))+?href=" (?:https?:)?//(?:www\.)?dailymotion\.com/[^"\']++ "(?:[^&]|&(?!gt;))*+>.+?</a>\s*+</i> )?#ix';
|
||||
|
||||
foreach ( $regexes as $regex ) {
|
||||
if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
$url = esc_url( sprintf( 'https://dailymotion.com/video/%s', $match[1] ) );
|
||||
$replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $match[0], '#' ) );
|
||||
$content = preg_replace( $replace_regex, sprintf( "\n\n%s\n\n", $url ), $content );
|
||||
|
||||
/** This action is documented in modules/shortcodes/youtube.php */
|
||||
do_action( 'jetpack_embed_to_shortcode', 'dailymotion', $url );
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
add_filter( 'pre_kses', 'jetpack_dailymotion_embed_reversal' );
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/**
|
||||
* Descript.com embed
|
||||
*
|
||||
* Example URL: https://share.descript.com/view/jUxUmel6GyN
|
||||
* Example embed code: <iframe src="https://share.descript.com/embed/jUxUmel6GyN" width="640" height="360" frameborder="0" allowfullscreen></iframe>
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
add_action( 'init', 'jetpack_descript_enable_embeds' );
|
||||
} else {
|
||||
jetpack_descript_enable_embeds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register descript as oembed provider. Add filter to reverse iframes to shortcode. Register [descript] shortcode.
|
||||
*
|
||||
* @since 10.4
|
||||
*/
|
||||
function jetpack_descript_enable_embeds() {
|
||||
// Support their oEmbed Endpoint.
|
||||
wp_oembed_add_provider( '#https?://share.descript.com/(?:view|embed)/\w+#i', 'https://api.descript.com/v2/oembed', true );
|
||||
|
||||
// Allow script to be filtered to short code (so direct copy+paste can be done).
|
||||
add_filter( 'pre_kses', 'jetpack_shortcodereverse_descript' );
|
||||
|
||||
// Actually display the descript Embed.
|
||||
add_shortcode( 'descript', 'jetpack_descript_shortcode' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose shortcode based on Descript iframes.
|
||||
*
|
||||
* @since 10.4
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function jetpack_shortcodereverse_descript( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'share.descript.com' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$regexp = '/<iframe (?:loading="lazy" )?src="https:\/\/share.descript.com\/embed\/(\w+)" width="(\d+)" height="(\d+)" frameborder="0" allowfullscreen(?:="")?><\/iframe>/i';
|
||||
|
||||
if ( preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
foreach ( $matches as $match ) {
|
||||
// We need at least a id.
|
||||
if ( isset( $match[1] ) ) {
|
||||
$shortcode = sprintf(
|
||||
'[descript id="%1$s" width="%2$s" height="%3$s"]',
|
||||
esc_attr( $match[1] ),
|
||||
esc_attr( $match[2] ),
|
||||
esc_attr( $match[3] )
|
||||
);
|
||||
$content = str_replace( $match[0], $shortcode, $content );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** This action is documented in modules/widgets/social-media-icons.php */
|
||||
do_action( 'jetpack_bump_stats_extras', 'html_to_shortcode', 'descript' );
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse shortcode arguments and render its output.
|
||||
*
|
||||
* @since 10.4
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function jetpack_descript_shortcode( $atts ) {
|
||||
if ( ! empty( $atts['id'] ) ) {
|
||||
$id = $atts['id'];
|
||||
} else {
|
||||
return '<!-- Missing descript id -->';
|
||||
}
|
||||
|
||||
if ( ! empty( $atts['width'] ) ) {
|
||||
$width = $atts['width'];
|
||||
} else {
|
||||
$width = '640';
|
||||
}
|
||||
|
||||
if ( ! empty( $atts['height'] ) ) {
|
||||
$height = $atts['height'];
|
||||
} else {
|
||||
$height = '480';
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'id' => esc_attr( $id ),
|
||||
'width' => (int) $width,
|
||||
'height' => (int) $height,
|
||||
);
|
||||
|
||||
$embed_url = sprintf(
|
||||
'https://share.descript.com/view/%1$s',
|
||||
esc_attr( $id )
|
||||
);
|
||||
|
||||
$embed_code = wp_oembed_get( $embed_url, array_filter( $params ) );
|
||||
|
||||
// wrap the embed with wp-block-embed__wrapper, otherwise it would be aligned to the very left of the viewport.
|
||||
return sprintf(
|
||||
'<div class="wp-block-embed__wrapper">%1$s</div>',
|
||||
$embed_code
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
/**
|
||||
* Facebook embeds
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
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' );
|
||||
|
||||
/*
|
||||
* Example URL: https://www.facebook.com/permalink.php?id=222622504529111&story_fbid=559431180743788
|
||||
*/
|
||||
wp_embed_register_handler( 'facebook-alternate', JETPACK_FACEBOOK_ALTERNATE_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
|
||||
|
||||
/*
|
||||
* 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' );
|
||||
|
||||
/*
|
||||
* 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' );
|
||||
|
||||
/*
|
||||
* Videos
|
||||
*
|
||||
* Formats:
|
||||
* https://www.facebook.com/video.php?v=2836814009877992
|
||||
* https://www.facebook.com/watch/?v=2836814009877992
|
||||
*/
|
||||
wp_embed_register_handler( 'facebook-video', JETPACK_FACEBOOK_VIDEO_EMBED_REGEX, 'jetpack_facebook_embed_handler' );
|
||||
|
||||
/*
|
||||
* 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' );
|
||||
|
||||
/**
|
||||
* Callback to modify output of embedded Facebook posts.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
function jetpack_facebook_embed_handler( $matches, $attr, $url ) {
|
||||
// This is a stop-gap solution until Facebook hopefully resolves this ticket
|
||||
// https://developers.facebook.com/community/threads/1675075423353415/?post_id=1675075426686748
|
||||
$extra_styles = 'style="background-color: #fff; display: inline-block;"';
|
||||
|
||||
if (
|
||||
str_contains( $url, 'video.php' )
|
||||
|| str_contains( $url, '/videos/' )
|
||||
|| str_contains( $url, '/watch' )
|
||||
) {
|
||||
$embed = sprintf(
|
||||
'<div class="fb-video" data-allowfullscreen="true" data-href="%1$s" %2$s></div>',
|
||||
esc_url( $url ),
|
||||
$extra_styles
|
||||
);
|
||||
} else {
|
||||
$width = 552; // As of 01/2017, the default width of Facebook embeds when no width attribute provided.
|
||||
|
||||
global $content_width;
|
||||
if ( is_numeric( $content_width ) && $content_width > 0 ) {
|
||||
$width = min( $width, $content_width );
|
||||
}
|
||||
|
||||
$embed = sprintf(
|
||||
'<div class="fb-post" data-href="%1$s" data-width="%2$s" %3$s></div>',
|
||||
esc_url( $url ),
|
||||
esc_attr( $width ),
|
||||
$extra_styles
|
||||
);
|
||||
}
|
||||
|
||||
// Skip rendering scripts in an AMP context.
|
||||
if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
|
||||
return $embed;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcode handler.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function jetpack_facebook_shortcode_handler( $atts ) {
|
||||
global $wp_embed;
|
||||
|
||||
if ( empty( $atts['url'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! preg_match( JETPACK_FACEBOOK_EMBED_REGEX, $atts['url'] )
|
||||
&& ! preg_match( JETPACK_FACEBOOK_PHOTO_EMBED_REGEX, $atts['url'] )
|
||||
&& ! preg_match( JETPACK_FACEBOOK_VIDEO_EMBED_REGEX, $atts['url'] )
|
||||
&& ! preg_match( JETPACK_FACEBOOK_VIDEO_ALTERNATE_EMBED_REGEX, $atts['url'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $wp_embed->shortcode( $atts, $atts['url'] );
|
||||
}
|
||||
add_shortcode( 'facebook', 'jetpack_facebook_shortcode_handler' );
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* Flat.io embed
|
||||
*
|
||||
* Example URL: https://flat.io/score/5a5268ed41396318cbd7772c-string-quartet-for-rainy-days
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
// Register oEmbed provider.
|
||||
wp_oembed_add_provider( 'https://flat.io/score/*', 'https://flat.io/services/oembed', false );
|
||||
wp_oembed_add_provider( 'https://*.flat.io/score/*', 'https://flat.io/services/oembed', false );
|
||||
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
/**
|
||||
* Flickr Short Code
|
||||
* Author: kellan
|
||||
* License: BSD/GPL/public domain (take your pick)
|
||||
*
|
||||
* [flickr video=www.flickr.com/photos/kalakeli/49931239842]
|
||||
* [flickr video=49931239842]
|
||||
* [flickr video=49931239842 w=200 h=150]
|
||||
* [flickr video=49931239842 autoplay="yes" controls="no"]
|
||||
* [flickr video=49931239842 autoplay="no" controls="yes" w=200 h=150]
|
||||
*
|
||||
* <div class="flick_video" style="max-width: 100%;width: 500px;height: 300px;"><video src="https://www.flickr.com/photos/kalakeli/49931239842/play/360p/183f75d545/" controls autoplay ></video></div>
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Transform embed to shortcode on save.
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return string Shortcode or the embed content itself.
|
||||
*/
|
||||
function flickr_embed_to_shortcode( $content ) {
|
||||
if ( ! is_string( $content ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
if ( str_contains( $content, '<div class="flickr_video"' ) && str_contains( $content, '<video' ) ) {
|
||||
return jetpack_flickr_video_to_shortcode( $content );
|
||||
} elseif ( preg_match( '/<iframe src="(https?:)?\/\/([\da-z\-]+\.)*?((static)?flickr\.com|flic\.kr)\/[^\"]+\"/', $content ) ) {
|
||||
return jetpack_flickr_photo_to_shortcode( $content );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms embed to shortcode on save when the photo param is used.
|
||||
* If embed content can not be transformed to a valid shortcode,
|
||||
* the embed content itself is returned.
|
||||
*
|
||||
* @param string $content Embed output.
|
||||
*
|
||||
* @return string Shortcode or the embed content.
|
||||
*/
|
||||
function jetpack_flickr_photo_to_shortcode( $content ) {
|
||||
preg_match( '/<iframe src=\"([^\"]+)\"(\s+height=\"([^\"]*)\")?(\s+width=\"([^\"]*)\")?/', $content, $matches );
|
||||
|
||||
if ( empty( $matches[1] ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$src = esc_attr( str_replace( 'player/', '', $matches[1] ) );
|
||||
$height = empty( $matches[3] ) ? '' : esc_attr( $matches[3] );
|
||||
$width = empty( $matches[5] ) ? '' : esc_attr( $matches[5] );
|
||||
|
||||
/** This action is documented in modules/shortcodes/youtube.php */
|
||||
do_action( 'jetpack_embed_to_shortcode', 'flickr_photo', $src );
|
||||
|
||||
return '[flickr photo="' . $src . '" w=' . $width . ' h=' . $height . ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms embed to shortcode on save when the video param is used.
|
||||
* If embed content can not be transformed to a valid shortcode,
|
||||
* the embed content itself is returned.
|
||||
*
|
||||
* @param string $content Embed output.
|
||||
*
|
||||
* @return string Shortcode or the embed content.
|
||||
*/
|
||||
function jetpack_flickr_video_to_shortcode( $content ) {
|
||||
// Get video src.
|
||||
preg_match( '/<video src=\"([^\"]+)\"/', $content, $matches );
|
||||
|
||||
if ( empty( $matches[1] ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
preg_match( '/(https?:)?\/\/([\da-z\-]+\.)*?((static)?flickr\.com|flic\.kr)\/photos\/([^\/]+)\/\d+\//', $matches[1], $matches );
|
||||
|
||||
$video_src = esc_attr( $matches[0] );
|
||||
|
||||
// Get width and height.
|
||||
|
||||
preg_match( '/style=\"max-width: 100%;(width:\s(\d+)px;)?(height:\s(\d+)px;)?/', $content, $matches );
|
||||
|
||||
$width = empty( $matches[2] ) ? '' : 'w=' . esc_attr( $matches[2] );
|
||||
|
||||
$height = empty( $matches[4] ) ? '' : 'h=' . esc_attr( $matches[4] );
|
||||
|
||||
$controls = str_contains( $content, 'controls' ) ? 'yes' : 'no';
|
||||
|
||||
$autoplay = str_contains( $content, 'autoplay' ) ? 'yes' : 'no';
|
||||
|
||||
/** This action is documented in modules/shortcodes/youtube.php */
|
||||
do_action( 'jetpack_embed_to_shortcode', 'flickr_video', $video_src );
|
||||
|
||||
return '[flickr video="' . $video_src . '" ' . $width . ' ' . $height . ' controls="' . $controls . '" autoplay="' . $autoplay . '"]';
|
||||
}
|
||||
|
||||
add_filter( 'pre_kses', 'flickr_embed_to_shortcode' );
|
||||
|
||||
/**
|
||||
* Flickr Shortcode handler.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*
|
||||
* @return string Shortcode Output.
|
||||
*/
|
||||
function flickr_shortcode_handler( $atts ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'video' => 0,
|
||||
'photo' => 0,
|
||||
'w' => '',
|
||||
'h' => '',
|
||||
'controls' => 'yes',
|
||||
'autoplay' => '',
|
||||
),
|
||||
$atts,
|
||||
'flickr'
|
||||
);
|
||||
|
||||
if ( ! empty( $atts['video'] ) ) {
|
||||
$showing = 'video';
|
||||
$src = $atts['video'];
|
||||
} elseif ( ! empty( $atts['photo'] ) ) {
|
||||
$showing = 'photo';
|
||||
$src = $atts['photo'];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
$src = str_replace( 'http://', 'https://', $src );
|
||||
|
||||
if ( 'video' === $showing ) {
|
||||
|
||||
$video_id = flick_shortcode_video_id( $src );
|
||||
|
||||
if ( empty( $video_id ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$atts = array_map( 'esc_attr', $atts );
|
||||
return flickr_shortcode_video_markup( $atts, $video_id, $src );
|
||||
} elseif ( 'photo' === $showing ) {
|
||||
|
||||
if ( ! preg_match( '~^(https?:)?//([\da-z\-]+\.)*?((static)?flickr\.com|flic\.kr)/.*~i', $src ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$height = empty( $atts['h'] ) ? 'auto' : esc_attr( $atts['h'] );
|
||||
|
||||
$src = sprintf( '%s/player/', untrailingslashit( $src ) );
|
||||
|
||||
$allow_full_screen = 'allowfullscreen webkitallowfullscreen mozallowfullscreen oallowfullscreen msallowfullscreen';
|
||||
|
||||
if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
|
||||
$allow_full_screen = str_replace( ' oallowfullscreen msallowfullscreen', '', $allow_full_screen );
|
||||
}
|
||||
|
||||
return sprintf( '<iframe src="%s" height="%s" width="%s" frameborder="0" %s></iframe>', esc_url( $src ), $height, esc_attr( $atts['w'] ), $allow_full_screen );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return HTML markup for a Flickr embed.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @param string $id Video ID.
|
||||
* @param string $video_param video param of the shortcode.
|
||||
*
|
||||
* @return string Shortcode ouput for video.
|
||||
*/
|
||||
function flickr_shortcode_video_markup( $atts, $id, $video_param ) {
|
||||
|
||||
$transient_name = "flickr_video_$id";
|
||||
$video_src = get_transient( $transient_name );
|
||||
|
||||
if ( empty( $video_src ) ) {
|
||||
$video_url = '';
|
||||
if ( ! is_numeric( $video_param ) ) {
|
||||
$video_url = $video_param;
|
||||
} else {
|
||||
// Get the URL of the video from the page of the video.
|
||||
$video_page_content = wp_remote_get( "http://flickr.com/photo.gne?id=$video_param" );
|
||||
|
||||
// Bail if we do not get any info from Flickr.
|
||||
if ( is_wp_error( $video_page_content ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Extract the URL from the og:url meta tag.
|
||||
preg_match( '/property=\"og:url\"\scontent=\"([^\"]+)\"/', $video_page_content['body'], $matches );
|
||||
if ( empty( $matches[1] ) ) {
|
||||
return '';
|
||||
}
|
||||
$video_url = $matches[1];
|
||||
}
|
||||
|
||||
$provider = 'https://www.flickr.com/services/oembed/';
|
||||
$oembed = _wp_oembed_get_object();
|
||||
$data = (array) $oembed->fetch( $provider, $video_url );
|
||||
if ( empty( $data['html'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get the embed url.
|
||||
preg_match( '/src=\"([^\"]+)\"/', $data['html'], $matches );
|
||||
|
||||
$embed_url = $matches[1];
|
||||
|
||||
$embed_page = wp_remote_get( $embed_url );
|
||||
|
||||
// Bail if the request returns an error.
|
||||
if ( ! is_array( $embed_page ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get the video url from embed html markup.
|
||||
|
||||
preg_match( '/video.+src=\"([^\"]+)\"/', $embed_page['body'], $matches );
|
||||
|
||||
$video_src = $matches[1];
|
||||
|
||||
set_transient( $transient_name, $video_src, 2592000 ); // 30 days transient.
|
||||
}
|
||||
|
||||
$style = 'max-width: 100%;';
|
||||
|
||||
if ( ! empty( $atts['w'] ) && is_numeric( $atts['w'] ) ) {
|
||||
$style .= sprintf( 'width: %dpx;', $atts['w'] );
|
||||
}
|
||||
|
||||
if ( ! empty( $atts['h'] ) && is_numeric( $atts['h'] ) ) {
|
||||
$style .= sprintf( 'height: %dpx;', $atts['h'] );
|
||||
}
|
||||
|
||||
$controls = 'yes' === $atts['controls'] ? 'controls' : '';
|
||||
$autoplay = 'yes' === $atts['autoplay'] ? 'autoplay' : '';
|
||||
|
||||
return sprintf(
|
||||
'<div class="flick_video" style="%s"><video src="%s" %s %s /></div>',
|
||||
esc_attr( $style ),
|
||||
esc_attr( $video_src ),
|
||||
$controls,
|
||||
$autoplay
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the id of the flickr video from the video param.
|
||||
*
|
||||
* @param string $video_param Video parameter of the shortcode.
|
||||
*
|
||||
* @return string|boolean ID of the video or false in case the ID can not be extracted.
|
||||
*/
|
||||
function flick_shortcode_video_id( $video_param ) {
|
||||
if ( preg_match( '/^https?:\/\/(www\.)?flickr\.com\/.+/', $video_param ) || preg_match( '/^https?:\/\/flic\.kr\/.+/', $video_param ) ) {
|
||||
|
||||
// Extract the video id from the url.
|
||||
preg_match( '/\d+/', $video_param, $matches );
|
||||
|
||||
if ( empty( $matches ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $matches[0];
|
||||
|
||||
} elseif ( is_numeric( $video_param ) ) {
|
||||
return $video_param;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
add_shortcode( 'flickr', 'flickr_shortcode_handler' );
|
||||
|
||||
// Override core's Flickr support because Flickr oEmbed doesn't support web embeds.
|
||||
wp_embed_register_handler( 'flickr', '#https?://(www\.)?flickr\.com/.*#i', 'jetpack_flickr_oembed_handler' );
|
||||
|
||||
/**
|
||||
* Callback to modify output of embedded Vimeo video using Jetpack's shortcode.
|
||||
*
|
||||
* @since 3.9
|
||||
*
|
||||
* @param array $matches Regex partial matches against the URL passed.
|
||||
* @param array $attr Attributes received in embed response.
|
||||
* @param array $url Requested URL to be embedded.
|
||||
*
|
||||
* @return string Return output of Vimeo shortcode with the proper markup.
|
||||
*/
|
||||
function jetpack_flickr_oembed_handler( $matches, $attr, $url ) {
|
||||
/*
|
||||
* Legacy slideshow embeds end with /show/
|
||||
* e.g. http://www.flickr.com/photos/yarnaholic/sets/72157615194738969/show/
|
||||
*/
|
||||
if ( '/show/' !== substr( $url, -strlen( '/show/' ) ) ) {
|
||||
// These lookups need cached, as they don't use WP_Embed (which caches).
|
||||
$cache_key = md5( $url . wp_json_encode( $attr ) );
|
||||
$cache_group = 'oembed_flickr';
|
||||
|
||||
$html = wp_cache_get( $cache_key, $cache_group );
|
||||
|
||||
if ( false === $html ) {
|
||||
$html = _wp_oembed_get_object()->get_html( $url, $attr );
|
||||
|
||||
wp_cache_set( $cache_key, $html, $cache_group, 60 * MINUTE_IN_SECONDS );
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
return flickr_shortcode_handler( array( 'photo' => $url ) );
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
/**
|
||||
* Getty shortcode
|
||||
*
|
||||
* [getty src="82278805" width="$width" height="$height"]
|
||||
* <div class="getty embed image" style="background-color:#fff;display:inline-block;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#a7a7a7;font-size:11px;width:100%;max-width:462px;"><div style="padding:0;margin:0;text-align:left;"><a href="http://www.gettyimages.com/detail/82278805" target="_blank" style="color:#a7a7a7;text-decoration:none;font-weight:normal !important;border:none;display:inline-block;">Embed from Getty Images</a></div><div style="overflow:hidden;position:relative;height:0;padding:80.086580% 0 0 0;width:100%;"><iframe src="//embed.gettyimages.com/embed/82278805?et=jGiu6FXXSpJDGf1SnwLV2g&sig=TFVNFtqghwNw5iJQ1MFWnI8f4Y40_sfogfZLhai6SfA=" width="462" height="370" scrolling="no" frameborder="0" style="display:inline-block;position:absolute;top:0;left:0;width:100%;height:100%;"></iframe></div><p style="margin:0;"></p></div>
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
add_action( 'init', 'jetpack_getty_enable_embeds' );
|
||||
} else {
|
||||
jetpack_getty_enable_embeds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Getty as oembed provider. Add filter to reverse iframes to shortcode. Register [getty] shortcode.
|
||||
*
|
||||
* @since 4.5.0
|
||||
* @since 5.8.0 removed string parameter.
|
||||
*/
|
||||
function jetpack_getty_enable_embeds() {
|
||||
|
||||
// Support their oEmbed Endpoint.
|
||||
wp_oembed_add_provider( '#https?://www\.gettyimages\.com/detail/.*#i', 'https://embed.gettyimages.com/oembed/', true );
|
||||
wp_oembed_add_provider( '#https?://(www\.)?gty\.im/.*#i', 'https://embed.gettyimages.com/oembed/', true );
|
||||
|
||||
// Allow iframes to be filtered to short code (so direct copy+paste can be done).
|
||||
add_filter( 'pre_kses', 'wpcom_shortcodereverse_getty' );
|
||||
|
||||
// Actually display the Getty Embed.
|
||||
add_shortcode( 'getty', 'jetpack_getty_shortcode' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the oEmbed provider URL for Getty URLs to include site URL host as
|
||||
* caller if available, falling back to "wordpress.com". Must be applied at
|
||||
* time of embed in case that `init` is too early (WP.com REST API).
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @see WP_oEmbed::fetch
|
||||
*
|
||||
* @return string oEmbed provider URL
|
||||
*/
|
||||
add_filter( 'oembed_fetch_url', 'getty_add_oembed_endpoint_caller' );
|
||||
|
||||
/**
|
||||
* Filter the embeds to add a caller parameter.
|
||||
*
|
||||
* @param string $provider URL of the oEmbed provider.
|
||||
*/
|
||||
function getty_add_oembed_endpoint_caller( $provider ) {
|
||||
// By time filter is called, original provider URL has had url, maxwidth,
|
||||
// maxheight query parameters added.
|
||||
if ( ! str_starts_with( $provider, 'https://embed.gettyimages.com/oembed/' ) ) {
|
||||
return $provider;
|
||||
}
|
||||
|
||||
// Set the caller argument to pass to Getty's oembed provider.
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
|
||||
// Only include caller for non-private sites.
|
||||
if ( ! function_exists( 'is_private_blog' ) || ! is_private_blog() ) {
|
||||
$host = wp_parse_url( get_bloginfo( 'url' ), PHP_URL_HOST );
|
||||
}
|
||||
|
||||
// Fall back to WordPress.com.
|
||||
if ( empty( $host ) ) {
|
||||
$host = 'wordpress.com';
|
||||
}
|
||||
} else {
|
||||
$host = wp_parse_url( get_home_url(), PHP_URL_HOST );
|
||||
}
|
||||
|
||||
return add_query_arg( 'caller', $host, $provider );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose shortcode based on Getty iframes.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function wpcom_shortcodereverse_getty( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, '.gettyimages.com/' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$regexp = '!<iframe\s+src=[\'"](https?:)?//embed\.gettyimages\.com/embed(/|/?\?assets=)([a-z0-9_-]+(,[a-z0-9_-]+)*)[^\'"]*?[\'"]((?:\s+\w+=[\'"][^\'"]*[\'"])*)((?:[\s\w]*))></iframe>!i';
|
||||
$regexp_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );
|
||||
|
||||
// Markup pattern for 2017 embed syntax with significant differences from the prior pattern.
|
||||
$regexp_2017 = '!<a.+?class=\'gie-(single|slideshow)\'.+?gie\.widgets\.load\({([^}]+)}\).+?embed-cdn\.gettyimages\.com/widgets\.js.+?</script>!';
|
||||
$regexp_2017_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $regexp_2017, ENT_NOQUOTES ) );
|
||||
|
||||
foreach ( compact( 'regexp_2017', 'regexp_2017_ent', 'regexp', 'regexp_ent' ) as $reg => $regexp ) {
|
||||
if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
if ( 'regexp_2017' === $reg || 'regexp_2017_ent' === $reg ) {
|
||||
// Extract individual keys from the matched JavaScript object.
|
||||
$params = $match[2];
|
||||
if ( ! preg_match_all( '!(?P<key>\w+)\s*:\s*([\'"](?P<value>[^\'"]*?)(px)?[\'"])!', $params, $key_matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $key_matches as $key_match ) {
|
||||
switch ( $key_match['key'] ) {
|
||||
case 'items':
|
||||
$ids = $key_match['value'];
|
||||
break;
|
||||
case 'w':
|
||||
$width = (int) $key_match['value'];
|
||||
break;
|
||||
case 'h':
|
||||
$height = (int) $key_match['value'];
|
||||
break;
|
||||
case 'tld':
|
||||
$tld = $key_match['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$params = $match[5];
|
||||
if ( 'regexp_ent' === $reg ) {
|
||||
$params = html_entity_decode( $params, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
|
||||
}
|
||||
$params = wp_kses_hair( $params, array( 'http' ) );
|
||||
|
||||
$ids = esc_html( $match[3] );
|
||||
$width = isset( $params['width'] ) ? (int) $params['width']['value'] : 0;
|
||||
$height = isset( $params['height'] ) ? (int) $params['height']['value'] : 0;
|
||||
}
|
||||
|
||||
if ( empty( $ids ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$shortcode = '[getty src="' . esc_attr( $ids ) . '"';
|
||||
if ( ! empty( $width ) ) {
|
||||
$shortcode .= ' width="' . esc_attr( $width ) . '"';
|
||||
}
|
||||
if ( ! empty( $height ) ) {
|
||||
$shortcode .= ' height="' . esc_attr( $height ) . '"';
|
||||
}
|
||||
|
||||
/*
|
||||
* While it does not appear to have any practical impact, Getty has
|
||||
* requested that we include TLD in the embed request
|
||||
*/
|
||||
if ( ! empty( $tld ) ) {
|
||||
$shortcode .= ' tld="' . esc_attr( $tld ) . '"';
|
||||
}
|
||||
$shortcode .= ']';
|
||||
|
||||
$content = str_replace( $match[0], $shortcode, $content );
|
||||
}
|
||||
}
|
||||
|
||||
// strip out enclosing div and any other markup.
|
||||
$regexp = '%<div class="getty\s[^>]*+>.*?<div[^>]*+>(\[getty[^\]]*+\])\s*</div>.*?</div>%is';
|
||||
$regexp_ent = str_replace( array( '&#0*58;', '[^>]' ), array( '&#0*58;|�*58;', '[^&]' ), htmlspecialchars( $regexp, ENT_NOQUOTES ) );
|
||||
|
||||
foreach ( compact( 'regexp', 'regexp_ent' ) as $reg => $regexp ) {
|
||||
if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
$content = str_replace( $match[0], $match[1], $content );
|
||||
}
|
||||
}
|
||||
|
||||
/** This action is documented in modules/widgets/social-media-icons.php */
|
||||
do_action( 'jetpack_bump_stats_extras', 'html_to_shortcode', 'getty' );
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse shortcode arguments and render its output.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
* @param string $content Content enclosed by shortcode tags.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function jetpack_getty_shortcode( $atts, $content = '' ) {
|
||||
|
||||
if ( ! empty( $content ) ) {
|
||||
$src = $content;
|
||||
} elseif ( ! empty( $atts['src'] ) ) {
|
||||
$src = $atts['src'];
|
||||
} elseif ( ! empty( $atts[0] ) ) {
|
||||
$src = $atts[0];
|
||||
} else {
|
||||
return '<!-- Missing Getty Source ID -->';
|
||||
}
|
||||
|
||||
$src = preg_replace( '/^([\da-z-]+(,[\da-z-]+)*).*$/', '$1', $src );
|
||||
|
||||
$params = array(
|
||||
'width' => isset( $atts['width'] ) ? (int) $atts['width'] : null,
|
||||
'height' => isset( $atts['height'] ) ? (int) $atts['height'] : null,
|
||||
);
|
||||
|
||||
if ( ! empty( $atts['tld'] ) ) {
|
||||
$params['tld'] = $atts['tld'];
|
||||
}
|
||||
|
||||
return wp_oembed_get( 'https://gty.im/' . $src, array_filter( $params ) );
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
<?php
|
||||
/**
|
||||
* GitHub's Gist site supports oEmbed but their oembed provider only
|
||||
* returns raw HTML (no styling) and the first little bit of the code.
|
||||
*
|
||||
* Their JavaScript-based embed method is a lot better, so that's what we're using.
|
||||
*
|
||||
* Supported formats:
|
||||
* Full URL: https://gist.github.com/57cc50246aab776e110060926a2face2
|
||||
* Full URL with username: https://gist.github.com/jeherve/57cc50246aab776e110060926a2face2
|
||||
* Full URL linking to specific file: https://gist.github.com/jeherve/57cc50246aab776e110060926a2face2#file-wp-config-php
|
||||
* Full URL, no username, linking to specific file: https://gist.github.com/57cc50246aab776e110060926a2face2#file-wp-config-php
|
||||
* Gist ID: [gist]57cc50246aab776e110060926a2face2[/gist]
|
||||
* Gist ID within tag: [gist 57cc50246aab776e110060926a2face2]
|
||||
* Gist ID with username: [gist jeherve/57cc50246aab776e110060926a2face2]
|
||||
* Gist private ID with username: [gist xknown/fc5891af153e2cf365c9]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
wp_embed_register_handler( 'github-gist', '#https?://gist\.github\.com/([a-zA-Z0-9/]+)(\#file\-[a-zA-Z0-9\_\-]+)?#', 'github_gist_embed_handler' );
|
||||
add_shortcode( 'gist', 'github_gist_shortcode' );
|
||||
|
||||
/**
|
||||
* Handle gist embeds.
|
||||
*
|
||||
* @since 2.8.0
|
||||
*
|
||||
* @global WP_Embed $wp_embed
|
||||
*
|
||||
* @param array $matches Results after parsing the URL using the regex in wp_embed_register_handler().
|
||||
* @param array $attr Embed attributes.
|
||||
* @param string $url The original URL that was matched by the regex.
|
||||
* @param array $rawattr The original unmodified attributes.
|
||||
* @return string The embed HTML.
|
||||
*/
|
||||
function github_gist_embed_handler( $matches, $attr, $url, $rawattr ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
// Let the shortcode callback do all the work.
|
||||
return github_gist_shortcode( $matches, $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract an ID from a Gist shortcode or a full Gist URL.
|
||||
*
|
||||
* @since 7.3.0
|
||||
*
|
||||
* @param string $gist Gist shortcode or full Gist URL.
|
||||
*
|
||||
* @return array $gist_info {
|
||||
* Array of information about our gist.
|
||||
* @type string $id Unique identifier for the gist.
|
||||
* @type string $file File name if the gist links to a specific file.
|
||||
* }
|
||||
*/
|
||||
function jetpack_gist_get_shortcode_id( $gist = '' ) {
|
||||
$gist_info = array(
|
||||
'id' => '',
|
||||
'file' => '',
|
||||
'ts' => 8,
|
||||
);
|
||||
// Simple shortcode, with just an ID.
|
||||
if ( ctype_alnum( $gist ) ) {
|
||||
$gist_info['id'] = $gist;
|
||||
}
|
||||
|
||||
// Full URL? Only keep the relevant parts.
|
||||
$parsed_url = wp_parse_url( $gist );
|
||||
if (
|
||||
! empty( $parsed_url )
|
||||
&& is_array( $parsed_url )
|
||||
&& isset( $parsed_url['scheme'] ) && isset( $parsed_url['host'] ) && isset( $parsed_url['path'] )
|
||||
) {
|
||||
// Not a Gist URL? Bail.
|
||||
if ( 'gist.github.com' !== $parsed_url['host'] ) {
|
||||
return array(
|
||||
'id' => '',
|
||||
'file' => '',
|
||||
'ts' => 8,
|
||||
);
|
||||
}
|
||||
|
||||
// Keep the file name if there was one.
|
||||
if ( ! empty( $parsed_url['fragment'] ) ) {
|
||||
$gist_info['file'] = preg_replace( '/(?:file-)(.+)/', '$1', $parsed_url['fragment'] );
|
||||
}
|
||||
|
||||
// Keep the unique identifier without any leading or trailing slashes.
|
||||
if ( ! empty( $parsed_url['path'] ) ) {
|
||||
$gist_info['id'] = trim( $parsed_url['path'], '/' );
|
||||
// Overwrite $gist with our identifier to clean it up below.
|
||||
$gist = $gist_info['id'];
|
||||
}
|
||||
|
||||
// Parse the query args to obtain the tab spacing.
|
||||
if ( ! empty( $parsed_url['query'] ) ) {
|
||||
$query_args = array();
|
||||
wp_parse_str( $parsed_url['query'], $query_args );
|
||||
if ( ! empty( $query_args['ts'] ) ) {
|
||||
$gist_info['ts'] = absint( $query_args['ts'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not a URL nor an ID? Look for "username/id", "/username/id", or "id", and only keep the ID.
|
||||
if ( preg_match( '#^/?(([a-z0-9_-]+/)?([a-z0-9]+))$#i', $gist, $matches ) ) {
|
||||
$gist_info['id'] = $matches[3];
|
||||
}
|
||||
|
||||
return $gist_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for gist shortcode.
|
||||
*
|
||||
* @since 2.8.0
|
||||
*
|
||||
* @param array $atts Attributes found in the shortcode.
|
||||
* @param string $content Content enclosed by the shortcode.
|
||||
*
|
||||
* @return string The gist HTML.
|
||||
*/
|
||||
function github_gist_shortcode( $atts, $content = '' ) {
|
||||
|
||||
if ( empty( $atts[0] ) && empty( $content ) ) {
|
||||
if ( current_user_can( 'edit_posts' ) ) {
|
||||
return esc_html__( 'Please specify a Gist URL or ID.', 'jetpack' );
|
||||
} else {
|
||||
return '<!-- Missing Gist ID -->';
|
||||
}
|
||||
}
|
||||
|
||||
$id = ( ! empty( $content ) ) ? $content : $atts[0];
|
||||
|
||||
// Parse a URL to get an ID we can use.
|
||||
$gist_info = jetpack_gist_get_shortcode_id( $id );
|
||||
if ( empty( $gist_info['id'] ) ) {
|
||||
if ( current_user_can( 'edit_posts' ) ) {
|
||||
return esc_html__( 'The Gist ID you provided is not valid. Please try a different one.', 'jetpack' );
|
||||
} else {
|
||||
return '<!-- Invalid Gist ID -->';
|
||||
}
|
||||
} else {
|
||||
// Add trailing .json to all unique gist identifiers.
|
||||
$id = $gist_info['id'] . '.json';
|
||||
}
|
||||
|
||||
// The file name can come from the URL passed, or from a shortcode attribute.
|
||||
if ( ! empty( $gist_info['file'] ) ) {
|
||||
$file = $gist_info['file'];
|
||||
} elseif ( ! empty( $atts['file'] ) ) {
|
||||
$file = $atts['file'];
|
||||
} else {
|
||||
$file = '';
|
||||
}
|
||||
|
||||
// Replace - by . to get a real file name from slug.
|
||||
if ( ! empty( $file ) ) {
|
||||
// Find the last -.
|
||||
$dash_position = strrpos( $file, '-' );
|
||||
if ( false !== $dash_position ) {
|
||||
// Replace the - by a period.
|
||||
$file = substr_replace( $file, '.', $dash_position, 1 );
|
||||
}
|
||||
|
||||
$file = rawurlencode( $file );
|
||||
}
|
||||
|
||||
// Set the tab size, allowing attributes to override the query string.
|
||||
$tab_size = $gist_info['ts'];
|
||||
if ( ! empty( $atts['ts'] ) ) {
|
||||
$tab_size = absint( $atts['ts'] );
|
||||
}
|
||||
|
||||
if (
|
||||
class_exists( 'Jetpack_AMP_Support' )
|
||||
&& Jetpack_AMP_Support::is_amp_request()
|
||||
) {
|
||||
/*
|
||||
* According to <https://www.ampproject.org/docs/reference/components/amp-gist#height-(required)>:
|
||||
*
|
||||
* > Note: You must find the height of the gist by inspecting it with your browser (e.g., Chrome Developer Tools).
|
||||
*
|
||||
* However, this does not seem to be the case any longer. The actual height of the content does get set in the
|
||||
* page after loading. So this is just the initial height.
|
||||
* See <https://github.com/ampproject/amphtml/pull/17738>.
|
||||
*/
|
||||
$height = 240;
|
||||
|
||||
$amp_tag = sprintf(
|
||||
'<amp-gist layout="fixed-height" data-gistid="%s" height="%s"',
|
||||
esc_attr( basename( $id, '.json' ) ),
|
||||
esc_attr( $height )
|
||||
);
|
||||
if ( ! empty( $file ) ) {
|
||||
$amp_tag .= sprintf( ' data-file="%s"', esc_attr( $file ) );
|
||||
}
|
||||
$amp_tag .= '></amp-gist>';
|
||||
return $amp_tag;
|
||||
}
|
||||
|
||||
// URL points to the entire gist, including the file name if there was one.
|
||||
$id = ( ! empty( $file ) ? $id . '?file=' . $file : $id );
|
||||
$return = false;
|
||||
|
||||
$request = wp_remote_get( esc_url_raw( 'https://gist.github.com/' . esc_attr( $id ) ) );
|
||||
$request_code = wp_remote_retrieve_response_code( $request );
|
||||
|
||||
if ( 200 === $request_code ) {
|
||||
$request_body = wp_remote_retrieve_body( $request );
|
||||
$request_data = json_decode( $request_body );
|
||||
|
||||
wp_enqueue_style( 'jetpack-gist-styling', esc_url( $request_data->stylesheet ), array(), JETPACK__VERSION );
|
||||
|
||||
$gist = substr_replace( $request_data->div, sprintf( 'style="tab-size: %1$s" ', absint( $tab_size ) ), 5, 0 );
|
||||
|
||||
// Add inline styles for the tab style in the opening div of the gist.
|
||||
$gist = preg_replace(
|
||||
'#(\<div\s)+(id=\"gist[0-9]+\")+(\sclass=\"gist\"\>)?#',
|
||||
sprintf( '$1style="tab-size: %1$s" $2$3', absint( $tab_size ) ),
|
||||
$request_data->div,
|
||||
1
|
||||
);
|
||||
|
||||
// Add inline style to prevent the bottom margin to the embed that themes like TwentyTen, et al., add to tables.
|
||||
$return = sprintf( '<style>.gist table { margin-bottom: 0; }</style>%1$s', $gist );
|
||||
}
|
||||
|
||||
if (
|
||||
// No need to check for a nonce here, that's already handled by Core further up.
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||
isset( $_POST['type'] )
|
||||
&& 'embed' === $_POST['type']
|
||||
&& isset( $_POST['action'] )
|
||||
&& 'parse-embed' === $_POST['action']
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
) {
|
||||
return github_gist_simple_embed( $id, $tab_size );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use script tag to load shortcode in editor.
|
||||
* Can't use wp_enqueue_script here.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*
|
||||
* @param string $id The ID of the gist.
|
||||
* @param int $tab_size The tab size of the gist.
|
||||
* @return string The script tag of the gist.
|
||||
*/
|
||||
function github_gist_simple_embed( $id, $tab_size = 8 ) {
|
||||
$id = str_replace( 'json', 'js', $id );
|
||||
return '<script src="' . esc_url( "https://gist.github.com/$id?ts=$tab_size" ) . '"></script>'; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
/**
|
||||
* Google Docs and Google Calendar Shortcode
|
||||
*
|
||||
* Presentation:
|
||||
* <iframe src="https://docs.google.com/present/embed?id=dhfhrphh_123drp8s65c&interval=15&autoStart=true&loop=true&size=l" frameborder="0" width="700" height="559"></iframe>
|
||||
* <iframe src="https://docs.google.com/presentation/embed?id=13ItX4jV0SOSdr-ZjHarcpTh9Lr4omfsHAp87jpxv8-0&start=false&loop=false&delayms=3000" frameborder="0" width="960" height="749" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
|
||||
*
|
||||
* Document:
|
||||
* <iframe src="https://docs.google.com/document/pub?id=1kDatklacdZ_tZUOpWtt_ONzY97Ldj2zFcuO9LBY2Ln4&embedded=true"></iframe>
|
||||
* <iframe src="https://docs.google.com/document/d/1kDatklacdZ_tZUOpWtt_ONzY97Ldj2zFcuO9LBY2Ln4/pub?embedded=true"></iframe>
|
||||
* <iframe src="https://docs.google.com/document/d/e/2PACX-1vRkpIdasKL-eKXDjJgpEONduUspZTz0YmKaajfie0eJYnzikuyusuG1_V8X8T9XflN9l8A1oCM2sgEA/pub?embedded=true"></iframe>
|
||||
*
|
||||
* External document:
|
||||
* <iframe width=100% height=560px frameborder=0 src=https://docs.google.com/a/pranab.in/viewer?a=v&pid=explorer&chrome=false&embedded=true&srcid=1VTMwdgGiDMt8MCr75-YkQP-4u9WmEp1Qvf6C26KYBgFilxU2qndpd-VHhBIn&hl=en></iframe>
|
||||
*
|
||||
* Spreadsheet Form:
|
||||
* <iframe src="https://spreadsheets.google.com/embeddedform?formkey=dEVOYnMzZG5jMUpGbjFMYjFYNVB3NkE6MQ" width="760" height="710" frameborder="0" marginheight="0" marginwidth="0">Loading...</iframe>
|
||||
*
|
||||
* Spreadsheet Widget:
|
||||
* <iframe width='500' height='300' frameborder='0' src='https://spreadsheets1.google.com/a/petedavies.com/pub?hl=en&hl=en&key=0AjSij7nlnXvKdHNsNjRSWG12YmVfOEFwdlMxQ3J1S1E&single=true&gid=0&output=html&widget=true'></iframe>
|
||||
* <iframe width='500' height='300' frameborder='0' src='https://spreadsheets.google.com/spreadsheet/pub?hl=en&hl=en&key=0AhInIwfvYrIUdGJiTXhtUEhBSFVPUzdRZU5OMDlqdnc&output=html&widget=true'></iframe>
|
||||
*
|
||||
* Calendar:
|
||||
* <iframe src="https://www.google.com/calendar/embed?src=serjant%40gmail.com&ctz=Europe/Sofia" style="border: 0" width="800" height="600" frameborder="0" scrolling="no"></iframe>
|
||||
* <iframe src="http://www.google.com/calendar/hosted/belcastro.com/embed?src=n8nr8sd6v9hnus3nmlk7ed1238%40group.calendar.google.com&ctz=Europe/Zurich" style="border: 0" width="800" height="600" frameborder="0" scrolling="no"></iframe>
|
||||
*
|
||||
* Customized calendar:
|
||||
* <iframe src="https://www.google.com/calendar/embed?title=asdf&showTitle=0&showNav=0&showDate=0&showPrint=0&showTabs=0&showCalendars=0&
|
||||
* showTz=0&mode=AGENDA&height=300&wkst=2&hl=fi&bgcolor=%23ffcccc&src=m52gdmbgelo3itf00u1v44g0ns%40group.calendar.google.com&color=%234E5D6C&
|
||||
* src=serjant%40gmail.com&color=%235229A3&ctz=Europe%2FRiga" style=" border:solid 1px #777 " width="500" height="300" frameborder="0" scrolling="no"></iframe>
|
||||
*
|
||||
* Generic
|
||||
* <iframe src="https://docs.google.com/file/d/0B0SIdZW7iu-zX1RWREJpMXVHZVU/preview" width="640" height="480"></iframe>
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
add_filter( 'pre_kses', 'googleapps_embed_to_shortcode' );
|
||||
add_shortcode( 'googleapps', 'googleapps_shortcode' );
|
||||
|
||||
/**
|
||||
* Reverse iframe embed to shortcode mapping HTML attributes to shortcode attributes.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function googleapps_embed_to_shortcode( $content ) {
|
||||
if (
|
||||
! is_string( $content )
|
||||
|| false === stripos( $content, '<iframe' )
|
||||
&& false === stripos( $content, '.google.com' )
|
||||
) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$regexp = '#<iframe((?:\s+\w+="[^"]*")*?)\s*src="https?://(docs|drive|spreadsheets\d*|calendar|www)*\.google\.com/(?!maps)([-\w\./]+)(?:\?)?([^"]+)?"\s*((?:\s+\w+="[^"]*")*?)>.*?</iframe>#i';
|
||||
$regexp_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );
|
||||
$regexp_squot = str_replace( '"', "'", $regexp );
|
||||
$regexp_ent_squot = str_replace( '"', "'", $regexp_ent );
|
||||
$regexp_noquot = '!<iframe(.*?)src=https://(docs|drive)\.google\.com/[-\.\w/]*?(viewer)\?(.*?)>(.*?)</iframe>!';
|
||||
$regexp_ent_noquot = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $regexp_noquot, ENT_NOQUOTES ) );
|
||||
|
||||
foreach ( compact( 'regexp', 'regexp_ent', 'regexp_squot', 'regexp_ent_squot', 'regexp_noquot', 'regexp_ent_noquot' ) as $reg => $regexp ) {
|
||||
if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
$params = $match[1] . $match[5];
|
||||
if ( in_array( $reg, array( 'regexp_ent', 'regexp_ent_squot' ), true ) ) {
|
||||
$params = html_entity_decode( $params, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
|
||||
}
|
||||
|
||||
$params = wp_kses_hair( $params, array( 'http' ) );
|
||||
|
||||
$width = 0;
|
||||
$height = 0;
|
||||
|
||||
if ( isset( $params['width'] ) ) {
|
||||
$width = (int) $params['width']['value'];
|
||||
}
|
||||
|
||||
if ( isset( $params['height'] ) ) {
|
||||
$height = (int) $params['height']['value'];
|
||||
}
|
||||
|
||||
// allow the user to specify width greater than 200 inside text widgets.
|
||||
if (
|
||||
$width > 400
|
||||
// We don't need to check a nonce here. A nonce is already checked "further up" in most code paths.
|
||||
// In the case where no nonce is ever checked, setting this $_POST parameter doesn't do anything the submitter couldn't already do (set the width/height).
|
||||
&& isset( $_POST['widget-text'] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
) {
|
||||
$width = 200;
|
||||
$height = 200;
|
||||
}
|
||||
|
||||
$attributes = '';
|
||||
if ( isset( $params['width'] ) && '100%' === $params['width']['value'] ) {
|
||||
$width = '100%';
|
||||
}
|
||||
|
||||
if ( $width ) {
|
||||
$attributes = ' width="' . $width . '"';
|
||||
}
|
||||
|
||||
if ( $height ) {
|
||||
$attributes .= ' height="' . $height . '"';
|
||||
}
|
||||
|
||||
$domain = 'spreadsheets';
|
||||
if ( in_array( $match[2], array( 'docs', 'drive', 'www', 'calendar' ), true ) ) {
|
||||
$domain = $match[2];
|
||||
}
|
||||
|
||||
// Make sure this is actually something that the shortcode supports. If it's not, leave the HTML alone.
|
||||
if ( ! googleapps_validate_domain_and_dir( $domain, $match[3] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** This action is documented in modules/widgets/social-media-icons.php */
|
||||
do_action( 'jetpack_bump_stats_extras', 'html_to_shortcode', googleapps_service_name( $domain, $match[3] ) );
|
||||
|
||||
$content = str_replace( $match[0], '[googleapps domain="' . $domain . '" dir="' . $match[3] . '" query="' . esc_attr( $match[4] ) . '"' . $attributes . ' /]', $content );
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse shortcode attributes and output a Google Docs embed.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function googleapps_shortcode( $atts ) {
|
||||
global $content_width;
|
||||
|
||||
$attr = shortcode_atts(
|
||||
array(
|
||||
'width' => '100%',
|
||||
'height' => '560',
|
||||
'domain' => 'docs',
|
||||
'dir' => 'document',
|
||||
'query' => '',
|
||||
'src' => '',
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
if ( is_numeric( $content_width ) && $content_width > 0 && is_numeric( $attr['width'] ) && $attr['width'] > $content_width ) {
|
||||
$attr['width'] = $content_width;
|
||||
}
|
||||
|
||||
if ( is_numeric( $content_width ) && $content_width > 0 && '560' === $attr['height'] ) {
|
||||
$attr['height'] = floor( $content_width * 3 / 4 );
|
||||
}
|
||||
|
||||
if ( isset( $atts[0] ) && $atts[0] ) {
|
||||
$attr['src'] = $atts[0];
|
||||
}
|
||||
|
||||
if ( $attr['src'] && preg_match( '!https?://(docs|drive|spreadsheets\d*|calendar|www)*\.google\.com/([-\w\./]+)\?([^"]+)!', $attr['src'], $matches ) ) {
|
||||
$attr['domain'] = $matches[1];
|
||||
$attr['dir'] = $matches[2];
|
||||
parse_str( htmlspecialchars_decode( $matches[3], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ), $query_ar );
|
||||
$query_ar['chrome'] = 'false';
|
||||
$query_ar['embedded'] = 'true';
|
||||
$attr['query'] = http_build_query( $query_ar );
|
||||
}
|
||||
|
||||
if ( ! googleapps_validate_domain_and_dir( $attr['domain'], $attr['dir'] ) ) {
|
||||
return '<!-- Unsupported URL -->';
|
||||
}
|
||||
|
||||
$attr['query'] = $attr['dir'] . '?' . $attr['query'];
|
||||
|
||||
/** This action is documented in modules/widgets/social-media-icons.php */
|
||||
do_action( 'jetpack_bump_stats_extras', 'embeds', googleapps_service_name( $attr['domain'], $attr['dir'] ) );
|
||||
|
||||
return sprintf(
|
||||
'<iframe src="%s" frameborder="0" width="%s" height="%s" marginheight="0" marginwidth="0" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>',
|
||||
esc_url( 'https://' . $attr['domain'] . '.google.com/' . $attr['query'] ),
|
||||
esc_attr( $attr['width'] ),
|
||||
esc_attr( $attr['height'] )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the domain blogs to a Google Apps domain.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $domain Google subdomain.
|
||||
* @param string $dir Subdirectory of the shared URL.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function googleapps_validate_domain_and_dir( $domain, $dir ) {
|
||||
if ( ! in_array( $domain, array( 'docs', 'drive', 'www', 'spreadsheets', 'calendar' ), true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calendars.
|
||||
if ( ( 'www' === $domain || 'calendar' === $domain ) && ! str_starts_with( $dir, 'calendar/' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Docs.
|
||||
if ( in_array( $domain, array( 'docs', 'drive' ), true ) && ! preg_match( '![-\.\w/]*(presentation/embed|presentation/d/(.*)|present/embed|document/pub|spreadsheets/d/(.*)|document/d/(e/)?[\w-]+/pub|file/d/[\w-]+/preview|viewer|forms/d/(.*)/viewform|spreadsheet/\w+)$!', $dir ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Spreadsheets.
|
||||
if ( 'spreadsheets' === $domain && ! preg_match( '!^([-\.\w/]+/pub|[-\.\w/]*embeddedform)$!', $dir ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the service we'll be embedding.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $domain Google subdomain.
|
||||
* @param string $dir Subdirectory of the shared URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function googleapps_service_name( $domain, $dir ) {
|
||||
switch ( $domain ) {
|
||||
case 'drive':
|
||||
case 'docs':
|
||||
$service_name = ( 'present/embed' === $dir ) ? 'googledocs_presentation' : 'googledocs_document';
|
||||
break;
|
||||
case 'spreadsheets':
|
||||
$service_name = ( 'embeddedform' === $dir ) ? 'googledocs_form' : 'googledocs_spreadsheet';
|
||||
break;
|
||||
case 'calendar':
|
||||
default:
|
||||
$service_name = 'google_calendar';
|
||||
}
|
||||
|
||||
return $service_name;
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
/**
|
||||
* Google Maps embeds.
|
||||
*
|
||||
* Supported formats:
|
||||
* <iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://maps.google.com/maps?f=q&source=s_q&hl=bg&geocode=&q=%D0%9C%D0%BB%D0%B0%D0%B4%D0%BE%D1%81%D1%82+1,+%D0%A1%D0%BE%D1%84%D0%B8%D1%8F,+%D0%91%D1%8A%D0%BB%D0%B3%D0%B0%D1%80%D0%B8%D1%8F&sll=37.0625,-95.677068&sspn=40.545434,79.013672&ie=UTF8&hq=&hnear=%D0%9C%D0%BB%D0%B0%D0%B4%D0%BE%D1%81%D1%82+1&ll=42.654446,23.372061&spn=0.036864,0.077162&t=h&z=14&output=embed"></iframe><br /><small><a href="http://maps.google.com/maps?f=q&source=embed&hl=bg&geocode=&q=%D0%9C%D0%BB%D0%B0%D0%B4%D0%BE%D1%81%D1%82+1,+%D0%A1%D0%BE%D1%84%D0%B8%D1%8F,+%D0%91%D1%8A%D0%BB%D0%B3%D0%B0%D1%80%D0%B8%D1%8F&sll=37.0625,-95.677068&sspn=40.545434,79.013672&ie=UTF8&hq=&hnear=%D0%9C%D0%BB%D0%B0%D0%B4%D0%BE%D1%81%D1%82+1&ll=42.654446,23.372061&spn=0.036864,0.077162&t=h&z=14" style="color:#0000FF;text-align:left">Вижте по-голяма карта</a></small>
|
||||
* [googlemaps https://maps.google.com/maps?f=q&hl=en&geocode=&q=San+Francisco,+CA&sll=43.469466,-83.998504&sspn=0.01115,0.025942&g=San+Francisco,+CA&ie=UTF8&z=12&iwloc=addr&ll=37.808156,-122.402458&output=embed&s=AARTsJp56EajYksz3JXgNCwT3LJnGsqqAQ&w=425&h=350]
|
||||
* [googlemaps https://mapsengine.google.com/map/embed?mid=zbBhkou4wwtE.kUmp8K6QJ7SA&w=640&h=480]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Google maps iframe - transforms code that looks like that:
|
||||
* <iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://maps.google.com/maps?f=q&source=s_q&hl=bg&geocode=&q=%D0%9C%D0%BB%D0%B0%D0%B4%D0%BE%D1%81%D1%82+1,+%D0%A1%D0%BE%D1%84%D0%B8%D1%8F,+%D0%91%D1%8A%D0%BB%D0%B3%D0%B0%D1%80%D0%B8%D1%8F&sll=37.0625,-95.677068&sspn=40.545434,79.013672&ie=UTF8&hq=&hnear=%D0%9C%D0%BB%D0%B0%D0%B4%D0%BE%D1%81%D1%82+1&ll=42.654446,23.372061&spn=0.036864,0.077162&t=h&z=14&output=embed"></iframe><br /><small><a href="http://maps.google.com/maps?f=q&source=embed&hl=bg&geocode=&q=%D0%9C%D0%BB%D0%B0%D0%B4%D0%BE%D1%81%D1%82+1,+%D0%A1%D0%BE%D1%84%D0%B8%D1%8F,+%D0%91%D1%8A%D0%BB%D0%B3%D0%B0%D1%80%D0%B8%D1%8F&sll=37.0625,-95.677068&sspn=40.545434,79.013672&ie=UTF8&hq=&hnear=%D0%9C%D0%BB%D0%B0%D0%B4%D0%BE%D1%81%D1%82+1&ll=42.654446,23.372061&spn=0.036864,0.077162&t=h&z=14" style="color:#0000FF;text-align:left">Вижте по-голяма карта</a></small>
|
||||
* into the [googlemaps http://...] shortcode format
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*/
|
||||
function jetpack_googlemaps_embed_to_short_code( $content ) {
|
||||
|
||||
if ( ! is_string( $content ) || ( ! str_contains( $content, 'maps.google.' ) && 1 !== preg_match( '@google\.[^/]+/maps?@', $content ) ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
/*
|
||||
* IE and TinyMCE format things differently
|
||||
* <iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="<a href="https://maps.google.co.uk/maps/ms?msa=0&amp;msid=206216869547772496318.0004bf5f0ff25aea47bd9&amp;hl=en&amp;ie=UTF8&amp;t=m&amp;ll=50.91917,-1.398808&amp;spn=0.013225,0.011794&amp;output=embed"></iframe><br">https://maps.google.co.uk/maps/ms?msa=0&amp;msid=206216869547772496318.0004bf5f0ff25aea47bd9&amp;hl=en&amp;ie=UTF8&amp;t=m&amp;ll=50.91917,-1.398808&amp;spn=0.013225,0.011794&amp;output=embed"></iframe><br</a> /><small>View <a href="<a href="https://maps.google.co.uk/maps/ms?msa=0&amp;msid=206216869547772496318.0004bf5f0ff25aea47bd9&amp;hl=en&amp;ie=UTF8&amp;t=m&amp;ll=50.91917,-1.398808&amp;spn=0.013225,0.011794&amp;source=embed">https://maps.google.co.uk/maps/ms?msa=0&amp;msid=206216869547772496318.0004bf5f0ff25aea47bd9&amp;hl=en&amp;ie=UTF8&amp;t=m&amp;ll=50.91917,-1.398808&amp;spn=0.013225,0.011794&amp;source=embed</a>" style="color:#0000FF;text-align:left">OARA Membership Discount Map</a> in a larger map</small>
|
||||
*/
|
||||
if ( strpos( $content, 'src="<a href="' ) !== false ) {
|
||||
$content = preg_replace_callback( '#<iframe\s[^&]*?(?:&(?!gt;)[^&]*?)*?src="<a href="https?://(.*)?\.google\.(.*?)/(.*?)\?(.+?)"[^&]*?(?:&(?!gt;)[^&]*?)*?>\s*</iframe><br">[^"]*?">\s*</iframe>(?:<br</a>\s*/>\s*<small>.*?</small>)?#i', 'jetpack_googlemaps_embed_to_short_code_callback', $content );
|
||||
return $content;
|
||||
}
|
||||
|
||||
$content = preg_replace_callback( '!\<iframe\s[^>]*?src="https?://(.*)?\.google\.(.*?)/(.*?)\?(.+?)"[^>]*?\>\s*\</iframe\>(?:\s*(?:\<br\s*/?\>)?\s*\<small\>.*?\</small\>)?!i', 'jetpack_googlemaps_embed_to_short_code_callback', $content );
|
||||
|
||||
$content = preg_replace_callback( '#<iframe\s[^&]*?(?:&(?!gt;)[^&]*?)*?src="https?://(.*)?\.google\.(.*?)/(.*?)\?(.+?)"[^&]*?(?:&(?!gt;)[^&]*?)*?>\s*</iframe>(?:\s*(?:<br\s*/?>)?\s*<small>.*?</small>)?#i', 'jetpack_googlemaps_embed_to_short_code_callback', $content );
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback transforming a Google Maps iFrame code into a shortcode.
|
||||
*
|
||||
* @param array $match Array of embed parameters used to build the final URL.
|
||||
*/
|
||||
function jetpack_googlemaps_embed_to_short_code_callback( $match ) {
|
||||
|
||||
if ( preg_match( '/\bwidth=[\'"](\d+)(%)?/', $match[0], $width ) ) {
|
||||
$percent = ! empty( $width[2] ) ? '%' : '';
|
||||
$width = absint( $width[1] ) . $percent;
|
||||
} else {
|
||||
$width = 425;
|
||||
}
|
||||
|
||||
if ( preg_match( '/\bheight=[\'"](\d+)(%)?/', $match[0], $height ) ) {
|
||||
$percent = ! empty( $height[2] ) ? '%' : '';
|
||||
$height = absint( $height[1] ) . $percent;
|
||||
} else {
|
||||
$height = 350;
|
||||
}
|
||||
|
||||
$url = "https://{$match[1]}.google.{$match[2]}/{$match[3]}?{$match[4]}&w={$width}&h={$height}";
|
||||
|
||||
/** This action is documented in modules/shortcodes/youtube.php */
|
||||
do_action( 'jetpack_embed_to_shortcode', 'googlemaps', $url );
|
||||
|
||||
return "[googlemaps $url]";
|
||||
}
|
||||
|
||||
add_filter( 'pre_kses', 'jetpack_googlemaps_embed_to_short_code' );
|
||||
|
||||
/**
|
||||
* Display the [googlemaps] shortcode
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function jetpack_googlemaps_shortcode( $atts ) {
|
||||
if ( ! isset( $atts[0] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$params = ltrim( $atts[0], '=' );
|
||||
|
||||
$width = 425;
|
||||
$height = 350;
|
||||
|
||||
if ( preg_match( '!^https?://(www|maps|mapsengine)\.google(\.co|\.com)?(\.[a-z]+)?/.*?(\?.+)!i', $params, $match ) ) {
|
||||
$params = str_replace( '&amp;', '&', $params );
|
||||
$params = str_replace( '&', '&', $params );
|
||||
parse_str( $params, $arg );
|
||||
|
||||
if ( isset( $arg['hq'] ) ) {
|
||||
unset( $arg['hq'] );
|
||||
}
|
||||
|
||||
$url = '';
|
||||
foreach ( (array) $arg as $key => $value ) {
|
||||
if ( 'w' === $key ) {
|
||||
$percent = ( str_ends_with( $value, '%' ) ) ? '%' : '';
|
||||
$width = (int) $value . $percent;
|
||||
} elseif ( 'h' === $key ) {
|
||||
$height = (int) $value;
|
||||
} else {
|
||||
$key = str_replace( '_', '.', $key );
|
||||
$url .= esc_attr( "$key=$value&" );
|
||||
}
|
||||
}
|
||||
$url = substr( $url, 0, -5 );
|
||||
|
||||
$url = str_replace( 'http://', 'https://', $url );
|
||||
|
||||
$css_class = 'googlemaps';
|
||||
|
||||
if ( ! empty( $atts['align'] ) && in_array( strtolower( $atts['align'] ), array( 'left', 'center', 'right' ), true ) ) {
|
||||
$atts['align'] = strtolower( $atts['align'] );
|
||||
|
||||
if ( 'left' === $atts['align'] ) {
|
||||
$css_class .= ' alignleft';
|
||||
} elseif ( 'center' === $atts['align'] ) {
|
||||
$css_class .= ' aligncenter';
|
||||
} elseif ( 'right' === $atts['align'] ) {
|
||||
$css_class .= ' alignright';
|
||||
}
|
||||
}
|
||||
|
||||
$sandbox = class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request()
|
||||
? 'sandbox="allow-popups allow-scripts allow-same-origin"'
|
||||
: '';
|
||||
|
||||
return sprintf(
|
||||
'<div class="%1$s">
|
||||
<iframe width="%2$d" height="%3$d" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" %5$s src="%4$s"></iframe>
|
||||
</div>',
|
||||
esc_attr( $css_class ),
|
||||
absint( $width ),
|
||||
absint( $height ),
|
||||
esc_url( $url ),
|
||||
$sandbox
|
||||
);
|
||||
}
|
||||
}
|
||||
add_shortcode( 'googlemaps', 'jetpack_googlemaps_shortcode' );
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* Google+ embeds
|
||||
* Google+ has shut down. Output the link for history's sake.
|
||||
* Other than that, there's not much we can do.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
define( 'JETPACK_GOOGLEPLUS_EMBED_REGEX', '#^https?://plus\.(sandbox\.)?google\.com/(u/\d+/)?([^/]+)/posts/([^/]+)$#' );
|
||||
|
||||
/*
|
||||
* Example URL: https://plus.google.com/114986219448604314131/posts/LgHkesWCmJo
|
||||
* Alternate example: https://plus.google.com/u/0/100004581596612508203/posts/2UKwN67MBQs (note the /u/0/)
|
||||
*/
|
||||
wp_embed_register_handler( 'googleplus', JETPACK_GOOGLEPLUS_EMBED_REGEX, 'jetpack_deprecated_embed_handler' );
|
||||
|
||||
add_shortcode( 'googleplus', 'jetpack_googleplus_shortcode_handler' );
|
||||
|
||||
/**
|
||||
* Display the Google+ shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function jetpack_googleplus_shortcode_handler( $atts ) {
|
||||
global $wp_embed;
|
||||
|
||||
if ( empty( $atts['url'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! preg_match( JETPACK_GOOGLEPLUS_EMBED_REGEX, $atts['url'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return sprintf( '<p>%s</p>', $wp_embed->shortcode( $atts, $atts['url'] ) );
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
/**
|
||||
* Gravatar shortcode for avatar and profile.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* [gravatar email="user@example.org" size="48"]
|
||||
* [gravatar_profile who="user@example.org"]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
add_shortcode( 'gravatar', 'jetpack_gravatar_shortcode' );
|
||||
add_shortcode( 'gravatar_profile', 'jetpack_gravatar_profile_shortcode' );
|
||||
|
||||
/**
|
||||
* Get gravatar using the email provided at the specified size.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
function jetpack_gravatar_shortcode( $atts ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'email' => '',
|
||||
'size' => 96,
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
if ( empty( $atts['email'] ) || ! is_email( $atts['email'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$atts['size'] = (int) $atts['size'];
|
||||
if ( 0 > $atts['size'] ) {
|
||||
$atts['size'] = 96;
|
||||
}
|
||||
|
||||
return get_avatar( $atts['email'], $atts['size'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Gravatar profile
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*
|
||||
* @uses shortcode_atts()
|
||||
* @uses get_user_by()
|
||||
* @uses is_email()
|
||||
* @uses sanitize_email()
|
||||
* @uses sanitize_user()
|
||||
* @uses set_url_scheme()
|
||||
* @uses wpcom_get_avatar_url()
|
||||
* @uses get_user_attribute()
|
||||
* @uses esc_url()
|
||||
* @uses esc_html()
|
||||
* @uses _e()
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function jetpack_gravatar_profile_shortcode( $atts ) {
|
||||
// Give each use of the shortcode a unique ID.
|
||||
static $instance = 0;
|
||||
|
||||
// Process passed attributes.
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'who' => null,
|
||||
),
|
||||
$atts,
|
||||
'jetpack_gravatar_profile'
|
||||
);
|
||||
|
||||
// Can specify username, user ID, or email address.
|
||||
if ( is_numeric( $atts['who'] ) ) {
|
||||
$user_id = (int) $atts['who'];
|
||||
if ( ! is_user_member_of_blog( $user_id, get_current_blog_id() ) ) {
|
||||
// Bail if the user id is not a member of this site.
|
||||
return false;
|
||||
}
|
||||
$user = get_user_by( 'id', $user_id );
|
||||
} elseif ( is_email( $atts['who'] ) ) {
|
||||
$user = get_user_by( 'email', sanitize_email( $atts['who'] ) );
|
||||
} elseif ( is_string( $atts['who'] ) ) {
|
||||
$user = get_user_by( 'login', sanitize_user( $atts['who'] ) );
|
||||
} else {
|
||||
$user = false;
|
||||
}
|
||||
|
||||
// Bail if we don't have a user.
|
||||
if ( false === $user ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hashed_email = hash( 'sha256', strtolower( trim( $user->user_email ) ) );
|
||||
$cache_key = 'jetpack_gravatar_profile_' . $hashed_email;
|
||||
$profile = get_transient( $cache_key );
|
||||
|
||||
if ( empty( $profile ) ) {
|
||||
$profile_url = sprintf(
|
||||
'https://secure.gravatar.com/%s.json',
|
||||
$hashed_email
|
||||
);
|
||||
|
||||
$response = wp_remote_get(
|
||||
esc_url_raw( $profile_url ),
|
||||
array( 'User-Agent' => 'Jetpack Plugin Gravatar Profile Shortcode' )
|
||||
);
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
$expire = 300; // Cache any errors for 5 minutes.
|
||||
$profile = array();
|
||||
|
||||
if ( $response_code === 200 ) {
|
||||
$profile = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
|
||||
if (
|
||||
is_array( $profile )
|
||||
&& ! empty( $profile['entry'] )
|
||||
&& is_array( $profile['entry'] )
|
||||
) {
|
||||
// Sucessfully fetched the profile. Cache for 15 minutes.
|
||||
$expire = 900;
|
||||
$profile = $profile['entry'][0];
|
||||
}
|
||||
}
|
||||
|
||||
set_transient( $cache_key, $profile, $expire );
|
||||
}
|
||||
|
||||
// Fetching the profile returned an error. Bail.
|
||||
if ( empty( $profile ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Render the shortcode.
|
||||
$gravatar_url = 'https://gravatar.com/' . $hashed_email;
|
||||
$user_location = ! empty( $profile['currentLocation'] ) ? $profile['currentLocation'] : '';
|
||||
$display_name = ! empty( $profile['displayName'] ) ? $profile['displayName'] : '';
|
||||
$user_description = ! empty( $profile['aboutMe'] ) ? $profile['aboutMe'] : '';
|
||||
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
$gravatar_url = 'https://gravatar.com/' . $user->user_login;
|
||||
$avatar_url = wpcom_get_avatar_url( $user->ID, 96 );
|
||||
$avatar_url = $avatar_url[0];
|
||||
} else {
|
||||
$avatar_url = get_avatar_url( $user->user_email, array( 'size' => 96 ) );
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
|
||||
wp_enqueue_style( 'gravatar-style', plugins_url( '/css/gravatar-amp.css', __FILE__ ), array(), JETPACK__VERSION );
|
||||
} else {
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
( function() {
|
||||
if ( null === document.getElementById( 'gravatar-profile-embed-styles' ) ) {
|
||||
var headID = document.getElementsByTagName( 'head' )[0];
|
||||
var styleNode = document.createElement( 'style' );
|
||||
styleNode.type = 'text/css';
|
||||
styleNode.id = 'gravatar-profile-embed-styles';
|
||||
|
||||
var gCSS = '.grofile-wrap { border: solid 1px #f0f0f1; padding: 10px; } .grofile { padding: 0 0 5px 0; } .grofile-left { float: left; display: block; width: 96px; margin-right: 15px; } .grofile .gravatar { margin-bottom: 5px; } .grofile-clear { clear: left; font-size: 1px; height: 1px; } .grofile ul li a { text-indent: -99999px; } .grofile .grofile-left a:hover { text-decoration: none !important; border: none !important; } .grofile-name { margin-top: 0; }';
|
||||
|
||||
if ( document.all ) {
|
||||
styleNode.innerText = gCSS;
|
||||
} else {
|
||||
styleNode.textContent = gCSS;
|
||||
}
|
||||
|
||||
headID.appendChild( styleNode );
|
||||
}
|
||||
} )();
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="grofile vcard" id="grofile-embed-<?php echo esc_attr( $instance ); ?>">
|
||||
<div class="grofile-inner">
|
||||
<div class="grofile-left">
|
||||
<div class="grofile-img">
|
||||
<a href="<?php echo esc_url( $gravatar_url ); ?>">
|
||||
<img src="<?php echo esc_url( $avatar_url ); ?>" width="96" height="96" class="no-grav gravatar photo" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grofile-right">
|
||||
<p class="grofile-name fn">
|
||||
<strong><?php echo esc_html( $display_name ); ?></strong>
|
||||
<?php
|
||||
if ( ! empty( $user_location ) ) :
|
||||
?>
|
||||
<br><span class="grofile-location adr"><?php echo esc_html( $user_location ); ?></span><?php endif; ?>
|
||||
</p>
|
||||
<p class="grofile-bio">
|
||||
<strong><?php esc_html_e( 'Bio:', 'jetpack' ); ?></strong> <?php echo wp_kses_post( $user_description ); ?>
|
||||
</p>
|
||||
<p class="grofile-view">
|
||||
<a href="<?php echo esc_url( $gravatar_url ); ?>"><?php esc_html_e( 'View complete profile', 'jetpack' ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
<span class="grofile-clear"> </span>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
// Increment and return the rendered profile.
|
||||
++$instance;
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* Houzz Embed
|
||||
*
|
||||
* Examples:
|
||||
* Post content:
|
||||
* - [houzz=http://www.houzz.com/pro/james-crisp]
|
||||
* - http://www.houzz.com/pro/james-crisp
|
||||
* Blog sidebar: [houzz=http://www.houzz.com/profile/alon w=200 h=300]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
// Register oEmbed provider.
|
||||
wp_oembed_add_provider( '#https?://(.+?\.)?houzz\.(com|co\.uk|com\.au|de|fr|ru|jp|it|es|dk|se)/.*#i', 'https://www.houzz.com/oembed', true );
|
||||
|
||||
/**
|
||||
* Display shortcode
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function jetpack_houzz_shortcode( $atts ) {
|
||||
$url = substr( $atts[0], 1 );
|
||||
$args = array();
|
||||
if ( isset( $atts['w'] ) && is_numeric( $atts['w'] ) ) {
|
||||
$args['width'] = $atts['w'];
|
||||
}
|
||||
if ( isset( $atts['h'] ) && is_numeric( $atts['h'] ) ) {
|
||||
$args['height'] = $atts['h'];
|
||||
}
|
||||
$oembed = _wp_oembed_get_object();
|
||||
return $oembed->get_html( $url, $args );
|
||||
}
|
||||
add_shortcode( 'houzz', 'jetpack_houzz_shortcode' );
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 733 B |
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Embed support for Inline PDFs
|
||||
*
|
||||
* Takes a plain-text PDF URL (*.pdf), and attempts to embed it directly
|
||||
* in the post instead of leaving it as a bare link.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
wp_embed_register_handler( 'inline-pdfs', '#https?://[^<]*\.pdf$#i', 'jetpack_inline_pdf_embed_handler' );
|
||||
|
||||
/**
|
||||
* Callback to modify the output of embedded PDF files.
|
||||
*
|
||||
* @param array $matches Regex partial matches against the URL passed.
|
||||
* @param array $attr Attributes received in embed response.
|
||||
* @param array $url Requested URL to be embedded.
|
||||
*/
|
||||
function jetpack_inline_pdf_embed_handler( $matches, $attr, $url ) {
|
||||
/** This action is documented in modules/widgets/social-media-icons.php */
|
||||
do_action( 'jetpack_bump_stats_extras', 'embeds', 'inline-pdf' );
|
||||
|
||||
$filename = basename( wp_parse_url( $url, PHP_URL_PATH ) );
|
||||
$fallback_text = sprintf(
|
||||
/* translators: Placeholder is a file name, for example "file.pdf" */
|
||||
esc_html__( 'Click to access %1$s', 'jetpack' ),
|
||||
$filename
|
||||
);
|
||||
|
||||
return sprintf(
|
||||
'<p><a href="%1$s" target="_blank" rel="noopener noreferrer nofollow">%2$s</a></p>',
|
||||
esc_url( $url ),
|
||||
$fallback_text
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
<?php
|
||||
/**
|
||||
* Instagram Embeds.
|
||||
*
|
||||
* Full links: https://www.instagram.com/p/BnMOk_FFsxg/
|
||||
* https://www.instagram.com/tv/BkQjCfsBIzi/
|
||||
* [instagram url=https://www.instagram.com/p/BnMOk_FFsxg/]
|
||||
* [instagram url=https://www.instagram.com/p/BZoonmAHvHf/ width=320]
|
||||
* Embeds can be converted to a shortcode when the author does not have unfiltered_html caps:
|
||||
* <blockquote class="instagram-media" data-instgrm-captioned data-instgrm-version="2" style=" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);"><div style="padding:8px;"><div style=" background:#F8F8F8; line-height:0; margin-top:40px; padding-bottom:55%; padding-top:45%; text-align:center; width:100%;"><div style="position:relative;"><div style=" -webkit-animation:dkaXkpbBxI 1s ease-out infinite; animation:dkaXkpbBxI 1s ease-out infinite; background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAAAGFBMVEUiIiI9PT0eHh4gIB4hIBkcHBwcHBwcHBydr+JQAAAACHRSTlMABA4YHyQsM5jtaMwAAADfSURBVDjL7ZVBEgMhCAQBAf//42xcNbpAqakcM0ftUmFAAIBE81IqBJdS3lS6zs3bIpB9WED3YYXFPmHRfT8sgyrCP1x8uEUxLMzNWElFOYCV6mHWWwMzdPEKHlhLw7NWJqkHc4uIZphavDzA2JPzUDsBZziNae2S6owH8xPmX8G7zzgKEOPUoYHvGz1TBCxMkd3kwNVbU0gKHkx+iZILf77IofhrY1nYFnB/lQPb79drWOyJVa/DAvg9B/rLB4cC+Nqgdz/TvBbBnr6GBReqn/nRmDgaQEej7WhonozjF+Y2I/fZou/qAAAAAElFTkSuQmCC); display:block; height:44px; margin:0 auto -44px; position:relative; top:-44px; width:44px;"></div><span style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:12px; font-style:normal; font-weight:bold; position:relative; top:15px;">Loading</span></div></div><p style=" font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin:8px 0 0 0; padding:0 4px; word-wrap:break-word;"> Balloons</p><p style=" line-height:32px; margin-bottom:0; margin-top:8px; padding:0; text-align:center;"> <a href="https://instagram.com/p/r9vfPrmjeB/" style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; text-decoration:none;" target="_top"> View on Instagram</a></p></div><style>@-webkit-keyframes"dkaXkpbBxI"{ 0%{opacity:0.5;} 50%{opacity:1;} 100%{opacity:0.5;} } @keyframes"dkaXkpbBxI"{ 0%{opacity:0.5;} 50%{opacity:1;} 100%{opacity:0.5;} }</style></blockquote>
|
||||
* <script async defer src="https://platform.instagram.com/en_US/embeds.js"></script>
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\Jetpack\Status;
|
||||
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
add_action( 'init', 'jetpack_instagram_enable_embeds' );
|
||||
} else {
|
||||
jetpack_instagram_enable_embeds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Instagram as oembed provider, and add required filters for the API request.
|
||||
* Add filter to reverse iframes to shortcode. Register [instagram] shortcode.
|
||||
*
|
||||
* @since 9.1.0
|
||||
*/
|
||||
function jetpack_instagram_enable_embeds() {
|
||||
wp_oembed_add_provider(
|
||||
'#https?://(www\.)?instagr(\.am|am\.com)/(p|tv|reel)/.*#i',
|
||||
'https://graph.facebook.com/v5.0/instagram_oembed/',
|
||||
true
|
||||
);
|
||||
|
||||
/**
|
||||
* Handle an alternate Instagram URL format, where the username is also part of the URL.
|
||||
*/
|
||||
wp_oembed_add_provider(
|
||||
'#https?://(?:www\.)?instagr(?:\.am|am\.com)/(?:[^/]*)/(p|tv|reel)/([^\/]*)#i',
|
||||
'https://graph.facebook.com/v5.0/instagram_oembed/',
|
||||
true
|
||||
);
|
||||
|
||||
/**
|
||||
* Add auth token required by Instagram's oEmbed REST API, or proxy through WP.com.
|
||||
*/
|
||||
add_filter( 'oembed_fetch_url', 'jetpack_instagram_oembed_fetch_url', 10, 3 );
|
||||
|
||||
/**
|
||||
* Add JP auth headers if we're proxying through WP.com.
|
||||
*/
|
||||
add_filter( 'oembed_remote_get_args', 'jetpack_instagram_oembed_remote_get_args', 10, 2 );
|
||||
|
||||
/**
|
||||
* Embed reversal: Convert an embed code from Instagram.com to an oEmbeddable URL.
|
||||
*/
|
||||
add_filter( 'pre_kses', 'jetpack_instagram_embed_reversal' );
|
||||
|
||||
/**
|
||||
* Add the shortcode.
|
||||
*/
|
||||
add_shortcode( 'instagram', 'jetpack_shortcode_instagram' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Embed Reversal for Instagram
|
||||
*
|
||||
* Hooked to pre_kses, converts an embed code from Instagram.com to an oEmbeddable URL.
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return string The filtered or the original content.
|
||||
**/
|
||||
function jetpack_instagram_embed_reversal( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'instagram.com' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample embed code:
|
||||
* <blockquote class="instagram-media" data-instgrm-captioned data-instgrm-version="2" style=" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);"><div style="padding:8px;"><div style=" background:#F8F8F8; line-height:0; margin-top:40px; padding-bottom:55%; padding-top:45%; text-align:center; width:100%;"><div style="position:relative;"><div style=" -webkit-animation:dkaXkpbBxI 1s ease-out infinite; animation:dkaXkpbBxI 1s ease-out infinite; background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAAAGFBMVEUiIiI9PT0eHh4gIB4hIBkcHBwcHBwcHBydr+JQAAAACHRSTlMABA4YHyQsM5jtaMwAAADfSURBVDjL7ZVBEgMhCAQBAf//42xcNbpAqakcM0ftUmFAAIBE81IqBJdS3lS6zs3bIpB9WED3YYXFPmHRfT8sgyrCP1x8uEUxLMzNWElFOYCV6mHWWwMzdPEKHlhLw7NWJqkHc4uIZphavDzA2JPzUDsBZziNae2S6owH8xPmX8G7zzgKEOPUoYHvGz1TBCxMkd3kwNVbU0gKHkx+iZILf77IofhrY1nYFnB/lQPb79drWOyJVa/DAvg9B/rLB4cC+Nqgdz/TvBbBnr6GBReqn/nRmDgaQEej7WhonozjF+Y2I/fZou/qAAAAAElFTkSuQmCC); display:block; height:44px; margin:0 auto -44px; position:relative; top:-44px; width:44px;"></div><span style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:12px; font-style:normal; font-weight:bold; position:relative; top:15px;">Loading</span></div></div><p style=" font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin:8px 0 0 0; padding:0 4px; word-wrap:break-word;"> Balloons</p><p style=" line-height:32px; margin-bottom:0; margin-top:8px; padding:0; text-align:center;"> <a href="https://instagram.com/p/r9vfPrmjeB/" style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; text-decoration:none;" target="_top"> View on Instagram</a></p></div><style>@-webkit-keyframes"dkaXkpbBxI"{ 0%{opacity:0.5;} 50%{opacity:1;} 100%{opacity:0.5;} } @keyframes"dkaXkpbBxI"{ 0%{opacity:0.5;} 50%{opacity:1;} 100%{opacity:0.5;} }</style></blockquote>
|
||||
* <script async defer src="https://platform.instagram.com/en_US/embeds.js"></script>
|
||||
*/
|
||||
|
||||
$regexes = array();
|
||||
|
||||
// new style js.
|
||||
$regexes[] = '#<blockquote[^>]+?class="instagram-media"[^>].+?>(.+?)</blockquote><script[^>]+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"></script>#ix';
|
||||
|
||||
// Let's play nice with the visual editor too.
|
||||
$regexes[] = '#<blockquote(?:[^&]|&(?!gt;))+?class="instagram-media"(?:[^&]|&(?!gt;)).+?>(.+?)</blockquote><script(?:[^&]|&(?!gt;))+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"(?:[^&]|&(?!gt;))*+></script>#ix';
|
||||
|
||||
// old style iframe.
|
||||
$regexes[] = '#<iframe[^>]+?src="((?:https?:)?//(?:www\.)?instagram\.com/p/([^"\'/]++)[^"\']*?)"[^>]*+>\s*?</iframe>#i';
|
||||
|
||||
// Let's play nice with the visual editor too.
|
||||
$regexes[] = '#<iframe(?:[^&]|&(?!gt;))+?src="((?:https?:)?//(?:www\.)instagram\.com/p/([^"\'/]++)[^"\']*?)"(?:[^&]|&(?!gt;))*+>\s*?</iframe>#i';
|
||||
|
||||
foreach ( $regexes as $regex ) {
|
||||
if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
if ( ! preg_match( '#(https?:)?//(?:www\.)?instagr(\.am|am\.com)/p/([^/]*)#i', $match[1], $url_matches ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Since we support Instagram via oEmbed, we simply leave a link on a line by itself.
|
||||
$replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $match[0], '#' ) );
|
||||
$url = esc_url( $url_matches[0] );
|
||||
|
||||
$content = preg_replace( $replace_regex, sprintf( "\n\n%s\n\n", $url ), $content );
|
||||
/** This action is documented in modules/shortcodes/youtube.php */
|
||||
do_action( 'jetpack_embed_to_shortcode', 'instagram', $url );
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of allowed and sanitized parameters
|
||||
* that can be used with the Instagram oEmbed endpoint.
|
||||
*
|
||||
* Those parameters can be provided via the Instagram URL, or via shortcode parameters.
|
||||
*
|
||||
* @see https://developers.facebook.com/docs/graph-api/reference/instagram-oembed#parameters
|
||||
*
|
||||
* @since 9.1.0
|
||||
*
|
||||
* @param string $url URL of the content to be embedded.
|
||||
* @param array $atts Shortcode attributes.
|
||||
*
|
||||
* @return array $params Array of parameters to be used in Instagram query.
|
||||
*/
|
||||
function jetpack_instagram_get_allowed_parameters( $url, $atts = array() ) {
|
||||
global $content_width;
|
||||
|
||||
// Any URL passed via a shortcode attribute takes precedence.
|
||||
if ( ! empty( $atts['url'] ) ) {
|
||||
$url = $atts['url'];
|
||||
unset( $atts['url'] );
|
||||
}
|
||||
|
||||
/*
|
||||
* Get URL and parameters from the URL if possible.
|
||||
*
|
||||
* We'll also clean any other query params from the URL since Facebook's new API for Instagram
|
||||
* embeds does not like query parameters. See p7H4VZ-2DU-p2.
|
||||
*/
|
||||
$parsed_url = wp_parse_url( $url );
|
||||
if ( $parsed_url && isset( $parsed_url['host'] ) && isset( $parsed_url['path'] ) ) {
|
||||
// Bail early if this is not an Instagram URL.
|
||||
if ( ! preg_match( '/(?:^|\.)instagr(?:\.am|am\.com)$/', $parsed_url['host'] ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$url = 'https://www.instagram.com' . $parsed_url['path'];
|
||||
|
||||
// If we have any parameters as part of the URL, we merge them with our attributes.
|
||||
if ( ! empty( $parsed_url['query'] ) ) {
|
||||
$query_args = array();
|
||||
wp_parse_str( $parsed_url['query'], $query_args );
|
||||
|
||||
$atts = array_merge( $atts, $query_args );
|
||||
}
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
|
||||
$max_width = 698;
|
||||
$min_width = 320;
|
||||
|
||||
$params = shortcode_atts(
|
||||
array(
|
||||
'url' => $url,
|
||||
'width' => ( is_numeric( $content_width ) && $content_width > 0 ) ? $content_width : $max_width,
|
||||
'height' => '',
|
||||
'hidecaption' => false,
|
||||
),
|
||||
$atts,
|
||||
'instagram'
|
||||
);
|
||||
|
||||
// Ensure width is within bounds.
|
||||
$params['width'] = absint( $params['width'] );
|
||||
if ( $params['width'] > $max_width ) {
|
||||
$params['width'] = $max_width;
|
||||
} elseif ( $params['width'] < $min_width ) {
|
||||
$params['width'] = $min_width;
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add auth token required by Instagram's oEmbed REST API, or proxy through WP.com.
|
||||
*
|
||||
* @since 9.1.0
|
||||
*
|
||||
* @param string $provider URL of the oEmbed provider.
|
||||
* @param string $url URL of the content to be embedded.
|
||||
* @param array $args Additional arguments for retrieving embed HTML.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function jetpack_instagram_oembed_fetch_url( $provider, $url, $args ) {
|
||||
if ( ! wp_startswith( $provider, 'https://graph.facebook.com/v5.0/instagram_oembed/' ) ) {
|
||||
return $provider;
|
||||
}
|
||||
|
||||
// Get a set of URL and parameters supported by Facebook.
|
||||
$clean_parameters = jetpack_instagram_get_allowed_parameters( $url, $args );
|
||||
|
||||
// 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_instagram_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_connection_ready() || ( new Status() )->is_offline_mode() ) {
|
||||
return $provider;
|
||||
}
|
||||
|
||||
// @TODO Use Core's /oembed/1.0/proxy endpoint on WP.com
|
||||
// (Currently not global but per-site, i.e. /oembed/1.0/sites/1234567/proxy)
|
||||
// and deprecate /oembed-proxy/instagram endpoint.
|
||||
$wpcom_oembed_proxy = Constants::get_constant( 'JETPACK__WPCOM_JSON_API_BASE' ) . '/wpcom/v2/oembed-proxy/instagram/';
|
||||
return str_replace( 'https://graph.facebook.com/v5.0/instagram_oembed/', $wpcom_oembed_proxy, $provider );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add JP auth headers if we're proxying through WP.com.
|
||||
*
|
||||
* @param array $args oEmbed remote get arguments.
|
||||
* @param string $url URL to be inspected.
|
||||
*/
|
||||
function jetpack_instagram_oembed_remote_get_args( $args, $url ) {
|
||||
if ( ! wp_startswith( $url, Constants::get_constant( 'JETPACK__WPCOM_JSON_API_BASE' ) . '/wpcom/v2/oembed-proxy/instagram/' ) ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
$method = 'GET';
|
||||
$signed_request = Client::build_signed_request(
|
||||
compact( 'url', 'method' )
|
||||
);
|
||||
|
||||
return $signed_request['request'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a Facebook API access token used for query for Instagram embed information, if one is set.
|
||||
*
|
||||
* @return string The access token or ''
|
||||
*/
|
||||
function jetpack_instagram_get_access_token() {
|
||||
/**
|
||||
* Filters the Instagram 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.0.0
|
||||
*
|
||||
* @param string string The access token set via the JETPACK_INSTAGRAM_EMBED_TOKEN constant.
|
||||
*/
|
||||
return (string) apply_filters( 'jetpack_instagram_embed_token', (string) Constants::get_constant( 'JETPACK_INSTAGRAM_EMBED_TOKEN' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the Instagram shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function jetpack_shortcode_instagram( $atts ) {
|
||||
global $wp_embed;
|
||||
|
||||
if ( empty( $atts['url'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$atts = jetpack_instagram_get_allowed_parameters( $atts['url'], $atts );
|
||||
|
||||
if ( empty( $atts['url'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
|
||||
$url_pattern = '#http(s?)://(www\.)?instagr(\.am|am\.com)/(p|tv|reel)/([^/?]+)#i';
|
||||
preg_match( $url_pattern, $atts['url'], $matches );
|
||||
if ( ! $matches ) {
|
||||
return sprintf(
|
||||
'<a href="%1$s" class="amp-wp-embed-fallback">%1$s</a>',
|
||||
esc_url( $atts['url'] )
|
||||
);
|
||||
}
|
||||
|
||||
$shortcode_id = end( $matches );
|
||||
$width = ! empty( $atts['width'] ) ? $atts['width'] : 600;
|
||||
$height = ! empty( $atts['height'] ) ? $atts['height'] : 600;
|
||||
return sprintf(
|
||||
'<amp-instagram data-shortcode="%1$s" layout="responsive" width="%2$d" height="%3$d" data-captioned></amp-instagram>',
|
||||
esc_attr( $shortcode_id ),
|
||||
absint( $width ),
|
||||
absint( $height )
|
||||
);
|
||||
}
|
||||
|
||||
return $wp_embed->shortcode( $atts, $atts['url'] );
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/* global brightcove, brightcoveData */
|
||||
( function ( $ ) {
|
||||
var script = document.createElement( 'script' ),
|
||||
tld = 'co.jp' === brightcoveData.tld ? 'co.jp' : 'com',
|
||||
timer = false;
|
||||
|
||||
// Load Brightcove script
|
||||
script.src = 'https://sadmin.brightcove.' + tld + '/js/BrightcoveExperiences.js';
|
||||
script.type = 'text/javascript';
|
||||
script.language = 'JavaScript';
|
||||
document.head.appendChild( script );
|
||||
|
||||
// Start detection for Brightcove script loading in its object
|
||||
try_brightcove();
|
||||
|
||||
// Detect if Brightcove script has loaded and bind some events once loaded
|
||||
function try_brightcove() {
|
||||
clearTimeout( timer );
|
||||
|
||||
if ( 'object' === typeof brightcove ) {
|
||||
$( document ).ready( brightcove.createExperiences );
|
||||
$( 'body' ).on( 'post-load', brightcove.createExperiences );
|
||||
|
||||
brightcove.createExperiences();
|
||||
} else {
|
||||
timer = setTimeout( try_brightcove, 100 );
|
||||
}
|
||||
}
|
||||
} )( jQuery );
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,258 @@
|
||||
( function ( $ ) {
|
||||
var jmpressOpts = {
|
||||
fullscreen: false,
|
||||
hash: { use: false },
|
||||
mouse: { clickSelects: false },
|
||||
keyboard: { use: true },
|
||||
animation: { transitionDuration: '1s' },
|
||||
presentationMode: false,
|
||||
stepSelector: '.step',
|
||||
duration: {
|
||||
defaultValue: 0,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Presentation constructor
|
||||
*/
|
||||
function Presentation( wrapper ) {
|
||||
var _self, duration, new_css, ie_regex, matches;
|
||||
|
||||
_self = this;
|
||||
|
||||
_self.wrapper = $( wrapper ); // The wrapper for toggling fullscreen
|
||||
_self.slideshow = $( '.presentation', wrapper ); // Holds the slides for jmpress
|
||||
_self.navLeft = $( '.nav-arrow-left', wrapper );
|
||||
_self.navRight = $( '.nav-arrow-right', wrapper );
|
||||
_self.expandButton = $( '.nav-fullscreen-button', wrapper );
|
||||
_self.overlay = $( '.autoplay-overlay', wrapper );
|
||||
_self.fullscreen = false;
|
||||
_self.autoPlaying = false;
|
||||
_self.autoplayTime = parseFloat( _self.slideshow.attr( 'data-autoplay' ), 10 ) || 0;
|
||||
|
||||
// The wrapper is scaled to the contents' size so that its border wraps tightly
|
||||
_self.wrapper.css( {
|
||||
width: _self.slideshow.width(),
|
||||
height: _self.slideshow.height(),
|
||||
} );
|
||||
|
||||
duration = _self.slideshow.attr( 'duration' ) || '1s';
|
||||
jmpressOpts.animation.transitionDuration = duration;
|
||||
|
||||
// Compensate for transition times
|
||||
if ( _self.autoplayTime ) {
|
||||
_self.autoplayTime += parseFloat( duration, 10 ) * 1000;
|
||||
}
|
||||
|
||||
// Set the opacity transition duration
|
||||
// as it is delegated by css and not jmpress
|
||||
duration = 'opacity ' + duration;
|
||||
new_css = {
|
||||
width: _self.slideshow.width(),
|
||||
height: _self.slideshow.height(),
|
||||
'-webkit-transition': duration,
|
||||
'-moz-transition': duration,
|
||||
'-ms-transition': duration,
|
||||
'-o-transition': duration,
|
||||
transition: duration,
|
||||
};
|
||||
|
||||
$( '.step', _self.slideshow ).each( function ( i, step ) {
|
||||
$( step ).css( new_css );
|
||||
} );
|
||||
|
||||
// Apply attribute to allow fading individual bullets here,
|
||||
// otherwise wp_kses will strip the attribute out
|
||||
$( '.step.fadebullets li', _self.slideshow ).each( function ( i, step ) {
|
||||
$( step ).attr( 'data-jmpress', 'fade' );
|
||||
} );
|
||||
|
||||
// Register resizing to window when fullscreen
|
||||
$( window ).resize( function () {
|
||||
if ( _self.fullscreen ) {
|
||||
_self.resizePresentation();
|
||||
}
|
||||
} );
|
||||
|
||||
// Register the nav bars to move the slides
|
||||
_self.navLeft.on( 'click', function () {
|
||||
_self.slideshow.jmpress( 'prev' );
|
||||
_self.overlay.css( 'opacity', 0 );
|
||||
return false;
|
||||
} );
|
||||
|
||||
_self.navRight.on( 'click', function () {
|
||||
_self.slideshow.jmpress( 'next' );
|
||||
_self.overlay.css( 'opacity', 0 );
|
||||
return false;
|
||||
} );
|
||||
|
||||
_self.slideshow.on( 'click', function () {
|
||||
_self.setAutoplay( true );
|
||||
return false;
|
||||
} );
|
||||
|
||||
_self.slideshow.on( 'focusout', function () {
|
||||
_self.setAutoplay( false );
|
||||
} );
|
||||
|
||||
// Register toggling fullscreen except for IE 9 or lower
|
||||
ie_regex = /MSIE\s(\d+)\.\d+/;
|
||||
matches = ie_regex.exec( navigator.userAgent );
|
||||
|
||||
if ( matches && parseInt( matches[ 1 ], 10 ) < 10 ) {
|
||||
_self.expandButton.remove();
|
||||
_self.expandButton = null;
|
||||
} else {
|
||||
_self.expandButton.on( 'click', function () {
|
||||
_self.setFullscreen( ! _self.fullscreen );
|
||||
return false;
|
||||
} );
|
||||
}
|
||||
|
||||
// Register ESC key to exit fullscreen
|
||||
$( window ).on( 'keydown', function ( event ) {
|
||||
if ( event.which === 27 ) {
|
||||
_self.setFullscreen( false );
|
||||
}
|
||||
} );
|
||||
|
||||
// Start the presentation
|
||||
_self.slideshow.jmpress( jmpressOpts );
|
||||
|
||||
// Make content visible and remove error message on jmpress success
|
||||
if ( _self.slideshow.jmpress( 'initialized' ) ) {
|
||||
_self.slideshow.css( 'display', '' );
|
||||
_self.overlay.css( 'display', '' );
|
||||
$( '.not-supported-msg', _self.wrapper ).remove();
|
||||
}
|
||||
|
||||
// A bug in Firefox causes issues with the nav arrows appearing
|
||||
// on hover in presentation mode. Explicitly disabling fullscreen
|
||||
// on init seems to fix the issue
|
||||
_self.setFullscreen( false );
|
||||
}
|
||||
|
||||
$.extend( Presentation.prototype, {
|
||||
resizePresentation: function () {
|
||||
var scale, duration, settings, new_css, widthScale, heightScale;
|
||||
|
||||
// Set the animation duration to 0 during resizing
|
||||
// so that there isn't an animation delay when scaling
|
||||
// up the slide contents
|
||||
settings = this.slideshow.jmpress( 'settings' );
|
||||
duration = settings.animation.transitionDuration;
|
||||
|
||||
settings.animation.transitionDuration = '0s';
|
||||
this.slideshow.jmpress( 'reselect' );
|
||||
|
||||
scale = 1;
|
||||
new_css = {
|
||||
top: 0,
|
||||
left: 0,
|
||||
zoom: 1,
|
||||
};
|
||||
|
||||
// Expand the presentation to fill the lesser of the max width or height
|
||||
// This avoids content moving past the window for certain window sizes
|
||||
if ( this.fullscreen ) {
|
||||
widthScale = $( window ).width() / this.slideshow.width();
|
||||
heightScale = $( window ).height() / this.slideshow.height();
|
||||
|
||||
scale = Math.min( widthScale, heightScale );
|
||||
|
||||
new_css.top = ( $( window ).height() - scale * this.slideshow.height() ) / 2;
|
||||
new_css.left = ( $( window ).width() - scale * this.slideshow.width() ) / 2;
|
||||
}
|
||||
|
||||
// Firefox does not support the zoom property; IE does, but it does not work
|
||||
// well like in webkit, so we manually transform and position the slideshow
|
||||
if ( this.slideshow.css( '-moz-transform' ) || this.slideshow.css( '-ms-transform' ) ) {
|
||||
// Firefox keeps the center of the element in place and expands outward
|
||||
// so we must shift everything to compensate
|
||||
new_css.top += ( ( scale - 1 ) * this.slideshow.height() ) / 2;
|
||||
new_css.left += ( ( scale - 1 ) * this.slideshow.width() ) / 2;
|
||||
|
||||
scale = 'scale(' + scale + ')';
|
||||
|
||||
$.extend( new_css, {
|
||||
'-moz-transform': scale,
|
||||
'-ms-transform': scale,
|
||||
transform: scale,
|
||||
} );
|
||||
} else {
|
||||
// webkit scales everything with zoom so we need to offset the right amount
|
||||
// so that the content is vertically centered after scaling effects
|
||||
new_css.top /= scale;
|
||||
new_css.left /= scale;
|
||||
new_css.zoom = scale;
|
||||
}
|
||||
|
||||
this.slideshow.css( new_css );
|
||||
|
||||
settings.animation.transitionDuration = duration;
|
||||
this.slideshow.jmpress( 'reselect' );
|
||||
},
|
||||
|
||||
setFullscreen: function ( on ) {
|
||||
this.fullscreen = on;
|
||||
this.setAutoplay( false );
|
||||
|
||||
// Save the scroll positions before going into fullscreen mode
|
||||
if ( on ) {
|
||||
this.scrollVert = $( window ).scrollTop();
|
||||
this.scrollHoriz = $( window ).scrollLeft();
|
||||
|
||||
// Chrome Bug: Force scroll to be at top
|
||||
// otherwise the presentation can end up offscreen
|
||||
$( window ).scrollTop( 0 );
|
||||
$( window ).scrollLeft( 0 );
|
||||
}
|
||||
|
||||
$( 'html' ).toggleClass( 'presentation-global-fullscreen', on );
|
||||
$( 'body' ).toggleClass( 'presentation-global-fullscreen', on );
|
||||
|
||||
this.wrapper.toggleClass( 'presentation-wrapper-fullscreen', on );
|
||||
|
||||
this.wrapper.parents().each( function ( i, e ) {
|
||||
$( e ).toggleClass( 'presentation-wrapper-fullscreen-parent', on );
|
||||
} );
|
||||
|
||||
this.resizePresentation();
|
||||
|
||||
// Reset the scroll positions after exiting fullscreen mode
|
||||
if ( ! on ) {
|
||||
$( window ).scrollTop( this.scrollVert );
|
||||
$( window ).scrollLeft( this.scrollHoriz );
|
||||
}
|
||||
},
|
||||
|
||||
setAutoplay: function ( on ) {
|
||||
var _self = this,
|
||||
newAutoplayTime;
|
||||
|
||||
if ( _self.autoPlaying === on ) {
|
||||
return;
|
||||
}
|
||||
|
||||
newAutoplayTime = on && _self.autoplayTime > 0 ? _self.autoplayTime : 0;
|
||||
_self.slideshow.jmpress( 'settings' ).duration.defaultValue = newAutoplayTime;
|
||||
|
||||
// Move to the next slide when activating autoplay
|
||||
if ( newAutoplayTime ) {
|
||||
_self.slideshow.jmpress( 'next' );
|
||||
_self.overlay.css( 'opacity', 0 );
|
||||
} else {
|
||||
_self.slideshow.jmpress( 'reselect' );
|
||||
}
|
||||
|
||||
_self.autoPlaying = on;
|
||||
},
|
||||
} );
|
||||
|
||||
$( document ).ready( function () {
|
||||
$( '.presentation-wrapper' ).forEach( function () {
|
||||
new Presentation( this );
|
||||
} );
|
||||
} );
|
||||
} )( jQuery );
|
||||
@@ -0,0 +1,92 @@
|
||||
( function ( $ ) {
|
||||
$.fn.shuffleQuiz = function () {
|
||||
var allElems = this.get(),
|
||||
getRandom = function ( max ) {
|
||||
return Math.floor( Math.random() * max );
|
||||
},
|
||||
shuffled = $.map( allElems, function () {
|
||||
var random = getRandom( allElems.length ),
|
||||
randEl = $( allElems[ random ] ).clone( true )[ 0 ];
|
||||
allElems.splice( random, 1 );
|
||||
return randEl;
|
||||
} );
|
||||
|
||||
this.each( function ( i ) {
|
||||
$( this ).replaceWith( $( shuffled[ i ] ) );
|
||||
} );
|
||||
|
||||
return $( shuffled );
|
||||
};
|
||||
} )( jQuery );
|
||||
|
||||
jQuery( function ( $ ) {
|
||||
$( '.jetpack-quiz' ).each( function () {
|
||||
var quiz = $( this );
|
||||
quiz.find( 'div.jetpack-quiz-answer' ).shuffleQuiz();
|
||||
quiz.find( 'div[data-correct]' ).removeAttr( 'data-correct' ).data( 'correct', 1 );
|
||||
quiz.find( 'div.jetpack-quiz-answer:last' ).addClass( 'last' );
|
||||
} );
|
||||
|
||||
$( 'div.jetpack-quiz' ).on( 'click', 'div.jetpack-quiz-answer', function () {
|
||||
var trackid,
|
||||
answer = $( this ),
|
||||
quiz = answer.closest( 'div.jetpack-quiz' );
|
||||
|
||||
if ( quiz.data( 'a8ctraining' ) ) {
|
||||
new Image().src =
|
||||
'//pixel.wp.com/b.gif?v=wpcom-no-pv&x_trainingchaos-' +
|
||||
quiz.data( 'username' ) +
|
||||
'=' +
|
||||
quiz.data( 'a8ctraining' ) +
|
||||
'&rand=' +
|
||||
Math.random();
|
||||
quiz.data( 'a8ctraining', false );
|
||||
quiz.data( 'trackid', false );
|
||||
}
|
||||
|
||||
trackid = quiz.data( 'trackid' );
|
||||
if ( answer.data( 'correct' ) ) {
|
||||
answer.addClass( 'correct' );
|
||||
if ( trackid ) {
|
||||
new Image().src =
|
||||
'//pixel.wp.com/b.gif?v=wpcom-no-pv&x_quiz-' + trackid + '=correct&rand=' + Math.random();
|
||||
}
|
||||
} else {
|
||||
answer.addClass( 'wrong' );
|
||||
if ( trackid ) {
|
||||
new Image().src =
|
||||
'//pixel.wp.com/b.gif?v=wpcom-no-pv&x_quiz-' + trackid + '=wrong&rand=' + Math.random();
|
||||
}
|
||||
}
|
||||
// only track the first answer
|
||||
quiz.data( 'trackid', false );
|
||||
} );
|
||||
} );
|
||||
|
||||
document.querySelectorAll( '.jetpack-quiz-wrapper' ).forEach( function ( quiz ) {
|
||||
quiz.childNodes.forEach( function ( element, number ) {
|
||||
element.style.display = 'none';
|
||||
element.setAttribute( 'quiz-number', number );
|
||||
element.querySelector( '.jetpack-quiz-count' ).innerHTML =
|
||||
number + 1 + '/' + quiz.childElementCount;
|
||||
} );
|
||||
|
||||
quiz.childNodes[ 0 ].style.display = 'block';
|
||||
} );
|
||||
|
||||
document.querySelectorAll( '.jetpack-quiz-option-button' ).forEach( function ( element ) {
|
||||
element.addEventListener( 'click', function () {
|
||||
var currentQuiz = element.parentElement.parentElement;
|
||||
currentQuiz.style.display = 'none';
|
||||
var switchNumber = element.getAttribute( 'data-quiz-option' ) === 'next' ? 1 : -1;
|
||||
var newQuiz =
|
||||
currentQuiz.parentElement.childNodes[
|
||||
parseInt( currentQuiz.getAttribute( 'quiz-number' ) ) + switchNumber
|
||||
];
|
||||
newQuiz.style.display = 'block';
|
||||
var newQuizQuestionEl = newQuiz.querySelector( '.jetpack-quiz-question' );
|
||||
if ( newQuizQuestionEl ) {
|
||||
newQuizQuestionEl.focus();
|
||||
}
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,291 @@
|
||||
/*!
|
||||
* printThis v1.9.0
|
||||
* @desc Printing plug-in for jQuery
|
||||
* @author Jason Day
|
||||
*
|
||||
* Resources (based on) :
|
||||
* jPrintArea: http://plugins.jquery.com/project/jPrintArea
|
||||
* jqPrint: https://github.com/permanenttourist/jquery.jqprint
|
||||
* Ben Nadal: http://www.bennadel.com/blog/1591-Ask-Ben-Print-Part-Of-A-Web-Page-With-jQuery.htm
|
||||
*
|
||||
* Licensed under the MIT licence:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* (c) Jason Day 2015
|
||||
*/
|
||||
/*
|
||||
* Usage:
|
||||
*
|
||||
* $("#mySelector").printThis({
|
||||
* debug: false, * show the iframe for debugging
|
||||
* importCSS: true, * import page CSS
|
||||
* importStyle: false, * import style tags
|
||||
* printContainer: true, * grab outer container as well as the contents of the selector
|
||||
* loadCSS: "path/to/my.css", * path to additional css file - us an array [] for multiple
|
||||
* pageTitle: "", * add title to print page
|
||||
* removeInline: false, * remove all inline styles from print elements
|
||||
* printDelay: 333, * variable print delay
|
||||
* header: null, * prefix to html
|
||||
* footer: null, * postfix to html
|
||||
* base: false, * preserve the BASE tag, or accept a string for the URL
|
||||
* formValues: true * preserve input/form values
|
||||
* canvas: false * copy canvas elements (experimental)
|
||||
* doctypeString: '...' * enter a different doctype for older markup
|
||||
* });
|
||||
*
|
||||
* Notes:
|
||||
* - the loadCSS will load additional css (with or without @media print) into the iframe, adjusting layout
|
||||
*
|
||||
*/
|
||||
( function ( $ ) {
|
||||
var opt;
|
||||
$.fn.printThis = function ( options ) {
|
||||
opt = $.extend( {}, $.fn.printThis.defaults, options );
|
||||
var $element = this instanceof jQuery ? this : $( this );
|
||||
|
||||
var strFrameName = 'printThis-' + new Date().getTime();
|
||||
|
||||
if ( window.location.hostname !== document.domain && navigator.userAgent.match( /msie/i ) ) {
|
||||
// Ugly IE hacks due to IE not inheriting document.domain from parent
|
||||
// checks if document.domain is set by comparing the host name against document.domain
|
||||
var iframeSrc =
|
||||
'javascript:document.write("<head><script>document.domain=\\"' +
|
||||
document.domain +
|
||||
'\\";</s' +
|
||||
'cript></head><body></body>")';
|
||||
var printI = document.createElement( 'iframe' );
|
||||
printI.name = 'printIframe';
|
||||
printI.id = strFrameName;
|
||||
printI.className = 'MSIE';
|
||||
document.body.appendChild( printI );
|
||||
printI.src = iframeSrc;
|
||||
} else {
|
||||
// other browsers inherit document.domain, and IE works if document.domain is not explicitly set
|
||||
var $frame = $( "<iframe id='" + strFrameName + "' name='printIframe' />" );
|
||||
$frame.appendTo( 'body' );
|
||||
}
|
||||
|
||||
var $iframe = $( '#' + strFrameName );
|
||||
|
||||
// show frame if in debug mode
|
||||
if ( ! opt.debug )
|
||||
$iframe.css( {
|
||||
position: 'absolute',
|
||||
width: '0px',
|
||||
height: '0px',
|
||||
left: '-600px',
|
||||
top: '-600px',
|
||||
} );
|
||||
|
||||
// $iframe.ready() and $iframe.load were inconsistent between browsers
|
||||
setTimeout( function () {
|
||||
// Add doctype to fix the style difference between printing and render
|
||||
function setDocType( $iframe, doctype ) {
|
||||
var win, doc;
|
||||
win = $iframe.get( 0 );
|
||||
win = win.contentWindow || win.contentDocument || win;
|
||||
doc = win.document || win.contentDocument || win;
|
||||
doc.open();
|
||||
doc.write( doctype );
|
||||
doc.close();
|
||||
}
|
||||
if ( opt.doctypeString ) {
|
||||
setDocType( $iframe, opt.doctypeString );
|
||||
}
|
||||
|
||||
var $doc = $iframe.contents(),
|
||||
$head = $doc.find( 'head' ),
|
||||
$body = $doc.find( 'body' ),
|
||||
$base = $( 'base' ),
|
||||
baseURL;
|
||||
|
||||
// add base tag to ensure elements use the parent domain
|
||||
if ( opt.base === true && $base.length > 0 ) {
|
||||
// take the base tag from the original page
|
||||
baseURL = $base.attr( 'href' );
|
||||
} else if ( typeof opt.base === 'string' ) {
|
||||
// An exact base string is provided
|
||||
baseURL = opt.base;
|
||||
} else {
|
||||
// Use the page URL as the base
|
||||
baseURL = document.location.protocol + '//' + document.location.host;
|
||||
}
|
||||
|
||||
$head.append( '<base href="' + baseURL + '">' );
|
||||
|
||||
// import page stylesheets
|
||||
if ( opt.importCSS )
|
||||
$( 'link[rel=stylesheet]' ).each( function () {
|
||||
var href = $( this ).attr( 'href' );
|
||||
if ( href ) {
|
||||
var media = $( this ).attr( 'media' ) || 'all';
|
||||
$head.append(
|
||||
"<link type='text/css' rel='stylesheet' href='" + href + "' media='" + media + "'>"
|
||||
);
|
||||
}
|
||||
} );
|
||||
|
||||
// import style tags
|
||||
if ( opt.importStyle )
|
||||
$( 'style' ).each( function () {
|
||||
$( this ).clone().appendTo( $head );
|
||||
} );
|
||||
|
||||
// add title of the page
|
||||
if ( opt.pageTitle ) $head.append( '<title>' + opt.pageTitle + '</title>' );
|
||||
|
||||
// import additional stylesheet(s)
|
||||
if ( opt.loadCSS ) {
|
||||
if ( $.isArray( opt.loadCSS ) ) {
|
||||
jQuery.each( opt.loadCSS, function ( index, value ) {
|
||||
$head.append( "<link type='text/css' rel='stylesheet' href='" + this + "'>" );
|
||||
} );
|
||||
} else {
|
||||
$head.append( "<link type='text/css' rel='stylesheet' href='" + opt.loadCSS + "'>" );
|
||||
}
|
||||
}
|
||||
|
||||
// print header
|
||||
if ( opt.header ) $body.append( opt.header );
|
||||
|
||||
if ( opt.canvas ) {
|
||||
// add canvas data-ids for easy access after the cloning.
|
||||
var canvasId = 0;
|
||||
$element.find( 'canvas' ).each( function () {
|
||||
$( this ).attr( 'data-printthis', canvasId++ );
|
||||
} );
|
||||
}
|
||||
|
||||
// grab $.selector as container
|
||||
if ( opt.printContainer ) $body.append( $element.outer() );
|
||||
// otherwise just print interior elements of container
|
||||
else
|
||||
$element.each( function () {
|
||||
$body.append( $( this ).html() );
|
||||
} );
|
||||
|
||||
if ( opt.canvas ) {
|
||||
// Re-draw new canvases by referencing the originals
|
||||
$body.find( 'canvas' ).each( function () {
|
||||
var cid = $( this ).data( 'printthis' ),
|
||||
$src = $( '[data-printthis="' + cid + '"]' );
|
||||
|
||||
this.getContext( '2d' ).drawImage( $src[ 0 ], 0, 0 );
|
||||
|
||||
// Remove the mark-up from the original
|
||||
$src.removeData( 'printthis' );
|
||||
} );
|
||||
}
|
||||
|
||||
// capture form/field values
|
||||
if ( opt.formValues ) {
|
||||
// loop through inputs
|
||||
var $input = $element.find( 'input' );
|
||||
if ( $input.length ) {
|
||||
$input.each( function () {
|
||||
var $this = $( this ),
|
||||
$name = $( this ).attr( 'name' ),
|
||||
$checker = $this.is( ':checkbox' ) || $this.is( ':radio' ),
|
||||
$iframeInput = $doc.find( 'input[name="' + $name + '"]' ),
|
||||
$value = $this.val();
|
||||
|
||||
// order matters here
|
||||
if ( ! $checker ) {
|
||||
$iframeInput.val( $value );
|
||||
} else if ( $this.is( ':checked' ) ) {
|
||||
if ( $this.is( ':checkbox' ) ) {
|
||||
$iframeInput.attr( 'checked', 'checked' );
|
||||
} else if ( $this.is( ':radio' ) ) {
|
||||
$doc
|
||||
.find( 'input[name="' + $name + '"][value="' + $value + '"]' )
|
||||
.attr( 'checked', 'checked' );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
// loop through selects
|
||||
var $select = $element.find( 'select' );
|
||||
if ( $select.length ) {
|
||||
$select.each( function () {
|
||||
var $this = $( this ),
|
||||
$name = $( this ).attr( 'name' ),
|
||||
$value = $this.val();
|
||||
$doc.find( 'select[name="' + $name + '"]' ).val( $value );
|
||||
} );
|
||||
}
|
||||
|
||||
// loop through textareas
|
||||
var $textarea = $element.find( 'textarea' );
|
||||
if ( $textarea.length ) {
|
||||
$textarea.each( function () {
|
||||
var $this = $( this ),
|
||||
$name = $( this ).attr( 'name' ),
|
||||
$value = $this.val();
|
||||
$doc.find( 'textarea[name="' + $name + '"]' ).val( $value );
|
||||
} );
|
||||
}
|
||||
} // end capture form/field values
|
||||
|
||||
// remove inline styles
|
||||
if ( opt.removeInline ) {
|
||||
// $.removeAttr available jQuery 1.7+
|
||||
if ( $.isFunction( $.removeAttr ) ) {
|
||||
$doc.find( 'body *' ).removeAttr( 'style' );
|
||||
} else {
|
||||
$doc.find( 'body *' ).attr( 'style', '' );
|
||||
}
|
||||
}
|
||||
|
||||
// print "footer"
|
||||
if ( opt.footer ) $body.append( opt.footer );
|
||||
|
||||
setTimeout( function () {
|
||||
if ( $iframe.hasClass( 'MSIE' ) ) {
|
||||
// check if the iframe was created with the ugly hack
|
||||
// and perform another ugly hack out of neccessity
|
||||
window.frames[ 'printIframe' ].focus();
|
||||
$head.append( '<script> window.print(); </s' + 'cript>' );
|
||||
} else {
|
||||
// proper method
|
||||
if ( document.queryCommandSupported( 'print' ) ) {
|
||||
$iframe[ 0 ].contentWindow.document.execCommand( 'print', false, null );
|
||||
} else {
|
||||
$iframe[ 0 ].contentWindow.focus();
|
||||
$iframe[ 0 ].contentWindow.print();
|
||||
}
|
||||
}
|
||||
|
||||
// remove iframe after print
|
||||
if ( ! opt.debug ) {
|
||||
setTimeout( function () {
|
||||
$iframe.remove();
|
||||
}, 1000 );
|
||||
}
|
||||
}, opt.printDelay );
|
||||
}, 333 );
|
||||
};
|
||||
|
||||
// defaults
|
||||
$.fn.printThis.defaults = {
|
||||
debug: false, // show the iframe for debugging
|
||||
importCSS: true, // import parent page css
|
||||
importStyle: false, // import style tags
|
||||
printContainer: true, // print outer container/$.selector
|
||||
loadCSS: '', // load an additional css file - load multiple stylesheets with an array []
|
||||
pageTitle: '', // add title to print page
|
||||
removeInline: false, // remove all inline styles
|
||||
printDelay: 333, // variable print delay
|
||||
header: null, // prefix to html
|
||||
footer: null, // postfix to html
|
||||
formValues: true, // preserve input/form values
|
||||
canvas: false, // Copy canvas content (experimental)
|
||||
base: false, // preserve the BASE tag, or accept a string for the URL
|
||||
doctypeString: '<!DOCTYPE html>', // html doctype
|
||||
};
|
||||
|
||||
// $.selector container
|
||||
jQuery.fn.outer = function () {
|
||||
return $( $( '<div></div>' ).html( this.clone() ) ).html();
|
||||
};
|
||||
} )( jQuery );
|
||||
@@ -0,0 +1,14 @@
|
||||
/* global jetpack_recipes_vars */
|
||||
( function ( $ ) {
|
||||
$( window ).load( function () {
|
||||
$( '.jetpack-recipe-print a' ).click( function ( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
// Print the DIV.
|
||||
$( this ).closest( '.jetpack-recipe' ).printThis( {
|
||||
pageTitle: jetpack_recipes_vars.pageTitle,
|
||||
loadCSS: jetpack_recipes_vars.loadCSS,
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
} )( jQuery );
|
||||
@@ -0,0 +1,213 @@
|
||||
/* global jetpackSlideshowSettings */
|
||||
|
||||
function JetpackSlideshow( element, transition, autostart ) {
|
||||
this.element = element;
|
||||
this.images = [];
|
||||
this.controls = {};
|
||||
this.transition = transition || 'fade';
|
||||
this.autostart = autostart;
|
||||
}
|
||||
|
||||
JetpackSlideshow.prototype.showLoadingImage = function ( toggle ) {
|
||||
if ( toggle ) {
|
||||
this.loadingImage_ = document.createElement( 'div' );
|
||||
this.loadingImage_.className = 'jetpack-slideshow-loading';
|
||||
var img = document.createElement( 'img' );
|
||||
img.src = jetpackSlideshowSettings.spinner;
|
||||
this.loadingImage_.appendChild( img );
|
||||
this.loadingImage_.appendChild( this.makeZeroWidthSpan() );
|
||||
this.element.append( this.loadingImage_ );
|
||||
} else if ( this.loadingImage_ ) {
|
||||
this.loadingImage_.parentNode.removeChild( this.loadingImage_ );
|
||||
this.loadingImage_ = null;
|
||||
}
|
||||
};
|
||||
|
||||
JetpackSlideshow.prototype.init = function () {
|
||||
this.showLoadingImage( true );
|
||||
|
||||
var self = this;
|
||||
// Set up DOM.
|
||||
for ( var i = 0; i < this.images.length; i++ ) {
|
||||
var imageInfo = this.images[ i ];
|
||||
var img = document.createElement( 'img' );
|
||||
img.src = imageInfo.src;
|
||||
img.title = typeof imageInfo.title !== 'undefined' ? imageInfo.title : '';
|
||||
img.alt = typeof imageInfo.alt !== 'undefined' ? imageInfo.alt : '';
|
||||
img.setAttribute( 'itemprop', 'image' );
|
||||
img.nopin = 'nopin';
|
||||
var caption = document.createElement( 'div' );
|
||||
caption.className = 'jetpack-slideshow-slide-caption';
|
||||
caption.setAttribute( 'itemprop', 'caption description' );
|
||||
caption.innerHTML = imageInfo.caption;
|
||||
var container = document.createElement( 'div' );
|
||||
container.className = 'jetpack-slideshow-slide';
|
||||
container.setAttribute( 'itemprop', 'associatedMedia' );
|
||||
container.setAttribute( 'itemscope', '' );
|
||||
container.setAttribute( 'itemtype', 'https://schema.org/ImageObject' );
|
||||
|
||||
// Hide loading image once first image has loaded.
|
||||
if ( i === 0 ) {
|
||||
if ( img.complete ) {
|
||||
// IE, image in cache
|
||||
setTimeout( function () {
|
||||
self.finishInit_();
|
||||
}, 1 );
|
||||
} else {
|
||||
img.addEventListener( 'load', function () {
|
||||
self.finishInit_();
|
||||
} );
|
||||
}
|
||||
}
|
||||
container.appendChild( img );
|
||||
// I'm not sure where these were coming from, but IE adds
|
||||
// bad values for width/height for portrait-mode images
|
||||
img.removeAttribute( 'width' );
|
||||
img.removeAttribute( 'height' );
|
||||
container.appendChild( this.makeZeroWidthSpan() );
|
||||
container.appendChild( caption );
|
||||
this.element.append( container );
|
||||
}
|
||||
};
|
||||
|
||||
JetpackSlideshow.prototype.makeZeroWidthSpan = function () {
|
||||
var emptySpan = document.createElement( 'span' );
|
||||
emptySpan.className = 'jetpack-slideshow-line-height-hack';
|
||||
// Having a NBSP makes IE act weird during transitions, but other
|
||||
// browsers ignore a text node with a space in it as whitespace.
|
||||
if ( -1 !== window.navigator.userAgent.indexOf( 'MSIE ' ) ) {
|
||||
emptySpan.appendChild( document.createTextNode( ' ' ) );
|
||||
} else {
|
||||
emptySpan.innerHTML = ' ';
|
||||
}
|
||||
return emptySpan;
|
||||
};
|
||||
|
||||
JetpackSlideshow.prototype.finishInit_ = function () {
|
||||
this.showLoadingImage( false );
|
||||
this.renderControls_();
|
||||
|
||||
var self = this;
|
||||
if ( this.images.length > 1 ) {
|
||||
// Initialize Cycle instance.
|
||||
jQuery( this.element ).cycle( {
|
||||
fx: this.transition,
|
||||
prev: this.controls.prev,
|
||||
next: this.controls.next,
|
||||
timeout: jetpackSlideshowSettings.speed,
|
||||
slideExpr: '.jetpack-slideshow-slide',
|
||||
onPrevNextEvent: function () {
|
||||
return self.onCyclePrevNextClick_.apply( self, arguments );
|
||||
},
|
||||
} );
|
||||
|
||||
var slideshow = this.element;
|
||||
|
||||
if ( ! this.autostart ) {
|
||||
jQuery( slideshow ).cycle( 'pause' );
|
||||
this.controls.stop.classList.remove( 'running' );
|
||||
this.controls.stop.classList.add( 'paused' );
|
||||
}
|
||||
|
||||
this.controls.stop.addEventListener( 'click', function ( event ) {
|
||||
var button = event.currentTarget;
|
||||
|
||||
if ( button === event.target ) {
|
||||
event.preventDefault();
|
||||
|
||||
if ( ! button.classList.contains( 'paused' ) ) {
|
||||
jQuery( slideshow ).cycle( 'pause' );
|
||||
button.classList.remove( 'running' );
|
||||
button.classList.add( 'paused' );
|
||||
} else {
|
||||
button.classList.add( 'running' );
|
||||
button.classList.remove( 'paused' );
|
||||
jQuery( slideshow ).cycle( 'resume', true );
|
||||
}
|
||||
}
|
||||
} );
|
||||
} else {
|
||||
this.element.children( ':first' ).show();
|
||||
this.element.css( 'position', 'relative' );
|
||||
}
|
||||
this.initialized_ = true;
|
||||
};
|
||||
|
||||
JetpackSlideshow.prototype.renderControls_ = function () {
|
||||
if ( this.controlsDiv_ ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var controlsDiv = document.createElement( 'div' );
|
||||
controlsDiv.className = 'jetpack-slideshow-controls';
|
||||
|
||||
var controls = [ 'prev', 'stop', 'next' ];
|
||||
for ( var i = 0; i < controls.length; i++ ) {
|
||||
var controlName = controls[ i ];
|
||||
var label_name = 'label_' + controlName;
|
||||
var a = document.createElement( 'a' );
|
||||
|
||||
a.href = '#';
|
||||
a.className = 'button-' + controlName;
|
||||
a.setAttribute( 'aria-label', jetpackSlideshowSettings[ label_name ] );
|
||||
a.setAttribute( 'role', 'button' );
|
||||
|
||||
controlsDiv.appendChild( a );
|
||||
this.controls[ controlName ] = a;
|
||||
}
|
||||
this.element.append( controlsDiv );
|
||||
this.controlsDiv_ = controlsDiv;
|
||||
};
|
||||
|
||||
JetpackSlideshow.prototype.onCyclePrevNextClick_ = function ( isNext, i /*, slideElement*/ ) {
|
||||
// If blog_id not present don't track page views
|
||||
if ( ! jetpackSlideshowSettings.blog_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var postid = this.images[ i ].id;
|
||||
var stats = new Image();
|
||||
stats.src =
|
||||
document.location.protocol +
|
||||
'//pixel.wp.com/g.gif?host=' +
|
||||
encodeURIComponent( document.location.host ) +
|
||||
'&rand=' +
|
||||
Math.random() +
|
||||
'&blog=' +
|
||||
jetpackSlideshowSettings.blog_id +
|
||||
'&subd=' +
|
||||
jetpackSlideshowSettings.blog_subdomain +
|
||||
'&user_id=' +
|
||||
jetpackSlideshowSettings.user_id +
|
||||
'&post=' +
|
||||
postid +
|
||||
'&ref=' +
|
||||
encodeURIComponent( document.location );
|
||||
};
|
||||
|
||||
( function () {
|
||||
function jetpack_slideshow_init() {
|
||||
document.querySelectorAll( '.jetpack-slideshow-noscript' ).forEach( function ( element ) {
|
||||
element.remove();
|
||||
} );
|
||||
document.querySelectorAll( '.jetpack-slideshow' ).forEach( function ( container ) {
|
||||
if ( container.dataset.processed === 'true' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract data attributes manually
|
||||
var transition = container.dataset.trans;
|
||||
var autostart = container.dataset.autostart === 'true';
|
||||
var gallery = JSON.parse( container.dataset.gallery || '[]' );
|
||||
|
||||
var slideshow = new JetpackSlideshow( container, transition, autostart );
|
||||
slideshow.images = gallery;
|
||||
slideshow.init();
|
||||
|
||||
container.dataset.processed = 'true';
|
||||
} );
|
||||
}
|
||||
|
||||
document.addEventListener( 'DOMContentLoaded', jetpack_slideshow_init );
|
||||
document.body.addEventListener( 'post-load', jetpack_slideshow_init );
|
||||
} )();
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* Kickstarter shortcode
|
||||
*
|
||||
* Usage:
|
||||
* [kickstarter url="https://www.kickstarter.com/projects/peaktoplateau/yak-wool-baselayers-from-tibet-to-the-world" width="480" height=""]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
add_shortcode( 'kickstarter', 'jetpack_kickstarter_shortcode' );
|
||||
add_filter( 'pre_kses', 'jetpack_kickstarter_embed_to_shortcode' );
|
||||
|
||||
/**
|
||||
* Parse shortcode arguments and render its output.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function jetpack_kickstarter_shortcode( $atts ) {
|
||||
if ( empty( $atts['url'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$url = esc_url_raw( $atts['url'] );
|
||||
if ( ! preg_match( '#^(www\.)?kickstarter\.com$#i', wp_parse_url( $url, PHP_URL_HOST ) ) ) {
|
||||
return '<!-- Invalid Kickstarter URL -->';
|
||||
}
|
||||
|
||||
global $wp_embed;
|
||||
return $wp_embed->shortcode( $atts, $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Kickstarter iframe embeds to a shortcode.
|
||||
*
|
||||
* EG: <iframe width="480" height="360" src="http://www.kickstarter.com/projects/deweymac/dewey-mac-kid-detective-book-make-diy-and-stem-spy/widget/video.html" frameborder="0" scrolling="no"> </iframe>
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $content Entry content that possibly includes a Kickstarter embed.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function jetpack_kickstarter_embed_to_shortcode( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'www.kickstarter.com/projects' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$regexp = '!<iframe((?:\s+\w+=[\'"][^\'"]*[\'"])*)\s+src=[\'"](http://www\.kickstarter\.com/projects/[^/]+/[^/]+)/[^\'"]+[\'"]((?:\s+\w+=[\'"][^\'"]*[\'"])*)>[\s]*</iframe>!i';
|
||||
$regexp_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) ); // phpcs:ignore
|
||||
|
||||
foreach ( array( 'regexp', 'regexp_ent' ) as $reg ) {
|
||||
if ( ! preg_match_all( $$reg, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
$url = esc_url( $match[2] );
|
||||
|
||||
$params = $match[1] . $match[3];
|
||||
|
||||
if ( 'regexp_ent' === $reg ) {
|
||||
$params = html_entity_decode( $params, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
|
||||
}
|
||||
|
||||
$params = wp_kses_hair( $params, array( 'http' ) );
|
||||
|
||||
$width = isset( $params['width'] ) ? (int) $params['width']['value'] : 0;
|
||||
|
||||
$shortcode = '[kickstarter url=' . $url . ( ( ! empty( $width ) ) ? " width=$width" : '' ) . ']';
|
||||
$content = str_replace( $match[0], $shortcode, $content );
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
/**
|
||||
* MailChimp Subscriber Popup Form shortcode
|
||||
*
|
||||
* Example:
|
||||
* [mailchimp_subscriber_popup baseUrl="mc.us11.list-manage.com" uuid="1ca7856462585a934b8674c71" lid="2d24f1898b"]
|
||||
*
|
||||
* Embed code example:
|
||||
* <script type="text/javascript" src="//downloads.mailchimp.com/js/signup-forms/popup/unique-methods/embed.js" data-dojo-config="usePlainJson: true, isDebug: false"></script><script type="text/javascript">window.dojoRequire(["mojo/signup-forms/Loader"], function(L) { L.start({"baseUrl":"mc.us11.list-manage.com","uuid":"1ca7856462585a934b8674c71","lid":"2d24f1898b","uniqueMethods":true}) })</script>
|
||||
*/
|
||||
|
||||
// phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
|
||||
|
||||
/**
|
||||
* Register [mailchimp_subscriber_popup] shortcode and add a filter to 'pre_kses' queue to reverse MailChimp embed to shortcode.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
function jetpack_mailchimp_subscriber_popup() {
|
||||
add_shortcode(
|
||||
'mailchimp_subscriber_popup',
|
||||
array(
|
||||
'MailChimp_Subscriber_Popup',
|
||||
'shortcode',
|
||||
)
|
||||
);
|
||||
add_filter(
|
||||
'pre_kses',
|
||||
array(
|
||||
'MailChimp_Subscriber_Popup',
|
||||
'reversal',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
add_action( 'init', 'jetpack_mailchimp_subscriber_popup' );
|
||||
} else {
|
||||
jetpack_mailchimp_subscriber_popup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class MailChimp_Subscriber_Popup
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
class MailChimp_Subscriber_Popup {
|
||||
|
||||
/**
|
||||
* Regular expressions to reverse script tags to shortcodes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $reversal_regexes = array(
|
||||
/* raw examplejs */
|
||||
'/<script type="text\/javascript" src="(https?:)?\/\/downloads\.mailchimp\.com\/js\/signup-forms\/popup\/unique-methods\/embed\.js" data-dojo-config="([^"]*?)"><\/script><script type="text\/javascript">window.dojoRequire\(\["mojo\/signup-forms\/Loader"\]\, function\(L\) { L\.start\({([^}]*?)}\) }\)<\/script>/s', //phpcs:ignore
|
||||
/* visual editor */
|
||||
'/<script type="text\/javascript" src="(https?:)?\/\/downloads\.mailchimp\.com\/js\/signup-forms\/popup\/unique-methods\/embed\.js" data-dojo-config="([^"]*?)"><\/script><script type="text\/javascript">window.dojoRequire\(\["mojo\/signup-forms\/Loader"]\, function\(L\) { L\.start\({([^}]*?)}\) }\)<\/script>/s',
|
||||
);
|
||||
|
||||
/**
|
||||
* Allowed configuration attributes. Used in reversal when checking allowed attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $allowed_config = array(
|
||||
'usePlainJson' => 'true',
|
||||
'isDebug' => 'false',
|
||||
);
|
||||
|
||||
/**
|
||||
* Allowed JS variables. Used in reversal to whitelist variables.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $allowed_js_vars = array(
|
||||
'baseUrl',
|
||||
'uuid',
|
||||
'lid',
|
||||
);
|
||||
|
||||
/**
|
||||
* Runs the whole reversal.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $content Post Content.
|
||||
*
|
||||
* @return string Content with embeds replaced
|
||||
*/
|
||||
public static function reversal( $content ) {
|
||||
// Bail without the js src.
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'downloads.mailchimp.com/js/signup-forms/popup/unique-methods/embed.js' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
// loop through our rules and find valid embeds.
|
||||
foreach ( self::$reversal_regexes as $regex ) {
|
||||
|
||||
if ( ! preg_match_all( $regex, $content, $matches ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches[3] as $index => $js_vars ) {
|
||||
// the regex rule for a specific embed.
|
||||
$replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $matches[0][ $index ], '#' ) );
|
||||
|
||||
$attrs = json_decode( '{' . $js_vars . '}' );
|
||||
|
||||
if ( $matches[2][ $index ] ) {
|
||||
$config_attrs = json_decode( '{' . $matches[2][ $index ] . '}' );
|
||||
foreach ( $config_attrs as $key => $value ) {
|
||||
$attrs->$key = ( 1 === $value ) ? 'true' : 'false';
|
||||
}
|
||||
}
|
||||
|
||||
$shortcode = self::build_shortcode_from_reversal_attrs( $attrs );
|
||||
|
||||
$content = preg_replace( $replace_regex, "\n\n$shortcode\n\n", $content );
|
||||
|
||||
/** This action is documented in modules/widgets/social-media-icons.php */
|
||||
do_action( 'jetpack_bump_stats_extras', 'html_to_shortcode', 'mailchimp_subscriber_popup' );
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the actual shortcode based on passed in attributes.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $attrs A valid list of attributes (gets matched against self::$allowed_config and self::$allowed_js_vars).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function build_shortcode_from_reversal_attrs( $attrs ) {
|
||||
$shortcode = '[mailchimp_subscriber_popup ';
|
||||
|
||||
foreach ( $attrs as $key => $value ) {
|
||||
// skip unsupported keys.
|
||||
if (
|
||||
! array_key_exists( $key, self::$allowed_config )
|
||||
&& ! in_array( $key, self::$allowed_js_vars, true )
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = esc_attr( $value );
|
||||
$shortcode .= "$key='$value' ";
|
||||
}
|
||||
return trim( $shortcode ) . ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the shortcode back out to embedded information.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $lcase_attrs Lowercase shortcode attributes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function shortcode( $lcase_attrs ) {
|
||||
static $displayed_once = false;
|
||||
|
||||
// Limit to one form per page load.
|
||||
if ( $displayed_once ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( empty( $lcase_attrs ) ) {
|
||||
return '<!-- Missing MailChimp baseUrl, uuid or lid -->';
|
||||
}
|
||||
|
||||
$defaults = array_fill_keys( self::$allowed_js_vars, '' );
|
||||
$defaults = array_merge( $defaults, self::$allowed_config );
|
||||
|
||||
// Convert $attrs back to proper casing since they come through in all lowercase.
|
||||
$attrs = array();
|
||||
foreach ( $defaults as $key => $value ) {
|
||||
if ( array_key_exists( strtolower( $key ), $lcase_attrs ) ) {
|
||||
$attrs[ $key ] = $lcase_attrs[ strtolower( $key ) ];
|
||||
}
|
||||
}
|
||||
$attrs = array_map( 'esc_js', array_filter( shortcode_atts( $defaults, $attrs ) ) );
|
||||
|
||||
// Split config & js vars.
|
||||
$js_vars = array();
|
||||
$config_vars = array();
|
||||
foreach ( $attrs as $key => $value ) {
|
||||
if (
|
||||
'baseUrl' === $key
|
||||
&& (
|
||||
! preg_match( '#mc\.us\d+\.list-manage\d?\.com#', $value, $matches )
|
||||
|| $value !== $matches[0]
|
||||
)
|
||||
) {
|
||||
return '<!-- Invalid MailChimp baseUrl -->';
|
||||
}
|
||||
|
||||
if ( in_array( $key, self::$allowed_js_vars, true ) ) {
|
||||
$js_vars[ $key ] = $value;
|
||||
} else {
|
||||
$config_vars[] = "$key: $value";
|
||||
}
|
||||
}
|
||||
|
||||
// If one of these parameters is missing we can't render the form so exist.
|
||||
if ( empty( $js_vars['baseUrl'] ) || empty( $js_vars['uuid'] ) || empty( $js_vars['lid'] ) ) {
|
||||
return '<!-- Missing MailChimp baseUrl, uuid or lid -->';
|
||||
}
|
||||
|
||||
// Add a uniqueMethods parameter if it is missing from the data we got from the embed code.
|
||||
$js_vars['uniqueMethods'] = true;
|
||||
|
||||
/** This action is already documented in modules/widgets/gravatar-profile.php */
|
||||
do_action( 'jetpack_stats_extra', 'mailchimp_subscriber_popup', 'view' );
|
||||
|
||||
$displayed_once = true;
|
||||
|
||||
return "\n\n" . '<script type="text/javascript" data-dojo-config="' . esc_attr( implode( ', ', $config_vars ) ) . '">jQuery.getScript( "//downloads.mailchimp.com/js/signup-forms/popup/unique-methods/embed.js", function( data, textStatus, jqxhr ) { window.dojoRequire(["mojo/signup-forms/Loader"], function(L) { L.start(' . wp_json_encode( $js_vars ) . ') });} );</script>' . "\n\n";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* Embed support for Medium
|
||||
*
|
||||
* Supported formats:
|
||||
* - Profiles: https://medium.com/@jeherve
|
||||
* - Stories: https://medium.com/@jeherve/this-is-a-story-19f582daaf5b
|
||||
* - And all the above in shortcode formats:
|
||||
* [medium url="https://medium.com/@jeherve/this-is-a-story-19f582daaf5b" width="100%" border="false" collapsed="true"]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
// Faux-oembed support for Medium permalinks.
|
||||
wp_embed_register_handler( 'medium', '#^https?://medium.com/([a-zA-z0-9-_@]+)#', 'jetpack_embed_medium_oembed' );
|
||||
|
||||
/**
|
||||
* Callback to modify output of embedded Medium posts.
|
||||
*
|
||||
* @param array $matches Regex partial matches against the URL passed.
|
||||
* @param array $attr Attributes received in embed response.
|
||||
* @param array $url Requested URL to be embedded.
|
||||
*/
|
||||
function jetpack_embed_medium_oembed( $matches, $attr, $url ) {
|
||||
$attr = jetpack_embed_medium_args( $attr );
|
||||
$attr['url'] = $url;
|
||||
|
||||
return jetpack_embed_medium_embed_html( $attr );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return custom markup to display a Medium profile, collection, or story.
|
||||
*
|
||||
* @param array $args Attributes received in embed response.
|
||||
*/
|
||||
function jetpack_embed_medium_embed_html( $args ) {
|
||||
$args = jetpack_embed_medium_args( $args );
|
||||
|
||||
if ( empty( $args['url'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$args['type'] = jetpack_embed_medium_get_embed_type( $args['url'] );
|
||||
|
||||
if ( 'collection' === $args['type'] ) {
|
||||
return sprintf(
|
||||
'<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
|
||||
esc_url( $args['url'] ),
|
||||
esc_html__( 'View this collection on Medium.com', 'jetpack' )
|
||||
);
|
||||
}
|
||||
|
||||
wp_enqueue_script(
|
||||
'medium-embed',
|
||||
'https://static.medium.com/embed.js',
|
||||
array(),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
return sprintf(
|
||||
'<a class="m-%1$s" href="%2$s" target="_blank" data-width="%3$s" data-border="%4$s" data-collapsed="%5$s">%6$s</a>',
|
||||
esc_attr( $args['type'] ),
|
||||
esc_url( $args['url'] ),
|
||||
esc_attr( $args['width'] ),
|
||||
esc_attr( $args['border'] ),
|
||||
esc_attr( $args['collapsed'] ),
|
||||
esc_html__( 'View at Medium.com', 'jetpack' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcode support that allows passing in URL
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function jetpack_embed_medium_shortcode( $atts ) {
|
||||
$atts = jetpack_embed_medium_args( $atts );
|
||||
|
||||
if ( ! empty( $atts['url'] ) ) {
|
||||
global $wp_embed;
|
||||
return $wp_embed->shortcode( $atts, $atts['url'] );
|
||||
} elseif ( current_user_can( 'edit_posts' ) ) {
|
||||
return esc_html__( 'You did not provide a valid Medium URL.', 'jetpack' );
|
||||
} else {
|
||||
return '<!-- Missing Medium URL -->';
|
||||
}
|
||||
}
|
||||
add_shortcode( 'medium', 'jetpack_embed_medium_shortcode' );
|
||||
|
||||
/**
|
||||
* Get embed type (profile, collection, or story) based on Medium URL.
|
||||
*
|
||||
* @param string $url Medium URL.
|
||||
*/
|
||||
function jetpack_embed_medium_get_embed_type( $url ) {
|
||||
$url_path = wp_parse_url( $url, PHP_URL_PATH );
|
||||
if ( preg_match( '/^\/@[\.\w]+$/', $url_path ) ) {
|
||||
return 'profile';
|
||||
} elseif ( preg_match( '/^\/(?:s)\/(.+)$/', $url_path ) ) {
|
||||
return 'collection';
|
||||
}
|
||||
|
||||
return 'story';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Medium shortcode attributes.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function jetpack_embed_medium_args( $atts ) {
|
||||
return shortcode_atts(
|
||||
array(
|
||||
'url' => '',
|
||||
'width' => '400',
|
||||
'border' => true,
|
||||
'collapsed' => false,
|
||||
),
|
||||
$atts,
|
||||
'medium'
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/**
|
||||
* Mixcloud embeds
|
||||
*
|
||||
* Examples:
|
||||
* [mixcloud MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ /]
|
||||
* [mixcloud MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ width=640 height=480 /]
|
||||
* [mixcloud http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ /]
|
||||
* [mixcloud http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ width=640 height=480 /]
|
||||
* [mixcloud]http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/[/mixcloud]
|
||||
* [mixcloud]MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/[/mixcloud]
|
||||
* [mixcloud http://www.mixcloud.com/mat/playlists/classics/ width=660 height=208 hide_cover=1 hide_tracklist=1]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/*
|
||||
* Register oEmbed provider
|
||||
* Example URL: http://app.mixcloud.com/oembed/?url=http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/
|
||||
*/
|
||||
wp_oembed_add_provider( '#https?://(?:www\.)?mixcloud\.com/\S*#i', 'https://app.mixcloud.com/oembed/', true );
|
||||
|
||||
/**
|
||||
* Register mixcloud shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode atttributes.
|
||||
* @param string $content Post content.
|
||||
*/
|
||||
function mixcloud_shortcode( $atts, $content = null ) {
|
||||
|
||||
if ( empty( $atts[0] ) && empty( $content ) ) {
|
||||
return '<!-- mixcloud error: invalid mixcloud resource -->';
|
||||
}
|
||||
|
||||
$regular_expression = '/((?<=mixcloud\.com\/)[\w\-\/]+$)|(^[\w\-\/]+$)/i';
|
||||
preg_match( $regular_expression, $content, $match );
|
||||
if ( ! empty( $match ) ) {
|
||||
$resource_id = trim( $match[0] );
|
||||
} else {
|
||||
preg_match( $regular_expression, $atts[0], $match );
|
||||
if ( ! empty( $match ) ) {
|
||||
$resource_id = trim( $match[0] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $resource_id ) ) {
|
||||
return '<!-- mixcloud error: invalid mixcloud resource -->';
|
||||
}
|
||||
|
||||
$mixcloud_url = 'https://mixcloud.com/' . $resource_id;
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'width' => false,
|
||||
'height' => false,
|
||||
'color' => false,
|
||||
'light' => false,
|
||||
'dark' => false,
|
||||
'hide_tracklist' => false,
|
||||
'hide_cover' => false,
|
||||
'mini' => false,
|
||||
'hide_followers' => false,
|
||||
'hide_artwork' => false,
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
// remove falsey values.
|
||||
$atts = array_filter( $atts );
|
||||
|
||||
$query_args = array( 'url' => $mixcloud_url );
|
||||
$query_args = array_merge( $query_args, $atts );
|
||||
|
||||
$url = add_query_arg( urlencode_deep( $query_args ), 'https://app.mixcloud.com/oembed/' );
|
||||
$mixcloud_response = wp_remote_get( $url, array( 'redirection' => 0 ) );
|
||||
if ( is_wp_error( $mixcloud_response ) || 200 !== $mixcloud_response['response']['code'] || empty( $mixcloud_response['body'] ) ) {
|
||||
return '<!-- mixcloud error: invalid mixcloud resource -->';
|
||||
}
|
||||
|
||||
$response_body = json_decode( $mixcloud_response['body'] );
|
||||
|
||||
$html = $response_body->html;
|
||||
|
||||
preg_match( '/sandbox="([^"]*)"/', $html, $matches );
|
||||
|
||||
if ( empty( $matches ) ) { // Mixcloud doesn't use sandbox attribute.
|
||||
$html = preg_replace( '/>/', ' sandbox="allow-popups allow-scripts allow-same-origin allow-presentation">', $html, 1 );
|
||||
} else { // Mixcloud uses sandbox attribute.
|
||||
|
||||
$allowed_values = array();
|
||||
// Here we make sure that these string are not repeated in the sandbox attribute.
|
||||
$attrs = array( 'allow-popups', 'allow-scripts', 'allow-same-origin', 'allow-presentation' );
|
||||
foreach ( $attrs as $attr ) {
|
||||
if ( ! str_contains( $matches[1], $attr ) ) {
|
||||
$allowed_values[] = $attr;
|
||||
}
|
||||
}
|
||||
|
||||
$sandbox_value = $matches[1] . ' ' . implode( ' ', $allowed_values );
|
||||
|
||||
$html = preg_replace( '/sandbox="([^"]*)"/', "sandbox=\"$sandbox_value\"", $html );
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
add_shortcode( 'mixcloud', 'mixcloud_shortcode' );
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* Extra oEmbed providers that we use on wpcom for feature parity.
|
||||
*
|
||||
* This file will be loaded even when you don't use the Shortcodes feature,
|
||||
* as these embeds are considered safe to use on any site
|
||||
* (and may end up embedded in Core in the future).
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
wp_oembed_add_provider( 'https://me.sh/*', 'https://me.sh/oembed?format=json' );
|
||||
wp_oembed_add_provider( '#https?://(www\.)?gfycat\.com/.*#i', 'https://api.gfycat.com/v1/oembed', true );
|
||||
wp_oembed_add_provider( '#https?://[^.]+\.(wistia\.com|wi\.st)/(medias|embed)/.*#', 'https://fast.wistia.com/oembed', true );
|
||||
wp_oembed_add_provider( '#https?://sketchfab\.com/.*#i', 'https://sketchfab.com/oembed', true );
|
||||
wp_oembed_add_provider( '#https?://(www\.)?icloud\.com/keynote/.*#i', 'https://iwmb.icloud.com/iwmb/oembed', true );
|
||||
wp_oembed_add_provider( '#https?://(www\.)?icloud\.com\.cn/keynote/.*#i', 'https://iwmb.icloud.com.cn/iwmb/oembed', true );
|
||||
wp_oembed_add_provider( '#https?://((song|album|artist|pods|playlist)\.link|odesli\.com?|mylink\.page)/.*#', 'https://odesli.co/oembed', true );
|
||||
wp_oembed_add_provider( '#https?://(www\.)?loom\.com/share/.*#i', 'https://www.loom.com/v1/oembed', true );
|
||||
|
||||
/**
|
||||
* Filters the HTTP request timeout value so that we can increase the timeout for iCloud oEmbeds.
|
||||
*
|
||||
* @param int $timeout The timeout value in seconds.
|
||||
* @param string $url The URL to fetch.
|
||||
*
|
||||
* @return int The timeout value in seconds.
|
||||
*/
|
||||
function jetpack_oembed_timeout_override( $timeout, $url = '' ) {
|
||||
if (
|
||||
is_string( $url )
|
||||
&& str_contains( $url, 'iwmb.icloud.com' )
|
||||
) {
|
||||
return 10;
|
||||
}
|
||||
return $timeout;
|
||||
}
|
||||
|
||||
// TODO: Remove this. This should hopefully be a temporary hack since Apple's oEmbed often seems to take more than 5 seconds to respond. 10 is an arbitrary number of seconds that seems to work better.
|
||||
add_filter( 'http_request_timeout', 'jetpack_oembed_timeout_override', 10, 2 );
|
||||
|
||||
// WordPress core only registers pca.st, not pcast.pocketcasts.net.
|
||||
wp_oembed_add_provider( '#https?://pcast\.pocketcasts\.net/.+#i', 'https://pcast.pocketcasts.net/oembed.json', true );
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* Pinterest embeds
|
||||
*
|
||||
* Based on "Board Widget" example here: http://business.pinterest.com/widget-builder/#code
|
||||
*
|
||||
* Example URL: https://pinterest.com/pin/129056345550241149/
|
||||
* Second Example URL: https://uk.pinterest.com/annsawesomepins/travel/
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
wp_embed_register_handler(
|
||||
'pinterest',
|
||||
'#'
|
||||
. 'https?://'
|
||||
. '(?:www\.)?'
|
||||
. '(?:[a-z]{2}\.)?'
|
||||
. 'pinterest\.[a-z.]+/'
|
||||
. '([^/]+)'
|
||||
. '(/[^/]+)?'
|
||||
. '#',
|
||||
'pinterest_embed_handler'
|
||||
);
|
||||
|
||||
/**
|
||||
* Callback to modify output of embedded Pinterest posts.
|
||||
*
|
||||
* @param array $matches Regex partial matches against the URL passed.
|
||||
* @param array $attr Attributes received in embed response.
|
||||
* @param array $url Requested URL to be embedded.
|
||||
*/
|
||||
function pinterest_embed_handler( $matches, $attr, $url ) {
|
||||
// Pinterest's JS handles making the embed.
|
||||
$script_src = '//assets.pinterest.com/js/pinit.js';
|
||||
|
||||
wp_enqueue_script( 'pinterest-embed', $script_src, array(), JETPACK__VERSION, true );
|
||||
|
||||
$path = wp_parse_url( $url, PHP_URL_PATH );
|
||||
if ( str_starts_with( $path, '/pin/' ) ) {
|
||||
$embed_type = 'embedPin';
|
||||
} elseif ( preg_match( '#^/([^/]+)/?$#', $path ) ) {
|
||||
$embed_type = 'embedUser';
|
||||
} elseif ( preg_match( '#^/([^/]+)/([^/]+)/?$#', $path ) ) {
|
||||
$embed_type = 'embedBoard';
|
||||
} else {
|
||||
if ( current_user_can( 'edit_posts' ) ) {
|
||||
return __( 'Sorry, that Pinterest URL was not recognized.', 'jetpack' );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$return = sprintf( '<a data-pin-do="%s" href="%s"></a>', esc_attr( $embed_type ), esc_url( $url ) );
|
||||
|
||||
// If we're generating an embed view for the WordPress Admin via ajax.
|
||||
if ( doing_action( 'wp_ajax_parse-embed' ) ) {
|
||||
$return .= sprintf(
|
||||
'<script src="%s"></script>', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
|
||||
esc_url( $script_src )
|
||||
);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
/**
|
||||
* Presentations
|
||||
* Presentations plugin based on the work done by <a href="http://darylkoop.com/">Daryl Koopersmith</a>. Powered by jmpress.js
|
||||
*
|
||||
* HOW TO: How the plugin settings are organized and which features are supported.
|
||||
*
|
||||
* The entire presentation should be wrapped with a [presentation] shortcode, and every
|
||||
* individual slide should be wrapped with a [slide] shortcode. Any settings supported
|
||||
* by [slide] can be set into [presentation], which will apply that setting for the entire
|
||||
* presentation unless overridden by individual slides.
|
||||
*
|
||||
* - [presentation] only settings:
|
||||
* - duration: transition durations, default is one second.
|
||||
* - height: content height, default is 400px
|
||||
* - width: content width, default is 550px
|
||||
* - autoplay: delay between transitions in seconds, default 3s
|
||||
* when set the presentation will automatically transition between slides
|
||||
* as long as the presentation remains in focus
|
||||
*
|
||||
* - [slide] settings:
|
||||
* - transition: specifies where the next slide will be placed relative
|
||||
* to the last one before it. Supported values are "up", "down"
|
||||
* "left", "right", or "none". Default value is "down".
|
||||
*
|
||||
* - scale: scales the content relative to other slides, default value is one
|
||||
*
|
||||
* - rotate: rotates the content by the specified degrees, default is zero
|
||||
*
|
||||
* - fade: slides will fade in and out during transition. Values of "on" or
|
||||
* "true" will enable fading, while values of "no" or "false" will
|
||||
* disable it. Default value is "on"
|
||||
*
|
||||
* - bgcolor: specifies a background color for the slides. Any CSS valid value
|
||||
* is permitted. Default color is transparent.
|
||||
*
|
||||
* - bgimg: specifies an image url which will fill the background. Image is
|
||||
* set to fill the background 100% width and height
|
||||
*
|
||||
* - fadebullets: any html <li> tags will start out with an opacity of 0 and any
|
||||
* subsequent slide transitions will show the bullets one by one
|
||||
*
|
||||
* Known issues:
|
||||
*
|
||||
* - IE 7/8 are not supported by jmpress and presentations will not work
|
||||
* - IE 9 will not animate transitions at all, though it's possible to at least
|
||||
* switch between slides.
|
||||
* - Infinite Scroll themes will not load presentations properly unless the post
|
||||
* happens to be on the first loaded page. The permalink page will function
|
||||
* properly, however.
|
||||
* - Exiting fullscreen mode will not properly reset the scroll locations in Safari
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Assets;
|
||||
|
||||
if ( ! class_exists( 'Presentations' ) ) :
|
||||
/**
|
||||
* Create a shortcode to display Presentations and slides.
|
||||
*/
|
||||
class Presentations {
|
||||
|
||||
/**
|
||||
* Presentation settings.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $presentation_settings;
|
||||
/**
|
||||
* Do we have a Presentation shortcode to be displayed.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $presentation_initialized;
|
||||
/**
|
||||
* Were scripts and styles enqueued already.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $scripts_and_style_included;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->presentation_initialized = false;
|
||||
$this->scripts_and_style_included = false;
|
||||
|
||||
// Registers shortcodes.
|
||||
add_action( 'wp_head', array( $this, 'add_scripts' ), 1 );
|
||||
|
||||
add_shortcode( 'presentation', array( $this, 'presentation_shortcode' ) );
|
||||
add_shortcode( 'slide', array( $this, 'slide_shortcode' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue all scripts and styles.
|
||||
*/
|
||||
public function add_scripts() {
|
||||
$this->scripts_and_style_included = false;
|
||||
|
||||
if ( empty( $GLOBALS['posts'] ) || ! is_array( $GLOBALS['posts'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $GLOBALS['posts'] as $p ) {
|
||||
if ( isset( $p->post_content ) && has_shortcode( $p->post_content, 'presentation' ) ) {
|
||||
$this->scripts_and_style_included = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $this->scripts_and_style_included ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$plugin = plugin_dir_url( __FILE__ );
|
||||
// Add CSS.
|
||||
wp_enqueue_style( 'presentations', $plugin . 'css/style.css', array(), JETPACK__VERSION );
|
||||
// Add JavaScript.
|
||||
wp_enqueue_script( 'jquery' );
|
||||
wp_enqueue_script(
|
||||
'jmpress',
|
||||
Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/jmpress.min.js', 'modules/shortcodes/js/jmpress.js' ),
|
||||
array( 'jquery' ),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
wp_enqueue_script(
|
||||
'presentations',
|
||||
Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/main.min.js', 'modules/shortcodes/js/main.js' ),
|
||||
array( 'jquery', 'jmpress' ),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main Presentation shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @param string $content Post content.
|
||||
*/
|
||||
public function presentation_shortcode( $atts, $content = '' ) {
|
||||
// Mark that we've found a valid [presentation] shortcode.
|
||||
$this->presentation_initialized = true;
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'duration' => '',
|
||||
'height' => '',
|
||||
'width' => '',
|
||||
'bgcolor' => '',
|
||||
'bgimg' => '',
|
||||
'autoplay' => '',
|
||||
|
||||
// Settings.
|
||||
'transition' => '',
|
||||
'scale' => '',
|
||||
'rotate' => '',
|
||||
'fade' => '',
|
||||
'fadebullets' => '',
|
||||
),
|
||||
$atts,
|
||||
'presentation'
|
||||
);
|
||||
|
||||
$this->presentation_settings = array(
|
||||
'transition' => 'down',
|
||||
'scale' => 1,
|
||||
'rotate' => 0,
|
||||
'fade' => 'on',
|
||||
'fadebullets' => 0,
|
||||
'last' => array(
|
||||
'x' => 0,
|
||||
'y' => 0,
|
||||
'scale' => 1,
|
||||
'rotate' => 0,
|
||||
),
|
||||
);
|
||||
|
||||
// Set the presentation-wide settings.
|
||||
if ( '' !== trim( $atts['transition'] ) ) {
|
||||
$this->presentation_settings['transition'] = $atts['transition'];
|
||||
}
|
||||
|
||||
if ( '' !== trim( $atts['scale'] ) ) {
|
||||
$this->presentation_settings['scale'] = (float) $atts['scale'];
|
||||
}
|
||||
|
||||
if ( '' !== trim( $atts['rotate'] ) ) {
|
||||
$this->presentation_settings['rotate'] = (float) $atts['rotate'];
|
||||
}
|
||||
|
||||
if ( '' !== trim( $atts['fade'] ) ) {
|
||||
$this->presentation_settings['fade'] = $atts['fade'];
|
||||
}
|
||||
|
||||
if ( '' !== trim( $atts['fadebullets'] ) ) {
|
||||
$this->presentation_settings['fadebullets'] = $atts['fadebullets'];
|
||||
}
|
||||
|
||||
// Set any settings the slides don't care about.
|
||||
if ( '' !== trim( $atts['duration'] ) ) {
|
||||
$duration = (float) $atts['duration'] . 's';
|
||||
} else {
|
||||
$duration = '1s';
|
||||
}
|
||||
|
||||
// Autoplay durations are set in milliseconds.
|
||||
if ( '' !== trim( $atts['autoplay'] ) ) {
|
||||
$autoplay = (float) $atts['autoplay'] * 1000;
|
||||
} else {
|
||||
$autoplay = 0;
|
||||
} // No autoplay
|
||||
|
||||
// Set the presentation size as specified or with some nicely sized dimensions.
|
||||
if ( '' !== trim( $atts['width'] ) ) {
|
||||
$this->presentation_settings['width'] = (int) $atts['width'];
|
||||
} else {
|
||||
$this->presentation_settings['width'] = 480;
|
||||
}
|
||||
|
||||
if ( '' !== trim( $atts['height'] ) ) {
|
||||
$this->presentation_settings['height'] = (int) $atts['height'];
|
||||
} else {
|
||||
$this->presentation_settings['height'] = 370;
|
||||
}
|
||||
|
||||
// Hide the content by default in case the scripts fail.
|
||||
$style = 'display: none; width: ' . $this->presentation_settings['width'] . 'px; height: ' . $this->presentation_settings['height'] . 'px;';
|
||||
|
||||
/*
|
||||
* Check for background color XOR background image
|
||||
* Use a white background if nothing specified
|
||||
*/
|
||||
if ( preg_match( '/https?\:\/\/[^\'"\s]*/', $atts['bgimg'], $matches ) ) {
|
||||
$style .= ' background-image: url("' . esc_url( $matches[0] ) . '");';
|
||||
} elseif ( '' !== trim( $atts['bgcolor'] ) ) {
|
||||
$style .= ' background-color: ' . esc_attr( $atts['bgcolor'] ) . ';';
|
||||
} else {
|
||||
$style .= ' background-color: #fff;';
|
||||
}
|
||||
|
||||
// Not supported message style is inlined incase the style sheet doesn't get included.
|
||||
$out = "<section class='presentation-wrapper'>";
|
||||
$out .= "<p class='not-supported-msg' style='display: inherit; padding: 25%; text-align: center;'>";
|
||||
$out .= __( 'This slideshow could not be started. Try refreshing the page or viewing it in another browser.', 'jetpack' ) . '</p>';
|
||||
|
||||
$out .= sprintf(
|
||||
'<div class="presentation" duration="%s" data-autoplay="%s" style="%s">',
|
||||
esc_attr( $duration ),
|
||||
esc_attr( $autoplay ),
|
||||
esc_attr( $style )
|
||||
);
|
||||
$out .= "<div class='nav-arrow-left'></div>";
|
||||
$out .= "<div class='nav-arrow-right'></div>";
|
||||
$out .= "<div class='nav-fullscreen-button'></div>";
|
||||
|
||||
if ( $autoplay ) {
|
||||
$out .= '<div class="autoplay-overlay" style="display: none;"><p class="overlay-msg">';
|
||||
$out .= __( 'Click to autoplay the presentation!', 'jetpack' );
|
||||
$out .= '</p></div>';
|
||||
}
|
||||
|
||||
$out .= do_shortcode( $content );
|
||||
|
||||
$out .= '</section>';
|
||||
|
||||
$this->presentation_initialized = false;
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Slide shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @param string $content Post content.
|
||||
*/
|
||||
public function slide_shortcode( $atts, $content = '' ) {
|
||||
// Bail out unless wrapped by a [presentation] shortcode.
|
||||
if ( ! $this->presentation_initialized ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'transition' => '',
|
||||
'scale' => '',
|
||||
'rotate' => '',
|
||||
'fade' => '',
|
||||
'fadebullets' => '',
|
||||
'bgcolor' => '',
|
||||
'bgimg' => '',
|
||||
),
|
||||
$atts,
|
||||
'slide'
|
||||
);
|
||||
|
||||
// Determine positioning based on transition.
|
||||
if ( '' === trim( $atts['transition'] ) ) {
|
||||
$atts['transition'] = $this->presentation_settings['transition'];
|
||||
}
|
||||
|
||||
// Setting the content scale.
|
||||
if ( '' === trim( $atts['scale'] ) ) {
|
||||
$atts['scale'] = $this->presentation_settings['scale'];
|
||||
}
|
||||
|
||||
if ( '' === trim( $atts['scale'] ) ) {
|
||||
$scale = 1;
|
||||
} else {
|
||||
$scale = (float) $atts['scale'];
|
||||
}
|
||||
|
||||
if ( $scale < 0 ) {
|
||||
$scale *= -1;
|
||||
}
|
||||
|
||||
// Setting the content rotation.
|
||||
if ( '' === trim( $atts['rotate'] ) ) {
|
||||
$atts['rotate'] = $this->presentation_settings['rotate'];
|
||||
}
|
||||
|
||||
if ( '' === trim( $atts['rotate'] ) ) {
|
||||
$rotate = 0;
|
||||
} else {
|
||||
$rotate = (float) $atts['rotate'];
|
||||
}
|
||||
|
||||
// Setting if the content should fade.
|
||||
if ( '' === trim( $atts['fade'] ) ) {
|
||||
$atts['fade'] = $this->presentation_settings['fade'];
|
||||
}
|
||||
|
||||
if ( 'on' === $atts['fade'] || 'true' === $atts['fade'] ) {
|
||||
$fade = 'fade';
|
||||
} else {
|
||||
$fade = '';
|
||||
}
|
||||
|
||||
// Setting if bullets should fade on step changes.
|
||||
if ( '' === trim( $atts['fadebullets'] ) ) {
|
||||
$atts['fadebullets'] = $this->presentation_settings['fadebullets'];
|
||||
}
|
||||
|
||||
if ( 'on' === $atts['fadebullets'] || 'true' === $atts['fadebullets'] ) {
|
||||
$fadebullets = 'fadebullets';
|
||||
} else {
|
||||
$fadebullets = '';
|
||||
}
|
||||
|
||||
$coords = $this->get_coords(
|
||||
array(
|
||||
'transition' => $atts['transition'],
|
||||
'scale' => $scale,
|
||||
'rotate' => $rotate,
|
||||
)
|
||||
);
|
||||
|
||||
$x = $coords['x'];
|
||||
$y = $coords['y'];
|
||||
|
||||
/*
|
||||
* Check for background color XOR background image
|
||||
* Use a white background if nothing specified
|
||||
*/
|
||||
if ( preg_match( '/https?\:\/\/[^\'"\s]*/', $atts['bgimg'], $matches ) ) {
|
||||
$style = 'background-image: url("' . esc_url( $matches[0] ) . '");';
|
||||
} elseif ( '' !== trim( $atts['bgcolor'] ) ) {
|
||||
$style = 'background-color: ' . esc_attr( $atts['bgcolor'] ) . ';';
|
||||
} else {
|
||||
$style = '';
|
||||
}
|
||||
|
||||
// Put everything together and let jmpress do the magic!
|
||||
$out = sprintf(
|
||||
'<div class="step %s %s" data-x="%s" data-y="%s" data-scale="%s" data-rotate="%s" style="%s">',
|
||||
esc_attr( $fade ),
|
||||
esc_attr( $fadebullets ),
|
||||
esc_attr( $x ),
|
||||
esc_attr( $y ),
|
||||
esc_attr( $scale ),
|
||||
esc_attr( $rotate ),
|
||||
esc_attr( $style )
|
||||
);
|
||||
|
||||
$out .= '<div class="slide-content">';
|
||||
$out .= do_shortcode( $content );
|
||||
$out .= '</div></div>';
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the position of the next slide based on the position and scaling of the previous slide.
|
||||
*
|
||||
* @param array $args {
|
||||
* Array of key-value pairs.
|
||||
*
|
||||
* @type string $transition: the transition name, "up", "down", "left", or "right".
|
||||
* @type float $scale: the scale of the next slide (used to determine the position of the slide after that).
|
||||
* }
|
||||
*
|
||||
* @return array with the 'x' and 'y' coordinates of the slide.
|
||||
*/
|
||||
private function get_coords( $args ) {
|
||||
if ( 0 === $args['scale'] ) {
|
||||
$args['scale'] = 1;
|
||||
}
|
||||
|
||||
$width = $this->presentation_settings['width'];
|
||||
$height = $this->presentation_settings['height'];
|
||||
$last = $this->presentation_settings['last'];
|
||||
$scale = $last['scale'];
|
||||
|
||||
$next = array(
|
||||
'x' => $last['x'],
|
||||
'y' => $last['y'],
|
||||
'scale' => $args['scale'],
|
||||
'rotate' => $args['rotate'],
|
||||
);
|
||||
|
||||
// All angles are measured from the vertical axis, so everything is backwards!
|
||||
$diag_angle = atan2( $width, $height );
|
||||
$diagonal = sqrt( pow( $width, 2 ) + pow( $height, 2 ) );
|
||||
|
||||
/*
|
||||
* We offset the angles by the angle formed by the diagonal so that
|
||||
* we can multiply the sines directly against the diagonal length
|
||||
*/
|
||||
$theta = deg2rad( $last['rotate'] ) - $diag_angle;
|
||||
$phi = deg2rad( $next['rotate'] ) - $diag_angle;
|
||||
|
||||
// We start by displacing by the slide dimensions.
|
||||
$total_horiz_disp = $width * $scale;
|
||||
$total_vert_disp = $height * $scale;
|
||||
|
||||
/*
|
||||
* If the previous slide was rotated, we add the incremental offset from the rotation
|
||||
* Namely the difference between the regular dimension (no rotation) and the component
|
||||
* of the diagonal for that angle
|
||||
*/
|
||||
$total_horiz_disp += ( ( ( abs( sin( $theta ) ) * $diagonal ) - $width ) / 2 ) * $scale;
|
||||
$total_vert_disp += ( ( ( abs( cos( $theta ) ) * $diagonal ) - $height ) / 2 ) * $scale;
|
||||
|
||||
/*
|
||||
* Similarly, we check if the current slide has been rotated and add whatever additional
|
||||
* offset has been added. This is so that two rotated corners don't clash with each other.
|
||||
* Note: we are checking the raw angle relative to the vertical axis, NOT the diagonal angle.
|
||||
*/
|
||||
if ( 0 !== $next['rotate'] % 180 ) {
|
||||
$total_horiz_disp += ( abs( ( sin( $phi ) * $diagonal ) - $width ) / 2 ) * $next['scale'];
|
||||
$total_vert_disp += ( abs( ( cos( $phi ) * $diagonal ) - $height ) / 2 ) * $next['scale'];
|
||||
}
|
||||
|
||||
switch ( trim( $args['transition'] ) ) {
|
||||
case 'none':
|
||||
break;
|
||||
|
||||
case 'left':
|
||||
$next['x'] -= $total_horiz_disp;
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
$next['x'] += $total_horiz_disp;
|
||||
break;
|
||||
|
||||
case 'up':
|
||||
$next['y'] -= $total_vert_disp;
|
||||
break;
|
||||
|
||||
case 'down':
|
||||
default:
|
||||
$next['y'] += $total_vert_disp;
|
||||
break;
|
||||
}
|
||||
|
||||
$this->presentation_settings['last'] = $next;
|
||||
|
||||
return $next;
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['presentations'] = new Presentations();
|
||||
endif;
|
||||
@@ -0,0 +1,364 @@
|
||||
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileNam
|
||||
|
||||
use Automattic\Jetpack\Assets;
|
||||
|
||||
/**
|
||||
* Quiz shortcode.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* [quiz]
|
||||
* [question]What's the right answer?[/question]
|
||||
* [wrong]This one?[explanation]Nope[/explanation][/wrong]
|
||||
* [answer]Yes, this is the one![explanation]Yay![/explanation][/answer]
|
||||
* [wrong]Maybe this one[explanation]Keep trying[/explanation][/wrong]
|
||||
* [wrong]How about this one?[explanation]Try again[/explanation][/wrong]
|
||||
* [/quiz]
|
||||
*
|
||||
* Can also be wrapped in [quiz-wrapper] to display all quizzes together.
|
||||
*/
|
||||
class Quiz_Shortcode {
|
||||
|
||||
/**
|
||||
* Parameters admitted by [quiz] shortcode.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $quiz_params = array();
|
||||
|
||||
/**
|
||||
* Whether the [quiz-wrapper] shortcode is used.
|
||||
*
|
||||
* @since 10.1
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $quiz_wrapper = false;
|
||||
|
||||
/**
|
||||
* Whether the scripts were enqueued.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $scripts_enqueued = false;
|
||||
|
||||
/**
|
||||
* In a8c training, store user currently logged in.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @var null
|
||||
*/
|
||||
private static $username = null;
|
||||
|
||||
/**
|
||||
* Whether the noscript tag was already printed.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private static $noscript_info_printed = false;
|
||||
|
||||
/**
|
||||
* Whether JavaScript is available.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @var null
|
||||
*/
|
||||
private static $javascript_unavailable = null;
|
||||
|
||||
/**
|
||||
* Register all shortcodes.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public static function init() {
|
||||
add_shortcode( 'quiz-wrapper', array( __CLASS__, 'shortcode_wrapper' ) );
|
||||
add_shortcode( 'quiz', array( __CLASS__, 'shortcode' ) );
|
||||
add_shortcode( 'question', array( __CLASS__, 'question_shortcode' ) );
|
||||
add_shortcode( 'answer', array( __CLASS__, 'answer_shortcode' ) );
|
||||
add_shortcode( 'wrong', array( __CLASS__, 'wrong_shortcode' ) );
|
||||
add_shortcode( 'explanation', array( __CLASS__, 'explanation_shortcode' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue assets needed by the quiz,
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
private static function enqueue_scripts() {
|
||||
wp_enqueue_style( 'quiz', plugins_url( 'css/quiz.css', __FILE__ ), array(), JETPACK__VERSION );
|
||||
wp_enqueue_script(
|
||||
'quiz',
|
||||
Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/quiz.min.js', 'modules/shortcodes/js/quiz.js' ),
|
||||
array( 'jquery' ),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a feed and thus JS is unavailable.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @return bool|null
|
||||
*/
|
||||
private static function is_javascript_unavailable() {
|
||||
if ( self::$javascript_unavailable !== null ) {
|
||||
return self::$javascript_unavailable;
|
||||
}
|
||||
|
||||
if ( is_feed() ) {
|
||||
self::$javascript_unavailable = true;
|
||||
return self::$javascript_unavailable;
|
||||
}
|
||||
|
||||
self::$javascript_unavailable = false;
|
||||
return self::$javascript_unavailable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display message when JS is not available.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function noscript_info() {
|
||||
if ( self::$noscript_info_printed ) {
|
||||
return '';
|
||||
}
|
||||
self::$noscript_info_printed = true;
|
||||
return '<noscript><div><i>' . esc_html__( 'Please view this post in your web browser to complete the quiz.', 'jetpack' ) . '</i></div></noscript>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we're in WordPress.com.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_wpcom() {
|
||||
return defined( 'IS_WPCOM' ) && IS_WPCOM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse shortcode arguments and render its output.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
* @param string $content Content enclosed by shortcode tags.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function shortcode( $atts, $content = null ) {
|
||||
|
||||
// There's nothing to do if there's nothing enclosed.
|
||||
if ( empty( $content ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$id = '';
|
||||
|
||||
if ( self::is_javascript_unavailable() ) {
|
||||
// in an e-mail print the question and the info sentence once per question, too.
|
||||
self::$noscript_info_printed = false;
|
||||
} else {
|
||||
|
||||
if ( ! self::$scripts_enqueued ) {
|
||||
// lazy enqueue cannot use the wp_enqueue_scripts action anymore.
|
||||
self::enqueue_scripts();
|
||||
self::$scripts_enqueued = true;
|
||||
}
|
||||
|
||||
$default_atts = self::is_wpcom()
|
||||
? array(
|
||||
'trackid' => '',
|
||||
'a8ctraining' => '',
|
||||
)
|
||||
: array(
|
||||
'trackid' => '',
|
||||
);
|
||||
|
||||
self::$quiz_params = shortcode_atts( $default_atts, $atts );
|
||||
|
||||
if ( ! empty( self::$quiz_params['trackid'] ) ) {
|
||||
$id .= ' data-trackid="' . esc_attr( self::$quiz_params['trackid'] ) . '"';
|
||||
}
|
||||
if ( self::is_wpcom() && ! empty( self::$quiz_params['a8ctraining'] ) ) {
|
||||
if ( self::$username === null ) {
|
||||
self::$username = wp_get_current_user()->user_login;
|
||||
}
|
||||
$id .= ' data-a8ctraining="' . esc_attr( self::$quiz_params['a8ctraining'] ) . '" data-username="' . esc_attr( self::$username ) . '"';
|
||||
}
|
||||
}
|
||||
|
||||
$quiz = self::do_shortcode( $content );
|
||||
$quiz_options = '';
|
||||
|
||||
if ( self::$quiz_wrapper ) {
|
||||
$quiz_options = '<div class="jetpack-quiz-options">
|
||||
<span class="jetpack-quiz-count"></span>
|
||||
<a class="jetpack-quiz-option-button" data-quiz-option="previous" role="button" aria-label="' . esc_attr__( 'Previous quiz', 'jetpack' ) . '">
|
||||
<svg viewBox="0 0 24 24" class="quiz-gridicon">
|
||||
<g><path d="M14 20l-8-8 8-8 1.414 1.414L8.828 12l6.586 6.586"></path></g></svg></a>
|
||||
<a class="jetpack-quiz-option-button" data-quiz-option="next" role="button" aria-label="' . esc_attr__( 'Next quiz', 'jetpack' ) . '">
|
||||
<svg viewBox="0 0 24 24" class="quiz-gridicon">
|
||||
<g><path d="M10 20l8-8-8-8-1.414 1.414L15.172 12l-6.586 6.586"></path></g></svg></a>
|
||||
</div>';
|
||||
}
|
||||
|
||||
return '<div class="jetpack-quiz quiz"' . $id . '>' . $quiz . $quiz_options . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap shortcode contents.
|
||||
*
|
||||
* @since 10.1
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
* @param string $content Content enclosed by shortcode tags.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function shortcode_wrapper( $atts, $content = null ) {
|
||||
self::$quiz_wrapper = true;
|
||||
return '<div class="jetpack-quiz-wrapper">' . self::do_shortcode( $content ) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip line breaks, restrict allowed HTML to a few allowed tags and execute nested shortcodes.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
private static function do_shortcode( $content ) {
|
||||
// strip autoinserted line breaks.
|
||||
$content = preg_replace( '#(<(?:br /|/?p)>\n?)*(\[/?[a-z]+\])(<(?:br /|/?p)>\n?)*#', '$2', $content );
|
||||
|
||||
// Add internal parameter so it's only rendered when it has it.
|
||||
$content = preg_replace( '/\[(question|answer|wrong|explanation)\]/i', '[$1 quiz_item="true"]', $content );
|
||||
$content = do_shortcode( $content );
|
||||
$content = wp_kses(
|
||||
$content,
|
||||
array(
|
||||
'tt' => array(),
|
||||
'a' => array(
|
||||
'href' => true,
|
||||
'class' => true,
|
||||
'data-quiz-option' => true,
|
||||
'aria-label' => true,
|
||||
'role' => 'button',
|
||||
),
|
||||
'pre' => array(),
|
||||
'strong' => array(),
|
||||
'i' => array(),
|
||||
'svg' => array(),
|
||||
'g' => array(),
|
||||
'path' => array( 'd' => true ),
|
||||
'br' => array(),
|
||||
'span' => array( 'class' => true ),
|
||||
'img' => array( 'src' => true ),
|
||||
'div' => array(
|
||||
'class' => true,
|
||||
'data-correct' => 1,
|
||||
'data-track-id' => 1,
|
||||
'data-a8ctraining' => 1,
|
||||
'data-username' => 1,
|
||||
'tabindex' => false,
|
||||
),
|
||||
)
|
||||
);
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render question.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @param null $content Post content.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function question_shortcode( $atts, $content = null ) {
|
||||
return isset( $atts['quiz_item'] )
|
||||
? '<div class="jetpack-quiz-question question" tabindex="-1">' . self::do_shortcode( $content ) . '</div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render correct answer.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @param null $content Post content.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function answer_shortcode( $atts, $content = null ) {
|
||||
if ( self::is_javascript_unavailable() ) {
|
||||
return self::noscript_info();
|
||||
}
|
||||
|
||||
return isset( $atts['quiz_item'] )
|
||||
? '<div class="jetpack-quiz-answer answer" data-correct="1">' . self::do_shortcode( $content ) . '</div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render wrong response.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @param null $content Post content.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function wrong_shortcode( $atts, $content = null ) {
|
||||
if ( self::is_javascript_unavailable() ) {
|
||||
return self::noscript_info();
|
||||
}
|
||||
|
||||
return isset( $atts['quiz_item'] )
|
||||
? '<div class="jetpack-quiz-answer answer">' . self::do_shortcode( $content ) . '</div>'
|
||||
: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Render explanation for wrong or right answer.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @param null $content Post content.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function explanation_shortcode( $atts, $content = null ) {
|
||||
if ( self::is_javascript_unavailable() ) {
|
||||
return self::noscript_info();
|
||||
}
|
||||
|
||||
return isset( $atts['quiz_item'] )
|
||||
? '<div class="jetpack-quiz-explanation explanation">' . self::do_shortcode( $content ) . '</div>'
|
||||
: '';
|
||||
}
|
||||
}
|
||||
|
||||
Quiz_Shortcode::init();
|
||||
@@ -0,0 +1,695 @@
|
||||
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
|
||||
use Automattic\Jetpack\Assets;
|
||||
|
||||
/**
|
||||
* Embed recipe 'cards' in post, with basic styling and print functionality
|
||||
*
|
||||
* To Do
|
||||
* - defaults settings
|
||||
* - basic styles/themecolor styles
|
||||
* - validation/sanitization
|
||||
* - print styles
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Register and display Recipes in posts.
|
||||
*/
|
||||
class Jetpack_Recipes {
|
||||
|
||||
/**
|
||||
* Have scripts and styles been enqueued already.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $scripts_and_style_included = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'action_init' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns KSES tags with Schema-specific attributes.
|
||||
*
|
||||
* @since 8.0.0
|
||||
*
|
||||
* @return array Array to be used by KSES.
|
||||
*/
|
||||
private static function kses_tags() {
|
||||
$allowedtags = wp_kses_allowed_html( 'post' );
|
||||
// Create an array of all the tags we'd like to add the itemprop attribute to.
|
||||
$tags = array( 'li', 'ol', 'ul', 'img', 'p', 'h3', 'time', 'span' );
|
||||
foreach ( $tags as $tag ) {
|
||||
if ( ! isset( $allowedtags[ $tag ] ) ) {
|
||||
$allowedtags[ $tag ] = array();
|
||||
}
|
||||
$allowedtags[ $tag ]['class'] = array();
|
||||
$allowedtags[ $tag ]['itemprop'] = array();
|
||||
$allowedtags[ $tag ]['datetime'] = array();
|
||||
}
|
||||
|
||||
// Allow the handler <a on=""> in AMP.
|
||||
$allowedtags['a']['on'] = array();
|
||||
|
||||
// Allow itemscope and itemtype for divs.
|
||||
if ( ! isset( $allowedtags['div'] ) ) {
|
||||
$allowedtags['div'] = array();
|
||||
}
|
||||
$allowedtags['div']['class'] = array();
|
||||
$allowedtags['div']['itemscope'] = array();
|
||||
$allowedtags['div']['itemtype'] = array();
|
||||
return $allowedtags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register our shortcode and enqueue necessary files.
|
||||
*/
|
||||
public function action_init() {
|
||||
// Enqueue styles if [recipe] exists.
|
||||
add_action( 'wp_head', array( $this, 'add_scripts' ), 1 );
|
||||
|
||||
// Render [recipe], along with other shortcodes that can be nested within.
|
||||
add_shortcode( 'recipe', array( $this, 'recipe_shortcode' ) );
|
||||
add_shortcode( 'recipe-notes', array( $this, 'recipe_notes_shortcode' ) );
|
||||
add_shortcode( 'recipe-ingredients', array( $this, 'recipe_ingredients_shortcode' ) );
|
||||
add_shortcode( 'recipe-directions', array( $this, 'recipe_directions_shortcode' ) );
|
||||
add_shortcode( 'recipe-nutrition', array( $this, 'recipe_nutrition_shortcode' ) );
|
||||
add_shortcode( 'recipe-image', array( $this, 'recipe_image_shortcode' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue scripts and styles
|
||||
*/
|
||||
public function add_scripts() {
|
||||
if ( empty( $GLOBALS['posts'] ) || ! is_array( $GLOBALS['posts'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $GLOBALS['posts'] as $p ) {
|
||||
if ( isset( $p->post_content ) && has_shortcode( $p->post_content, 'recipe' ) ) {
|
||||
$this->scripts_and_style_included = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $this->scripts_and_style_included ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_style( 'jetpack-recipes-style', plugins_url( '/css/recipes.css', __FILE__ ), array(), '20130919' );
|
||||
wp_style_add_data( 'jetpack-recipes-style', 'rtl', 'replace' );
|
||||
|
||||
// add $themecolors-defined styles.
|
||||
wp_add_inline_style( 'jetpack-recipes-style', self::themecolor_styles() );
|
||||
|
||||
if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_script(
|
||||
'jetpack-recipes-printthis',
|
||||
Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/recipes-printthis.min.js', 'modules/shortcodes/js/recipes-printthis.js' ),
|
||||
array( 'jquery' ),
|
||||
'20170202',
|
||||
false
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'jetpack-recipes-js',
|
||||
Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/recipes.min.js', 'modules/shortcodes/js/recipes.js' ),
|
||||
array( 'jquery', 'jetpack-recipes-printthis' ),
|
||||
'20131230',
|
||||
false
|
||||
);
|
||||
|
||||
$title_var = wp_title( '|', false, 'right' );
|
||||
$rtl = is_rtl() ? '-rtl' : '';
|
||||
$print_css_var = plugins_url( "/css/recipes-print{$rtl}.css", __FILE__ );
|
||||
|
||||
wp_localize_script(
|
||||
'jetpack-recipes-js',
|
||||
'jetpack_recipes_vars',
|
||||
array(
|
||||
'pageTitle' => $title_var,
|
||||
'loadCSS' => $print_css_var,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Our [recipe] shortcode.
|
||||
* Prints recipe data styled to look good on *any* theme.
|
||||
*
|
||||
* @param array $atts Array of shortcode attributes.
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return string HTML for recipe shortcode.
|
||||
*/
|
||||
public static function recipe_shortcode( $atts, $content = '' ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'title' => '', // string.
|
||||
'servings' => '', // intval.
|
||||
'time' => '', // strtotime-compatible time description.
|
||||
'difficulty' => '', // string.
|
||||
'print' => '', // URL for external print version.
|
||||
'source' => '', // string.
|
||||
'sourceurl' => '', // URL string. Only used if source set.
|
||||
'image' => '', // URL or attachment ID.
|
||||
'description' => '', // string.
|
||||
'cooktime' => '', // strtotime-compatible time description.
|
||||
'preptime' => '', // strtotime-compatible time description.
|
||||
'rating' => '', // string.
|
||||
),
|
||||
$atts,
|
||||
'recipe'
|
||||
);
|
||||
|
||||
return self::recipe_shortcode_html( $atts, $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* The recipe output
|
||||
*
|
||||
* @param array $atts Array of shortcode attributes.
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return string HTML output
|
||||
*/
|
||||
private static function recipe_shortcode_html( $atts, $content = '' ) {
|
||||
|
||||
$html = '<div class="hrecipe h-recipe jetpack-recipe" itemscope itemtype="https://schema.org/Recipe">';
|
||||
|
||||
// Print the recipe title if exists.
|
||||
if ( '' !== $atts['title'] ) {
|
||||
$html .= '<h3 class="p-name jetpack-recipe-title fn" itemprop="name">' . esc_html( $atts['title'] ) . '</h3>';
|
||||
}
|
||||
|
||||
// Print the recipe meta if exists.
|
||||
if (
|
||||
'' !== $atts['servings']
|
||||
|| '' !== $atts['time']
|
||||
|| '' !== $atts['difficulty']
|
||||
|| '' !== $atts['print']
|
||||
|| '' !== $atts['preptime']
|
||||
|| '' !== $atts['cooktime']
|
||||
|| '' !== $atts['rating']
|
||||
) {
|
||||
$html .= '<ul class="jetpack-recipe-meta">';
|
||||
|
||||
if ( '' !== $atts['servings'] ) {
|
||||
$html .= sprintf(
|
||||
'<li class="jetpack-recipe-servings p-yield yield" itemprop="recipeYield"><strong>%1$s: </strong>%2$s</li>',
|
||||
esc_html_x( 'Servings', 'recipe', 'jetpack' ),
|
||||
esc_html( $atts['servings'] )
|
||||
);
|
||||
}
|
||||
|
||||
$time_types = array( 'preptime', 'cooktime', 'time' );
|
||||
foreach ( $time_types as $time_type ) {
|
||||
if ( '' === $atts[ $time_type ] ) {
|
||||
continue;
|
||||
}
|
||||
$html .= self::output_time( $atts[ $time_type ], $time_type );
|
||||
}
|
||||
|
||||
if ( '' !== $atts['difficulty'] ) {
|
||||
$html .= sprintf(
|
||||
'<li class="jetpack-recipe-difficulty"><strong>%1$s: </strong>%2$s</li>',
|
||||
esc_html_x( 'Difficulty', 'recipe', 'jetpack' ),
|
||||
esc_html( $atts['difficulty'] )
|
||||
);
|
||||
}
|
||||
|
||||
if ( '' !== $atts['rating'] ) {
|
||||
$html .= sprintf(
|
||||
'<li class="jetpack-recipe-rating">
|
||||
<strong>%1$s: </strong>
|
||||
<span itemprop="contentRating">%2$s</span>
|
||||
</li>',
|
||||
esc_html_x( 'Rating', 'recipe', 'jetpack' ),
|
||||
esc_html( $atts['rating'] )
|
||||
);
|
||||
}
|
||||
|
||||
if ( '' !== $atts['source'] ) {
|
||||
$html .= sprintf(
|
||||
'<li class="jetpack-recipe-source"><strong>%1$s: </strong>',
|
||||
esc_html_x( 'Source', 'recipe', 'jetpack' )
|
||||
);
|
||||
|
||||
if ( '' !== $atts['sourceurl'] ) :
|
||||
// Show the link if we have one.
|
||||
$html .= sprintf(
|
||||
'<a href="%2$s">%1$s</a>',
|
||||
esc_html( $atts['source'] ),
|
||||
esc_url( $atts['sourceurl'] )
|
||||
);
|
||||
else :
|
||||
// Skip the link.
|
||||
$html .= sprintf(
|
||||
'%1$s',
|
||||
esc_html( $atts['source'] )
|
||||
);
|
||||
endif;
|
||||
|
||||
$html .= '</li>';
|
||||
}
|
||||
|
||||
if ( 'false' !== $atts['print'] ) {
|
||||
$is_amp = class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request();
|
||||
$print_action = $is_amp ? 'on="tap:AMP.print"' : '';
|
||||
$print_text = $is_amp ? esc_html__( 'Print page', 'jetpack' ) : esc_html_x( 'Print', 'recipe', 'jetpack' );
|
||||
$html .= sprintf(
|
||||
'<li class="jetpack-recipe-print"><a href="#" %1$s>%2$s</a></li>',
|
||||
$print_action,
|
||||
$print_text
|
||||
);
|
||||
}
|
||||
|
||||
$html .= '</ul>';
|
||||
}
|
||||
|
||||
// Output the image if we have one and it's not shown elsewhere.
|
||||
if ( '' !== $atts['image'] ) {
|
||||
if ( ! has_shortcode( $content, 'recipe-image' ) ) {
|
||||
$html .= self::output_image_html( $atts['image'] );
|
||||
}
|
||||
}
|
||||
|
||||
// Output the description, if we have one.
|
||||
if ( '' !== $atts['description'] ) {
|
||||
$html .= sprintf(
|
||||
'<p class="jetpack-recipe-description" itemprop="description">%1$s</p>',
|
||||
esc_html( $atts['description'] )
|
||||
);
|
||||
}
|
||||
|
||||
// Print content between codes.
|
||||
$html .= '<div class="jetpack-recipe-content">' . do_shortcode( $content ) . '</div>';
|
||||
|
||||
// Close it up.
|
||||
$html .= '</div>';
|
||||
|
||||
// If there is a recipe within a recipe, remove the shortcode.
|
||||
if ( has_shortcode( $html, 'recipe' ) ) {
|
||||
remove_shortcode( 'recipe' );
|
||||
}
|
||||
|
||||
// Sanitize html.
|
||||
$html = wp_kses( $html, self::kses_tags() );
|
||||
|
||||
// Return the HTML block.
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Our [recipe-image] shortcode.
|
||||
* Controls placement of image in recipe.
|
||||
*
|
||||
* @param array $atts Array of shortcode attributes.
|
||||
*
|
||||
* @return string HTML for recipe notes shortcode.
|
||||
*/
|
||||
public static function recipe_image_shortcode( $atts ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'image' => '', // string.
|
||||
0 => '', // string.
|
||||
),
|
||||
$atts,
|
||||
'recipe-image'
|
||||
);
|
||||
$src = $atts['image'];
|
||||
if ( ! empty( $atts[0] ) ) {
|
||||
$src = $atts[0];
|
||||
}
|
||||
return self::output_image_html( $src );
|
||||
}
|
||||
|
||||
/**
|
||||
* Our [recipe-notes] shortcode.
|
||||
* Outputs ingredients, styled in a div.
|
||||
*
|
||||
* @param array $atts Array of shortcode attributes.
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return string HTML for recipe notes shortcode.
|
||||
*/
|
||||
public static function recipe_notes_shortcode( $atts, $content = '' ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'title' => '', // string.
|
||||
),
|
||||
$atts,
|
||||
'recipe-notes'
|
||||
);
|
||||
|
||||
$html = '';
|
||||
|
||||
// Print a title if one exists.
|
||||
if ( '' !== $atts['title'] ) {
|
||||
$html .= '<h4 class="jetpack-recipe-notes-title">' . esc_html( $atts['title'] ) . '</h4>';
|
||||
}
|
||||
|
||||
$html .= '<div class="jetpack-recipe-notes">';
|
||||
|
||||
// Format content using list functionality, if desired.
|
||||
$html .= self::output_list_content( $content, 'notes' );
|
||||
|
||||
$html .= '</div>';
|
||||
|
||||
// Sanitize html.
|
||||
$html = wp_kses( $html, self::kses_tags() );
|
||||
|
||||
// Return the HTML block.
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Our [recipe-ingredients] shortcode.
|
||||
* Outputs notes, styled in a div.
|
||||
*
|
||||
* @param array $atts Array of shortcode attributes.
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return string HTML for recipe ingredients shortcode.
|
||||
*/
|
||||
public static function recipe_ingredients_shortcode( $atts, $content = '' ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'title' => esc_html_x( 'Ingredients', 'recipe', 'jetpack' ), // string.
|
||||
),
|
||||
$atts,
|
||||
'recipe-ingredients'
|
||||
);
|
||||
|
||||
$html = '<div class="jetpack-recipe-ingredients">';
|
||||
|
||||
// Print a title unless the user has opted to exclude it.
|
||||
if ( 'false' !== $atts['title'] ) {
|
||||
$html .= '<h4 class="jetpack-recipe-ingredients-title">' . esc_html( $atts['title'] ) . '</h4>';
|
||||
}
|
||||
|
||||
// Format content using list functionality.
|
||||
$html .= self::output_list_content( $content, 'ingredients' );
|
||||
|
||||
$html .= '</div>';
|
||||
|
||||
// Sanitize html.
|
||||
$html = wp_kses( $html, self::kses_tags() );
|
||||
|
||||
// Return the HTML block.
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Our [recipe-nutrition] shortcode.
|
||||
* Outputs notes, styled in a div.
|
||||
*
|
||||
* @param array $atts Array of shortcode attributes.
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return string HTML for recipe nutrition shortcode.
|
||||
*/
|
||||
public static function recipe_nutrition_shortcode( $atts, $content = '' ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'title' => esc_html_x( 'Nutrition', 'recipe', 'jetpack' ), // string.
|
||||
),
|
||||
$atts,
|
||||
'recipe-nutrition'
|
||||
);
|
||||
|
||||
$html = '<div class="jetpack-recipe-nutrition p-nutrition nutrition">';
|
||||
|
||||
// Print a title unless the user has opted to exclude it.
|
||||
if ( 'false' !== $atts['title'] ) {
|
||||
$html .= '<h4 class="jetpack-recipe-nutrition-title">' . esc_html( $atts['title'] ) . '</h4>';
|
||||
}
|
||||
|
||||
// Format content using list functionality.
|
||||
$html .= self::output_list_content( $content, 'nutrition' );
|
||||
|
||||
$html .= '</div>';
|
||||
|
||||
// Sanitize html.
|
||||
$html = wp_kses( $html, self::kses_tags() );
|
||||
|
||||
// Return the HTML block.
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reusable function to check for shortened formatting.
|
||||
* Basically, users can create lists with the following shorthand:
|
||||
* - item one
|
||||
* - item two
|
||||
* - item three
|
||||
* And we'll magically convert it to a list. This has the added benefit
|
||||
* of including itemprops for the recipe schema.
|
||||
*
|
||||
* @param string $content HTML content.
|
||||
* @param string $type Type of list.
|
||||
*
|
||||
* @return string content formatted as a list item
|
||||
*/
|
||||
private static function output_list_content( $content, $type ) {
|
||||
$html = '';
|
||||
|
||||
switch ( $type ) {
|
||||
case 'directions':
|
||||
$list_item_replacement = '<li class="jetpack-recipe-directions">${1}</li>';
|
||||
$itemprop = ' itemprop="recipeInstructions"';
|
||||
$listtype = 'ol';
|
||||
break;
|
||||
case 'ingredients':
|
||||
$list_item_replacement = '<li class="jetpack-recipe-ingredient p-ingredient ingredient" itemprop="recipeIngredient">${1}</li>';
|
||||
$itemprop = '';
|
||||
$listtype = 'ul';
|
||||
break;
|
||||
case 'nutrition':
|
||||
$list_item_replacement = '<li class="jetpack-recipe-nutrition">${1}</li>';
|
||||
$itemprop = ' itemprop="nutrition"';
|
||||
$listtype = 'ul';
|
||||
break;
|
||||
case 'nutrition':
|
||||
$list_item_replacement = '<li class="jetpack-recipe-nutrition nutrition">${1}</li>';
|
||||
$itemprop = ' itemprop="nutrition"';
|
||||
$listtype = 'ul';
|
||||
break;
|
||||
default:
|
||||
$list_item_replacement = '<li class="jetpack-recipe-notes">${1}</li>';
|
||||
$itemprop = '';
|
||||
$listtype = 'ul';
|
||||
}
|
||||
|
||||
// Check to see if the user is trying to use shortened formatting.
|
||||
if (
|
||||
str_contains( $content, '–' ) ||
|
||||
str_contains( $content, '—' ) ||
|
||||
str_contains( $content, '-' ) ||
|
||||
str_contains( $content, '*' ) ||
|
||||
str_contains( $content, '#' ) ||
|
||||
str_contains( $content, '–' ) || // ndash.
|
||||
str_contains( $content, '—' ) || // mdash.
|
||||
preg_match( '/\d+\.\s/', $content )
|
||||
) {
|
||||
// Remove breaks and extra whitespace.
|
||||
$content = str_replace( "<br />\n", "\n", $content );
|
||||
$content = trim( $content );
|
||||
|
||||
$ul_pattern = '/(?:^|\n|\<p\>)+(?:[\-–—]+|\–|\—|\*)+\h+(.*)/mi';
|
||||
$ol_pattern = '/(?:^|\n|\<p\>)+(?:\d+\.|#+)+\h+(.*)/mi';
|
||||
|
||||
preg_match_all( $ul_pattern, $content, $ul_matches );
|
||||
preg_match_all( $ol_pattern, $content, $ol_matches );
|
||||
|
||||
if ( ( is_countable( $ul_matches[0] ) && count( $ul_matches[0] ) > 0 ) || ( is_countable( $ol_matches[0] ) && count( $ol_matches[0] ) > 0 ) ) {
|
||||
|
||||
if ( is_countable( $ol_matches[0] ) && count( $ol_matches[0] ) > 0 ) {
|
||||
$listtype = 'ol';
|
||||
$list_item_pattern = $ol_pattern;
|
||||
} else {
|
||||
$listtype = 'ul';
|
||||
$list_item_pattern = $ul_pattern;
|
||||
}
|
||||
$html .= '<' . $listtype . $itemprop . '>';
|
||||
$html .= preg_replace( $list_item_pattern, $list_item_replacement, $content );
|
||||
$html .= '</' . $listtype . '>';
|
||||
|
||||
// Strip out any empty <p> tags and stray </p> tags, because those are just silly.
|
||||
$empty_p_pattern = '/(<p>)*\s*<\/p>/mi';
|
||||
$html = preg_replace( $empty_p_pattern, '', $html );
|
||||
} else {
|
||||
$html .= do_shortcode( $content );
|
||||
}
|
||||
} else {
|
||||
$html .= do_shortcode( $content );
|
||||
}
|
||||
|
||||
// Return our formatted content.
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Our [recipe-directions] shortcode.
|
||||
* Outputs directions, styled in a div.
|
||||
*
|
||||
* @param array $atts Array of shortcode attributes.
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return string HTML for recipe directions shortcode.
|
||||
*/
|
||||
public static function recipe_directions_shortcode( $atts, $content = '' ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'title' => esc_html_x( 'Directions', 'recipe', 'jetpack' ), // string.
|
||||
),
|
||||
$atts,
|
||||
'recipe-directions'
|
||||
);
|
||||
|
||||
$html = '<div class="jetpack-recipe-directions e-instructions">';
|
||||
|
||||
// Print a title unless the user has specified to exclude it.
|
||||
if ( 'false' !== $atts['title'] ) {
|
||||
$html .= '<h4 class="jetpack-recipe-directions-title">' . esc_html( $atts['title'] ) . '</h4>';
|
||||
}
|
||||
|
||||
// Format content using list functionality.
|
||||
$html .= self::output_list_content( $content, 'directions' );
|
||||
|
||||
$html .= '</div>';
|
||||
|
||||
// Sanitize html.
|
||||
$html = wp_kses( $html, self::kses_tags() );
|
||||
|
||||
// Return the HTML block.
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs time meta tag.
|
||||
*
|
||||
* @param string $time_str Raw time to output.
|
||||
* @param string $time_type Type of time to show.
|
||||
*
|
||||
* @return string HTML for recipe time meta.
|
||||
*/
|
||||
private static function output_time( $time_str, $time_type ) {
|
||||
// Get a time that's supported by Schema.org.
|
||||
$duration = WPCOM_JSON_API_Date::format_duration( $time_str );
|
||||
// If no duration can be calculated, let's output what the user provided.
|
||||
if ( ! $duration ) {
|
||||
$duration = $time_str;
|
||||
}
|
||||
|
||||
switch ( $time_type ) {
|
||||
case 'cooktime':
|
||||
$title = _x( 'Cook Time', 'recipe', 'jetpack' );
|
||||
$itemprop = 'cookTime';
|
||||
break;
|
||||
case 'preptime':
|
||||
$title = _x( 'Prep Time', 'recipe', 'jetpack' );
|
||||
$itemprop = 'prepTime';
|
||||
break;
|
||||
default:
|
||||
$title = _x( 'Time', 'recipe', 'jetpack' );
|
||||
$itemprop = 'totalTime';
|
||||
break;
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<li class="jetpack-recipe-%3$s">
|
||||
<time itemprop="%4$s" datetime="%5$s"><strong>%1$s:</strong> <span class="%3$s">%2$s</span></time>
|
||||
</li>',
|
||||
esc_html( $title ),
|
||||
esc_html( $time_str ),
|
||||
esc_attr( $time_type ),
|
||||
esc_attr( $itemprop ),
|
||||
esc_attr( $duration )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs image tag for recipe.
|
||||
*
|
||||
* @param string $src The image source.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function output_image_html( $src ) {
|
||||
// Exit if there is no provided source.
|
||||
if ( ! $src ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$image_attrs = array(
|
||||
'class' => 'jetpack-recipe-image u-photo photo',
|
||||
'itemprop' => 'image',
|
||||
);
|
||||
|
||||
if ( wp_lazy_loading_enabled( 'img', 'wp_get_attachment_image' ) ) {
|
||||
$image_attrs['loading'] = 'lazy';
|
||||
}
|
||||
|
||||
// If it's numeric, this may be an attachment.
|
||||
if ( is_numeric( $src ) ) {
|
||||
return wp_get_attachment_image(
|
||||
$src,
|
||||
'full',
|
||||
false,
|
||||
$image_attrs
|
||||
);
|
||||
}
|
||||
|
||||
// Check if it's an absolute or relative URL, and return if not.
|
||||
if (
|
||||
! str_starts_with( $src, '/' )
|
||||
&& false === filter_var( $src, FILTER_VALIDATE_URL )
|
||||
) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$image_attrs_markup = '';
|
||||
foreach ( $image_attrs as $name => $value ) {
|
||||
$image_attrs_markup .= sprintf(
|
||||
' %1$s="%2$s"',
|
||||
esc_attr( $name ),
|
||||
esc_attr( $value )
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<img%1$s src="%2$s" />',
|
||||
$image_attrs_markup,
|
||||
esc_url( $src )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use $themecolors array to style the Recipes shortcode
|
||||
*
|
||||
* @print style block
|
||||
* @return string $style
|
||||
*/
|
||||
public function themecolor_styles() {
|
||||
global $themecolors;
|
||||
$style = '';
|
||||
|
||||
if ( isset( $themecolors ) ) {
|
||||
$style .= '.jetpack-recipe { border-color: #' . esc_attr( $themecolors['border'] ) . '; }';
|
||||
$style .= '.jetpack-recipe-title { border-bottom-color: #' . esc_attr( $themecolors['link'] ) . '; }';
|
||||
}
|
||||
|
||||
return $style;
|
||||
}
|
||||
}
|
||||
|
||||
new Jetpack_Recipes();
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* Scribd Shortcode
|
||||
*
|
||||
* [scribd id=DOCUMENT_ID key=DOCUMENT_KEY mode=MODE]
|
||||
* DOCUMENT_ID is an integer (also used as an object_id)
|
||||
* DOCUMENT_KEY is an alphanumeric hash ('-' character as well)
|
||||
* MODE can be 'list', 'book', 'slide', 'slideshow', or 'tile'
|
||||
*
|
||||
* [scribd id=39027960 key=key-3kaiwcjqhtipf25m8tw mode=list]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Register Scribd shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function scribd_shortcode_handler( $atts ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
'key' => 0,
|
||||
'mode' => '',
|
||||
),
|
||||
$atts,
|
||||
'scribd'
|
||||
);
|
||||
|
||||
$modes = array( 'list', 'book', 'slide', 'slideshow', 'tile' );
|
||||
|
||||
$atts['id'] = (int) $atts['id'];
|
||||
if ( preg_match( '/^[A-Za-z0-9-]+$/', $atts['key'], $m ) ) {
|
||||
$atts['key'] = $m[0];
|
||||
|
||||
if ( ! in_array( $atts['mode'], $modes, true ) ) {
|
||||
$atts['mode'] = '';
|
||||
}
|
||||
|
||||
return scribd_shortcode_markup( $atts );
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string The rendered shortcode.
|
||||
*/
|
||||
function scribd_shortcode_markup( $atts ) {
|
||||
$sandbox = class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request()
|
||||
? 'sandbox="allow-popups allow-scripts allow-same-origin"'
|
||||
: '';
|
||||
|
||||
$url = add_query_arg(
|
||||
array(
|
||||
'start_page' => '1',
|
||||
'view_mode' => esc_attr( $atts['mode'] ),
|
||||
'access_key' => esc_attr( $atts['key'] ),
|
||||
),
|
||||
esc_url(
|
||||
sprintf(
|
||||
'https://www.scribd.com/embeds/%1$d/content',
|
||||
absint( $atts['id'] )
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return sprintf(
|
||||
'<iframe class="scribd_iframe_embed" src="%1$s" %2$s data-auto-height="true" scrolling="no" id="scribd_%3$d" width="100%%" height="500" frameborder="0"></iframe>
|
||||
<div style="font-size:10px;text-align:center;width:100%%"><a href="https://www.scribd.com/doc/%3$d" rel="noopener noreferrer" target="_blank">%4$s</a></div>',
|
||||
$url,
|
||||
$sandbox,
|
||||
absint( $atts['id'] ),
|
||||
esc_html__( 'View this document on Scribd', 'jetpack' )
|
||||
);
|
||||
}
|
||||
add_shortcode( 'scribd', 'scribd_shortcode_handler' );
|
||||
|
||||
/**
|
||||
* Scribd supports HTTPS, so use that endpoint to get HTTPS-compatible embeds.
|
||||
*
|
||||
* @param array $providers Array of oEmbed providers.
|
||||
*/
|
||||
function scribd_https_oembed( $providers ) {
|
||||
if ( isset( $providers['#https?://(www\.)?scribd\.com/doc/.*#i'] ) ) {
|
||||
$providers['#https?://(www\.)?scribd\.com/doc/.*#i'][0] = 'https://www.scribd.com/services/oembed';
|
||||
}
|
||||
|
||||
return $providers;
|
||||
}
|
||||
add_filter( 'oembed_providers', 'scribd_https_oembed' );
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* Sitemap shortcode.
|
||||
*
|
||||
* Usage: [sitemap]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
add_shortcode( 'sitemap', 'jetpack_sitemap_shortcode' );
|
||||
|
||||
/**
|
||||
* Renders a tree of pages.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function jetpack_sitemap_shortcode() {
|
||||
$tree = wp_list_pages(
|
||||
array(
|
||||
'title_li' => '<b><a href="/">' . esc_html( get_bloginfo( 'name' ) ) . '</a></b>',
|
||||
'exclude' => get_option( 'page_on_front' ),
|
||||
'echo' => false,
|
||||
)
|
||||
);
|
||||
return empty( $tree )
|
||||
? ''
|
||||
: '<ul class="jetpack-sitemap-shortcode">' . $tree . '</ul>';
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* Slideshare shortcode
|
||||
*
|
||||
* Formats:
|
||||
* Old style (still compatible): [slideshare id=5342235&doc=camprock-101002163655-phpapp01&w=300&h=200]
|
||||
* New style: [slideshare id=5342235&w=300&h=200&fb=0&mw=0&mh=0&sc=no]
|
||||
*
|
||||
* Legend:
|
||||
* id = Document ID provided by Slideshare
|
||||
* w = Width of iFrame (int)
|
||||
* h = Height of iFrame (int)
|
||||
* fb = iFrame frameborder (int)
|
||||
* mw = iFrame marginwidth (int)
|
||||
* mh = iFrame marginheight (int)
|
||||
* sc = iFrame Scrollbar (yes/no)
|
||||
* pro = Slideshare Pro (yes/no)
|
||||
* style = Inline CSS (string)
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Register and display shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function slideshare_shortcode( $atts ) {
|
||||
global $content_width;
|
||||
|
||||
$params = shortcode_new_to_old_params( $atts );
|
||||
parse_str( $params, $arguments );
|
||||
|
||||
if ( empty( $arguments ) ) {
|
||||
return '<!-- SlideShare error: no arguments -->';
|
||||
}
|
||||
|
||||
$attr = shortcode_atts(
|
||||
array(
|
||||
'id' => '',
|
||||
'w' => '',
|
||||
'h' => '',
|
||||
'fb' => '',
|
||||
'mw' => '',
|
||||
'mh' => '',
|
||||
'sc' => '',
|
||||
'pro' => '',
|
||||
'style' => '',
|
||||
),
|
||||
$arguments
|
||||
);
|
||||
|
||||
// check that the Slideshare ID contains letters, numbers and query strings.
|
||||
$pattern = '/[^-_a-zA-Z0-9?=&]/';
|
||||
if ( empty( $attr['id'] ) || preg_match( $pattern, $attr['id'] ) ) {
|
||||
return '<!-- SlideShare error: id is missing or has illegal characters -->';
|
||||
}
|
||||
|
||||
// check the width/height.
|
||||
$w = (int) $attr['w'];
|
||||
|
||||
// If no width was specified (or uses the wrong format), and if we have a $content_width, use that.
|
||||
if ( empty( $w ) && ! empty( $content_width ) ) {
|
||||
$w = (int) $content_width;
|
||||
} elseif ( $w < 300 || $w > 1600 ) { // If width was specified, but is too small/large, set default value.
|
||||
$w = 425;
|
||||
} else {
|
||||
$w = (int) $w;
|
||||
}
|
||||
|
||||
$h = ceil( $w * 348 / 425 ); // Note: user-supplied height is ignored.
|
||||
|
||||
if ( ! empty( $attr['pro'] ) ) {
|
||||
$source = 'https://www.slideshare.net/slidesharepro/' . $attr['id'];
|
||||
} else {
|
||||
$source = 'https://www.slideshare.net/slideshow/embed_code/' . $attr['id'];
|
||||
}
|
||||
|
||||
if ( isset( $attr['rel'] ) ) {
|
||||
$source = add_query_arg( 'rel', (int) $attr['rel'], $source );
|
||||
}
|
||||
|
||||
if ( ! empty( $attr['startSlide'] ) ) {
|
||||
$source = add_query_arg( 'startSlide', (int) $attr['startSlide'], $source );
|
||||
}
|
||||
|
||||
$player = sprintf( "<iframe src='%s' width='%d' height='%d'", esc_url( $source ), $w, $h );
|
||||
|
||||
// check the frameborder.
|
||||
if ( ! empty( $attr['fb'] ) || '0' === $attr['fb'] ) {
|
||||
$player .= " frameborder='" . (int) $attr['fb'] . "'";
|
||||
}
|
||||
|
||||
$is_amp = ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() );
|
||||
|
||||
if ( ! $is_amp ) {
|
||||
// check the margin width; if not empty, cast as int.
|
||||
if ( ( ! empty( $attr['mw'] ) || '0' === $attr['mw'] ) ) {
|
||||
$player .= " marginwidth='" . (int) $attr['mw'] . "'";
|
||||
}
|
||||
|
||||
// check the margin height, if not empty, cast as int.
|
||||
if ( ( ! empty( $attr['mh'] ) || '0' === $attr['mh'] ) ) {
|
||||
$player .= " marginheight='" . (int) $attr['mh'] . "'";
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $attr['style'] ) ) {
|
||||
$player .= " style='" . esc_attr( $attr['style'] ) . "'";
|
||||
}
|
||||
|
||||
// check the scrollbar; cast as a lowercase string for comparison.
|
||||
if ( ! empty( $attr['sc'] ) ) {
|
||||
$sc = strtolower( $attr['sc'] );
|
||||
|
||||
if ( in_array( $sc, array( 'yes', 'no' ), true ) ) {
|
||||
$player .= " scrolling='" . $sc . "'";
|
||||
}
|
||||
}
|
||||
|
||||
$player .= ' sandbox="allow-popups allow-scripts allow-same-origin allow-presentation" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe>';
|
||||
|
||||
/**
|
||||
* Filter the returned SlideShare shortcode.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param string $player The iframe to return.
|
||||
* @param array $atts The attributes specified in the shortcode.
|
||||
*/
|
||||
return apply_filters( 'jetpack_slideshare_shortcode', $player, $atts );
|
||||
}
|
||||
add_shortcode( 'slideshare', 'slideshare_shortcode' );
|
||||
@@ -0,0 +1,317 @@
|
||||
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
|
||||
use Automattic\Jetpack\Assets;
|
||||
use Automattic\Jetpack\Extensions\Slideshow;
|
||||
|
||||
/**
|
||||
* Slideshow shortcode.
|
||||
* Adds a new "slideshow" gallery type when adding a gallery using the classic editor.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Slideshow shortcode usage: [gallery type="slideshow"] or the older [slideshow]
|
||||
*/
|
||||
class Jetpack_Slideshow_Shortcode {
|
||||
/**
|
||||
* Number of slideshows on a page.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $instance_count = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
global $shortcode_tags;
|
||||
|
||||
// Only if the slideshow shortcode has not already been defined.
|
||||
if ( ! array_key_exists( 'slideshow', $shortcode_tags ) ) {
|
||||
add_shortcode( 'slideshow', array( $this, 'shortcode_callback' ) );
|
||||
}
|
||||
|
||||
// Only if the gallery shortcode has not been redefined.
|
||||
if ( isset( $shortcode_tags['gallery'] ) && 'gallery_shortcode' === $shortcode_tags['gallery'] ) {
|
||||
add_filter( 'post_gallery', array( $this, 'post_gallery' ), 1002, 2 );
|
||||
add_filter( 'jetpack_gallery_types', array( $this, 'add_gallery_type' ), 10 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to the [gallery] shortcode, but not an actual shortcode callback.
|
||||
*
|
||||
* @param string $value An empty string if nothing has modified the gallery output, the output html otherwise.
|
||||
* @param array $attr The shortcode attributes array.
|
||||
*
|
||||
* @return string The (un)modified $value
|
||||
*/
|
||||
public function post_gallery( $value, $attr ) {
|
||||
// Bail if somebody else has done something.
|
||||
if ( ! empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// If [gallery type="slideshow"] have it behave just like [slideshow].
|
||||
if ( ! empty( $attr['type'] ) && 'slideshow' === $attr['type'] ) {
|
||||
return $this->shortcode_callback( $attr );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the Slideshow type to gallery settings
|
||||
*
|
||||
* @see Jetpack_Tiled_Gallery::media_ui_print_templates
|
||||
*
|
||||
* @param array $types An array of types where the key is the value, and the value is the caption.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_gallery_type( $types = array() ) {
|
||||
$types['slideshow'] = esc_html__( 'Slideshow', 'jetpack' );
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display shortcode.
|
||||
*
|
||||
* @param array $attr Shortcode attributes.
|
||||
*/
|
||||
public function shortcode_callback( $attr ) {
|
||||
$post_id = get_the_ID();
|
||||
|
||||
$attr = shortcode_atts(
|
||||
array(
|
||||
'trans' => 'fade',
|
||||
'order' => 'ASC',
|
||||
'orderby' => 'menu_order ID',
|
||||
'id' => $post_id,
|
||||
'include' => '',
|
||||
'exclude' => '',
|
||||
'autostart' => true,
|
||||
'size' => '',
|
||||
),
|
||||
$attr,
|
||||
'slideshow'
|
||||
);
|
||||
|
||||
if ( 'rand' === strtolower( $attr['order'] ) ) {
|
||||
$attr['orderby'] = 'none';
|
||||
}
|
||||
|
||||
$attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
|
||||
if ( ! $attr['orderby'] ) {
|
||||
$attr['orderby'] = 'menu_order ID';
|
||||
}
|
||||
|
||||
if ( ! $attr['size'] ) {
|
||||
$attr['size'] = 'full';
|
||||
}
|
||||
|
||||
// Don't restrict to the current post if include.
|
||||
$post_parent = ( empty( $attr['include'] ) ) ? (int) $attr['id'] : null;
|
||||
|
||||
$attachments = get_posts(
|
||||
array(
|
||||
'post_status' => 'inherit',
|
||||
'post_type' => 'attachment',
|
||||
'post_mime_type' => 'image',
|
||||
'posts_per_page' => - 1,
|
||||
'post_parent' => $post_parent,
|
||||
'order' => $attr['order'],
|
||||
'orderby' => $attr['orderby'],
|
||||
'include' => $attr['include'],
|
||||
'exclude' => $attr['exclude'],
|
||||
'suppress_filters' => false,
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! is_countable( $attachments ) || count( $attachments ) < 1 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$gallery_instance = sprintf( 'gallery-%d-%d', $attr['id'], ++$this->instance_count );
|
||||
|
||||
$gallery = array();
|
||||
foreach ( $attachments as $attachment ) {
|
||||
$attachment_image_src = wp_get_attachment_image_src( $attachment->ID, $attr['size'] );
|
||||
$attachment_image_src = false !== $attachment_image_src ? $attachment_image_src[0] : ''; // [url, width, height].
|
||||
$attachment_image_title = get_the_title( $attachment->ID );
|
||||
$attachment_image_alt = get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true );
|
||||
/**
|
||||
* Filters the Slideshow slide caption.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 2.3.0
|
||||
*
|
||||
* @param string wptexturize( strip_tags( $attachment->post_excerpt ) ) Post excerpt.
|
||||
* @param string $attachment ->ID Attachment ID.
|
||||
*/
|
||||
$caption = apply_filters( 'jetpack_slideshow_slide_caption', wptexturize( wp_strip_all_tags( $attachment->post_excerpt ) ), $attachment->ID );
|
||||
|
||||
$gallery[] = (object) array(
|
||||
'src' => (string) esc_url_raw( $attachment_image_src ),
|
||||
'id' => (string) $attachment->ID,
|
||||
'title' => (string) esc_attr( $attachment_image_title ),
|
||||
'alt' => (string) esc_attr( $attachment_image_alt ),
|
||||
'caption' => (string) $caption,
|
||||
'itemprop' => 'image',
|
||||
);
|
||||
}
|
||||
|
||||
$color = Jetpack_Options::get_option( 'slideshow_background_color', 'black' );
|
||||
$autostart = $attr['autostart'] ? $attr['autostart'] : 'true';
|
||||
$js_attr = array(
|
||||
'gallery' => $gallery,
|
||||
'selector' => $gallery_instance,
|
||||
'trans' => $attr['trans'] ? $attr['trans'] : 'fade',
|
||||
'autostart' => $autostart,
|
||||
'color' => $color,
|
||||
);
|
||||
|
||||
// Show a link to the gallery in feeds.
|
||||
if ( is_feed() ) {
|
||||
return sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
esc_url( get_permalink( $post_id ) . '#' . $gallery_instance . '-slideshow' ),
|
||||
esc_html__( 'Click to view slideshow.', 'jetpack' )
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
class_exists( 'Jetpack_AMP_Support' )
|
||||
&& Jetpack_AMP_Support::is_amp_request()
|
||||
) {
|
||||
// Load the styles and use the rendering method from the Slideshow block.
|
||||
Jetpack_Gutenberg::load_styles_as_required( 'slideshow' );
|
||||
|
||||
$amp_args = array(
|
||||
'ids' => wp_list_pluck( $gallery, 'id' ),
|
||||
);
|
||||
|
||||
if ( 'true' == $autostart ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual -- attribute can be stored as boolean or string.
|
||||
$amp_args['autoplay'] = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Blocks can be disabled in Jetpack Settings.
|
||||
* If that's the case, we need to include the slideshow block manually.
|
||||
*/
|
||||
if ( ! class_exists( 'Automattic\Jetpack\Extensions\Slideshow' ) ) {
|
||||
require_once JETPACK__PLUGIN_DIR . 'extensions/blocks/slideshow/slideshow.php';
|
||||
}
|
||||
|
||||
return Slideshow\render_amp( $amp_args );
|
||||
}
|
||||
|
||||
return $this->slideshow_js( $js_attr );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the slideshow js
|
||||
*
|
||||
* Returns the necessary markup and js to fire a slideshow.
|
||||
*
|
||||
* @param array $attr Attributes for the slideshow.
|
||||
*
|
||||
* @uses $this->enqueue_scripts()
|
||||
*
|
||||
* @return string HTML output.
|
||||
*/
|
||||
public function slideshow_js( $attr ) {
|
||||
// Enqueue scripts.
|
||||
$this->enqueue_scripts();
|
||||
|
||||
$output = '<p class="jetpack-slideshow-noscript robots-nocontent">' . esc_html__( 'This slideshow requires JavaScript.', 'jetpack' ) . '</p>';
|
||||
|
||||
/*
|
||||
* Checking for JSON_HEX_AMP and friends here allows us to get rid of
|
||||
* '"', that can sometimes be included in the JSON input in some languages like French.
|
||||
*/
|
||||
$gallery_attributes = _wp_specialchars(
|
||||
wp_check_invalid_utf8(
|
||||
wp_json_encode( $attr['gallery'], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT )
|
||||
),
|
||||
ENT_QUOTES,
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
$output .= sprintf(
|
||||
'<div id="%s" class="jetpack-slideshow-window jetpack-slideshow jetpack-slideshow-%s" data-trans="%s" data-autostart="%s" data-gallery="%s" itemscope itemtype="https://schema.org/ImageGallery"></div>',
|
||||
esc_attr( $attr['selector'] . '-slideshow' ),
|
||||
esc_attr( $attr['color'] ),
|
||||
esc_attr( $attr['trans'] ),
|
||||
esc_attr( $attr['autostart'] ),
|
||||
$gallery_attributes
|
||||
);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually enqueues the scripts and styles.
|
||||
*/
|
||||
public function enqueue_scripts() {
|
||||
|
||||
wp_enqueue_script( 'jquery-cycle', plugins_url( '/js/jquery.cycle.min.js', __FILE__ ), array( 'jquery' ), '20161231', true );
|
||||
wp_enqueue_script(
|
||||
'jetpack-slideshow',
|
||||
Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/slideshow-shortcode.min.js', 'modules/shortcodes/js/slideshow-shortcode.js' ),
|
||||
array( 'jquery', 'jquery-cycle' ),
|
||||
'20160119.1',
|
||||
true
|
||||
);
|
||||
wp_enqueue_style(
|
||||
'jetpack-slideshow',
|
||||
plugins_url( '/css/slideshow-shortcode.css', __FILE__ ),
|
||||
array(),
|
||||
JETPACK__VERSION
|
||||
);
|
||||
wp_style_add_data( 'jetpack-slideshow', 'rtl', 'replace' );
|
||||
|
||||
wp_localize_script(
|
||||
'jetpack-slideshow',
|
||||
'jetpackSlideshowSettings',
|
||||
/**
|
||||
* Filters the slideshow JavaScript spinner.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 2.1.0
|
||||
* @since 4.7.0 Added the `speed` option to the array of options.
|
||||
*
|
||||
* @param array $args
|
||||
* - string - spinner - URL of the spinner image.
|
||||
* - string - speed - Speed of the slideshow. Defaults to 4000.
|
||||
* - string - label_prev - Aria label for slideshow's previous button
|
||||
* - string - label_stop - Aria label for slideshow's pause button
|
||||
* - string - label_next - Aria label for slideshow's next button
|
||||
*/
|
||||
apply_filters(
|
||||
'jetpack_js_slideshow_settings',
|
||||
array(
|
||||
'spinner' => plugins_url( '/img/slideshow-loader.gif', __FILE__ ),
|
||||
'speed' => '4000',
|
||||
'label_prev' => __( 'Previous Slide', 'jetpack' ),
|
||||
'label_stop' => __( 'Pause Slideshow', 'jetpack' ),
|
||||
'label_next' => __( 'Next Slide', 'jetpack' ),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate shortcode.
|
||||
*/
|
||||
public static function init() {
|
||||
new Jetpack_Slideshow_Shortcode();
|
||||
}
|
||||
}
|
||||
|
||||
Jetpack_Slideshow_Shortcode::init();
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* Smartframe.io embed
|
||||
*
|
||||
* Example URL: https://mikael-korpela.smartframe.io/p/mantymetsa_1630927773870/7673dc41a775fb845cc26acf24f1fe4?t=rql1c6dbpv2
|
||||
* Example embed code: <script src="https://embed.smartframe.io/6ae67829d1264ee0ea6071a788940eae.js" data-image-id="mantymetsa_1630927773870" data-width="100%" data-max-width="1412px"></script>
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
add_action( 'init', 'jetpack_smartframe_enable_embeds' );
|
||||
} else {
|
||||
jetpack_smartframe_enable_embeds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register smartframe as oembed provider. Add filter to reverse iframes to shortcode. Register [smartframe] shortcode.
|
||||
*
|
||||
* @since 10.2.0
|
||||
*/
|
||||
function jetpack_smartframe_enable_embeds() {
|
||||
// Support their oEmbed Endpoint.
|
||||
wp_oembed_add_provider( '#https?://(.*?)\.smartframe\.(io|net)/.*#i', 'https://oembed.smartframe.io/', true );
|
||||
|
||||
// Allow script to be filtered to short code (so direct copy+paste can be done).
|
||||
add_filter( 'pre_kses', 'jetpack_shortcodereverse_smartframe' );
|
||||
|
||||
// Actually display the smartframe Embed.
|
||||
add_shortcode( 'smartframe', 'jetpack_smartframe_shortcode' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose shortcode based on smartframe iframes.
|
||||
*
|
||||
* @since 10.2.0
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function jetpack_shortcodereverse_smartframe( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'embed.smartframe' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
|
||||
$regexp = '!<script\ssrc="https://embed\.smartframe\.(?:io|net)/(\w+)\.js"\sdata-image-id="(.*?)"(?:\sdata-width="(?:\d+(?:%|px))"\s)?(?:data-max-width="(\d+(%|px)))?"></script>!i';
|
||||
$regexp_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );
|
||||
|
||||
foreach ( compact( 'regexp', 'regexp_ent' ) as $regexp ) {
|
||||
if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
// We need at least a script ID and an image ID.
|
||||
if ( ! isset( $match[1] ) || ! isset( $match[2] ) ) {
|
||||
continue;
|
||||
}
|
||||
$shortcode = sprintf(
|
||||
'[smartframe script-id="%1$s" image-id="%2$s"%3$s]',
|
||||
esc_attr( $match[1] ),
|
||||
esc_attr( $match[2] ),
|
||||
! empty( $match[3] ) ? ' max-width="' . esc_attr( $match[3] ) . '"' : ''
|
||||
);
|
||||
$content = str_replace( $match[0], $shortcode, $content );
|
||||
}
|
||||
}
|
||||
/** This action is documented in modules/widgets/social-media-icons.php */
|
||||
do_action( 'jetpack_bump_stats_extras', 'html_to_shortcode', 'smartframe' );
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse shortcode arguments and render its output.
|
||||
*
|
||||
* @since 10.2.0
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function jetpack_smartframe_shortcode( $atts ) {
|
||||
if ( ! empty( $atts['image-id'] ) ) {
|
||||
$image_id = $atts['image-id'];
|
||||
} else {
|
||||
return '<!-- Missing smartframe image-id -->';
|
||||
}
|
||||
if ( ! empty( $atts['script-id'] ) ) {
|
||||
$script_id = $atts['script-id'];
|
||||
} else {
|
||||
return '<!-- Missing smartframe script-id -->';
|
||||
}
|
||||
|
||||
$params = array(
|
||||
// ignore width for now, smartframe embed code has it "100%". % isn't allowed in oembed, making it 100px.
|
||||
// 'width' => isset( $atts['width'] ) ? (int) $atts['width'] : null,.
|
||||
'max-width' => isset( $atts['max-width'] ) ? (int) $atts['max-width'] : null,
|
||||
);
|
||||
|
||||
$embed_url = sprintf(
|
||||
'https://imagecards.smartframe.io/%1$s/%2$s',
|
||||
esc_attr( $script_id ),
|
||||
esc_attr( $image_id )
|
||||
);
|
||||
|
||||
// wrap the embed with wp-block-embed__wrapper, otherwise it would be aligned to the very left of the viewport.
|
||||
return sprintf(
|
||||
'<div class="wp-block-embed__wrapper">%1$s</div>',
|
||||
wp_oembed_get( $embed_url, array_filter( $params ) )
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
/**
|
||||
* SoundCloud Shortcode
|
||||
* Based on this plugin: https://wordpress.org/plugins/soundcloud-shortcode/
|
||||
*
|
||||
* Credits:
|
||||
* Original version: Johannes Wagener <johannes@soundcloud.com>
|
||||
* Options support: Tiffany Conroy <tiffany@soundcloud.com>
|
||||
* HTML5 & oEmbed support: Tim Bormans <tim@soundcloud.com>
|
||||
*
|
||||
* Examples:
|
||||
* [soundcloud]http://soundcloud.com/forss/flickermood[/soundcloud]
|
||||
* [soundcloud url="https://api.soundcloud.com/tracks/156661852" params="auto_play=false&hide_related=false&visual=false" width="100%" height="450" iframe="true" /]
|
||||
* [soundcloud url="https://api.soundcloud.com/tracks/156661852" params="auto_play=false&hide_related=false&visual=true" width="100%" height="450" iframe="true" /]
|
||||
* [soundcloud url="https://soundcloud.com/closetorgan/paul-is-dead" width=400 height=400]
|
||||
* [soundcloud url="https://soundcloud.com/closetorgan/sets/smells-like-lynx-africa-private"]
|
||||
* [soundcloud url="https://soundcloud.com/closetorgan/sets/smells-like-lynx-africa-private" color="00cc11"]
|
||||
* <iframe width="100%" height="450" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/150745932&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true"></iframe>
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* SoundCloud shortcode handler
|
||||
*
|
||||
* @param string|array $atts The attributes passed to the shortcode like [soundcloud attr1="value" /].
|
||||
* Is an empty string when no arguments are given.
|
||||
* @param string $content The content between non-self closing [soundcloud]...[/soundcloud] tags.
|
||||
*
|
||||
* @return string Widget embed code HTML
|
||||
*/
|
||||
function soundcloud_shortcode( $atts, $content = null ) {
|
||||
global $wp_embed;
|
||||
|
||||
// Custom shortcode options.
|
||||
$shortcode_options = array_merge(
|
||||
array( 'url' => trim( $content ) ),
|
||||
is_array( $atts ) ? $atts : array()
|
||||
);
|
||||
|
||||
// The "url" option is required.
|
||||
if ( empty( $shortcode_options['url'] ) ) {
|
||||
if ( current_user_can( 'edit_posts' ) ) {
|
||||
return esc_html__( 'Please specify a Soundcloud URL.', 'jetpack' );
|
||||
} else {
|
||||
return '<!-- Missing Soundcloud URL -->';
|
||||
}
|
||||
}
|
||||
|
||||
// If the shortcode is displayed in a WPCOM notification, display a simple link only.
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
require_once WP_CONTENT_DIR . '/lib/display-context.php';
|
||||
$context = A8C\Display_Context\get_current_context();
|
||||
if ( A8C\Display_Context\NOTIFICATIONS === $context ) {
|
||||
return sprintf(
|
||||
'<a href="%1$s" target="_blank" rel="noopener noreferrer">%1$s</a>',
|
||||
esc_url( $shortcode_options['url'] )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Turn shortcode option "param" (param=value¶m2=value) into array of params.
|
||||
$shortcode_params = array();
|
||||
if ( isset( $shortcode_options['params'] ) ) {
|
||||
parse_str( html_entity_decode( $shortcode_options['params'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ), $shortcode_params );
|
||||
$shortcode_options = array_merge(
|
||||
$shortcode_options,
|
||||
$shortcode_params
|
||||
);
|
||||
unset( $shortcode_options['params'] );
|
||||
}
|
||||
|
||||
$options = shortcode_atts(
|
||||
// This list used to include an 'iframe' option. We don't include it anymore as we don't support the Flash player anymore.
|
||||
array(
|
||||
'url' => '',
|
||||
'width' => soundcloud_get_option( 'player_width' ),
|
||||
'height' => soundcloud_url_has_tracklist( $shortcode_options['url'] ) ? soundcloud_get_option( 'player_height_multi' ) : soundcloud_get_option( 'player_height' ),
|
||||
'auto_play' => soundcloud_get_option( 'auto_play' ),
|
||||
'hide_related' => false,
|
||||
'visual' => false,
|
||||
'show_comments' => soundcloud_get_option( 'show_comments' ),
|
||||
'color' => soundcloud_get_option( 'color' ),
|
||||
'show_user' => false,
|
||||
'show_reposts' => false,
|
||||
),
|
||||
$shortcode_options,
|
||||
'soundcloud'
|
||||
);
|
||||
|
||||
// "width" needs to be an integer.
|
||||
if ( ! empty( $options['width'] ) && ! preg_match( '/^\d+$/', $options['width'] ) ) {
|
||||
// set to 0 so oEmbed will use the default 100% and WordPress themes will leave it alone.
|
||||
$options['width'] = 0;
|
||||
}
|
||||
// Set default width if not defined.
|
||||
$width = ! empty( $options['width'] ) ? absint( $options['width'] ) : '100%';
|
||||
|
||||
// Set default height if not defined.
|
||||
if (
|
||||
empty( $options['height'] )
|
||||
|| (
|
||||
// "height" needs to be an integer.
|
||||
! empty( $options['height'] )
|
||||
&& ! preg_match( '/^\d+$/', $options['height'] )
|
||||
)
|
||||
) {
|
||||
if (
|
||||
soundcloud_url_has_tracklist( $options['url'] )
|
||||
|| 'true' === $options['visual']
|
||||
) {
|
||||
$height = 450;
|
||||
} else {
|
||||
$height = 166;
|
||||
}
|
||||
} else {
|
||||
$height = absint( $options['height'] );
|
||||
}
|
||||
|
||||
// Set visual to false when displaying the smallest player.
|
||||
if ( '20' === $options['height'] ) {
|
||||
$options['visual'] = false;
|
||||
}
|
||||
|
||||
if (
|
||||
class_exists( 'Jetpack_AMP_Support' )
|
||||
&& Jetpack_AMP_Support::is_amp_request()
|
||||
&& ! empty( $options['url'] )
|
||||
&& 'api.soundcloud.com' !== wp_parse_url( $options['url'], PHP_URL_HOST )
|
||||
) {
|
||||
// Defer to oEmbed if an oEmbeddable URL is provided.
|
||||
return $wp_embed->shortcode( $options, $options['url'] );
|
||||
}
|
||||
|
||||
// Build our list of Soundcloud parameters.
|
||||
$query_args = array(
|
||||
'url' => rawurlencode( $options['url'] ),
|
||||
);
|
||||
|
||||
// Add our options, if they are set to true or false.
|
||||
foreach ( $options as $name => $value ) {
|
||||
if ( 'true' === $value ) {
|
||||
$query_args[ $name ] = 'true';
|
||||
}
|
||||
|
||||
if ( 'false' === $value || false === $value ) {
|
||||
$query_args[ $name ] = 'false';
|
||||
}
|
||||
}
|
||||
|
||||
// Add the color parameter if it was specified and is a valid color.
|
||||
if ( ! empty( $options['color'] ) ) {
|
||||
$color = sanitize_hex_color_no_hash( $options['color'] );
|
||||
if ( ! empty( $color ) ) {
|
||||
$query_args['color'] = $color;
|
||||
}
|
||||
}
|
||||
|
||||
// Build final embed URL.
|
||||
$url = add_query_arg(
|
||||
$query_args,
|
||||
'https://w.soundcloud.com/player/'
|
||||
);
|
||||
|
||||
return sprintf(
|
||||
'<iframe width="%1$s" height="%2$d" scrolling="no" frameborder="no" src="%3$s"></iframe>',
|
||||
esc_attr( $width ),
|
||||
esc_attr( $height ),
|
||||
$url
|
||||
);
|
||||
}
|
||||
add_shortcode( 'soundcloud', 'soundcloud_shortcode' );
|
||||
|
||||
/**
|
||||
* Plugin options getter
|
||||
*
|
||||
* @param string|array $option Option name.
|
||||
* @param mixed $default Default value.
|
||||
*
|
||||
* @return mixed Option value
|
||||
*/
|
||||
function soundcloud_get_option( $option, $default = false ) {
|
||||
$value = get_option( 'soundcloud_' . $option );
|
||||
|
||||
return '' === $value ? $default : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide if a url has a tracklist
|
||||
*
|
||||
* @param string $url Soundcloud URL.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function soundcloud_url_has_tracklist( $url ) {
|
||||
return preg_match( '/^(.+?)\/(sets|groups|playlists)\/(.+?)$/', $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* SoundCloud Embed Reversal
|
||||
*
|
||||
* Converts a generic HTML embed code from SoundClound into a
|
||||
* WordPress.com-compatibly shortcode.
|
||||
*
|
||||
* @param string $content HTML content.
|
||||
*
|
||||
* @return string Parsed content.
|
||||
*/
|
||||
function jetpack_soundcloud_embed_reversal( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'w.soundcloud.com/player' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$regexes = array();
|
||||
|
||||
$regexes[] = '#<iframe[^>]+?src="((?:https?:)?//w\.soundcloud\.com/player/[^"\']++)"[^>]*+>\s*?</iframe>#i';
|
||||
$regexes[] = '#<iframe(?:[^&]|&(?!gt;))+?src="((?:https?:)?//w\.soundcloud\.com/player/[^"\']++)"(?:[^&]|&(?!gt;))*+>\s*?</iframe>#i';
|
||||
|
||||
foreach ( $regexes as $regex ) {
|
||||
if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
|
||||
// if pasted from the visual editor - prevent double encoding.
|
||||
$match[1] = str_replace( '&amp;', '&', $match[1] );
|
||||
|
||||
$args = wp_parse_url( html_entity_decode( $match[1], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ), PHP_URL_QUERY );
|
||||
$args = wp_parse_args( $args );
|
||||
|
||||
if ( ! preg_match( '#^(?:https?:)?//api\.soundcloud\.com/.+$#i', $args['url'], $url_matches ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! preg_match( '#height="(\d+)"#i', $match[0], $hmatch ) ) {
|
||||
$height = '';
|
||||
} else {
|
||||
$height = ' height="' . (int) $hmatch[1] . '"';
|
||||
}
|
||||
|
||||
unset( $args['url'] );
|
||||
$params = 'params="';
|
||||
if ( is_countable( $args ) && count( $args ) > 0 ) {
|
||||
foreach ( $args as $key => $value ) {
|
||||
$params .= esc_html( $key ) . '=' . esc_html( $value ) . '&';
|
||||
}
|
||||
$params = substr( $params, 0, -5 );
|
||||
}
|
||||
$params .= '"';
|
||||
|
||||
$shortcode = '[soundcloud url="' . esc_url( $url_matches[0] ) . '" ' . $params . ' width="100%"' . $height . ' iframe="true" /]';
|
||||
|
||||
$replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $match[0], '#' ) );
|
||||
$content = preg_replace( $replace_regex, sprintf( "\n\n%s\n\n", $shortcode ), $content );
|
||||
|
||||
/** This action is documented in modules/shortcodes/youtube.php */
|
||||
do_action( 'jetpack_embed_to_shortcode', 'soundcloud', $url_matches[0] );
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
add_filter( 'pre_kses', 'jetpack_soundcloud_embed_reversal' );
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* Spotify shortcode.
|
||||
*
|
||||
* Usage:
|
||||
* [spotify id="spotify:track:4bz7uB4edifWKJXSDxwHcs" width="400" height="100"]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
if ( ! shortcode_exists( 'spotify' ) ) {
|
||||
add_shortcode( 'spotify', 'jetpack_spotify_shortcode' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse shortcode arguments and render its output.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @param string $content Post Content.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function jetpack_spotify_shortcode( $atts = array(), $content = '' ) {
|
||||
if ( ! is_array( $atts ) ) {
|
||||
$atts = array();
|
||||
}
|
||||
|
||||
if ( ! empty( $content ) ) {
|
||||
$id = $content;
|
||||
} elseif ( ! empty( $atts['id'] ) ) {
|
||||
$id = $atts['id'];
|
||||
} elseif ( ! empty( $atts[0] ) ) {
|
||||
$id = $atts[0];
|
||||
} else {
|
||||
return '<!-- Missing Spotify ID -->';
|
||||
}
|
||||
|
||||
if ( empty( $atts['width'] ) ) {
|
||||
$atts['width'] = 300;
|
||||
}
|
||||
|
||||
if ( empty( $atts['height'] ) ) {
|
||||
$atts['height'] = 380;
|
||||
}
|
||||
|
||||
$atts['width'] = (int) $atts['width'];
|
||||
$atts['height'] = (int) $atts['height'];
|
||||
|
||||
// Spotify accepts both URLs and their Spotify ID format, so let them sort it out and validate.
|
||||
$embed_url = add_query_arg( 'uri', rawurlencode( $id ), 'https://embed.spotify.com/' );
|
||||
|
||||
// If the shortcode is displayed in a WPCOM notification, display a simple link only.
|
||||
// When the shortcode is displayed in the WPCOM Reader, use iframe instead.
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
require_once WP_CONTENT_DIR . '/lib/display-context.php';
|
||||
$context = A8C\Display_Context\get_current_context();
|
||||
if ( A8C\Display_Context\NOTIFICATIONS === $context ) {
|
||||
return sprintf(
|
||||
'<a href="%1$s" target="_blank" rel="noopener noreferrer">%1$s</a>',
|
||||
esc_url( $id )
|
||||
);
|
||||
} elseif ( A8C\Display_Context\READER === $context ) {
|
||||
return sprintf(
|
||||
'<iframe src="%1$s" height="%2$s" width="%3$s"></iframe>',
|
||||
esc_url( $embed_url ),
|
||||
esc_attr( $atts['height'] ),
|
||||
esc_attr( $atts['width'] )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return '<iframe src="' . esc_url( $embed_url ) . '" style="display:block; margin:0 auto; width:' . esc_attr( $atts['width'] ) . 'px; height:' . esc_attr( $atts['height'] ) . 'px;" frameborder="0" allowtransparency="true" loading="lazy"></iframe>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn text like this on it's own line into an embed: spotify:track:4bz7uB4edifWKJXSDxwHcs
|
||||
* The core WordPress embed functionality only works with URLs
|
||||
* Modified version of WP_Embed::autoembed()
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function jetpack_spotify_embed_ids( $content ) {
|
||||
$textarr = wp_html_split( $content );
|
||||
|
||||
foreach ( $textarr as &$element ) {
|
||||
if ( '' === $element || '<' === $element[0] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this element does not contain a Spotify embed, continue.
|
||||
if ( ! str_contains( $element, 'spotify:' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$element = preg_replace_callback( '|^\s*(spotify:[^\s"]+:[^\s"]+)\s*$|im', 'jetpack_spotify_embed_ids_callback', $element );
|
||||
}
|
||||
|
||||
return implode( '', $textarr );
|
||||
}
|
||||
add_filter( 'the_content', 'jetpack_spotify_embed_ids', 7 );
|
||||
|
||||
/**
|
||||
* Call shortcode with ID provided by matching pattern.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $matches Array of matches for Spofify links.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function jetpack_spotify_embed_ids_callback( $matches ) {
|
||||
return "\n" . jetpack_spotify_shortcode( array(), $matches[1] ) . "\n";
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* TED Player embed code
|
||||
* http://www.ted.com
|
||||
*
|
||||
* Examples:
|
||||
* http://www.ted.com/talks/view/id/210
|
||||
* http://www.ted.com/talks/marc_goodman_a_vision_of_crimes_in_the_future.html
|
||||
* [ted id="210" lang="en"]
|
||||
* [ted id="http://www.ted.com/talks/view/id/210" lang="en"]
|
||||
* [ted id=1539 lang=fr width=560 height=315]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
wp_oembed_add_provider( '!https?://(www\.)?ted.com/talks/view/id/.+!i', 'https://www.ted.com/talks/oembed.json', true );
|
||||
wp_oembed_add_provider( '!https?://(www\.)?ted.com/talks/[a-zA-Z\-\_]+\.html!i', 'https://www.ted.com/talks/oembed.json', true );
|
||||
|
||||
/**
|
||||
* Get the unique ID of a TED video.
|
||||
* Used in Jetpack_Media_Meta_Extractor.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function jetpack_shortcode_get_ted_id( $atts ) {
|
||||
return ( ! empty( $atts['id'] ) ? $atts['id'] : 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Ted Shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function shortcode_ted( $atts ) {
|
||||
global $wp_embed;
|
||||
|
||||
$defaults = array(
|
||||
'id' => '',
|
||||
'width' => '',
|
||||
'height' => '',
|
||||
'lang' => 'en',
|
||||
);
|
||||
$atts = shortcode_atts( $defaults, $atts, 'ted' );
|
||||
|
||||
if ( empty( $atts['id'] ) ) {
|
||||
return '<!-- Missing TED ID -->';
|
||||
}
|
||||
|
||||
$url = '';
|
||||
if ( preg_match( '#^[\d]+$#', $atts['id'], $matches ) ) {
|
||||
$url = 'https://ted.com/talks/view/id/' . $matches[0];
|
||||
} elseif ( preg_match( '#^https?://(www\.)?ted\.com/talks/view/id/[0-9]+$#', $atts['id'], $matches ) ) {
|
||||
$url = set_url_scheme( $matches[0], 'https' );
|
||||
}
|
||||
|
||||
unset( $atts['id'] );
|
||||
|
||||
$args = array();
|
||||
$embed_size_w = get_option( 'embed_size_w' );
|
||||
|
||||
if ( is_numeric( $atts['width'] ) ) {
|
||||
$args['width'] = $atts['width'];
|
||||
} elseif ( $embed_size_w ) {
|
||||
$args['width'] = $embed_size_w;
|
||||
} elseif ( ! empty( $GLOBALS['content_width'] ) ) {
|
||||
$args['width'] = (int) $GLOBALS['content_width'];
|
||||
} else {
|
||||
$args['width'] = 500;
|
||||
}
|
||||
|
||||
// Default to a 16x9 aspect ratio if there's no height set.
|
||||
if ( is_numeric( $atts['height'] ) ) {
|
||||
$args['height'] = $atts['height'];
|
||||
} else {
|
||||
$args['height'] = $args['width'] * 0.5625;
|
||||
}
|
||||
|
||||
if ( ! empty( $atts['lang'] ) ) {
|
||||
$args['lang'] = sanitize_key( $atts['lang'] );
|
||||
add_filter( 'oembed_fetch_url', 'ted_filter_oembed_fetch_url', 10, 3 );
|
||||
}
|
||||
$retval = $wp_embed->shortcode( $args, $url );
|
||||
remove_filter( 'oembed_fetch_url', 'ted_filter_oembed_fetch_url', 10 );
|
||||
|
||||
return $retval;
|
||||
}
|
||||
add_shortcode( 'ted', 'shortcode_ted' );
|
||||
|
||||
/**
|
||||
* Filter the request URL to also include the $lang parameter
|
||||
*
|
||||
* @param string $provider URL of provider that supplies the tweet we're requesting.
|
||||
* @param string $url URL of tweet to embed.
|
||||
* @param array $args Parameters supplied to shortcode and passed to wp_oembed_get.
|
||||
*/
|
||||
function ted_filter_oembed_fetch_url( $provider, $url, $args ) {
|
||||
return add_query_arg( 'lang', $args['lang'], $provider );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the oembed html to set the sandbox attribute in the iframe
|
||||
*
|
||||
* @param string|false $cache The cached HTML result, stored in post meta.
|
||||
* @param string $url The attempted embed URL.
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
function ted_filter_oembed_amp_iframe( $cache, $url ) {
|
||||
if ( is_string( $cache )
|
||||
&& strpos( $url, 'ted.com' )
|
||||
) {
|
||||
$cache = preg_replace(
|
||||
'/src=[\'"].*?[\'"]/',
|
||||
'$0 sandbox="allow-popups allow-scripts allow-same-origin"',
|
||||
$cache
|
||||
);
|
||||
}
|
||||
|
||||
return $cache;
|
||||
}
|
||||
add_filter( 'embed_oembed_html', 'ted_filter_oembed_amp_iframe', 10, 2 );
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
/**
|
||||
* Tweet shortcode.
|
||||
* Params map to key value pairs, and all but tweet are optional:
|
||||
* tweet = id or permalink url* (Required)
|
||||
* align = none|left|right|center
|
||||
* width = number in pixels example: width="300"
|
||||
* lang = en|fr|de|ko|etc... language country code.
|
||||
* hide_thread = true | false **
|
||||
* hide_media = true | false **
|
||||
*
|
||||
* Basic:
|
||||
* [tweet https://twitter.com/jack/statuses/20 width="350"]
|
||||
*
|
||||
* More parameters and another tweet syntax admitted:
|
||||
* [tweet tweet="https://twitter.com/jack/statuses/20" align="left" width="350" align="center" lang="es"]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
add_shortcode( 'tweet', array( 'Jetpack_Tweet', 'jetpack_tweet_shortcode' ) );
|
||||
|
||||
/**
|
||||
* Tweet Shortcode class.
|
||||
*/
|
||||
class Jetpack_Tweet {
|
||||
|
||||
/**
|
||||
* Array of arguments about a tweet.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $provider_args;
|
||||
|
||||
/**
|
||||
* Parse shortcode arguments and render its output.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts Shortcode parameters.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function jetpack_tweet_shortcode( $atts ) {
|
||||
global $wp_embed;
|
||||
|
||||
$default_atts = array(
|
||||
'tweet' => '',
|
||||
'align' => 'none',
|
||||
'width' => '',
|
||||
'lang' => 'en',
|
||||
'hide_thread' => 'false',
|
||||
'hide_media' => 'false',
|
||||
);
|
||||
|
||||
$attr = shortcode_atts( $default_atts, $atts );
|
||||
|
||||
self::$provider_args = $attr;
|
||||
|
||||
/*
|
||||
* figure out the tweet id for the requested tweet
|
||||
* supporting both omitted attributes and tweet="tweet_id"
|
||||
* and supporting both an id and a URL
|
||||
*/
|
||||
if ( empty( $attr['tweet'] ) && ! empty( $atts[0] ) ) {
|
||||
$attr['tweet'] = $atts[0];
|
||||
}
|
||||
|
||||
if ( ctype_digit( $attr['tweet'] ) ) {
|
||||
$id = 'https://twitter.com/jetpack/status/' . $attr['tweet'];
|
||||
$tweet_id = (int) $attr['tweet'];
|
||||
} else {
|
||||
preg_match( '/^http(s|):\/\/twitter\.com(\/\#\!\/|\/)([a-zA-Z0-9_]{1,20})\/status(es)*\/(\d+)$/', $attr['tweet'], $urlbits );
|
||||
|
||||
if ( isset( $urlbits[5] ) && (int) $urlbits[5] ) {
|
||||
$id = 'https://twitter.com/' . $urlbits[3] . '/status/' . (int) $urlbits[5];
|
||||
$tweet_id = (int) $urlbits[5];
|
||||
} else {
|
||||
return '<!-- Invalid tweet id -->';
|
||||
}
|
||||
}
|
||||
|
||||
// Add shortcode arguments to provider URL.
|
||||
add_filter( 'oembed_fetch_url', array( 'Jetpack_Tweet', 'jetpack_tweet_url_extra_args' ), 10, 3 );
|
||||
|
||||
/*
|
||||
* In Jetpack, we use $wp_embed->shortcode() to return the tweet output.
|
||||
* @see https://github.com/Automattic/jetpack/pull/11173
|
||||
*/
|
||||
$output = $wp_embed->shortcode( $atts, $id );
|
||||
|
||||
// Clean up filter.
|
||||
remove_filter( 'oembed_fetch_url', array( 'Jetpack_Tweet', 'jetpack_tweet_url_extra_args' ), 10 );
|
||||
|
||||
/** This action is documented in modules/widgets/social-media-icons.php */
|
||||
do_action( 'jetpack_bump_stats_extras', 'embeds', 'tweet' );
|
||||
|
||||
if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
|
||||
$width = ! empty( $attr['width'] ) ? $attr['width'] : 600;
|
||||
$height = 480;
|
||||
$output = sprintf(
|
||||
'<amp-twitter data-tweetid="%1$s" layout="responsive" width="%2$d" height="%3$d"></amp-twitter>',
|
||||
esc_attr( $tweet_id ),
|
||||
absint( $width ),
|
||||
absint( $height )
|
||||
);
|
||||
} else {
|
||||
// Add Twitter widgets.js script to the footer.
|
||||
add_action( 'wp_footer', array( 'Jetpack_Tweet', 'jetpack_tweet_shortcode_script' ) );
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds parameters to URL used to fetch the tweet.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $provider URL of provider that supplies the tweet we're requesting.
|
||||
* @param string $url URL of tweet to embed.
|
||||
* @param array $args Parameters supplied to shortcode and passed to wp_oembed_get.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function jetpack_tweet_url_extra_args( $provider, $url, $args = array() ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
foreach ( self::$provider_args as $key => $value ) {
|
||||
switch ( $key ) {
|
||||
case 'align':
|
||||
case 'lang':
|
||||
case 'hide_thread':
|
||||
case 'hide_media':
|
||||
$provider = add_query_arg( $key, $value, $provider );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Disable script since we're enqueing it in our own way in the footer.
|
||||
$provider = add_query_arg( 'omit_script', 'true', $provider );
|
||||
|
||||
// Twitter doesn't support maxheight so don't send it.
|
||||
$provider = remove_query_arg( 'maxheight', $provider );
|
||||
|
||||
/**
|
||||
* Filter the Twitter Partner ID.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 4.6.0
|
||||
*
|
||||
* @param string $partner_id Twitter partner ID.
|
||||
*/
|
||||
$partner = apply_filters( 'jetpack_twitter_partner_id', 'jetpack' );
|
||||
|
||||
// Add Twitter partner ID to track embeds from Jetpack.
|
||||
if ( ! empty( $partner ) ) {
|
||||
$provider = add_query_arg( 'partner', $partner, $provider );
|
||||
}
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue front end assets.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public static function jetpack_tweet_shortcode_script() {
|
||||
if ( ! wp_script_is( 'twitter-widgets', 'registered' ) ) {
|
||||
wp_register_script( 'twitter-widgets', 'https://platform.twitter.com/widgets.js', array(), JETPACK__VERSION, true );
|
||||
wp_print_scripts( 'twitter-widgets' );
|
||||
}
|
||||
}
|
||||
} // class end
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* Twitch.tv shortcode
|
||||
*
|
||||
* Examples:
|
||||
* [twitchtv url='https://www.twitch.tv/paperbat' height='378' width='620' autoplay='false']
|
||||
* [twitchtv url='https://www.twitch.tv/paperbat/b/323486192' height='378' width='620' autoplay='false']
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* (Live URL) https://www.twitch.tv/paperbat
|
||||
*
|
||||
* <iframe src="https://player.twitch.tv/?autoplay=false&muted=false&channel=paperbat" width="620" height="378" frameborder="0" scrolling="no" allowfullscreen></iframe>
|
||||
*
|
||||
* (Archive URL) https://www.twitch.tv/paperbat/v/323486192
|
||||
*
|
||||
* <iframe src="https://player.twitch.tv/?autoplay=false&muted=false&video=v323486192" width="620" height="378" frameborder="0" scrolling="no" allowfullscreen></iframe>
|
||||
*
|
||||
* @param array $atts User supplied shortcode arguments.
|
||||
*
|
||||
* @return string HTML output of the shortcode.
|
||||
*/
|
||||
function wpcom_twitchtv_shortcode( $atts ) {
|
||||
$attr = shortcode_atts(
|
||||
array(
|
||||
'height' => 378,
|
||||
'width' => 620,
|
||||
'url' => '',
|
||||
'autoplay' => 'false',
|
||||
'muted' => 'false',
|
||||
'time' => null,
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
if ( empty( $attr['url'] ) ) {
|
||||
return '<!-- Invalid twitchtv URL -->';
|
||||
}
|
||||
|
||||
preg_match( '|^https?://www.twitch.tv/([^/?]+)(/v/(\d+))?|i', $attr['url'], $match );
|
||||
|
||||
$url_args = array(
|
||||
'autoplay' => ( false !== $attr['autoplay'] && 'false' !== $attr['autoplay'] ) ? 'true' : 'false',
|
||||
'muted' => ( false !== $attr['muted'] && 'false' !== $attr['muted'] ) ? 'true' : 'false',
|
||||
'time' => $attr['time'],
|
||||
);
|
||||
|
||||
$width = (int) $attr['width'];
|
||||
$height = (int) $attr['height'];
|
||||
|
||||
$user_id = $match[1];
|
||||
$video_id = 0;
|
||||
if ( ! empty( $match[3] ) ) {
|
||||
$video_id = (int) $match[3];
|
||||
}
|
||||
|
||||
do_action( 'jetpack_bump_stats_extras', 'twitchtv', 'shortcode' );
|
||||
|
||||
if ( $video_id > 0 ) {
|
||||
$url_args['video'] = 'v' . $video_id;
|
||||
} else {
|
||||
$url_args['channel'] = $user_id;
|
||||
}
|
||||
|
||||
// See https://discuss.dev.twitch.tv/t/twitch-embedded-player-updates-in-2020/23956.
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
$url_args['parent'] = isset( $_SERVER['HTTP_HOST'] )
|
||||
? rawurlencode( wp_unslash( $_SERVER['HTTP_HOST'] ) ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
: '';
|
||||
|
||||
$url = add_query_arg( $url_args, 'https://player.twitch.tv/' );
|
||||
|
||||
return sprintf(
|
||||
'<iframe src="%s" width="%d" height="%d" frameborder="0" scrolling="no" allowfullscreen sandbox="allow-popups allow-scripts allow-same-origin allow-presentation"></iframe>',
|
||||
esc_url( $url ),
|
||||
esc_attr( $width ),
|
||||
esc_attr( $height )
|
||||
);
|
||||
}
|
||||
add_shortcode( 'twitch', 'wpcom_twitchtv_shortcode' );
|
||||
add_shortcode( 'twitchtv', 'wpcom_twitchtv_shortcode' );
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* Twitter Timeline Shortcode.
|
||||
*
|
||||
* Examples:
|
||||
* [twitter-timeline username=jetpack]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Render the Twitter shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function twitter_timeline_shortcode( $atts ) {
|
||||
$default_atts = array(
|
||||
'username' => '',
|
||||
'id' => '',
|
||||
'width' => '450',
|
||||
'height' => '282',
|
||||
);
|
||||
|
||||
$atts = shortcode_atts( $default_atts, $atts, 'twitter-timeline' );
|
||||
|
||||
$atts['username'] = preg_replace( '/[^A-Za-z0-9_]+/', '', $atts['username'] );
|
||||
|
||||
if ( empty( $atts['username'] ) && ! is_numeric( $atts['id'] ) ) {
|
||||
return '<!-- ' . __( 'Must specify Twitter Timeline id or username.', 'jetpack' ) . ' -->';
|
||||
}
|
||||
|
||||
$output = '<a class="twitter-timeline"';
|
||||
|
||||
/** This filter is documented in modules/shortcodes/tweet.php */
|
||||
$partner = apply_filters( 'jetpack_twitter_partner_id', 'jetpack' );
|
||||
if ( ! empty( $partner ) ) {
|
||||
$output .= ' data-partner="' . esc_attr( $partner ) . '"';
|
||||
}
|
||||
if ( is_numeric( $atts['width'] ) ) {
|
||||
$output .= ' data-width="' . esc_attr( $atts['width'] ) . '"';
|
||||
}
|
||||
if ( is_numeric( $atts['height'] ) ) {
|
||||
$output .= ' data-height="' . esc_attr( $atts['height'] ) . '"';
|
||||
}
|
||||
if ( is_numeric( $atts['id'] ) ) {
|
||||
$output .= ' data-widget-id="' . esc_attr( $atts['id'] ) . '"';
|
||||
}
|
||||
if ( ! empty( $atts['username'] ) ) {
|
||||
$output .= ' href="' . esc_url( 'https://twitter.com/' . $atts['username'] ) . '"';
|
||||
}
|
||||
|
||||
$output .= '>';
|
||||
|
||||
$output .= sprintf(
|
||||
/* Translators: placeholder is a Twitter username. */
|
||||
__( 'Tweets by @%s', 'jetpack' ),
|
||||
$atts['username']
|
||||
);
|
||||
|
||||
$output .= '</a>';
|
||||
|
||||
wp_enqueue_script( 'jetpack-twitter-timeline' );
|
||||
|
||||
return $output;
|
||||
}
|
||||
add_shortcode( 'twitter-timeline', 'twitter_timeline_shortcode' );
|
||||
|
||||
/**
|
||||
* Enqueue the js used by the Twitter shortcode.
|
||||
*/
|
||||
function twitter_timeline_js() {
|
||||
if ( is_customize_preview() ) {
|
||||
wp_enqueue_script( 'jetpack-twitter-timeline' );
|
||||
}
|
||||
}
|
||||
add_action( 'wp_enqueue_scripts', 'twitter_timeline_js' );
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
/**
|
||||
* Display a message on the frontend when we retire a shortcode,
|
||||
* explaining why the shortcode is not available anymore.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
// phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
|
||||
|
||||
/**
|
||||
* Class Jetpack_Shortcode_Unavailable
|
||||
*/
|
||||
class Jetpack_Shortcode_Unavailable {
|
||||
/**
|
||||
* Shortcodes that are unavailable.
|
||||
*
|
||||
* Key is the shortcode, value is string explaining why.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $shortcodes;
|
||||
|
||||
/**
|
||||
* Set up the actions and filters for the class to listen to.
|
||||
*
|
||||
* @param array $shortcodes An associative array of keys being the shortcodes that are unavailable, and a string explaining why.
|
||||
*/
|
||||
public function __construct( $shortcodes ) {
|
||||
$this->shortcodes = $shortcodes;
|
||||
|
||||
add_action( 'template_redirect', array( $this, 'add_shortcodes' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* For all of our defined unavailable shortcodes, if something else hasn't
|
||||
* already claimed them, add a handler to nullify their output.
|
||||
*/
|
||||
public function add_shortcodes() {
|
||||
foreach ( array_keys( $this->shortcodes ) as $shortcode ) {
|
||||
if ( ! shortcode_exists( $shortcode ) ) {
|
||||
add_shortcode( $shortcode, array( $this, 'stub_shortcode' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nullify the output of unavailable shortcodes. Includes a filter to make
|
||||
* it easier to notify admins that a shortcode that they used is unavailable.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @param string $content Post content.
|
||||
* @param string $shortcode Shortcode name.
|
||||
*
|
||||
* @return mixed|void
|
||||
*/
|
||||
public function stub_shortcode( $atts, $content = '', $shortcode = '' ) {
|
||||
$str = '';
|
||||
if ( current_user_can( 'edit_posts' ) && ! empty( $this->shortcodes[ $shortcode ] ) ) {
|
||||
$str = sprintf( '<div><strong>%s</strong></div>', $this->shortcodes[ $shortcode ] );
|
||||
}
|
||||
/**
|
||||
* Filter the front-end output of unavailable shortcodes.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param string $str The html displayed in lieu of the shortcode.
|
||||
* @param array $atts The attributes (numeric or named) passed to the shortcode.
|
||||
* @param string $content The content (if any) between the opening and closing tags.
|
||||
* @param string $shortcode The shortcode tag used to invoke this.
|
||||
*/
|
||||
return apply_filters( 'jetpack_stub_shortcode', $str, $atts, $content, $shortcode );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init class.
|
||||
*/
|
||||
function jetpack_init_shortcode_unavailable() {
|
||||
new Jetpack_Shortcode_Unavailable(
|
||||
array(
|
||||
'digg' => __( 'The Digg API was shut down in 2014.', 'jetpack' ),
|
||||
'hulu' => __( 'Hulu no longer allows embedding content.', 'jetpack' ),
|
||||
'blip.tv' => __( 'The Blip.tv service has been shut down since August 20th, 2015.', 'jetpack' ),
|
||||
'googlevideo' => __( 'The Google Video embed service is not available anymore, it has been replaced by YouTube.', 'jetpack' ),
|
||||
'jetpack-email-subscribe' => __( 'The Email Subscribe shortcode is now available as a block in the Block editor.', 'jetpack' ),
|
||||
'lytro' => __( 'Lytro has been shut down since March 2019.', 'jetpack' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
add_action( 'init', 'jetpack_init_shortcode_unavailable' );
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
/**
|
||||
* Untappd Shortcodes
|
||||
*
|
||||
* @author kraftbj
|
||||
*
|
||||
* [untappd-menu location="123" theme="123"]
|
||||
* @since 4.1.0
|
||||
* @param location int Location ID for the Untappd venue. Required.
|
||||
* @param theme int Theme ID for the Untappd menu. Required.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Display Untappd data in posts and pages.
|
||||
*/
|
||||
class Jetpack_Untappd {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'action_init' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register our shortcodes.
|
||||
*/
|
||||
public function action_init() {
|
||||
add_shortcode( 'untappd-menu', array( $this, 'menu_shortcode' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [untappd-menu] shortcode.
|
||||
*
|
||||
* @param array $atts Shortocde attributes.
|
||||
* @param string $content Post content.
|
||||
*/
|
||||
public static function menu_shortcode( $atts, $content = '' ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
// Let's bail if we don't have location or theme.
|
||||
if ( ! isset( $atts['location'] ) || ! isset( $atts['theme'] ) ) {
|
||||
if ( current_user_can( 'edit_posts' ) ) {
|
||||
return __( 'No location or theme ID provided in the untappd-menu shortcode.', 'jetpack' );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's apply some defaults.
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'location' => '',
|
||||
'theme' => '',
|
||||
),
|
||||
$atts,
|
||||
'untappd-menu'
|
||||
);
|
||||
|
||||
// We're going to clean the user input.
|
||||
$atts = array_map( 'absint', $atts );
|
||||
|
||||
if ( $atts['location'] < 1 || $atts['theme'] < 1 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
static $untappd_menu = 1;
|
||||
|
||||
$html = '<div id="menu-container-untappd-' . $untappd_menu . '" class="untappd-menu"></div>';
|
||||
$html .= '<script type="text/javascript">' . PHP_EOL;
|
||||
$html .= '!function(e,n){var t=document.createElement("script"),a=document.getElementsByTagName("script")[0];' . PHP_EOL;
|
||||
$html .= 't.async=1,a.parentNode.insertBefore(t,a),t.onload=t.onreadystatechange=function(e,a){' . PHP_EOL;
|
||||
$html .= '(a||!t.readyState||/loaded|complete/.test(t.readyState))&&(t.onload=t.onreadystatechange=null,t=void 0,a||n&&n())},' . PHP_EOL;
|
||||
$html .= 't.src=e}("https://embed-menu-preloader.untappdapi.com/embed-menu-preloader.min.js",function(){' . PHP_EOL;
|
||||
$html .= 'PreloadEmbedMenu( "menu-container-untappd-' . $untappd_menu . '",' . $atts['location'] . ',' . $atts['theme'] . ' )});' . PHP_EOL;
|
||||
$html .= '</script>';
|
||||
|
||||
++$untappd_menu;
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
new Jetpack_Untappd();
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
|
||||
|
||||
/**
|
||||
* Display a list of upcoming events from a calendar.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Register a upcomingevents shortcode.
|
||||
* Most of the heavy lifting done in iCalendarReader class,
|
||||
* where the icalendar_render_events() function controls the display.
|
||||
*/
|
||||
class Upcoming_Events_Shortcode {
|
||||
|
||||
/**
|
||||
* Register things.
|
||||
*/
|
||||
public static function init() {
|
||||
add_shortcode( 'upcomingevents', array( __CLASS__, 'shortcode' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
public static function shortcode( $atts = array() ) {
|
||||
require_once JETPACK__PLUGIN_DIR . '/_inc/lib/icalendar-reader.php';
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'url' => '',
|
||||
'number' => 0,
|
||||
),
|
||||
$atts,
|
||||
'upcomingevents'
|
||||
);
|
||||
$args = array(
|
||||
'context' => 'shortcode',
|
||||
'number' => absint( $atts['number'] ),
|
||||
);
|
||||
|
||||
if ( empty( $atts['url'] ) ) {
|
||||
// If the current user can access the Appearance->Widgets page.
|
||||
if ( current_user_can( 'edit_theme_options' ) ) {
|
||||
return sprintf( '<p>%s</p>', __( 'You must specify a URL to an iCalendar feed in the shortcode. This notice is only displayed to administrators.', 'jetpack' ) );
|
||||
}
|
||||
return self::no_upcoming_event_text();
|
||||
}
|
||||
$events = icalendar_render_events( $atts['url'], $args );
|
||||
|
||||
if ( ! $events ) {
|
||||
$events = self::no_upcoming_event_text();
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns No Upcoming Event text.
|
||||
*/
|
||||
private static function no_upcoming_event_text() {
|
||||
return sprintf( '<p>%s</p>', __( 'No upcoming events', 'jetpack' ) );
|
||||
}
|
||||
}
|
||||
add_action( 'after_setup_theme', array( 'Upcoming_Events_Shortcode', 'init' ), 2 );
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* Ustream.tv shortcode
|
||||
*
|
||||
* Example:
|
||||
* [ustream id=1524 live=1]
|
||||
* [ustreamsocial id=12980237 width="500"]
|
||||
*
|
||||
* Embed code example, from http://www.ustream.tv/leolaporte
|
||||
* <iframe src="http://www.ustream.tv/embed/recorded/1524?v=3&wmode=direct" width="480" height="296" scrolling="no" frameborder="0" style="border: 0 none transparent;"></iframe>
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
add_shortcode( 'ustream', 'ustream_shortcode' );
|
||||
add_shortcode( 'ustreamsocial', 'ustreamsocial_shortcode' );
|
||||
|
||||
/**
|
||||
* Parse shortcode arguments and render output for ustream single video.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts array of user-supplied arguments.
|
||||
*
|
||||
* @return string HTML output.
|
||||
*/
|
||||
function ustream_shortcode( $atts ) {
|
||||
if ( isset( $atts[0] ) ) {
|
||||
return '<!-- ustream error: bad parameters -->';
|
||||
}
|
||||
|
||||
$defaults = array(
|
||||
'width' => 480,
|
||||
'height' => 296,
|
||||
'id' => 0,
|
||||
'live' => 0,
|
||||
'highlight' => 0,
|
||||
'version' => 3,
|
||||
'hwaccel' => 1,
|
||||
);
|
||||
$atts = array_map( 'intval', shortcode_atts( $defaults, $atts ) );
|
||||
|
||||
if ( 0 >= $atts['id'] ) {
|
||||
return '<!-- ustream error: bad video ID -->';
|
||||
}
|
||||
|
||||
if ( 0 >= $atts['height'] ) {
|
||||
return '<!-- ustream error: height invalid -->';
|
||||
}
|
||||
|
||||
if ( 0 >= $atts['width'] ) {
|
||||
return '<!-- ustream error: width invalid -->';
|
||||
}
|
||||
|
||||
if ( $atts['live'] ) {
|
||||
$recorded = '';
|
||||
} else {
|
||||
$recorded = 'recorded/';
|
||||
}
|
||||
|
||||
if ( ! $atts['live'] && ( 0 < $atts['highlight'] ) ) {
|
||||
$highlight = sprintf( '/highlight/%d', esc_attr( $atts['highlight'] ) );
|
||||
} else {
|
||||
$highlight = '';
|
||||
}
|
||||
|
||||
$url_base = sprintf(
|
||||
'https://www.ustream.tv/embed/%s%d%s',
|
||||
$recorded,
|
||||
esc_attr( $atts['id'] ),
|
||||
$highlight
|
||||
);
|
||||
|
||||
$video_options = array(
|
||||
'html5ui' => 1,
|
||||
'v' => absint( $atts['version'] ),
|
||||
);
|
||||
|
||||
if ( 0 < $atts['hwaccel'] ) {
|
||||
$video_options['wmode'] = 'direct';
|
||||
}
|
||||
|
||||
$url = add_query_arg(
|
||||
$video_options,
|
||||
$url_base
|
||||
);
|
||||
|
||||
$output = sprintf(
|
||||
'<iframe src="%1$s" width="%2$d" height="%3$d" scrolling="no" style="border: 0 none transparent;"></iframe>',
|
||||
esc_url( $url ),
|
||||
absint( $atts['width'] ),
|
||||
absint( $atts['height'] )
|
||||
);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse shortcode arguments and render output for ustream's Social Stream.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*
|
||||
* @param array $atts array of user-supplied arguments.
|
||||
*
|
||||
* @return string HTML output.
|
||||
*/
|
||||
function ustreamsocial_shortcode( $atts ) {
|
||||
$defaults = array(
|
||||
'id' => 0,
|
||||
'height' => 420,
|
||||
'width' => 320,
|
||||
);
|
||||
$atts = array_map( 'intval', shortcode_atts( $defaults, $atts ) );
|
||||
|
||||
if ( 0 >= $atts['id'] ) {
|
||||
return '<!-- ustreamsocial error: bad social stream ID -->';
|
||||
}
|
||||
|
||||
if ( 0 >= $atts['height'] ) {
|
||||
return '<!-- ustreamsocial error: height invalid -->';
|
||||
}
|
||||
|
||||
if ( 0 >= $atts['width'] ) {
|
||||
return '<!-- ustreamsocial error: width invalid -->';
|
||||
}
|
||||
|
||||
$url = 'https://www.ustream.tv/socialstream/' . esc_attr( $atts['id'] );
|
||||
|
||||
return sprintf(
|
||||
'<iframe id="SocialStream" src="%1$s" class="" name="SocialStream" width="%2$d" height="%3$d" scrolling="no" allowtransparency="true" style="visibility: visible; margin-top: 0; margin-bottom: 0; border: 0;"></iframe>',
|
||||
esc_url( $url ),
|
||||
absint( $atts['width'] ),
|
||||
absint( $atts['height'] )
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* Provides VideoPress videos support when module is disabled.
|
||||
*
|
||||
* @since 2.4
|
||||
* @since 3.9.5 Added compatibility with refactored VideoPress module.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
if ( ! Jetpack::is_module_active( 'videopress' ) ) {
|
||||
|
||||
\Automattic\Jetpack\Assets::add_resource_hint(
|
||||
'//v0.wordpress.com',
|
||||
'dns-prefetch'
|
||||
);
|
||||
|
||||
include_once JETPACK__PLUGIN_DIR . 'modules/videopress/shortcode.php';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,421 @@
|
||||
<?php
|
||||
/**
|
||||
* Vimeo Shortcode.
|
||||
*
|
||||
* Examples:
|
||||
* [vimeo 141358]
|
||||
* [vimeo http://vimeo.com/141358]
|
||||
* [vimeo 141358 h=500&w=350]
|
||||
* [vimeo 141358 h=500 w=350]
|
||||
* [vimeo id=141358 width=350 height=500]
|
||||
*
|
||||
* <iframe src="http://player.vimeo.com/video/18427511" width="400" height="225" frameborder="0"></iframe><p><a href="http://vimeo.com/18427511">Eskmo 'We Got More' (Official Video)</a> from <a href="http://vimeo.com/ninjatune">Ninja Tune</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Extract Vimeo ID from shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function jetpack_shortcode_get_vimeo_id( $atts ) {
|
||||
if ( isset( $atts[0] ) ) {
|
||||
$atts[0] = trim( $atts[0], '=' );
|
||||
if ( is_numeric( $atts[0] ) ) {
|
||||
return (int) $atts[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract Vimeo ID from the URL. For examples:
|
||||
* https://vimeo.com/12345
|
||||
* https://vimeo.com/289091934/cd1f466bcc
|
||||
* https://vimeo.com/album/2838732/video/6342264
|
||||
* https://vimeo.com/groups/758728/videos/897094040
|
||||
* https://vimeo.com/channels/staffpicks/123456789
|
||||
* https://vimeo.com/album/1234567/video/7654321
|
||||
* https://player.vimeo.com/video/18427511
|
||||
*/
|
||||
$pattern = '/(?:https?:\/\/)?vimeo\.com\/(?:groups\/\d+\/videos\/|album\/\d+\/video\/|video\/|channels\/[^\/]+\/videos\/|[^\/]+\/)?([0-9]+)(?:[^\'\"0-9<]|$)/i';
|
||||
$match = array();
|
||||
if ( preg_match( $pattern, $atts[0], $match ) ) {
|
||||
return (int) $match[1];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get video dimensions.
|
||||
*
|
||||
* @since 8.0.0
|
||||
*
|
||||
* @param array $attr The attributes of the shortcode.
|
||||
* @param array $old_attr Optional array of attributes from the old shortcode format.
|
||||
*
|
||||
* @return array Width and height.
|
||||
*/
|
||||
function jetpack_shortcode_get_vimeo_dimensions( $attr, $old_attr = array() ) {
|
||||
global $content_width;
|
||||
|
||||
$default_width = 600;
|
||||
$default_height = 338;
|
||||
$aspect_ratio = $default_height / $default_width;
|
||||
|
||||
/*
|
||||
* For width and height, we want to support both formats
|
||||
* that can be provided in the new shortcode format:
|
||||
* - for width: width or w
|
||||
* - for height: height or h
|
||||
*
|
||||
* For each variation, the full word takes priority.
|
||||
*
|
||||
* If no variation is set, we default to the default width and height values set above.
|
||||
*/
|
||||
if ( ! empty( $attr['width'] ) ) {
|
||||
$width = absint( $attr['width'] );
|
||||
} elseif ( ! empty( $attr['w'] ) ) {
|
||||
$width = absint( $attr['w'] );
|
||||
} else {
|
||||
$width = $default_width;
|
||||
}
|
||||
|
||||
if ( ! empty( $attr['height'] ) ) {
|
||||
$height = absint( $attr['height'] );
|
||||
} elseif ( ! empty( $attr['h'] ) ) {
|
||||
$height = absint( $attr['h'] );
|
||||
} else {
|
||||
$height = $default_height;
|
||||
}
|
||||
|
||||
/*
|
||||
* Support w and h argument as fallbacks in old shortcode format.
|
||||
*/
|
||||
if (
|
||||
$default_width === $width
|
||||
&& ! empty( $old_attr['w'] )
|
||||
) {
|
||||
$width = absint( $old_attr['w'] );
|
||||
|
||||
if (
|
||||
$default_width === $width
|
||||
&& empty( $old_attr['h'] )
|
||||
) {
|
||||
$height = round( $width * $aspect_ratio );
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
$default_height === $height
|
||||
&& ! empty( $old_attr['h'] )
|
||||
) {
|
||||
$height = absint( $old_attr['h'] );
|
||||
|
||||
if ( empty( $old_attr['w'] ) ) {
|
||||
$width = round( $height * $aspect_ratio );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a content width defined, let it be the new default.
|
||||
*/
|
||||
if (
|
||||
$default_width === $width
|
||||
&& ! empty( $content_width )
|
||||
) {
|
||||
$width = absint( $content_width );
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a custom width, we need a custom height as well
|
||||
* to maintain aspect ratio.
|
||||
*/
|
||||
if (
|
||||
$default_width !== $width
|
||||
&& $default_height === $height
|
||||
) {
|
||||
$height = round( ( $width / 640 ) * 360 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the Vimeo player width.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 3.4.0
|
||||
*
|
||||
* @param int $width Width of the Vimeo player in pixels.
|
||||
*/
|
||||
$width = (int) apply_filters( 'vimeo_width', $width );
|
||||
|
||||
/**
|
||||
* Filter the Vimeo player height.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 3.4.0
|
||||
*
|
||||
* @param int $height Height of the Vimeo player in pixels.
|
||||
*/
|
||||
$height = (int) apply_filters( 'vimeo_height', $height );
|
||||
|
||||
return array( $width, $height );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Vimeo shortcode into an embed code.
|
||||
*
|
||||
* @param array $atts An array of shortcode attributes.
|
||||
*
|
||||
* @return string The embed code for the Vimeo video.
|
||||
*/
|
||||
function vimeo_shortcode( $atts ) {
|
||||
$attr = array_map(
|
||||
'intval',
|
||||
shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
'width' => 0,
|
||||
'height' => 0,
|
||||
'autoplay' => 0,
|
||||
'loop' => 0,
|
||||
'w' => 0,
|
||||
'h' => 0,
|
||||
),
|
||||
$atts
|
||||
)
|
||||
);
|
||||
|
||||
if ( isset( $atts[0] ) ) {
|
||||
$attr['id'] = jetpack_shortcode_get_vimeo_id( $atts );
|
||||
}
|
||||
|
||||
if ( ! $attr['id'] ) {
|
||||
return '<!-- vimeo error: not a vimeo video -->';
|
||||
}
|
||||
|
||||
// Handle old shortcode params such as h=500&w=350.
|
||||
$params = shortcode_new_to_old_params( $atts );
|
||||
$params = str_replace( array( '&', '&' ), '&', $params );
|
||||
parse_str( $params, $args );
|
||||
|
||||
list( $width, $height ) = jetpack_shortcode_get_vimeo_dimensions( $attr, $args );
|
||||
|
||||
$url = esc_url( 'https://player.vimeo.com/video/' . $attr['id'] );
|
||||
|
||||
// Handle autoplay and loop arguments.
|
||||
if (
|
||||
isset( $args['autoplay'] ) && '1' === $args['autoplay'] // Parsed from the embedded URL.
|
||||
|| $attr['autoplay'] // Parsed from shortcode arguments.
|
||||
|| in_array( 'autoplay', $atts, true ) // Catch the argument passed without a value.
|
||||
) {
|
||||
$url = add_query_arg( 'autoplay', 1, $url );
|
||||
}
|
||||
|
||||
if (
|
||||
isset( $args['loop'] ) && '1' === $args['loop'] // Parsed from the embedded URL.
|
||||
|| $attr['loop'] // Parsed from shortcode arguments.
|
||||
|| in_array( 'loop', $atts, true ) // Catch the argument passed without a value.
|
||||
) {
|
||||
$url = add_query_arg( 'loop', 1, $url );
|
||||
}
|
||||
|
||||
if (
|
||||
class_exists( 'Jetpack_AMP_Support' )
|
||||
&& Jetpack_AMP_Support::is_amp_request()
|
||||
) {
|
||||
$html = sprintf(
|
||||
'<amp-vimeo data-videoid="%1$s" layout="responsive" width="%2$d" height="%3$d"></amp-vimeo>',
|
||||
esc_attr( $attr['id'] ),
|
||||
absint( $width ),
|
||||
absint( $height )
|
||||
);
|
||||
} else {
|
||||
$html = sprintf(
|
||||
'<div class="embed-vimeo" style="text-align: center;"><iframe src="%1$s" width="%2$u" height="%3$u" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>',
|
||||
esc_url( $url ),
|
||||
esc_attr( $width ),
|
||||
esc_attr( $height )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the Vimeo player HTML.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 1.2.3
|
||||
*
|
||||
* @param string $html Embedded Vimeo player HTML.
|
||||
*/
|
||||
$html = apply_filters( 'video_embed_html', $html );
|
||||
|
||||
return $html;
|
||||
}
|
||||
add_shortcode( 'vimeo', 'vimeo_shortcode' );
|
||||
|
||||
/**
|
||||
* Callback to modify output of embedded Vimeo video using Jetpack's shortcode.
|
||||
*
|
||||
* @since 3.9
|
||||
* @deprecated since 13.8
|
||||
*
|
||||
* @param array $matches Regex partial matches against the URL passed.
|
||||
* @param array $attr Attributes received in embed response.
|
||||
* @param array $url Requested URL to be embedded.
|
||||
*
|
||||
* @return string Return output of Vimeo shortcode with the proper markup.
|
||||
*/
|
||||
function wpcom_vimeo_embed_url( $matches, $attr, $url ) {
|
||||
_deprecated_function( __FUNCTION__, 'jetpack-13.8' );
|
||||
$vimeo_info = array( $url );
|
||||
|
||||
// If we are able to extract a video ID, use it in the shortcode instead of the full URL.
|
||||
if ( ! empty( $matches['video_id'] ) ) {
|
||||
$vimeo_info = array( 'id' => $matches['video_id'] );
|
||||
}
|
||||
|
||||
return vimeo_shortcode( $vimeo_info );
|
||||
}
|
||||
|
||||
/**
|
||||
* For bare URLs on their own line of the form.
|
||||
*
|
||||
* Accepted formats:
|
||||
* https://vimeo.com/289091934/cd1f466bcc
|
||||
* https://vimeo.com/album/2838732/video/6342264
|
||||
* https://vimeo.com/6342264
|
||||
* http://player.vimeo.com/video/18427511
|
||||
*
|
||||
* @since 3.9
|
||||
* @deprecated since 13.8
|
||||
*
|
||||
* @uses wpcom_vimeo_embed_url
|
||||
*/
|
||||
function wpcom_vimeo_embed_url_init() {
|
||||
_deprecated_function( __FUNCTION__, 'jetpack-13.8' );
|
||||
wp_embed_register_handler( 'wpcom_vimeo_embed_url', '#https?://(?:[^/]+\.)?vimeo\.com/(?:album/(?<album_id>\d+)/)?(?:video/)?(?<video_id>\d+)(?:/.*)?$#i', 'wpcom_vimeo_embed_url' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a Vimeo embed iFrame into a Vimeo shortcode.
|
||||
*
|
||||
* @param string $content Post content.
|
||||
*/
|
||||
function vimeo_embed_to_shortcode( $content ) {
|
||||
if ( ! is_string( $content ) || false === stripos( $content, 'player.vimeo.com/video/' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$regexp = '!<iframe\s+src=[\'"](https?:)?//player\.vimeo\.com/video/(\d+)[\w=&;?]*[\'"]((?:\s+\w+=[\'"][^\'"]*[\'"])*)((?:[\s\w]*))></iframe>!i';
|
||||
$regexp_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );
|
||||
|
||||
foreach ( compact( 'regexp', 'regexp_ent' ) as $reg => $regexp ) {
|
||||
if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
$id = (int) $match[2];
|
||||
|
||||
$params = $match[3];
|
||||
|
||||
if ( 'regexp_ent' === $reg ) {
|
||||
$params = html_entity_decode( $params, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
|
||||
}
|
||||
|
||||
$params = wp_kses_hair( $params, array( 'http' ) );
|
||||
|
||||
$width = isset( $params['width'] ) ? (int) $params['width']['value'] : 0;
|
||||
$height = isset( $params['height'] ) ? (int) $params['height']['value'] : 0;
|
||||
|
||||
$wh = '';
|
||||
if ( $width && $height ) {
|
||||
$wh = ' w=' . $width . ' h=' . $height;
|
||||
}
|
||||
|
||||
$shortcode = '[vimeo ' . $id . $wh . ']';
|
||||
$content = str_replace( $match[0], $shortcode, $content );
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
add_filter( 'pre_kses', 'vimeo_embed_to_shortcode' );
|
||||
|
||||
/**
|
||||
* Replaces shortcodes and plain-text URLs to Vimeo videos with Vimeo embeds.
|
||||
* Covers shortcode usage [vimeo 1234] | [vimeo https://vimeo.com/1234] | [vimeo http://vimeo.com/1234]
|
||||
* Or plain text URLs https://vimeo.com/1234 | vimeo.com/1234 | //vimeo.com/1234
|
||||
* Links are left intact.
|
||||
*
|
||||
* @since 3.7.0
|
||||
* @since 3.9.5 One regular expression matches shortcodes and plain URLs.
|
||||
*
|
||||
* @param string $content HTML content.
|
||||
*
|
||||
* @return string The content with embeds instead of URLs
|
||||
*/
|
||||
function vimeo_link( $content ) {
|
||||
/**
|
||||
* [vimeo 12345]
|
||||
* [vimeo http://vimeo.com/12345]
|
||||
*/
|
||||
$shortcode = '(?:\[vimeo\s+[^0-9]*)([0-9]+)(?:\])';
|
||||
|
||||
/**
|
||||
* Regex to look for a Vimeo link.
|
||||
*
|
||||
* - http://vimeo.com/12345
|
||||
* - https://vimeo.com/12345
|
||||
* - //vimeo.com/12345
|
||||
* - vimeo.com/some/descender/12345
|
||||
*
|
||||
* Should not capture inside HTML attributes
|
||||
* [Not] <a href="vimeo.com/12345">Cool Video</a>
|
||||
* [Not] <a href="https://vimeo.com/12345">vimeo.com/12345</a>
|
||||
*
|
||||
* Could erroneously capture:
|
||||
* <a href="some.link/maybe/even/vimeo">This video (vimeo.com/12345) is teh cat's meow!</a>
|
||||
*/
|
||||
$plain_url = "(?:[^'\">]?\/?(?:https?:\/\/)?vimeo\.com\/(?:groups\/\d+\/videos\/|album\/\d+\/video\/|video\/|channels\/[^\/]+\/videos\/|[^\/]+\/)?)([0-9]+)(?:[^'\"0-9<]|$)";
|
||||
|
||||
return jetpack_preg_replace_callback_outside_tags(
|
||||
sprintf( '#%s|%s#i', $shortcode, $plain_url ),
|
||||
'vimeo_link_callback',
|
||||
$content,
|
||||
'vimeo'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for the regex that replaces Vimeo URLs with Vimeo embeds.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @param array $matches An array containing a Vimeo URL.
|
||||
* @return string The Vimeo HTML embed code.
|
||||
*/
|
||||
function vimeo_link_callback( $matches ) {
|
||||
$id = isset( $matches[2] ) ? $matches[2] : $matches[1];
|
||||
if ( isset( $id ) && ctype_digit( $id ) ) {
|
||||
return "\n" . vimeo_shortcode( array( 'id' => $id ) ) . "\n";
|
||||
}
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
if (
|
||||
! is_admin()
|
||||
/** This filter is documented in modules/shortcodes/youtube.php */
|
||||
&& apply_filters( 'jetpack_comments_allow_oembed', true )
|
||||
// No need for this on WordPress.com, this is done for multiple shortcodes at a time there.
|
||||
&& ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM )
|
||||
) {
|
||||
/*
|
||||
* We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway,
|
||||
* so the iframe gets filtered out.
|
||||
* Higher priority because we need it before auto-link and autop get to it
|
||||
*/
|
||||
add_filter( 'comment_text', 'vimeo_link', 1 );
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/**
|
||||
* Vine shortcode
|
||||
* The service is now archived, but existing embeds are still accessible.
|
||||
*
|
||||
* Examples:
|
||||
* Vine embed code:
|
||||
* <iframe class="vine-embed" src="https://vine.co/v/bjHh0zHdgZT" width="600" height="600" frameborder="0"></iframe>
|
||||
* <script async src="//platform.vine.co/static/scripts/embed.js" charset="utf-8"></script>
|
||||
*
|
||||
* URL example:
|
||||
* https://vine.co/v/bjHh0zHdgZT/
|
||||
*
|
||||
* Embed shortcode examples:
|
||||
* [embed]https://vine.co/v/bjHh0zHdgZT[/embed]
|
||||
* [embed width="300"]https://vine.co/v/bjHh0zHdgZT[/embed]
|
||||
* [embed type="postcard" width="300"]https://vine.co/v/bjHh0zHdgZT[/embed]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handle Vine embeds.
|
||||
*
|
||||
* @param array $matches Results after parsing the URL using the regex in wp_embed_register_handler().
|
||||
* @param array $attr Embed attributes.
|
||||
* @param string $url The original URL that was matched by the regex.
|
||||
* @param array $rawattr The original unmodified attributes.
|
||||
* @return string The embed HTML.
|
||||
*/
|
||||
function vine_embed_video( $matches, $attr, $url, $rawattr ) {
|
||||
$max_height = 300;
|
||||
$type = 'simple';
|
||||
|
||||
// Only allow 'postcard' or 'simple' types.
|
||||
if (
|
||||
isset( $rawattr['type'] )
|
||||
&& 'postcard' === $rawattr['type']
|
||||
) {
|
||||
$type = 'postcard';
|
||||
}
|
||||
|
||||
$vine_size = Jetpack::get_content_width();
|
||||
|
||||
// If the user enters a value for width or height, we ignore the Jetpack::get_content_width().
|
||||
if ( isset( $rawattr['width'] ) || isset( $rawattr['height'] ) ) {
|
||||
// 300 is the minimum size that Vine provides for embeds. Lower than that, the postcard embeds looks weird.
|
||||
$vine_size = max( $max_height, min( $attr['width'], $attr['height'] ) );
|
||||
}
|
||||
|
||||
if ( empty( $vine_size ) ) {
|
||||
$vine_size = $max_height;
|
||||
}
|
||||
|
||||
$url = 'https://vine.co/v/' . $matches[1] . '/embed/' . $type;
|
||||
$vine_html = sprintf(
|
||||
'<span class="embed-vine" style="display: block;"><iframe class="vine-embed" src="%1$s" width="%2$d" height="%3$d" frameborder="0"></iframe></span>',
|
||||
esc_url( $url ),
|
||||
(int) $vine_size,
|
||||
(int) $vine_size
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'vine-embed',
|
||||
'https://platform.vine.co/static/scripts/embed.js',
|
||||
array(),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
return $vine_html;
|
||||
}
|
||||
wp_embed_register_handler( 'jetpack_vine', '#https?://vine.co/v/([a-z0-9]+).*#i', 'vine_embed_video' );
|
||||
|
||||
/**
|
||||
* Display the Vine shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function vine_shortcode( $atts ) {
|
||||
global $wp_embed;
|
||||
|
||||
if ( empty( $atts['url'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( ! preg_match( '#https?://vine.co/v/([a-z0-9]+).*#i', $atts['url'] ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $wp_embed->shortcode( $atts, $atts['url'] );
|
||||
}
|
||||
add_shortcode( 'vine', 'vine_shortcode' );
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/**
|
||||
* VR Viewer Shortcode
|
||||
* converts [vr] shortcode to an iframe viewer hosted on vr.me.sh
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Scrub URL paramaters for VR viewer
|
||||
*
|
||||
* @param array $params {
|
||||
* parameter array which is passed to the jetpack_vr_viewer.
|
||||
*
|
||||
* @type string $url url of 360 media
|
||||
* @type string $guid guid for videopress
|
||||
* @type string $view cinema, 360 - controls if panaroma view, or 360
|
||||
* @type string $rotation number for rotating media
|
||||
* @type string $preview show preview image or not
|
||||
* }
|
||||
*
|
||||
* @return array|false $url_params Array of URL parameters.
|
||||
*/
|
||||
function jetpack_vr_viewer_get_viewer_url_params( $params ) {
|
||||
$url_params = array();
|
||||
|
||||
if ( isset( $params['rotation'] ) ) {
|
||||
$url_params['rotation'] = (int) $params['rotation'];
|
||||
}
|
||||
|
||||
if ( isset( $params['view'] ) && in_array( $params['view'], array( 'cinema', '360' ), true ) ) {
|
||||
$url_params['view'] = $params['view'];
|
||||
}
|
||||
|
||||
if ( isset( $params['preview'] ) && $params['preview'] ) {
|
||||
$url_params['preview'] = 1;
|
||||
}
|
||||
|
||||
if ( isset( $params['url'] ) ) {
|
||||
return array_merge( $url_params, array( 'url' => $params['url'] ) );
|
||||
} elseif ( isset( $params['guid'] ) ) {
|
||||
return array_merge( $url_params, array( 'guid' => $params['guid'] ) );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get padding for IFRAME depending on view type
|
||||
*
|
||||
* @param string $view string cinema, 360 - default cinema.
|
||||
*
|
||||
* @return string $css padding
|
||||
*/
|
||||
function jetpack_vr_viewer_iframe_padding( $view ) {
|
||||
if ( '360' === $view ) {
|
||||
return '100%'; // 1:1 square aspect for 360
|
||||
}
|
||||
|
||||
return '50%'; // 2:1 panorama aspect
|
||||
}
|
||||
|
||||
/**
|
||||
* Create HTML for VR Viewer IFRAME and wrapper
|
||||
* The viewer code is hosted on vr.me.sh site which is then displayed
|
||||
* within posts via an IFRAME. This function returns the IFRAME html.
|
||||
*
|
||||
* @param array $url_params {
|
||||
* parameter array which is passed to the jetpack_vr_viewer.
|
||||
*
|
||||
* @type string $url url of 360 media
|
||||
* @type string $guid guid for videopress
|
||||
* @type string $view cinema, 360 - controls if panaroma view, or 360
|
||||
* @type string $rotation number for rotating media
|
||||
* @type string $preview show preview image or not
|
||||
* }
|
||||
*
|
||||
* @return string $rtn an iframe for viewer.
|
||||
*/
|
||||
function jetpack_vr_viewer_get_html( $url_params ) {
|
||||
global $content_width;
|
||||
|
||||
$iframe = add_query_arg( $url_params, 'https://vr.me.sh/view/' );
|
||||
|
||||
// set some defaults.
|
||||
$maxwidth = ( is_numeric( $content_width ) && $content_width > 0 ) ? $content_width : 720;
|
||||
$view = ( isset( $url_params['view'] ) ) ? $url_params['view'] : 'cinema';
|
||||
|
||||
// If the shortcode is displayed in a WPCOM notification, display a simple link only.
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
require_once WP_CONTENT_DIR . '/lib/display-context.php';
|
||||
$context = A8C\Display_Context\get_current_context();
|
||||
if ( A8C\Display_Context\NOTIFICATIONS === $context ) {
|
||||
return sprintf(
|
||||
'<a href="%1$s" target="_blank" rel="noopener noreferrer">%1$s</a>',
|
||||
esc_url( $iframe )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$rtn = '<div style="position: relative; max-width: ' . $maxwidth . 'px; margin-left: auto; margin-right: auto; overflow: hidden; margin-bottom: 1em;">';
|
||||
$rtn .= '<div style="padding-top: ' . jetpack_vr_viewer_iframe_padding( $view ) . ';"></div>';
|
||||
$rtn .= '<iframe style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; height: 100%" allowfullscreen="true" frameborder="0" width="100%" height="300" src="' . esc_url( $iframe ) . '">';
|
||||
$rtn .= '</iframe>';
|
||||
$rtn .= '</div>';
|
||||
|
||||
return $rtn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert [vr] shortcode to viewer
|
||||
*
|
||||
* Shortcode example:
|
||||
* [vr url="https://en-blog.files.wordpress.com/2016/12/regents_park.jpg" view="360"]
|
||||
*
|
||||
* VR Viewer embed code:
|
||||
* <div style="position: relative; max-width: 720px; margin-left: auto; margin-right: auto; overflow: hidden;">
|
||||
* <div style="padding-top: 100%;"></div>
|
||||
* <iframe style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; height: 100%" allowfullscreen="true" frameborder="0" width="100%" height="400" src="https://vr.me.sh/view/?view=360&url=https://en-blog.files.wordpress.com/2016/12/regents_park.jpg">
|
||||
* </iframe>
|
||||
* </div>
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*
|
||||
* @return string complete vr viewer html
|
||||
*/
|
||||
function jetpack_vr_viewer_shortcode( $atts ) {
|
||||
$params = shortcode_atts(
|
||||
array(
|
||||
0 => null,
|
||||
'url' => null,
|
||||
'src' => null,
|
||||
'guid' => null,
|
||||
'rotation' => null,
|
||||
'view' => null,
|
||||
'preview' => false,
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
// We offer a few ways to specify the URL.
|
||||
if ( $params[0] ) {
|
||||
$params['url'] = $params[0];
|
||||
} elseif ( $params['src'] ) {
|
||||
$params['url'] = $params['src'];
|
||||
}
|
||||
|
||||
$url_params = jetpack_vr_viewer_get_viewer_url_params( $params );
|
||||
if ( $url_params ) {
|
||||
return jetpack_vr_viewer_get_html( $url_params );
|
||||
}
|
||||
|
||||
// add check for user.
|
||||
if ( current_user_can( 'edit_posts' ) ) {
|
||||
return '[vr] shortcode requires a data source to be given';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
add_shortcode( 'vr', 'jetpack_vr_viewer_shortcode' );
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Wufoo Shortcode
|
||||
* Based on https://wordpress.org/plugins/wufoo-shortcode/
|
||||
*
|
||||
* Examples:
|
||||
* [wufoo username="jeherve" formhash="z1x13ltw1m8jtrw" autoresize="true" height="338" header="show"]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Display the Wufoo shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*/
|
||||
function wufoo_shortcode( $atts ) {
|
||||
$attr = shortcode_atts(
|
||||
array(
|
||||
'username' => '',
|
||||
'formhash' => '',
|
||||
'autoresize' => true,
|
||||
'height' => '500',
|
||||
'header' => 'show',
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
// Check username and formhash to ensure they only have alphanumeric characters or underscores, and aren't empty.
|
||||
if (
|
||||
! preg_match( '/^[a-zA-Z0-9_]+$/', $attr['username'] )
|
||||
|| ! preg_match( '/^[a-zA-Z0-9_]+$/', $attr['formhash'] )
|
||||
) {
|
||||
/*
|
||||
* Return an error to the users with instructions if one of these params is invalid
|
||||
* They don't have default values because they are user/form-specific
|
||||
*/
|
||||
if ( current_user_can( 'edit_posts' ) ) {
|
||||
return sprintf(
|
||||
wp_kses(
|
||||
/* translators: URL to Wufoo support page. */
|
||||
__( 'Something is wrong with your Wufoo shortcode. Try following the instructions <a href="%s" target="_blank" rel="noopener noreferrer">here</a> to embed a form on your site.', 'jetpack' ),
|
||||
array(
|
||||
'a' => array(
|
||||
'href' => array(),
|
||||
'target' => array(),
|
||||
'rel' => array(),
|
||||
),
|
||||
)
|
||||
),
|
||||
'https://help.wufoo.com/articles/en_US/kb/Embed'
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Placeholder which will tell Wufoo where to render the form.
|
||||
*/
|
||||
$js_embed_placeholder = sprintf(
|
||||
'<div id="wufoo-%s"></div>',
|
||||
esc_attr( $attr['formhash'] )
|
||||
);
|
||||
|
||||
/**
|
||||
* Required parameters are present.
|
||||
* An error will be returned inside the form if they are invalid.
|
||||
*/
|
||||
$js_embed = sprintf(
|
||||
'(function(){try{var wufoo_%1$s = new WufooForm();wufoo_%1$s.initialize({"userName":"%2$s","formHash":"%1$s","autoResize":%3$s,"height":"%4$d","header":"%5$s","ssl":true,"async":true});wufoo_%1$s.display();}catch(e){}})();',
|
||||
esc_attr( $attr['formhash'] ),
|
||||
esc_attr( $attr['username'] ),
|
||||
'true' == $attr['autoresize'] ? 'true' : 'false', // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
|
||||
absint( $attr['height'] ),
|
||||
'show' === $attr['header'] ? 'show' : 'hide'
|
||||
);
|
||||
|
||||
// Embed URL.
|
||||
$embed_url = sprintf(
|
||||
'https://%1$s.wufoo.com/embed/%2$s/',
|
||||
$attr['username'],
|
||||
$attr['formhash']
|
||||
);
|
||||
|
||||
// Form URL.
|
||||
$form_url = sprintf(
|
||||
'https://%1$s.wufoo.com/forms/%2$s/',
|
||||
$attr['username'],
|
||||
$attr['formhash']
|
||||
);
|
||||
|
||||
/*
|
||||
* iframe embed, loaded inside <noscript> tags.
|
||||
*/
|
||||
$iframe_embed = sprintf(
|
||||
'<iframe height="%1$d" src="%2$s" allowTransparency="true" frameborder="0" scrolling="no" style="width:100%%;border:none;">
|
||||
<a href="%3$s" target="_blank" rel="noopener noreferrer">%4$s</a>
|
||||
</iframe>',
|
||||
absint( $attr['height'] ),
|
||||
esc_url( $embed_url ),
|
||||
esc_url( $form_url ),
|
||||
esc_html__( 'Fill out my Wufoo form!', 'jetpack' )
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'wufoo-form',
|
||||
'https://www.wufoo.com/scripts/embed/form.js',
|
||||
array(),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
wp_add_inline_script( 'wufoo-form', $js_embed );
|
||||
|
||||
/** This action is already documented in modules/widgets/gravatar-profile.php */
|
||||
do_action( 'jetpack_stats_extra', 'embeds', 'wufoo' );
|
||||
|
||||
/**
|
||||
* Return embed in JS and iframe.
|
||||
*/
|
||||
return "$js_embed_placeholder<noscript>$iframe_embed</noscript>";
|
||||
}
|
||||
add_shortcode( 'wufoo', 'wufoo_shortcode' );
|
||||
@@ -0,0 +1,664 @@
|
||||
<?php
|
||||
/**
|
||||
* Youtube shortcode
|
||||
*
|
||||
* Contains shortcode + some improvements over the Core Embeds syntax (see http://codex.wordpress.org/Embeds )
|
||||
*
|
||||
* Examples:
|
||||
* [youtube https://www.youtube.com/watch?v=WVbQ-oro7FQ]
|
||||
* [youtube=http://www.youtube.com/watch?v=wq0rXGLs0YM&fs=1&hl=bg_BG&autohide=1&rel=0]
|
||||
* http://www.youtube.com/watch?v=H2Ncxw1xfck&w=320&h=240&fmt=1&rel=0&showsearch=1&hd=0
|
||||
* http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US
|
||||
* https://www.youtube.com/playlist?list=PLP7HaNDU4Cifov7C2fQM8Ij6Ew_uPHEXW
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Replaces YouTube embeds with YouTube shortcodes.
|
||||
*
|
||||
* Covers the following formats:
|
||||
* 2008-07-15:
|
||||
* <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/bZBHZT3a-FA&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/bZBHZT3a-FA&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object>
|
||||
* around 2008-06-06 youtube changed their old embed code to this:
|
||||
* <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/M1D30gS7Z8U&hl=en"></param><embed src="http://www.youtube.com/v/M1D30gS7Z8U&hl=en" type="application/x-shockwave-flash" width="425" height="344"></embed></object>
|
||||
* old style was:
|
||||
* <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/dGY28Qbj76A&rel=0"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/dGY28Qbj76A&rel=0" type="application/x-shockwave-flash" wmode="transparent" width="425" height="344"></embed></object>
|
||||
* 12-2010:
|
||||
* <object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/3H8bnKdf654?fs=1&hl=en_GB"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/3H8bnKdf654?fs=1&hl=en_GB" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object>
|
||||
* 01-2011:
|
||||
* <iframe title="YouTube video player" class="youtube-player" width="640" height="390" src="http://www.youtube.com/embed/Qq9El3ki0_g" frameborder="0" allowFullScreen></iframe>
|
||||
* <iframe class="youtube-player" width="640" height="385" src="http://www.youtube.com/embed/VIDEO_ID" frameborder="0"></iframe>
|
||||
*
|
||||
* @param string $content HTML content.
|
||||
* @return string The content with YouTube embeds replaced with YouTube shortcodes.
|
||||
*/
|
||||
function youtube_embed_to_short_code( $content ) {
|
||||
if ( ! is_string( $content ) || ! str_contains( $content, 'youtube.com' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
// older codes.
|
||||
$regexp = '!<object(.*?)>.*?<param\s+name=[\'"]movie[\'"]\s+value=[\'"](https?:)?//www\.youtube\.com/v/([^\'"]+)[\'"].*?>.*?</object>!i';
|
||||
$regexp_ent = htmlspecialchars( $regexp, ENT_NOQUOTES );
|
||||
$old_regexp = '!<embed(?:\s+\w+="[^"]*")*\s+src="https?(?:\:|�*58;)//www\.youtube\.com/v/([^"]+)"(?:\s+\w+="[^"]*")*\s*(?:/>|>\s*</embed>)!';
|
||||
$old_regexp_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $old_regexp, ENT_NOQUOTES ) );
|
||||
|
||||
// new code.
|
||||
$ifr_regexp = '!<iframe((?:\s+\w+="[^"]*")*?)\s+src="(https?:)?//(?:www\.)*youtube.com/embed/([^"]+)".*?</iframe>!i';
|
||||
$ifr_regexp_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $ifr_regexp, ENT_NOQUOTES ) );
|
||||
|
||||
foreach ( compact( 'regexp', 'regexp_ent', 'old_regexp', 'old_regexp_ent', 'ifr_regexp', 'ifr_regexp_ent' ) as $reg => $regexp ) {
|
||||
if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $matches as $match ) {
|
||||
/*
|
||||
* Hack, but '?' should only ever appear once, and
|
||||
* it should be for the 1st field-value pair in query string,
|
||||
* if it is present
|
||||
* YouTube changed their embed code.
|
||||
* Example of how it is now:
|
||||
* <object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/aP9AaD4tgBY?fs=1&hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/aP9AaD4tgBY?fs=1&hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object>
|
||||
* As shown at the start of function, previous YouTube didn't '?'
|
||||
* the 1st field-value pair.
|
||||
*/
|
||||
if ( in_array( $reg, array( 'ifr_regexp', 'ifr_regexp_ent', 'regexp', 'regexp_ent' ), true ) ) {
|
||||
$params = $match[1];
|
||||
|
||||
if ( in_array( $reg, array( 'ifr_regexp_ent', 'regexp_ent' ), true ) ) {
|
||||
$params = html_entity_decode( $params, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
|
||||
}
|
||||
|
||||
$params = wp_kses_hair( $params, array( 'http' ) );
|
||||
|
||||
$width = isset( $params['width'] ) ? (int) $params['width']['value'] : 0;
|
||||
$height = isset( $params['height'] ) ? (int) $params['height']['value'] : 0;
|
||||
$wh = '';
|
||||
|
||||
if ( $width && $height ) {
|
||||
$wh = "&w=$width&h=$height";
|
||||
}
|
||||
|
||||
$url = esc_url_raw( "https://www.youtube.com/watch?v={$match[3]}{$wh}" );
|
||||
} else {
|
||||
$match[1] = str_replace( '?', '&', $match[1] );
|
||||
|
||||
$url = esc_url_raw( 'https://www.youtube.com/watch?v=' . html_entity_decode( $match[1], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ) );
|
||||
}
|
||||
|
||||
$content = str_replace( $match[0], "[youtube $url]", $content );
|
||||
|
||||
/**
|
||||
* Fires before the YouTube embed is transformed into a shortcode.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 1.2.0
|
||||
*
|
||||
* @param string youtube Shortcode name.
|
||||
* @param string $url YouTube video URL.
|
||||
*/
|
||||
do_action( 'jetpack_embed_to_shortcode', 'youtube', $url );
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
add_filter( 'pre_kses', 'youtube_embed_to_short_code' );
|
||||
|
||||
/**
|
||||
* Replaces plain-text links to YouTube videos with YouTube embeds.
|
||||
*
|
||||
* @param string $content HTML content.
|
||||
*
|
||||
* @return string The content with embeds instead of URLs
|
||||
*/
|
||||
function youtube_link( $content ) {
|
||||
return jetpack_preg_replace_callback_outside_tags( '!(?:\n|\A)https?://(?:www\.)?(?:youtube.com/(?:v/|playlist|watch[/\#?])|youtu\.be/)[^\s]+?(?:\n|\Z)!i', 'youtube_link_callback', $content, 'youtube.com/' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for the regex that replaces YouTube URLs with
|
||||
* YouTube embeds.
|
||||
*
|
||||
* @param array $matches An array containing a YouTube URL.
|
||||
*/
|
||||
function youtube_link_callback( $matches ) {
|
||||
return "\n" . youtube_id( $matches[0] ) . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a YouTube URL to include a v= parameter and a query string free of encoded ampersands.
|
||||
*
|
||||
* @param string|array $url Youtube URL.
|
||||
* @return string|false The normalized URL or false if input is invalid.
|
||||
*/
|
||||
if ( ! function_exists( 'youtube_sanitize_url' ) ) :
|
||||
/**
|
||||
* Clean up Youtube URL to match a single format.
|
||||
*
|
||||
* @param string|array $url Youtube URL.
|
||||
*/
|
||||
function youtube_sanitize_url( $url ) {
|
||||
if ( is_array( $url ) && isset( $url['url'] ) ) {
|
||||
$url = $url['url'];
|
||||
}
|
||||
if ( ! is_string( $url ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$url = trim( $url, ' "' );
|
||||
$url = trim( $url );
|
||||
$url = str_replace( array( 'youtu.be/', '/v/', '#!v=', '&', '&', 'playlist' ), array( 'youtu.be/?v=', '/?v=', '?v=', '&', '&', 'videoseries' ), $url );
|
||||
|
||||
// Replace any extra question marks with ampersands - the result of a URL like "http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US" being passed in.
|
||||
$query_string_start = strpos( $url, '?' );
|
||||
|
||||
if ( false !== $query_string_start ) {
|
||||
$url = substr( $url, 0, $query_string_start + 1 ) . str_replace( '?', '&', substr( $url, $query_string_start + 1 ) );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
endif;
|
||||
|
||||
/**
|
||||
* Converts a YouTube URL into an embedded YouTube video.
|
||||
*
|
||||
* URL can be:
|
||||
* http://www.youtube.com/embed/videoseries?list=PL94269DA08231042B&hl=en_US
|
||||
* http://www.youtube.com/watch#!v=H2Ncxw1xfck
|
||||
* http://www.youtube.com/watch?v=H2Ncxw1xfck
|
||||
* http://www.youtube.com/watch?v=H2Ncxw1xfck&w=320&h=240&fmt=1&rel=0&showsearch=1&hd=0
|
||||
* http://www.youtube.com/v/jF-kELmmvgA
|
||||
* http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US
|
||||
* http://youtu.be/Rrohlqeir5E
|
||||
* https://www.youtube.com/watch?v=GJNxoe-iSb4&list=PLAVZ4NFtZX0fE54mDSqNKym-o_rz-8xmk
|
||||
*
|
||||
* @param string $url Youtube URL.
|
||||
*/
|
||||
function youtube_id( $url ) {
|
||||
$id = jetpack_get_youtube_id( $url );
|
||||
|
||||
if ( ! $id ) {
|
||||
return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: bad URL entered', 'jetpack' ) );
|
||||
}
|
||||
|
||||
$url = youtube_sanitize_url( $url );
|
||||
$url = wp_parse_url( $url );
|
||||
|
||||
$thumbnail = "https://i.ytimg.com/vi/$id/hqdefault.jpg";
|
||||
$video_url = add_query_arg( 'v', $id, 'https://www.youtube.com/watch' );
|
||||
|
||||
$args = jetpack_shortcode_youtube_args( $url );
|
||||
if ( empty( $args ) ) {
|
||||
return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: empty URL args', 'jetpack' ) );
|
||||
}
|
||||
|
||||
// Account for URL having both v and list, where jetpack_get_youtube_id() only accounts for one or the other.
|
||||
if ( isset( $args['list'] ) && $args['list'] === $id ) {
|
||||
$id = null;
|
||||
}
|
||||
if ( isset( $args['v'] ) ) {
|
||||
$id = $args['v'];
|
||||
}
|
||||
if ( ! $id && empty( $args['list'] ) ) {
|
||||
return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: missing id and/or list', 'jetpack' ) );
|
||||
}
|
||||
|
||||
list( $w, $h ) = jetpack_shortcode_youtube_dimensions( $args );
|
||||
|
||||
$params = array(
|
||||
'rel' => ( isset( $args['rel'] ) && '0' === $args['rel'] ) ? 0 : 1,
|
||||
'showsearch' => ( isset( $args['showsearch'] ) && '1' === $args['showsearch'] ) ? 1 : 0, // Now deprecated. See https://developers.google.com/youtube/player_parameters#march-29,-2012.
|
||||
'showinfo' => ( isset( $args['showinfo'] ) && '0' === $args['showinfo'] ) ? 0 : 1, // Now obsolete. See https://developers.google.com/youtube/player_parameters#showinfo.
|
||||
'iv_load_policy' => ( isset( $args['iv_load_policy'] ) && '3' === $args['iv_load_policy'] ) ? 3 : 1,
|
||||
'fs' => 1,
|
||||
'hl' => str_replace( '_', '-', get_locale() ),
|
||||
);
|
||||
if ( isset( $args['fmt'] ) && (int) $args['fmt'] ) {
|
||||
$params['fmt'] = (int) $args['fmt']; // Apparently an obsolete parameter. Not referenced on https://developers.google.com/youtube/player_parameters.
|
||||
}
|
||||
|
||||
// The autohide parameter has been deprecated since 2015. See https://developers.google.com/youtube/player_parameters#august-19,-2015.
|
||||
if ( ! isset( $args['autohide'] ) || ( $args['autohide'] < 0 || 2 < $args['autohide'] ) ) {
|
||||
$params['autohide'] = 2;
|
||||
} else {
|
||||
$params['autohide'] = (int) $args['autohide'];
|
||||
}
|
||||
|
||||
$start = 0;
|
||||
if ( isset( $args['start'] ) ) {
|
||||
$start = (int) $args['start'];
|
||||
} elseif ( isset( $args['t'] ) ) {
|
||||
if ( is_numeric( $args['t'] ) ) {
|
||||
$start = (int) $args['t'];
|
||||
} elseif ( is_string( $args['t'] ) ) {
|
||||
$time_pieces = preg_split( '/(?<=\D)(?=\d+)/', $args['t'] );
|
||||
|
||||
foreach ( $time_pieces as $time_piece ) {
|
||||
$int = (int) $time_piece;
|
||||
switch ( substr( $time_piece, - 1 ) ) {
|
||||
case 'h':
|
||||
$start += $int * 3600;
|
||||
break;
|
||||
case 'm':
|
||||
$start += $int * 60;
|
||||
break;
|
||||
case 's':
|
||||
$start += $int;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( $start ) {
|
||||
$params['start'] = (int) $start;
|
||||
}
|
||||
|
||||
if ( isset( $args['end'] ) && (int) $args['end'] ) {
|
||||
$params['end'] = (int) $args['end'];
|
||||
}
|
||||
if ( isset( $args['hd'] ) && (int) $args['hd'] ) {
|
||||
$params['hd'] = (int) $args['hd']; // Now obsolete per https://developers.google.com/youtube/player_parameters#march-29,-2012.
|
||||
}
|
||||
if ( isset( $args['vq'] ) && in_array( $args['vq'], array( 'hd720', 'hd1080' ), true ) ) {
|
||||
$params['vq'] = $args['vq']; // Note, this appears to be obsolete. Not referenced on https://developers.google.com/youtube/player_parameters.
|
||||
}
|
||||
if ( isset( $args['cc_load_policy'] ) ) {
|
||||
$params['cc_load_policy'] = 1;
|
||||
}
|
||||
if ( isset( $args['cc_lang_pref'] ) ) {
|
||||
$params['cc_lang_pref'] = preg_replace( '/[^_a-z0-9-]/i', '', $args['cc_lang_pref'] );
|
||||
}
|
||||
|
||||
// The wmode parameter appears to be obsolete. Not referenced on https://developers.google.com/youtube/player_parameters.
|
||||
if ( isset( $args['wmode'] ) && in_array( strtolower( $args['wmode'] ), array( 'opaque', 'window', 'transparent' ), true ) ) {
|
||||
$params['wmode'] = $args['wmode'];
|
||||
} else {
|
||||
$params['wmode'] = 'transparent';
|
||||
}
|
||||
|
||||
// The theme parameter is obsolete per https://developers.google.com/youtube/player_parameters#august-19,-2015.
|
||||
if ( isset( $args['theme'] ) && in_array( strtolower( $args['theme'] ), array( 'dark', 'light' ), true ) ) {
|
||||
$params['theme'] = $args['theme'];
|
||||
}
|
||||
|
||||
if ( isset( $args['list'] ) ) {
|
||||
$params['listType'] = 'playlist';
|
||||
$params['list'] = preg_replace( '|[^_a-z0-9-]|i', '', $args['list'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow YouTube videos to start playing automatically.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 2.2.2
|
||||
*
|
||||
* @param bool false Enable autoplay for YouTube videos.
|
||||
*/
|
||||
if ( apply_filters( 'jetpack_youtube_allow_autoplay', false ) && isset( $args['autoplay'] ) ) {
|
||||
$params['autoplay'] = (int) $args['autoplay'];
|
||||
}
|
||||
|
||||
$is_amp = class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request();
|
||||
|
||||
if ( $is_amp && $id ) {
|
||||
// Note that <amp-youtube> currently is not well suited for playlists that don't have an individual video selected, hence the $id check above.
|
||||
$placeholder = sprintf(
|
||||
'<a href="%1$s" placeholder><amp-img src="%2$s" alt="%3$s" layout="fill" object-fit="cover"><noscript><img src="%2$s" loading="lazy" decoding="async" alt="%3$s"></noscript></amp-img></a>',
|
||||
esc_url( $video_url ),
|
||||
esc_url( $thumbnail ),
|
||||
esc_attr__( 'YouTube Poster', 'jetpack' ) // Would be preferable to provide YouTube video title, but not available in this non-oEmbed context.
|
||||
);
|
||||
|
||||
$html_attributes = array();
|
||||
foreach ( $params as $param_name => $param_value ) {
|
||||
$html_attributes[] = sprintf(
|
||||
'data-param-%s="%s"',
|
||||
sanitize_key( $param_name ),
|
||||
esc_attr( $param_value )
|
||||
);
|
||||
}
|
||||
|
||||
$html = sprintf(
|
||||
'<amp-youtube data-videoid="%s" %s width="%d" height="%d" layout="responsive">%s</amp-youtube>',
|
||||
esc_attr( $id ),
|
||||
implode( ' ', $html_attributes ), // Note: Escaping done above.
|
||||
esc_attr( $w ),
|
||||
esc_attr( $h ),
|
||||
$placeholder
|
||||
);
|
||||
} else {
|
||||
// In AMP, the AMP_Iframe_Sanitizer will convert into <amp-iframe> as required.
|
||||
$src = 'https://www.youtube.com/embed';
|
||||
if ( $id ) {
|
||||
$src .= "/$id";
|
||||
}
|
||||
$src = add_query_arg(
|
||||
array_merge(
|
||||
array( 'version' => 3 ),
|
||||
$params
|
||||
),
|
||||
$src
|
||||
);
|
||||
|
||||
$layout = $is_amp ? 'layout="responsive" ' : '';
|
||||
|
||||
$html = sprintf(
|
||||
'<iframe class="youtube-player" width="%s" height="%s" %ssrc="%s" allowfullscreen="true" style="border:0;" sandbox="allow-scripts allow-same-origin allow-popups allow-presentation allow-popups-to-escape-sandbox"></iframe>',
|
||||
esc_attr( $w ),
|
||||
esc_attr( $h ),
|
||||
$layout,
|
||||
esc_url( $src )
|
||||
);
|
||||
}
|
||||
|
||||
// Let's do some alignment wonder in a span, unless we're producing a feed.
|
||||
if ( ! is_feed() ) {
|
||||
$alignmentcss = 'text-align:center;';
|
||||
if ( isset( $args['align'] ) ) {
|
||||
switch ( $args['align'] ) {
|
||||
case 'left':
|
||||
$alignmentcss = "float:left; width:{$w}px; height:{$h}px; margin-right:10px; margin-bottom: 10px;";
|
||||
break;
|
||||
case 'right':
|
||||
$alignmentcss = "float:right; width:{$w}px; height:{$h}px; margin-left:10px; margin-bottom: 10px;";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$html = sprintf(
|
||||
'<span class="embed-youtube" style="%s display: block;">%s</span>',
|
||||
esc_attr( $alignmentcss ),
|
||||
$html
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Format output for Calypso Reader/Notifications/Comments
|
||||
*/
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
require_once WP_CONTENT_DIR . '/lib/display-context.php';
|
||||
$context = A8C\Display_Context\get_current_context();
|
||||
if ( A8C\Display_Context\NOTIFICATIONS === $context ) {
|
||||
return sprintf(
|
||||
'<a href="%1$s" target="_blank" rel="noopener noreferrer"><img src="%2$s" alt="%3$s" /></a>',
|
||||
esc_url( $video_url ),
|
||||
esc_url( $thumbnail ),
|
||||
esc_html__( 'YouTube video', 'jetpack' )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the YouTube video HTML output.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 1.2.3
|
||||
*
|
||||
* @param string $html YouTube video HTML output.
|
||||
*/
|
||||
$html = apply_filters( 'video_embed_html', $html );
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the args present in the YouTube shortcode URL.
|
||||
*
|
||||
* @since 8.0.0
|
||||
*
|
||||
* @param array $url The parsed URL of the shortcode.
|
||||
*
|
||||
* @return array|false The query args of the URL, or false.
|
||||
*/
|
||||
function jetpack_shortcode_youtube_args( $url ) {
|
||||
$qargs = array();
|
||||
if ( ! empty( $url['query'] ) ) {
|
||||
wp_parse_str( $url['query'], $qargs );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
$fargs = array();
|
||||
if ( ! empty( $url['fragment'] ) ) {
|
||||
wp_parse_str( $url['fragment'], $fargs );
|
||||
}
|
||||
|
||||
return array_merge( $fargs, $qargs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the Youtube shortcode.
|
||||
*
|
||||
* @param array $atts Shortcode attributes.
|
||||
*
|
||||
* @return string The rendered shortcode.
|
||||
*/
|
||||
function youtube_shortcode( $atts ) {
|
||||
$url = ( isset( $atts[0] ) ) ? ltrim( $atts[0], '=' ) : shortcode_new_to_old_params( $atts );
|
||||
return youtube_id( $url );
|
||||
}
|
||||
add_shortcode( 'youtube', 'youtube_shortcode' );
|
||||
|
||||
/**
|
||||
* Gets the dimensions of the [youtube] shortcode.
|
||||
*
|
||||
* Calculates the width and height, taking $content_width into consideration.
|
||||
*
|
||||
* @since 8.0.0
|
||||
*
|
||||
* @param array $query_args The query args of the URL.
|
||||
*
|
||||
* @return array The width and height of the shortcode.
|
||||
*/
|
||||
function jetpack_shortcode_youtube_dimensions( $query_args ) {
|
||||
$h = null;
|
||||
global $content_width;
|
||||
|
||||
$input_w = ( isset( $query_args['w'] ) && (int) $query_args['w'] ) ? (int) $query_args['w'] : 0;
|
||||
$input_h = ( isset( $query_args['h'] ) && (int) $query_args['h'] ) ? (int) $query_args['h'] : 0;
|
||||
|
||||
// If we have $content_width, use it.
|
||||
if ( ! empty( $content_width ) ) {
|
||||
$default_width = $content_width;
|
||||
} else {
|
||||
// Otherwise get default width from the old, now deprecated embed_size_w option.
|
||||
$default_width = get_option( 'embed_size_w' );
|
||||
}
|
||||
|
||||
// If we don't know those 2 values use a hardcoded width.
|
||||
if ( empty( $default_width ) ) {
|
||||
$default_width = 640;
|
||||
}
|
||||
|
||||
if ( $input_w > 0 && $input_h > 0 ) {
|
||||
$w = $input_w;
|
||||
$h = $input_h;
|
||||
} elseif ( 0 === $input_w && 0 === $input_h ) {
|
||||
if ( isset( $query_args['fmt'] ) && (int) $query_args['fmt'] ) {
|
||||
$w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 );
|
||||
} else {
|
||||
$w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width );
|
||||
$h = ceil( ( $w / 16 ) * 9 );
|
||||
}
|
||||
} elseif ( $input_w > 0 ) {
|
||||
$w = $input_w;
|
||||
$h = ceil( ( $w / 16 ) * 9 );
|
||||
} elseif ( isset( $query_args['fmt'] ) && (int) $query_args['fmt'] ) {
|
||||
$w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 );
|
||||
} else {
|
||||
$w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width );
|
||||
$h = $input_h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the YouTube player width.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 1.1.0
|
||||
*
|
||||
* @param int $w Width of the YouTube player in pixels.
|
||||
*/
|
||||
$w = (int) apply_filters( 'youtube_width', $w );
|
||||
|
||||
/**
|
||||
* Filter the YouTube player height.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 1.1.0
|
||||
*
|
||||
* @param int $h Height of the YouTube player in pixels.
|
||||
*/
|
||||
$h = (int) apply_filters( 'youtube_height', $h );
|
||||
|
||||
return array( $w, $h );
|
||||
}
|
||||
|
||||
/**
|
||||
* For bare URLs on their own line of the form
|
||||
* http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
function wpcom_youtube_embed_crazy_url( $matches, $attr, $url ) {
|
||||
return youtube_id( $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the regex for Youtube URLs.
|
||||
*/
|
||||
function wpcom_youtube_get_regex() {
|
||||
return '#https?://(?:www\.)?(?:youtube.com/(?:v/|playlist|watch[/\#?])|youtu\.be/).*#i';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new handler to automatically transform custom Youtube URLs (like playlists) into embeds.
|
||||
*/
|
||||
function wpcom_youtube_embed_crazy_url_init() {
|
||||
if ( ! defined( 'REST_API_REQUEST' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register the custom handler to provide the better support for the private video.
|
||||
wp_embed_register_handler( 'wpcom_youtube_embed_crazy_url', wpcom_youtube_get_regex(), 'wpcom_youtube_embed_crazy_url' );
|
||||
}
|
||||
add_action( 'init', 'wpcom_youtube_embed_crazy_url_init' );
|
||||
|
||||
/**
|
||||
* Filters the oEmbed result before any HTTP requests are made for YouTube.
|
||||
*
|
||||
* @since 13.9
|
||||
*
|
||||
* @param null|string $result The UNSANITIZED (and potentially unsafe) HTML that should be used to embed. Default null.
|
||||
* @param string $url The URL that should be inspected for discovery `<link>` tags.
|
||||
* @param array $args oEmbed remote get arguments.
|
||||
* @return null|string The UNSANITIZED (and potentially unsafe) HTML that should be used to embed.
|
||||
* Null if the URL does not belong to the current site.
|
||||
*/
|
||||
function wpcom_youtube_filter_pre_oembed_result( $result, $url, $args ) {
|
||||
// Return early if it's not a YouTube URL.
|
||||
if ( ! preg_match( wpcom_youtube_get_regex(), $url, $matches ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Try to get the oembed data by the Core's approach.
|
||||
$wp_oembed = _wp_oembed_get_object();
|
||||
$data = $wp_oembed->get_data( $url, $args );
|
||||
if ( $data ) {
|
||||
/** This filter is documented in wp-includes/class-wp-oembed.php */
|
||||
return apply_filters( 'oembed_result', $wp_oembed->data2html( $data, $url ), $url, $args );
|
||||
}
|
||||
|
||||
// Fallback to the custom handler if the oembed result is not found, especially for the private video.
|
||||
return youtube_id( $url );
|
||||
}
|
||||
add_filter( 'pre_oembed_result', 'wpcom_youtube_filter_pre_oembed_result', 10, 3 );
|
||||
|
||||
/**
|
||||
* Remove the ending question mark from the video id of the YouTube URL.
|
||||
*
|
||||
* Example: https://www.youtube.com/watch?v=AVAWwXeOyyQ?
|
||||
*
|
||||
* @since 13.9
|
||||
*
|
||||
* @param string $provider URL of the oEmbed provider.
|
||||
* @param string $url URL of the content to be embedded.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function wpcom_youtube_oembed_fetch_url( $provider, $url ) {
|
||||
if ( ! wp_startswith( $provider, 'https://www.youtube.com/oembed' ) ) {
|
||||
return $provider;
|
||||
}
|
||||
|
||||
$parsed = wp_parse_url( $url );
|
||||
if ( ! isset( $parsed['query'] ) ) {
|
||||
return $provider;
|
||||
}
|
||||
|
||||
$query_vars = array();
|
||||
wp_parse_str( $parsed['query'], $query_vars );
|
||||
if ( isset( $query_vars['v'] ) && wp_endswith( $query_vars['v'], '?' ) ) {
|
||||
$url = remove_query_arg( array( 'v' ), $url );
|
||||
$url = add_query_arg( 'v', preg_replace( '/\?$/', '', $query_vars['v'] ), $url );
|
||||
}
|
||||
|
||||
$provider = remove_query_arg( array( 'url' ), $provider );
|
||||
$provider = add_query_arg( 'url', rawurlencode( $url ), $provider );
|
||||
|
||||
return $provider;
|
||||
}
|
||||
add_filter( 'oembed_fetch_url', 'wpcom_youtube_oembed_fetch_url', 10, 2 );
|
||||
|
||||
if (
|
||||
! is_admin()
|
||||
/**
|
||||
* Allow oEmbeds in Jetpack's Comment form.
|
||||
*
|
||||
* @module shortcodes
|
||||
*
|
||||
* @since 2.8.0
|
||||
*
|
||||
* @param int $allow_oembed Option to automatically embed all plain text URLs.
|
||||
*/
|
||||
&& apply_filters( 'jetpack_comments_allow_oembed', true )
|
||||
// No need for this on WordPress.com, this is done for multiple shortcodes at a time there.
|
||||
&& ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM )
|
||||
) {
|
||||
/*
|
||||
* We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway,
|
||||
* so the iframe gets filtered out.
|
||||
* Higher priority because we need it before auto-link and autop get to it.
|
||||
*/
|
||||
add_filter( 'comment_text', 'youtube_link', 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Core changes to do_shortcode (https://core.trac.wordpress.org/changeset/34747) broke "improper" shortcodes
|
||||
* with the format [shortcode=http://url.com].
|
||||
*
|
||||
* This removes the "=" from the shortcode so it can be parsed.
|
||||
*
|
||||
* @see https://github.com/Automattic/jetpack/issues/3121
|
||||
*
|
||||
* @param string $content HTML content.
|
||||
*/
|
||||
function jetpack_fix_youtube_shortcode_display_filter( $content ) {
|
||||
if ( strpos( $content, '[youtube=' ) !== false ) {
|
||||
$content = preg_replace( '@\[youtube=(.*?)\]@', '[youtube $1]', $content );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
add_filter( 'the_content', 'jetpack_fix_youtube_shortcode_display_filter', 7 );
|
||||
Reference in New Issue
Block a user