├── blocks ├── .nvmrc ├── build │ ├── index.asset.php │ └── index.js ├── src │ ├── pdf.svg │ ├── icons.js │ └── index.js ├── package.json └── build.md ├── css └── embed-pdf-viewer.css ├── composer.json ├── README.md ├── languages └── embed-pdf-viewer.pot ├── CHANGES.md ├── readme.txt ├── embed-pdf-viewer.php └── LICENSE /blocks/.nvmrc: -------------------------------------------------------------------------------- 1 | v10.24.1 2 | -------------------------------------------------------------------------------- /blocks/build/index.asset.php: -------------------------------------------------------------------------------- 1 | array('wp-element', 'wp-polyfill'), 'version' => 'a2f617c4218bad87aa224073f26661c5'); -------------------------------------------------------------------------------- /css/embed-pdf-viewer.css: -------------------------------------------------------------------------------- 1 | iframe.embed-pdf-viewer { 2 | margin: 0 auto; 3 | display: block; 4 | border-style: none; 5 | } 6 | 7 | @media only screen and (max-device-width : 768px) { 8 | iframe.embed-pdf-viewer { 9 | width: 100%; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /blocks/src/pdf.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /blocks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "embed-pdf-viewer", 3 | "description": "Block for embedding PDF documents.", 4 | "version": "0.2.0", 5 | "license": "GPL-2.0-or-later", 6 | "main": "./src/index.js", 7 | "devDependencies": { 8 | "@wordpress/scripts": "12.1.1" 9 | }, 10 | "scripts": { 11 | "build": "wp-scripts build", 12 | "start": "wp-scripts start" 13 | }, 14 | "dependencies": { 15 | "build": "^0.1.4", 16 | "classnames": "^2.2.6" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /blocks/src/icons.js: -------------------------------------------------------------------------------- 1 | const icons = {}; 2 | 3 | icons.pdf = 4 | 5 | export default icons; 6 | -------------------------------------------------------------------------------- /blocks/build.md: -------------------------------------------------------------------------------- 1 | # Block build Instructions 2 | 3 | https://developer.wordpress.org/block-editor/tutorials/javascript/js-build-setup/ 4 | 5 | Ensure that @wordpress/scripts are installed. 6 | * `npm install @wordpress/scripts --save-dev --save-exact` 7 | 8 | Ensure that classnames is installed. 9 | * `npm install classnames --save` 10 | 11 | Use node 10.x 12 | `nvm use .` 13 | 14 | If `package.json` has the above dependencies then `npm install` 15 | 16 | `npm start` for testing. 17 | 18 | `npm run build` 19 | 20 | 21 | ## Add custom SVG icon 22 | 23 | https://since1979.dev/wordpress-adding-custom-svg-icons-to-your-gutenberg-blocks-plugin/ 24 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "afragen/embed-pdf-viewer", 3 | "description": "Embed a PDF from the Media Library or elsewhere via oEmbed or as a block into an `iframe` tag or Google Doc Viewer.", 4 | "type": "wordpress-plugin", 5 | "keywords": [ 6 | "pdf", 7 | "viewer", 8 | "oembed", 9 | "block" 10 | ], 11 | "license": "GPL-2.0-or-later", 12 | "authors": [ 13 | { 14 | "name": "Andy Fragen", 15 | "email": "andy@thefragens.com", 16 | "homepage": "https://thefragens.com", 17 | "role": "Developer" 18 | } 19 | ], 20 | "repositories": [ 21 | { 22 | "type": "vcs", 23 | "url": "https://github.com/afragen/embed-pdf-viewer" 24 | } 25 | ], 26 | "support": { 27 | "issues": "https://github.com/afragen/embed-pdf-viewer/issues", 28 | "source": "https://github.com/afragen/embed-pdf-viewer" 29 | }, 30 | "prefer-stable": true, 31 | "require": { 32 | "php": ">=7.4" 33 | }, 34 | "require-dev": { 35 | "wp-coding-standards/wpcs": "^3.0.0" 36 | }, 37 | "config": { 38 | "allow-plugins": { 39 | "dealerdirect/phpcodesniffer-composer-installer": true 40 | } 41 | }, 42 | "scripts": { 43 | "make-pot": [ 44 | "wp i18n make-pot . languages/embed-pdf-viewer.pot --exclude='/build'" 45 | ], 46 | "wpcs": [ 47 | "vendor/bin/phpcbf .; vendor/bin/phpcs ." 48 | ] 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Embed PDF Viewer 2 | 3 | * Contributors: afragen, akirk, costdev 4 | * Tags: pdf, embed, oembed, viewer, block 5 | * Requires at least: 6.0 6 | * Requires PHP: 7.4 7 | * Stable tag: master 8 | * License: GPL v2+ 9 | * License URI: 10 | 11 | Embed a PDF from the Media Library or elsewhere via oEmbed or as a block into an `iframe` tag. 12 | 13 | ## Description 14 | Embed a PDF from the Media Library or elsewhere via oEmbed or as a block into an `iframe` tag. The URL only has to be world reachable link. Chrome uses Google Doc Viewer as Chrome seems to automatically rendered embedded JS in PDFs automatically. Uses Google Doc Viewer with mobile. 15 | 16 | Inspired by [Embed PDF](https://wordpress.org/plugins/dirtysuds-embed-pdf/) and [RV Embed PDF](https://wordpress.org/plugins/rv-embed-pdf/). 17 | 18 | Many thanks to [Alex Kirk](https://github.com/akirk) for making Embed PDF Viewer compatible with the new block editor. 19 | 20 | Pull requests are welcome against the `develop` branch. 21 | 22 | ### Known Issues 23 | Occasionally Google Doc Viewer will not correctly load the PDF. Reloading the page should correct the issue, though this may need to be done several times. 24 | 25 | ## Screenshots 26 | ![Embed PDF Viewer block](./.wordpress-org/screenshot-1.png "Embed PDF Viewer block") 27 | 28 | Embed PDF Viewer block 29 | 30 | ![Select PDF](./.wordpress-org/screenshot-2.png "Select PDF") 31 | 32 | Select PDF 33 | 34 | 35 | ![PDF block and attributes](./.wordpress-org/screenshot-3.png "PDF block and attributes") 36 | 37 | PDF block and attributes 38 | -------------------------------------------------------------------------------- /languages/embed-pdf-viewer.pot: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 Andy Fragen 2 | # This file is distributed under the GPLv2+. 3 | msgid "" 4 | msgstr "" 5 | "Project-Id-Version: Embed PDF Viewer 2.4.0\n" 6 | "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/embed-pdf-viewer\n" 7 | "Last-Translator: FULL NAME \n" 8 | "Language-Team: LANGUAGE \n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "POT-Creation-Date: 2024-08-06T16:39:15+00:00\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "X-Generator: WP-CLI 2.10.0\n" 15 | "X-Domain: embed-pdf-viewer\n" 16 | 17 | #. Plugin Name of the plugin 18 | #: embed-pdf-viewer.php 19 | #: blocks/src/index.js:127 20 | msgid "Embed PDF Viewer" 21 | msgstr "" 22 | 23 | #. Plugin URI of the plugin 24 | #: embed-pdf-viewer.php 25 | msgid "https://github.com/afragen/embed-pdf-viewer" 26 | msgstr "" 27 | 28 | #. Description of the plugin 29 | #: embed-pdf-viewer.php 30 | msgid "Embed a PDF from the Media Library or elsewhere via oEmbed or as a block into an `iframe` tag." 31 | msgstr "" 32 | 33 | #. Author of the plugin 34 | #: embed-pdf-viewer.php 35 | msgid "Andy Fragen" 36 | msgstr "" 37 | 38 | #. Author URI of the plugin 39 | #: embed-pdf-viewer.php 40 | msgid "https://github.com/afragen" 41 | msgstr "" 42 | 43 | #: blocks/src/index.js:78 44 | #: blocks/src/index.js:221 45 | msgid "PDF" 46 | msgstr "" 47 | 48 | #: blocks/src/index.js:79 49 | msgid "Drag a PDF, upload a new one or select a PDF from your library." 50 | msgstr "" 51 | 52 | #: blocks/src/index.js:130 53 | msgid "Long Description (optional)" 54 | msgstr "" 55 | 56 | #: blocks/src/index.js:133 57 | msgid "Long Description used for `title` tag and accessibility." 58 | msgstr "" 59 | 60 | #: blocks/src/index.js:138 61 | msgid "Width" 62 | msgstr "" 63 | 64 | #: blocks/src/index.js:144 65 | msgid "Height" 66 | msgstr "" 67 | 68 | #: blocks/src/index.js:163 69 | #: blocks/src/index.js:176 70 | msgid "Edit PDF" 71 | msgstr "" 72 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | #### [unreleased] 2 | 3 | #### 2.4.6 / 2024-11-01 4 | * remove `load_plugin_textdomain()` 5 | 6 | #### 2.4.5 / 2024-10-7 7 | * escape block parameters 8 | 9 | #### 2.4.4 / 2024-08-16 10 | * refactor `$description` in `dynamic_render_callback()`, who knew the title attribute could be not set 11 | * update requirements, PHP 7.4+, WP 6.0 12 | 13 | #### 2.4.1 - 2.4.3 / 2024-08-08 14 | * more sanitizing of URL 15 | * fix typos and update readme 16 | * use media file description for title if present 17 | * escape description in render 18 | 19 | #### 2.4.0 / 2024-08-06 20 | * convert to only use `iframe` 21 | * use Google Doc Viewer for Chrome and mobile 22 | * dynamically render `iframe` in block based on browser 23 | * mitigate [Chromium issue](https://issues.chromium.org/issues/40063550) by rendering PDF with Google Doc Viewer 24 | * thanks to @costdev for helping with dynamic block rendering 25 | 26 | #### 2.3.1 / 2023-09-10 27 | * update GA 28 | * update tested to 29 | 30 | #### 2.3.0 / 2021-07-07 31 | * add @10up GitHub Actions integration for WordPress SVN 32 | 33 | #### 2.2.0 / 2021-03-05 34 | * update Toolbar to ToolbarGroup and ToolbarButton 35 | * add limited support for block alignment toolbar 36 | * fixes for i18n in block 37 | * exclude `/build` from `make-pot` in `composer.json`, doesn't work with minimized JS 38 | 39 | #### 2.1.2 / 2020-09-15 40 | * use same _block name_ for oembed 41 | * add additional dependencies to enqueue 42 | 43 | ### 2.1.1 / 2020-07-20 44 | * update block for deprecated items and minor errors 45 | * update media selector for only PDFs 46 | 47 | #### 2.1.0 / 2020-07-20 48 | * update block build process 49 | * add title and description attributes for a11y 50 | * add PDF svg for block 51 | 52 | #### 2.0.5 / 2020-03-09 53 | * minor updates to plugin structure on GitHub 54 | * update tested to 55 | 56 | #### 2.0.4 / 2019-10-05 57 | * fixed [PDF upload within block](https://wordpress.org/support/topic/uploading-from-within-block-doesnt-work/) 58 | 59 | #### 2.0.3 / 2019-04-25 60 | * move block registration to it's own function and hook 61 | * WPCS updates 62 | 63 | #### 2.0.2 / 2019-02-03 64 | * update WordPress requirements 65 | 66 | #### 2.0.1 / 2019-01-11 67 | * added `composer.json` and automatically create POT with `composer update` 68 | * added check for `register_block_type()` for WP 4.9.x and below 69 | 70 | #### 2.0.0 / 2018-12-20 🎂 71 | * a proper PDF block was added with much help from [Alex Kirk](https://github.com/akirk), many thanks 72 | 73 | #### 1.6.1 / 2018-11-25 74 | * properly initialize `load_plugin_textdomain()` 75 | 76 | #### 1.6.0 / 2018-07-22 77 | * added filter `embed_pdf_viewer_pdf_attributes` 78 | * updated `readme.txt` to include `Requires PHP` header 79 | * added paragraph tag around link to PDF 80 | 81 | #### 1.5.0 / 2016-12-17 82 | * added CSS to fallback to `iframe` on iOS as `object` isn't scrollable :P 83 | 84 | #### 1.4.0 / 2016-12-16 85 | * switch to using `object` tag, with `iframe` as fallback display method 86 | 87 | #### 1.3.0 / 2016-08-13 88 | * bugfix for not returning non-PDF file from Media Library 89 | * added textdomain for translating title etc 90 | 91 | #### 1.2.1 / 2016-07-11 92 | * fixed a couple of PHP warnings 93 | 94 | #### 1.2.0 / 2016-07-10 95 | * inserting a PDF from the Media Library now simply inserts the URL for oEmbed 96 | * oEmbed a PDF from any source 97 | 98 | #### 1.1.2 / 2016-07-03 99 | * simplify `instance()` just a little more 100 | 101 | #### 1.1.1 / 2016-06-14 102 | * rename instance variable to `$instance` and make private 103 | * update DocBlocks 104 | * ensure `$atts` is an array 105 | 106 | #### 1.1 / 2016-06-11 107 | * bugfix for not returning media item when not PDF, Bad Andy :( 108 | 109 | #### 1.0.1 / 2016-06-01 110 | * add to DocBlocks 111 | 112 | #### 1.0 / 2016-05-09 113 | * refactor to put embed code in one function 114 | * add assets 115 | 116 | #### 0.1 117 | * initial commit 118 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | # Embed PDF Viewer 2 | 3 | Contributors: afragen, akirk, costdev 4 | Tags: pdf, embed, oembed, viewer, block 5 | Requires at least: 6.0 6 | Tested up to: 6.7 7 | Requires PHP: 7.4 8 | Stable tag: 2.4.6 9 | License: GPL v2+ 10 | License URI: https://www.gnu.org/licenses/gpl-2.0.html 11 | 12 | Embed a PDF from the Media Library or elsewhere via oEmbed or as a block into an `iframe` tag. 13 | 14 | ## Description 15 | Embed a PDF from the Media Library or elsewhere via oEmbed or as a block into an `iframe` tag. The URL only has to be world reachable link. Chrome uses Google Doc Viewer as Chrome seems to automatically rendered embedded JS in PDFs automatically. Uses Google Doc Viewer with mobile. 16 | 17 | Inspired by [Embed PDF](https://wordpress.org/plugins/dirtysuds-embed-pdf/) and [RV Embed PDF](https://wordpress.org/plugins/rv-embed-pdf/). 18 | 19 | Many thanks to [Alex Kirk](https://github.com/akirk) for making Embed PDF Viewer compatible with the new block editor. 20 | 21 | Development on [GitHub](https://github.com/afragen/embed-pdf-viewer). Pull requests are welcome against the `develop` branch. 22 | 23 | ### Known Issues 24 | Occasionally Google Doc Viewer will not correctly load the PDF. Reloading the page should correct the issue, though this may need to be done several times. 25 | 26 | ## Screenshots 27 | 1. Embed PDF Viewer block 28 | 2. Select PDF 29 | 3. PDF block and attributes 30 | 31 | ## Changelog 32 | 33 | #### 2.4.6 / 2024-11-01 34 | * remove `load_plugin_textdomain()` 35 | 36 | #### 2.4.5 / 2024-10-7 37 | * escape block parameters 38 | 39 | #### 2.4.4 / 2024-08-16 40 | * refactor `$description` in `dynamic_render_callback()`, who knew the title attribute could be not set 41 | * update requirements, PHP 7.4+, WP 6.0 42 | 43 | #### 2.4.1 - 2.4.3 / 2024-08-08 44 | * more sanitizing of URL 45 | * fix typos and update readme 46 | * use media file description for title if present 47 | * escape description in render 48 | 49 | #### 2.4.0 / 2024-08-06 50 | * convert to only use `iframe` 51 | * use Google Doc Viewer for Chrome and mobile 52 | * dynamically render `iframe` in block based on browser 53 | * mitigate [Chromium issue](https://issues.chromium.org/issues/40063550) by rendering PDF with Google Doc Viewer 54 | * thanks to @costdev for helping with dynamic block rendering 55 | 56 | #### 2.3.1 / 2023-09-10 57 | * update GA 58 | * update tested to 59 | 60 | #### 2.3.0 / 2021-07-07 61 | * add @10up GitHub Actions integration for WordPress SVN 62 | 63 | #### 2.2.0 / 2021-03-05 64 | * update Toolbar to ToolbarGroup and ToolbarButton 65 | * add limited support for block alignment toolbar 66 | * fixes for i18n in block 67 | * exclude `/build` from `make-pot` in `composer.json`, doesn't work with minimized JS 68 | 69 | #### 2.1.2 / 2020-09-15 70 | * use same _block name_ for oembed 71 | * add additional dependencies to enqueue 72 | 73 | ### 2.1.1 / 2020-07-20 74 | * update block for deprecated items and minor errors 75 | * update media selector for only PDFs 76 | 77 | #### 2.1.0 / 2020-07-20 78 | * update block build process 79 | * add title and description attributes for a11y 80 | * add PDF svg for block 81 | 82 | #### 2.0.5 / 2020-03-09 83 | * minor updates to plugin structure on GitHub 84 | * update tested to 85 | 86 | #### 2.0.4 / 2019-10-05 87 | * fixed [PDF upload within block](https://wordpress.org/support/topic/uploading-from-within-block-doesnt-work/) 88 | 89 | #### 2.0.3 / 2019-04-25 90 | * move block registration to it's own function and hook 91 | * WPCS updates 92 | 93 | #### 2.0.2 / 2019-02-03 94 | * update WordPress requirements 95 | 96 | #### 2.0.1 / 2019-01-11 97 | * added `composer.json` and automatically create POT with `composer update` 98 | * added check for `register_block_type()` for WP 4.9.x and below 99 | 100 | #### 2.0.0 / 2018-12-20 🎂 101 | * a proper PDF block was added with much help from [Alex Kirk](https://github.com/akirk), many thanks 102 | 103 | #### 1.6.1 / 2018-11-25 104 | * properly initialize `load_plugin_textdomain()` 105 | 106 | #### 1.6.0 / 2018-07-22 107 | * added filter `embed_pdf_viewer_pdf_attributes` 108 | * updated `readme.txt` to include `Requires PHP` header 109 | * added paragraph tag around link to PDF 110 | 111 | #### 1.5.0 / 2016-12-17 112 | * added CSS to fallback to `iframe` on iOS as `object` isn't scrollable :P 113 | 114 | #### 1.4.0 115 | * switch to using `object` tag, with `iframe` as fallback display method 116 | 117 | #### 1.3.0 118 | * inserting anything other than PDF from Media Library now works as expected. 119 | 120 | #### 1.2.1 121 | * fixed a couple of PHP warnings 122 | 123 | #### 1.2.0 124 | * inserting a PDF from the Media Library now simply inserts the URL for oEmbed 125 | * oEmbed a PDF from any source 126 | 127 | #### 1.1.2 128 | * simplify `instance()` just a little more 129 | 130 | #### 1.1.1 131 | * rename instance variable to `$instance` and make private 132 | * update DocBlocks 133 | * ensure `$atts` is an array 134 | 135 | #### 1.1 136 | * bugfix for not returning media item when not PDF, Bad Andy :( 137 | 138 | #### 1.0.1 139 | * add to DocBlocks 140 | 141 | = 1.0 = 142 | * refactor to put embed code in one function 143 | * add assets 144 | 145 | = 0.1 = 146 | * initial commit 147 | -------------------------------------------------------------------------------- /blocks/build/index.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var i=t[n]={i:n,l:!1,exports:{}};return e[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)r.d(n,i,function(t){return e[t]}.bind(null,i));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=3)}([function(e,t){e.exports=window.wp.element},function(e,t){function r(){return e.exports=r=Object.assign?Object.assign.bind():function(e){for(var t=1;t url && !id && !isBlobURL(url); 13 | 14 | const renderEmbed = (props) => { 15 | const { attributes: { title, description, url, width, height, align } } = props; 16 | const style = { width, height }; 17 | const myClassName = getBlockDefaultClassName('embed-pdf-viewer/pdf'); 18 | const isChrome = navigator && navigator?.userAgent && navigator.userAgent.toLowerCase().includes('chrome'); 19 | const classNames = "embed-pdf-viewer"; 20 | const src = isChrome && 'https://docs.google.com/viewer?url=' + encodeURIComponent(url) + '&embedded=true' || encodeURI(url); 21 | 22 | if (undefined === url || !url) { 23 | return null; 24 | } 25 | 26 | return ( 27 |
28 | 37 |
38 | ); 39 | }; 40 | 41 | const renderEdit = (props) => { 42 | const { attributes: { id, title, description, url, width, height, align }, setAttributes, isEditing, hasError, setState, className, media, noticeUI, noticeOperations, toggleSelection, isRTL } = props; 43 | const isExternal = isExternalPDF(id, url); 44 | 45 | function updateAttribute(key) { 46 | return function (value) { 47 | const attr = {}; 48 | attr[key] = value; 49 | setAttributes(attr); 50 | } 51 | } 52 | 53 | function onSelectFile(media) { 54 | if (media && media.url) { 55 | setState({ 56 | hasError: false, 57 | }); 58 | setAttributes({ 59 | url: media.url, 60 | id: media.id, 61 | title: media.title, 62 | description: media.description, 63 | }); 64 | } 65 | } 66 | 67 | function toggleIsEditing() { 68 | setState({ 69 | isEditing: !isEditing, 70 | }); 71 | } 72 | 73 | if (undefined === url || !url || hasError || isEditing) { 74 | return ( 75 | 88 | ); 89 | } 90 | 91 | 92 | const classes = classnames(className, { 93 | 'is-transient': isBlobURL(url), 94 | }); 95 | 96 | 97 | let showRightHandle = false; 98 | let showLeftHandle = false; 99 | 100 | // See block-library/src/image/edit.js 101 | if (align === 'center') { 102 | // When the image is centered, show both handles. 103 | showRightHandle = true; 104 | showLeftHandle = true; 105 | } else if (isRTL) { 106 | // In RTL mode the image is on the right by default. 107 | // Show the right handle and hide the left handle only when it is aligned left. 108 | // Otherwise always show the left handle. 109 | if (align === 'left') { 110 | showRightHandle = true; 111 | } else { 112 | showLeftHandle = true; 113 | } 114 | } else { 115 | // Show the left handle and hide the right handle only when the image is aligned right. 116 | // Otherwise always show the right handle. 117 | if (align === 'right') { 118 | showLeftHandle = true; 119 | } else { 120 | showRightHandle = true; 121 | } 122 | } 123 | 124 | return ( 125 | 126 | 127 | 128 |
129 | 135 | 142 | 149 |
150 |
151 |
152 | 153 | 154 | 159 | 160 | {isExternal && ( 161 | 167 | )} 168 | {!isExternal && ( 169 | 170 | ( 174 |