| 1 |
<?php |
| 2 |
/** |
| 3 |
* Embed PDF Viewer |
| 4 |
* |
| 5 |
* @author Andy Fragen |
| 6 |
* @license GPL-2.0+ |
| 7 |
* @link https://github.com/afragen/embed-pdf-viewer |
| 8 |
* @package embed-pdf-viewer |
| 9 |
*/ |
| 10 |
|
| 11 |
/** |
| 12 |
* Plugin Name: Embed PDF Viewer |
| 13 |
* Plugin URI: https://github.com/afragen/embed-pdf-viewer |
| 14 |
* Description: Embed a PDF from the Media Library or elsewhere via oEmbed or as a block into an `iframe` tag. |
| 15 |
* Author: Andy Fragen |
| 16 |
* Author URI: https://github.com/afragen |
| 17 |
* Version: 2.4.6 |
| 18 |
* License: GPLv2+ |
| 19 |
* Domain Path: /languages |
| 20 |
* Text Domain: embed-pdf-viewer |
| 21 |
* License URI: http://www.gnu.org/licenses/gpl-2.0.html |
| 22 |
* GitHub Plugin URI: https://github.com/afragen/embed-pdf-viewer |
| 23 |
* Requires PHP: 7.4 |
| 24 |
* Requires at least: 6.0 |
| 25 |
*/ |
| 26 |
|
| 27 |
/** |
| 28 |
* Exit if called directly. |
| 29 |
*/ |
| 30 |
if ( ! defined( 'WPINC' ) ) { |
| 31 |
die; |
| 32 |
} |
| 33 |
|
| 34 |
$epd_version = get_file_data( __FILE__, [ 'Version' => 'version' ] )['Version']; |
| 35 |
add_filter( 'media_send_to_editor', [ Embed_PDF_Viewer::instance( $epd_version ), 'embed_pdf_media_editor' ], 20, 2 ); |
| 36 |
wp_embed_register_handler( |
| 37 |
'oembed_pdf_viewer', |
| 38 |
'#(^(https?)\:\/\/.+\.pdf$)#i', |
| 39 |
[ |
| 40 |
Embed_PDF_Viewer::instance( $epd_version ), |
| 41 |
'oembed_pdf_viewer', |
| 42 |
] |
| 43 |
); |
| 44 |
add_action( |
| 45 |
'init', |
| 46 |
function () use ( $epd_version ) { |
| 47 |
wp_set_script_translations( 'embed-pdf-viewer-scripts', 'embed-pdf-viewer' ); |
| 48 |
|
| 49 |
// phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NoExplicitVersion |
| 50 |
wp_enqueue_style( |
| 51 |
'embed-pdf-viewer', |
| 52 |
plugins_url( 'css/embed-pdf-viewer.css', __FILE__ ), |
| 53 |
[], |
| 54 |
$epd_version, |
| 55 |
'screen' |
| 56 |
); |
| 57 |
} |
| 58 |
); |
| 59 |
add_action( 'init', [ Embed_PDF_Viewer::instance( $epd_version ), 'register_block' ] ); |
| 60 |
|
| 61 |
/** |
| 62 |
* Class Embed_PDF_Viewer |
| 63 |
*/ |
| 64 |
class Embed_PDF_Viewer { |
| 65 |
/** |
| 66 |
* For singleton. |
| 67 |
* |
| 68 |
* @var bool |
| 69 |
*/ |
| 70 |
private static $instance = false; |
| 71 |
|
| 72 |
/** |
| 73 |
* Plugin version number. |
| 74 |
* |
| 75 |
* @var string |
| 76 |
*/ |
| 77 |
private static $version = ''; |
| 78 |
|
| 79 |
/** |
| 80 |
* Create singleton. |
| 81 |
* |
| 82 |
* @param string $version Plugin version number. |
| 83 |
* @return bool |
| 84 |
*/ |
| 85 |
public static function instance( $version ) { |
| 86 |
static::$version = $version; |
| 87 |
if ( false === static::$instance ) { |
| 88 |
static::$instance = new self( $version ); |
| 89 |
} |
| 90 |
|
| 91 |
return static::$instance; |
| 92 |
} |
| 93 |
|
| 94 |
/** |
| 95 |
* Register block. |
| 96 |
* |
| 97 |
* @return void |
| 98 |
*/ |
| 99 |
public function register_block() { |
| 100 |
if ( ! function_exists( 'register_block_type' ) ) { |
| 101 |
return; |
| 102 |
} |
| 103 |
|
| 104 |
// phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NoExplicitVersion |
| 105 |
wp_register_script( |
| 106 |
'embed-pdf-viewer', |
| 107 |
plugins_url( 'blocks/build/index.js', __FILE__ ), |
| 108 |
[ 'wp-i18n', 'wp-blocks', 'wp-block-editor', 'wp-element', 'wp-components', 'wp-compose', 'wp-blob' ], |
| 109 |
static::$version, |
| 110 |
true |
| 111 |
); |
| 112 |
|
| 113 |
register_block_type( |
| 114 |
'embed-pdf-viewer/pdf', |
| 115 |
[ |
| 116 |
'editor_script' => 'embed-pdf-viewer', |
| 117 |
'render_callback' => [ static::$instance, 'dynamic_render_callback' ], |
| 118 |
] |
| 119 |
); |
| 120 |
} |
| 121 |
|
| 122 |
/** |
| 123 |
* Dynamically render callback based on browser. |
| 124 |
* |
| 125 |
* @global bool $is_chrome Tests for Chrome browser. |
| 126 |
* |
| 127 |
* @param array $attributes Array of attributes. |
| 128 |
* |
| 129 |
* @return string |
| 130 |
*/ |
| 131 |
public function dynamic_render_callback( $attributes ) { |
| 132 |
global $is_chrome; |
| 133 |
|
| 134 |
$url = $attributes['url'] ?? null; |
| 135 |
if ( ! $url ) { |
| 136 |
return ''; |
| 137 |
} |
| 138 |
|
| 139 |
$classes = 'embed-pdf-viewer'; |
| 140 |
$src = $is_chrome || wp_is_mobile() ? 'https://docs.google.com/viewer?url=' . rawurlencode( $url ) . '&embedded=true' : $url; |
| 141 |
$description = $attributes['title'] ?? ''; |
| 142 |
$description = $attributes['description'] ?? $description; |
| 143 |
$width = $attributes['width'] ?? '600'; |
| 144 |
$height = $attributes['height'] ?? '600'; |
| 145 |
return sprintf( |
| 146 |
'<iframe class="%1$s" src="%2$s" height="%3$s" width="%4$s" title="%5$s"%6$s></iframe>', |
| 147 |
$classes, |
| 148 |
sanitize_url( $src ), |
| 149 |
esc_attr( $width ), |
| 150 |
esc_attr( $height ), |
| 151 |
esc_attr( $description ), |
| 152 |
$is_chrome || wp_is_mobile() ? ' frameborder="0"' : '' |
| 153 |
); |
| 154 |
} |
| 155 |
|
| 156 |
/** |
| 157 |
* Insert URL to PDF from Media Library, then render as oEmbed. |
| 158 |
* |
| 159 |
* @param string $html an href link to the media. |
| 160 |
* @param integer $id post_id. |
| 161 |
* |
| 162 |
* @return string |
| 163 |
*/ |
| 164 |
public function embed_pdf_media_editor( $html, $id ) { |
| 165 |
$post = get_post( $id ); |
| 166 |
if ( 'application/pdf' !== $post->post_mime_type ) { |
| 167 |
return $html; |
| 168 |
} |
| 169 |
|
| 170 |
return $post->guid . "\n\n"; |
| 171 |
} |
| 172 |
|
| 173 |
/** |
| 174 |
* Create oEmbed code. |
| 175 |
* |
| 176 |
* @param array $matches Regex matches. |
| 177 |
* @param array $atts array of media height/width. |
| 178 |
* @param string $url URI for media file. |
| 179 |
* |
| 180 |
* @return string|WP_Error |
| 181 |
*/ |
| 182 |
public function oembed_pdf_viewer( $matches, $atts, $url ) { |
| 183 |
$attachment_id = $this->get_attachment_id_by_url( $url ); |
| 184 |
if ( ! empty( $attachment_id ) ) { |
| 185 |
$post = get_post( $this->get_attachment_id_by_url( $url ) ); |
| 186 |
} else { |
| 187 |
/* |
| 188 |
* URL is from outside of the Media Library. |
| 189 |
*/ |
| 190 |
$response = wp_remote_get( $url ); |
| 191 |
if ( is_wp_error( $response ) ) { |
| 192 |
return $response; |
| 193 |
} |
| 194 |
$post = new WP_Post( new stdClass() ); |
| 195 |
$post->guid = $matches[0]; |
| 196 |
$post->post_mime_type = wp_remote_retrieve_header( $response, 'content-type' ); |
| 197 |
$post->post_name = preg_replace( '/\.pdf$/', '', basename( $matches[0] ) ); |
| 198 |
} |
| 199 |
|
| 200 |
return $this->create_output( $post, $atts ); |
| 201 |
} |
| 202 |
|
| 203 |
/** |
| 204 |
* Create output for iframe and/or Google Doc Viewer and href link to file. |
| 205 |
* |
| 206 |
* @param \WP_Post $post Current post. |
| 207 |
* @param array|string $atts array of media height/width or |
| 208 |
* href to media library asset. |
| 209 |
* |
| 210 |
* @return bool|string |
| 211 |
*/ |
| 212 |
private function create_output( WP_Post $post, $atts = [] ) { |
| 213 |
global $is_chrome; |
| 214 |
|
| 215 |
if ( 'application/pdf' !== $post->post_mime_type ) { |
| 216 |
return $atts; |
| 217 |
} |
| 218 |
|
| 219 |
$default = [ |
| 220 |
'height' => 500, |
| 221 |
'width' => 800, |
| 222 |
'title' => $post->post_title, |
| 223 |
'description' => $post->post_content, |
| 224 |
]; |
| 225 |
|
| 226 |
/* |
| 227 |
* Ensure $atts isn't the href. |
| 228 |
*/ |
| 229 |
$atts = is_array( $atts ) ? $atts : []; |
| 230 |
|
| 231 |
if ( isset( $atts['width'] ) ) { |
| 232 |
$atts['width'] = '100%'; |
| 233 |
} |
| 234 |
$atts = array_merge( $default, $atts ); |
| 235 |
|
| 236 |
/** |
| 237 |
* Filter PDF attributes. |
| 238 |
* |
| 239 |
* @since 1.6.0 |
| 240 |
* @param array $atts Array of PDF attributes. |
| 241 |
* @return array $atts |
| 242 |
*/ |
| 243 |
$atts = apply_filters( 'embed_pdf_viewer_pdf_attributes', $atts ); |
| 244 |
|
| 245 |
// Fix title or create from filename. |
| 246 |
$atts['title'] = empty( $atts['title'] ) |
| 247 |
? ucwords( preg_replace( '/(-|_)/', ' ', $post->post_name ) ) |
| 248 |
: ucwords( preg_replace( '/(-|_)/', ' ', $atts['title'] ) ); |
| 249 |
|
| 250 |
$description = ! empty( $atts['description'] ) ? $atts['description'] : $atts['title']; |
| 251 |
$sanitized_url = sanitize_url( $post->guid ); |
| 252 |
|
| 253 |
if ( $is_chrome || wp_is_mobile() ) { |
| 254 |
$iframe = '<iframe class="embed-pdf-viewer" src="https://docs.google.com/viewer?url=' . rawurlencode( $sanitized_url ); |
| 255 |
$iframe .= '&embedded=true" frameborder="0" '; |
| 256 |
} else { |
| 257 |
$iframe = '<iframe class="embed-pdf-viewer" src="' . $sanitized_url . '" '; |
| 258 |
} |
| 259 |
$iframe .= 'height="' . esc_attr( $atts['height'] ) . '" width="' . esc_attr( $atts['width'] ) . '" '; |
| 260 |
$iframe .= 'title="' . esc_attr( $description ) . '"></iframe>' . "\n"; |
| 261 |
|
| 262 |
$embed = '<div>'; |
| 263 |
$embed .= $iframe; |
| 264 |
$embed .= '<p><a href="' . $sanitized_url . '" title="' . esc_attr( $description ) . '">' . esc_html( $description ) . '</a></p>'; |
| 265 |
$embed .= '</div>'; |
| 266 |
|
| 267 |
return $embed; |
| 268 |
} |
| 269 |
|
| 270 |
/** |
| 271 |
* Get attachment id by url. Thanks Pippin. |
| 272 |
* |
| 273 |
* @link https://pippinsplugins.com/retrieve-attachment-id-from-image-url/ |
| 274 |
* |
| 275 |
* @param string $url URI of attachment. |
| 276 |
* |
| 277 |
* @return mixed |
| 278 |
*/ |
| 279 |
private function get_attachment_id_by_url( $url ) { |
| 280 |
global $wpdb; |
| 281 |
// phpcs:ignore WordPress.DB |
| 282 |
$attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE guid='%s';", $url ) ); |
| 283 |
|
| 284 |
if ( empty( $attachment ) ) { |
| 285 |
return null; |
| 286 |
} |
| 287 |
|
| 288 |
return $attachment[0]; |
| 289 |
} |
| 290 |
} |
| 291 |
|