├── .gitignore ├── img ├── ajax-loader.gif ├── wordpressicon-93x88.png ├── embedly-white-70-40.svg ├── embedly_logo_blue.svg └── embedly_wordpress_logo.png ├── svn-assets ├── icon-128x128.png ├── icon-256x256.png ├── screenshot-1.png ├── screenshot-2.png ├── screenshot-3.png ├── banner-1544x500.png ├── banner-772x250.png └── icon.svg ├── Gruntfile.js ├── package.json ├── .jshintrc ├── README.md ├── css └── embedly-admin.css ├── readme.txt ├── js └── embedly.js └── embedly.php /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /img/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedly/embedly_wordpress_plugin/HEAD/img/ajax-loader.gif -------------------------------------------------------------------------------- /img/wordpressicon-93x88.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedly/embedly_wordpress_plugin/HEAD/img/wordpressicon-93x88.png -------------------------------------------------------------------------------- /svn-assets/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedly/embedly_wordpress_plugin/HEAD/svn-assets/icon-128x128.png -------------------------------------------------------------------------------- /svn-assets/icon-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedly/embedly_wordpress_plugin/HEAD/svn-assets/icon-256x256.png -------------------------------------------------------------------------------- /svn-assets/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedly/embedly_wordpress_plugin/HEAD/svn-assets/screenshot-1.png -------------------------------------------------------------------------------- /svn-assets/screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedly/embedly_wordpress_plugin/HEAD/svn-assets/screenshot-2.png -------------------------------------------------------------------------------- /svn-assets/screenshot-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedly/embedly_wordpress_plugin/HEAD/svn-assets/screenshot-3.png -------------------------------------------------------------------------------- /svn-assets/banner-1544x500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedly/embedly_wordpress_plugin/HEAD/svn-assets/banner-1544x500.png -------------------------------------------------------------------------------- /svn-assets/banner-772x250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedly/embedly_wordpress_plugin/HEAD/svn-assets/banner-772x250.png -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function(grunt) { 3 | 4 | grunt.loadNpmTasks('grunt-contrib-jshint'); 5 | 6 | // Project configuration. 7 | grunt.initConfig({ 8 | pkg: grunt.file.readJSON('package.json'), 9 | jshint: { 10 | options: { 11 | jshintrc: '.jshintrc' 12 | }, 13 | 14 | all: ['Gruntfile.js', 'js/**/*.js'] 15 | } 16 | }); 17 | 18 | grunt.registerTask("default", ['jshint']); 19 | }; 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "embedly-wordpress", 3 | "version": "4.0.0", 4 | "description": "Embedly Worpress Plugin", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/embedly/embedly_wordpress_plugin.git" 8 | }, 9 | "author": "Embedly", 10 | "license": "BSD-2-Clause", 11 | "bugs": { 12 | "url": "https://github.com/embedly/embedly_wordpress_plugin/issues" 13 | }, 14 | "homepage": "https://github.com/embedly/embedly_wordpress_plugin#readme", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-contrib-jshint": "^0.11.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "window", "location", "document", "XMLSerializer", 4 | "setTimeout", "clearTimeout", "setInterval", "clearInterval", 5 | "require", "module" 6 | ], 7 | 8 | "node" : false, 9 | "browser" : false, 10 | 11 | "boss" : true, 12 | "curly": false, 13 | "debug": false, 14 | "devel": false, 15 | "eqeqeq": true, 16 | "evil": true, 17 | "forin": false, 18 | "immed": false, 19 | "laxbreak": false, 20 | "newcap": true, 21 | "noarg": true, 22 | "noempty": false, 23 | "nonew": false, 24 | "nomen": false, 25 | "onevar": false, 26 | "plusplus": false, 27 | "regexp": false, 28 | "undef": true, 29 | "sub": true, 30 | "strict": false, 31 | "white": false, 32 | "eqnull": true, 33 | "es3": true, 34 | "unused": true 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Embedly Wordpress Plugin 2 | 3 | Updating the plugin: 4 | 5 | 1. Ensure the github repo readme.txt and embedly.php are showing the correct version of the plugin (i.e. from 4.0.1 -> 4.0.2, this version needs to be reflected in these two files) 6 | 7 | 2. in the svn repo, `svn up` to update, if necessary 8 | 9 | 3. `cp github_repo_dir/* svn_repo_dir/trunk/` (remove any .git or other unnecessary files (like this 'README.md' file!)) 10 | 11 | 4. `cd svn_repo_dir/trunk` 12 | 13 | 5. check updates with `svn stat` and `svn diff` (especially the version bump) 14 | 15 | 6. `svn ci -m "a public message" --username USERNAME --password PASSWORD` 16 | 17 | 7. `cd ..` go up to the master svn directory 18 | 19 | 8. make a new tag `mkdir tags/X.Y.Z && svn add tags/X.Y.Z` 20 | 21 | 9. svn-copy the trunk files `svn cp trunk/* tags/X.Y.Z/` 22 | 23 | 10. Check changes again with `svn stat` and `svn diff` if necessary 24 | 25 | 11. `svn ci -m "tagging version X.Y.Z" --username USERNAME --password PASSWORD` 26 | -------------------------------------------------------------------------------- /img/embedly-white-70-40.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /img/embedly_logo_blue.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /img/embedly_wordpress_logo.png: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /svn-assets/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 11 | 22 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /css/embedly-admin.css: -------------------------------------------------------------------------------- 1 | .embedly-wrap { 2 | width:90%; 3 | margin:0 auto; 4 | position:relative; 5 | padding:20px; 6 | font-size: 16px; 7 | font-weight: 500; 8 | /* font weight should be 500 */ 9 | } 10 | .embedly-ui { 11 | color: #36495e; 12 | font-family: 'museo-sans-fontspring', sans-serif; 13 | -webkit-font-smoothing: antialiased; 14 | background:#fff; 15 | } 16 | 17 | .embedly-ui a { 18 | text-decoration:none; 19 | color: #36495e; 20 | } 21 | .embedly-ui a.emb-button { 22 | color: #fff; 23 | } 24 | .embedly-ui h1 { 25 | font-family: 'proxima-nova-extra-condensed-fontspring'; 26 | font-size: 70px; 27 | line-height: 80px; 28 | margin:0; 29 | } 30 | /* Overrides color of checkmarks in checkboxes*/ 31 | .embedly-ui input[type="checkbox"]:checked:before { 32 | color: #36495e; 33 | } 34 | 35 | .embedly-analytics { 36 | font-size: 16px; 37 | text-align: center; 38 | vertical-align: middle; 39 | } 40 | 41 | .embedly-analytics .active-viewers, .embedly-analytics .historical-viewers { 42 | margin: 30px 0 70px; 43 | } 44 | 45 | .embedly-analytics p { 46 | font-size: 16px; 47 | letter-spacing: 0.25px; 48 | } 49 | .embedly-ui-header-wrapper { 50 | height:99px; 51 | text-align: center; 52 | vertical-align: middle; 53 | } 54 | .embedly-ui-header { 55 | position:relative; 56 | width: 100%; 57 | } 58 | .embedly-ui-logo { 59 | background:url('../img/wordpressicon-93x88.png') no-repeat 0 0; 60 | display:block; 61 | height:88px; 62 | width:93px; 63 | overflow:hidden; 64 | text-indent:100%; 65 | white-space:nowrap; 66 | margin-left: auto; 67 | margin-right: auto; 68 | 69 | } 70 | .embedly-ui-key-wrap { 71 | margin-left: 30px; 72 | margin-right:30px; 73 | margin-bottom: 30px; 74 | background:#fff; 75 | padding:1px; 76 | } 77 | .embedly-ui-key-form { 78 | background:#fff; 79 | border-radius:0px; 80 | padding:14px; 81 | } 82 | #welcome-blurb{ 83 | text-align: left; 84 | margin: 30px; 85 | } 86 | #welcome-blurb h2 { 87 | size: 14px; 88 | color: #36495e; 89 | } 90 | #welcome-blurb h3 { 91 | size: 18px; 92 | color: #36495e; 93 | } 94 | .embedly-footer { 95 | text-align: center; 96 | vertical-align: middle; 97 | font-size: 14px; 98 | float:bottom; 99 | color: #808080; 100 | } 101 | .embedly-footer .dashicons:before { 102 | color: #808080; 103 | } 104 | #footer { 105 | clear: both; 106 | position: relative; 107 | z-index: 10; 108 | height: 3em; 109 | margin-top: -3em; 110 | } 111 | /*styles for advanced dropdown*/ 112 | .dropdown-wrapper h3 { 113 | font-weight: bold; 114 | color: #36495e; 115 | } 116 | .advanced-wrapper p { 117 | letter-spacing: 0.25px; 118 | } 119 | #embedly-settings-saved { 120 | margin-left: 30px; 121 | font-weight: normal; 122 | display: none; 123 | } 124 | .advanced-body { 125 | padding: 5px; 126 | } 127 | .advanced-body p { 128 | font-size: 16px; 129 | font-weight: 500; 130 | } 131 | .advanced-selections { 132 | float: left; 133 | width: 20%; 134 | } 135 | .advanced-wrapper .advanced-body li { 136 | margin-top: 30px; 137 | margin-bottom: 30px; 138 | } 139 | .max-width-input-container p { 140 | margin-top: 12px; 141 | } 142 | .card-preview-container { 143 | padding-top: 30px; 144 | padding-bottom: 30px; 145 | padding-left: 50px; 146 | padding-right: 50px; /* to acommodate the sharing buttons */ 147 | width: 65%; 148 | min-height: 550px; 149 | float: right; 150 | vertical-align: middle; 151 | border: 2px solid #F1F1F2; 152 | } 153 | .card-preview-container.dark-theme { 154 | background-color: #3A3A3A; 155 | } 156 | .card-preview-container.dark-theme h3 { 157 | color: #EEE; /* matches card text */ 158 | } 159 | .card-preview-container h3 { 160 | margin-bottom: 20px; 161 | margin-top: 0px; 162 | } 163 | /* end styles for advanced dropdown menu*/ 164 | 165 | /* styles for api key dropdown */ 166 | .api-key-body { 167 | display: none; 168 | padding: 5px; 169 | padding-bottom: 50px; 170 | } 171 | 172 | .api-key-body p { 173 | font-size: 16px; 174 | } 175 | 176 | /* styles for tutorial dropdown */ 177 | .tutorial-body { 178 | display: none; 179 | padding: 5px; 180 | } 181 | .tutorial-body p { 182 | font-size: 16px; 183 | } 184 | .tutorial-wrapper { 185 | clear: both; 186 | } 187 | .embedly-create-account-btn-wrap { 188 | /*page-break-inside: '';*/ 189 | } 190 | .embedly-create-account-btn-wrap a { 191 | color: #4CC6E6; 192 | } 193 | .embedly-create-account-btn-wrap p { 194 | color: #808080; 195 | } 196 | #create-account-btn { 197 | font-size: 20px; 198 | -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ 199 | -moz-box-sizing: border-box; /* Firefox, other Gecko */ 200 | box-sizing: border-box; /* Opera/IE 8+ */ 201 | } 202 | .emb-button { 203 | -webkit-appearance: none; 204 | -moz-appearance: none; 205 | border: solid 0 #1eb0d7; 206 | border-radius: 0; 207 | cursor: pointer; 208 | font-family: 'museo-sans-fontspring',Helvetica,Arial,sans-serif; 209 | font-size: 16px; 210 | font-weight: 700; 211 | line-height: normal; 212 | position: relative; 213 | text-align: center; 214 | text-decoration: none; 215 | display: inline-block; 216 | padding: 1.25rem 1.5rem; 217 | background-color: #36495e; 218 | color: #FFF; 219 | transition: background-color 300ms ease-out; 220 | letter-spacing: .75px; 221 | } 222 | .emb-button:hover { 223 | background-color:#556d82; 224 | } 225 | .emb-button-long { 226 | width: 100%; 227 | } 228 | /* welcome page styles */ 229 | .welcome-page-body section{ 230 | margin: 50px 0; 231 | } 232 | #twitter-icon { 233 | font-size: 25px; 234 | margin: 4px; 235 | } 236 | .welcome-page-body p { 237 | font-size: 20px; 238 | margin: 0 auto; 239 | } 240 | #embedly-welcome-blurb { 241 | max-width: 1000px; 242 | margin: 0 auto; 243 | } 244 | 245 | #connect-button { 246 | outline: none; 247 | background-color: #4CC6E6; 248 | font-size: 20px; 249 | } 250 | .inner-connect-button{ 251 | vertical-align: center; 252 | } 253 | #connect-btn-img { 254 | height: 21px; 255 | width: auto; 256 | vertical-align: middle; 257 | } 258 | span.inner-button-span { 259 | vertical-align: middle; 260 | } 261 | #embedly-which { 262 | padding: 20px; 263 | display: none; 264 | background-color: #4CC6E6; 265 | } 266 | #embedly-which p { 267 | color: #fff; 268 | margin: 0 auto; 269 | font-size: 16px; 270 | } 271 | #embedly-which a { 272 | text-decoration: none; 273 | display: block; 274 | color: #fff; 275 | cursor: pointer; 276 | font-size: 20px; 277 | font-weight: bold; 278 | } 279 | #embedly-which-list li { 280 | margin: 10px; 281 | font-size: 14px; 282 | } 283 | #embedly-connect-failed-refresh { 284 | display: none; 285 | } 286 | /* wp styles */ 287 | #wpwrap { 288 | background-color: #FFF; 289 | } 290 | /* Background color along admin panel right side*/ 291 | #wpcontent { 292 | background-color: #FFF; 293 | } 294 | /* Background color for rest of setting page*/ 295 | #wpbody-content { 296 | background-color:#FFF; 297 | } 298 | .embedly-di .dashicons { 299 | margin:0px; 300 | padding:3px; 301 | vertical-align:middle; 302 | color:#000000; 303 | } 304 | .embedly-di .dashicons:before { 305 | -webkit-font-smoothing: antialiased; 306 | font:400 20px/1 dashicons; 307 | color: #36495e; 308 | } 309 | .embedly-di .dashicons:hover:before { 310 | color: #4CC6E6; 311 | } 312 | .embedly-di .dashicons.di-center { 313 | margin:0; 314 | } 315 | .embedly-di .dashicons.di-center:before { 316 | content:"\f134"; 317 | } 318 | .embedly-di .dashicons.di-none:before { 319 | content:"\f138"; 320 | } 321 | /* reverses divicon-align-none to appear as a right align*/ 322 | .embedly-di .dashicons.di-reverse { 323 | -moz-transform: scale(-1, 1); 324 | -webkit-transform: scale(-1, 1); 325 | -o-transform: scale(-1, 1); 326 | -ms-transform: scale(-1, 1); 327 | transform: scale(-1, 1); 328 | } 329 | 330 | ul.align-select { 331 | list-style-type: none; 332 | margin: 2000; 333 | padding: 0; 334 | } 335 | ul.align-select li { 336 | display: inline; 337 | } 338 | /* Hilights selected align icon */ 339 | span.selected-align-select { 340 | outline-width: 1px; 341 | outline-style: solid; 342 | outline-color: #36495e; 343 | } 344 | span.selected-align-select:hover { 345 | outline-color: #4CC6E6; /* outline color */ 346 | } 347 | 348 | /* BEGIN STYLES FOR NEW USER MODAL */ 349 | .embedly-new-user-modal { 350 | text-align: center; 351 | vertical-align: middle; 352 | } 353 | .dashicons-twitter:before { 354 | color: #55acee; 355 | } 356 | 357 | /* END STYLES FOR NEW USER MODAL */ 358 | #embedly-max-width { 359 | width: 80%; 360 | height: 40px; 361 | border: 1px solid #36495e; 362 | } 363 | 364 | #embedly-api-key { 365 | width: 80%; 366 | height: 40px; 367 | } 368 | 369 | input.default-input { 370 | border: 1px solid #36495e; 371 | } 372 | 373 | input.success-input { 374 | border: 1px solid #6bbd5b; 375 | } 376 | 377 | input.error-input{ 378 | border: 1px solid #ff0033; 379 | { 380 | 381 | ::-webkit-input-placeholder { /* WebKit, Blink, Edge */ 382 | color: #808080; 383 | } 384 | :-moz-placeholder { /* Mozilla Firefox 4 to 18 */ 385 | color: #808080; 386 | opacity: 1; 387 | } 388 | ::-moz-placeholder { /* Mozilla Firefox 19+ */ 389 | color: #808080; 390 | opacity: 1; 391 | } 392 | :-ms-input-placeholder { /* Internet Explorer 10-11 */ 393 | color: #808080; 394 | } 395 | 396 | .embedly-default-card-settings { 397 | width: 50%; 398 | } 399 | .embedly-default-card-settings ul li { 400 | margin-top: 15px; 401 | margin-bottom: 15px; 402 | } 403 | 404 | 405 | 406 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === Embedly === 2 | 3 | Contributors: Embedly 4 | Tags: embed, oembed, video, image, pdf, card 5 | Requires at least: 3.8 6 | Tested up to: 4.9.4 7 | Stable tag: 4.9.2 8 | License: GPLv2 9 | License URI: http://www.gnu.org/licenses/gpl-2.0.html 10 | 11 | The Embedly Plugin extends Wordpress's auto-embed feature to give your blog more media types and style optons. 12 | 13 | == Description == 14 | 15 | Enhance the default Wordpress embedding to get previews for any article, 16 | including your own blog posts. You also get embeds for Gfycat, Twitch, Google 17 | Maps, and Embedly’s growing list of [500+ supported 18 | providers](http://embed.ly/providers). 19 | 20 | You can customize the style of the embeds, to optimize for darker WP themes, 21 | alignment, and width. In addition, social buttons can be added around the embeds 22 | to make it easier to share content from your blog posts. 23 | 24 | If you have an Embedly Cards account, you can link it to the plugin with your Embedly API key. Not only does this remove branding from the cards, it also gives you access to analytics and viewer behaviors for most popular music and video player embeds (YouTube, Vimeo, Instagram, SoundCloud). Find out how many people viewed your embeds for how long. To learn more about Embedly Cards please visit [our website](http://embed.ly/cards). 25 | 26 | Using it is as simple as the default Wordpress embedding. Embed media by pasting its URL in a single line when writing a post 27 | 28 | The plugin automatically displays an embed of the media in the Wordpress post 29 | editor (for WP 4.0+). 30 | 31 | Fair Warning: This plugin generates static HTML content for your posts. After you deactivate 32 | the plugin, that HTML will still remain behind in all posts where the plugin was used to create 33 | embeds. 34 | 35 | 36 | == Installation == 37 | 38 | 39 | Using the Plugin Manager 40 | 41 | 1. Click Plugins in the Wordpress Dashboard sidebar. 42 | 43 | 1. Click Add New. 44 | 45 | 1. Search for Embedly. 46 | 47 | 1. Click Install 48 | 49 | 1. Click Install Now 50 | 51 | 1. Click Activate Plugin 52 | 53 | 1. Create a new post and paste a URL. It will automatically turn into an embed. 54 | 55 | 1. (optional) Save your Embedly API key to link your Embedly Cards account for analytics and unbranding 56 | 57 | 58 | Manually 59 | 60 | 1. Upload `embedly` to the `/wp-content/plugins/` directory 61 | 62 | 1. Activate the plugin through the 'Plugins' menu in WordPress 63 | 64 | 1. Go through the sign up flow as described above. 65 | 66 | 67 | 68 | Multi-Site 69 | 70 | 1. Navigate to My Sites -> Network Admin 71 | 72 | 1. Follow Steps 1-5 in Using the Plugin Manager setup above, `Do not Network Activate` 73 | 74 | 1. Go to each site's dashboard and activate Embedly in Plugins section 75 | 76 | 1. Go through the sign up flow as described above. 77 | 78 | 79 | 80 | == Frequently Asked Questions == 81 | 82 | = 83 | Is this plugin for me? 84 | = 85 | 86 | Yes 87 | 88 | = 89 | Where do I get a key? 90 | = 91 | 92 | You can obtain a key when sign up for an Embedly account. You 93 | can also get your key anytime by going to your [Embedly 94 | account](http://app.embed.ly). 95 | 96 | = 97 | How do I embed "any" URL? 98 | = 99 | 100 | In the post editor, once the plugin is installed, paste in the URL you are 101 | trying to embed. 102 | 103 | = 104 | What happens after I deactivate the plugin or delete my Embedly account? 105 | = 106 | 107 | Cards will remain active even if you delete the plugin and/or delete your Embedly account. This happens 108 | because after we generate a card for your post, it is converted into static HTML. This HTML gets saved 109 | to the post. Removing the plugin has no effect on posts that were created in the past. 110 | 111 | = 112 | I updated a setting for an embed but the embed didn't reflect the change? 113 | = 114 | 115 | Advanced Settings only affect newly generated cards. If you wish to change the appearance of a pre-existing 116 | card, you will have to recreate the card in the post editor after making any settings changes. 117 | 118 | = 119 | Do I need a key? 120 | = 121 | 122 | No. An Embedly API key is optional. It's only required if you have an Embedly Cards account and you want to remove embedly branding or you want to view analytics about the content embedded on your posts. 123 | 124 | = 125 | What is your support email? 126 | = 127 | 128 | support@embed.ly 129 | 130 | = 131 | Do you support multi-site? 132 | = 133 | 134 | Yes, see steps above to install for multi-site. 135 | Note: You will need to activate Embedly for each site. 136 | 137 | = 138 | Can the width and alignment be changed? 139 | = 140 | Yes! Both the width and alignment can be changed for embeds that use the plugin. 141 | You can make these adjustments under Advanced Embed Settings in the Embedly 142 | plugin settings in your Wordpress Dashboard. 143 | 144 | = 145 | Can I change the CSS of the embeds? 146 | = 147 | 148 | No, but you have a few options in styling under the Advanced Embed Settings section of 149 | the Embedly plugin dashboard. 150 | 151 | = 152 | What options are there for styling the embeds? 153 | = 154 | 155 | You can change the width, alignment, and adjust the cards to work better for 156 | darker themes. 157 | 158 | = 159 | How do I find more analytics? 160 | = 161 | 162 | You can view the full set of analytics on your embed by going to your account 163 | dashboard. 164 | 165 | = 166 | How does this affect my SEO? 167 | = 168 | 169 | The embeds from the Embedly Wordpress plugin include title and description meta 170 | information that can provide relevant information to search engines about the 171 | embeds to boost SEO. 172 | 173 | == Screenshots == 174 | 175 | 176 | 1. Advanced Embed Settings 177 | 178 | 2. Writing a post and embedding. 179 | 180 | 3. Sample Post. 181 | 182 | 183 | == Changelog == 184 | 185 | = 4.7.0 = 186 | 187 | * Having an active app.embed.ly account is now optional to use the plugin! Users who want access to unbranded 188 | card embeds and/or analytics can elect to input their Embedly API key in the plugin settings, but users who just want 189 | to get started embedding no longer need to create an embedly account and activate the plugin. 190 | 191 | = 4.0.9 = 192 | 193 | * Improved plugin security. 194 | 195 | = 4.0.6 = 196 | 197 | * Embedly is not currently supporting historical analytics for embeds, but you can still see realtime views. 198 | * Improves the implementation of javascript dependencies via the wp_enqueue_script api. 199 | 200 | = 4.0 = 201 | 202 | * Removed Embedly TinyMCE Button. 203 | * Added Editor Preview URL functionality for all URLS (WP v4.0+) 204 | * Redesigned Embedly Admin page 205 | * All embeds will be generated as Embedly Cards 206 | 207 | = 3.2 = 208 | 209 | * Embedly TinyMCE dialog and dependencies managed server side. 210 | * Refactor code to use class structure. 211 | * Clean up deprecated SQL generation to make compliant with WP3.6 and above. 212 | 213 | = 3.1.3 = 214 | 215 | * Fix Add Post bug in IE. 216 | 217 | = 3.1.2 = 218 | 219 | * Enable Twitter WP OEmbed. 220 | 221 | = 3.1 = 222 | 223 | * Fixes issue with Embedly not loading on WP3.9. 224 | * Load tiny_mce_popup_4_0.js when TinyMCE is v4.0. 225 | 226 | = 3.0 = 227 | 228 | * Upgrade Embedly TinyMce editor option to use Embedly Cards. 229 | 230 | = 2.3.0 = 231 | 232 | * Use TinyMCE provided by WP Core. 233 | * Fixes issue with HTML editting and formatting. 234 | 235 | = 2.2.2 = 236 | 237 | * Change server side calls to HTTP to avoid issues. 238 | * Disable rocketloader syntax. 239 | 240 | = 2.2 = 241 | 242 | * Update TinyMce Popup js to latest. 243 | * Update to latest JQuery 1.10.2. 244 | * Update Powered by link destination to code generator. 245 | * Fix powered by logo for RSS generation. 246 | * Add support for links to open in new window. 247 | 248 | = 2.1.4 = 249 | 250 | * Support for blogs using HTTPS. 251 | * Steps for multi-site setup. 252 | 253 | = 2.1.2 = 254 | 255 | * Use wp-includes tiny_mce_popup.js 256 | * Compatible with WP 3.5 257 | 258 | = 2.1.1 = 259 | 260 | * Providers save fix. 261 | 262 | = 2.1 = 263 | 264 | * Admin Redesign. 265 | * embedly_settngs option for wp_options table. 266 | * SQL optimizations. 267 | 268 | = 2.0.9 = 269 | 270 | * Fix for feature status check. 271 | 272 | = 2.0.8 = 273 | 274 | * Allow script tag embeds. 275 | 276 | = 2.0.6 = 277 | 278 | * Add Embedly providers on 'plugins_loaded' instead of 'init' and other tweaks 279 | 280 | = 2.0.5 = 281 | 282 | * Fixing the path to TinyMCE plugin. 283 | 284 | = 2.0.4 = 285 | 286 | * Updated flow for previewing and updating embeds. 287 | 288 | * Improved previews for preview endpoint. 289 | 290 | * Better error handling for loading plugin in Post Editor. 291 | 292 | = 2.0.3 = 293 | 294 | * Resolve issue with tag attributes getting stripped 295 | 296 | * Resolve quirks with height getting set incorrectly 297 | 298 | = 2.0.2 = 299 | 300 | * Resolve conflict with WordPress image editing 301 | 302 | = 2.0.1 = 303 | 304 | * Resolves Rich Editor not showing up. 305 | 306 | = 2.0 = 307 | 308 | * Adds Embedly TinyMCE plugin to Rich Editor. 309 | 310 | * Support for Embedly Key to Embed "any" URL. 311 | 312 | = 1.0 = 313 | 314 | A few fixes. 315 | 316 | = 0.9 = 317 | 318 | Initial Version 319 | 320 | 321 | 322 | == Upgrade Notice == 323 | 324 | = 2.0 = 325 | 326 | Embed "any" URL. 327 | 328 | = 2.1 = 329 | 330 | Admin Redesign. 331 | 332 | = 2.2 = 333 | 334 | Update tinymce and jquery libs. 335 | 336 | = 3.0 = 337 | 338 | Embedly rich post editor option now uses Embedly Cards layout. 339 | 340 | = 3.1 = 341 | 342 | Dynamically loading Embedly popup based on TinyMCE Version. 343 | 344 | = 3.2 = 345 | 346 | Refactor Embedly TinyMCE Dialog to generate via iframe request. 347 | -------------------------------------------------------------------------------- /js/embedly.js: -------------------------------------------------------------------------------- 1 | /* globals EMBEDLY_CONFIG:true, jQuery:true */ 2 | // EMBEDLY ADMIN PAGE JAVASCRIPT 3 | // Copyright 2015 Embedly (email : developer@embed.ly) 4 | 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License, version 2, as 7 | // published by the Free Software Foundation. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 | 18 | // valid class prefixes for modulation of key state 19 | 20 | // To avoid poluting the global namespace, everything should be in here. 21 | (function($){ 22 | 23 | // for mapping backend data to preview card data-card-* attrs 24 | var preview_map = { 25 | 'card_chrome': 'data-card-chrome', 26 | 'card_controls': 'data-card-controls', 27 | 'card_width': 'data-card-width', 28 | 'card_theme': 'data-card-theme', 29 | 'card_align': 'data-card-align' 30 | }; 31 | 32 | var utils = {}; 33 | 34 | utils.comma = function(val){ 35 | while (/(\d+)(\d{3})/.test(val.toString())){ 36 | val = val.toString().replace(/(\d+)(\d{3})/, '$1'+','+'$2'); 37 | } 38 | return val; 39 | }; 40 | 41 | utils.unparam = function(param){ 42 | var query = window.location.search.substring(1).split('&').reduce(function(obj, tuple){ 43 | var parts = tuple.split('='); 44 | obj[parts[0]] = decodeURIComponent(parts[1]); 45 | return obj; 46 | }, {}); 47 | 48 | if (param){ 49 | return query[param]; 50 | } 51 | return query; 52 | }; 53 | 54 | 55 | // Returns 'YYYYMMDD' for now, or and offset in days. 56 | utils.date = function(days){ 57 | var now = new Date(), 58 | utc = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()); 59 | 60 | if (days){ 61 | utc.setDate(utc.getDate() + days); 62 | } 63 | 64 | var str = utc.getFullYear().toString(); 65 | 66 | return str + $.map([utc.getMonth(), utc.getDate()], function(v){ 67 | return ("00" + v).slice(-2); 68 | }).join(''); 69 | }; 70 | 71 | window.utils = utils; 72 | 73 | /* 74 | * APP 75 | * Connect button integration 76 | */ 77 | var app = { 78 | _ready: false, 79 | _iframe: null, 80 | _queue: false, 81 | _callback: null 82 | }; 83 | 84 | app.init = function () { 85 | window.addEventListener('message', function (e) { 86 | var data; 87 | try { 88 | data = window.JSON.parse(e.data); 89 | } catch (err) { 90 | return false; 91 | } 92 | if (!data) { 93 | return false; 94 | } 95 | if (data.method === 'connect' && data.context === 'embedly-app') { 96 | app.message(data); 97 | } 98 | }); 99 | 100 | var iframe = document.createElement('iframe'); 101 | app._iframe = iframe; 102 | 103 | iframe.addEventListener('load', function () { 104 | app._ready = true; 105 | // If we set a callback earlier, use it. 106 | if (app._callback !== null){ 107 | app.connect(app._callback); 108 | } 109 | }); 110 | 111 | iframe.frameborder = '0'; 112 | iframe.style.width = '1px'; 113 | iframe.style.border = 'none'; 114 | iframe.style.position = 'absolute'; 115 | iframe.style.top = '-9999em'; 116 | iframe.style.width = '10px'; 117 | iframe.style.height = '10px'; 118 | iframe.src = 'https://app.embed.ly/api/connect'; 119 | document.body.appendChild(iframe); 120 | }; 121 | 122 | app.message = function (data) { 123 | if (app._callback) { 124 | app._callback.call(window, data); 125 | } 126 | }; 127 | 128 | // connection code 129 | app.connect = function (callback) { 130 | app._callback = callback; 131 | 132 | if (app._ready === false){ 133 | return false; 134 | } 135 | 136 | var msg = window.JSON.stringify({ 137 | method: 'connect' 138 | }); 139 | app._iframe.contentWindow.postMessage(msg, '*'); 140 | }; 141 | 142 | 143 | /* 144 | * ANALYTICS 145 | * Everything that has to do with getting information from Embedly's Analytics Engines. 146 | * Disabled after GDPR 147 | */ 148 | //var analytics = {}; 149 | 150 | // loads the analytics from narrate. 151 | /** 152 | analytics.actives = function() { 153 | if (EMBEDLY_CONFIG.analyticsKey){ 154 | $.getJSON('https://narrate.embed.ly/1/keys?' + $.param({ 155 | key: EMBEDLY_CONFIG.analyticsKey 156 | })).then(function(response){ 157 | $(".embedly-analytics .active-viewers .active-count").text(response.active); 158 | }); 159 | } 160 | }; 161 | **/ 162 | 163 | // Number of impressions in the last week. 164 | // analytics.historical = function() { 165 | // if (EMBEDLY_CONFIG.analyticsKey){ 166 | // var start = utils.date(-7), 167 | // end = utils.date(1); 168 | 169 | // $.getJSON('https://api.embed.ly/2/analytics/stats?' + $.param({ 170 | // key: EMBEDLY_CONFIG.analyticsKey, 171 | // start: start, 172 | // end: end 173 | // })).then(function(response){ 174 | // var value = '-'; 175 | // if (response){ 176 | // value = response.reduce(function(sum, entry){ 177 | // return sum + entry.actions.load; 178 | // }, 0); 179 | // value = utils.comma(value); 180 | // } 181 | // $(".embedly-analytics .historical-viewers .weekly-count").html(value); 182 | // }); 183 | // } 184 | // }; 185 | 186 | // Start everything. 187 | /** 188 | analytics.init = function(){ 189 | analytics.actives(); 190 | setInterval(analytics.actives, 10000); 191 | analytics.historical(); 192 | }; 193 | **/ 194 | 195 | 196 | /* 197 | * SETTINGS 198 | * Everything that has to do with the saving things to the Wordpress Backend. 199 | */ 200 | var settings = {}; 201 | 202 | // given a key, value pair for a card setting, performs 203 | // ajax request to ajaxurl backend to update option 204 | settings.update = function (key, value) { 205 | $.post( 206 | EMBEDLY_CONFIG.ajaxurl, 207 | { 208 | 'action': 'embedly_update_option', 209 | 'security': EMBEDLY_CONFIG.updateOptionNonce, 210 | 'key': key, 211 | 'value': value 212 | }, function(response) { 213 | if(key === 'card_width') { 214 | // if the input was invalid for width, 215 | // the value will default to previous value 216 | value = response; 217 | } 218 | settings.preview(preview_map[key], String(value)); 219 | }); 220 | 221 | $('#embedly-settings-saved').show(); 222 | 223 | // Fade out after 3 seconds. 224 | setTimeout(function(){ 225 | $('#embedly-settings-saved').fadeOut(); 226 | }, 3000); 227 | }; 228 | 229 | // Build the card. 230 | settings.card = function() { 231 | if (window.embedly){ 232 | // clone the template 233 | var clone = $('a.embedly-card-template').clone(); 234 | clone.removeClass('embedly-card-template').addClass('embedly-card-preview'); 235 | // remove the old card 236 | $('.card-preview-container .embedly-card').remove(); 237 | // insert the new card template 238 | clone.insertAfter('a.embedly-card-template'); 239 | // cardify it. 240 | window.embedly.card($('a.embedly-card-preview')[0]); 241 | } else { 242 | // when embedly loads build the card. 243 | window.onEmbedlyReady = function(){ 244 | settings.card(); 245 | }; 246 | } 247 | }; 248 | 249 | // function that updates the template card with the key value pair 250 | settings.preview = function(key, value){ 251 | // update the template first 252 | $('a.embedly-card-template').attr(key, value); 253 | // then render the new card 254 | settings.card(); 255 | }; 256 | 257 | // Save the account. 258 | settings.save = function(api_key, analytics_key, name) { 259 | $.post( 260 | EMBEDLY_CONFIG.ajaxurl, 261 | { 262 | 'action': 'embedly_save_account', 263 | 'security': EMBEDLY_CONFIG.saveAccountNonce, 264 | 'api_key': api_key, 265 | 'analytics_key': analytics_key, 266 | 'org_name': name 267 | }, 268 | function(response) { 269 | if(response === 'true') { 270 | location.reload(); 271 | } else { 272 | window.alert([ 273 | 'We were unable to save your Embedly information your Wordpress ', 274 | 'install. Please email support@embed.ly and we will try to help.'].join('')); 275 | } 276 | 277 | }); 278 | }; 279 | 280 | // Save the account. 281 | settings.save_api_key = function(api_key) { 282 | $.post( 283 | EMBEDLY_CONFIG.ajaxurl, 284 | { 285 | 'action': 'embedly_save_api_key', 286 | 'security': EMBEDLY_CONFIG.saveAccountNonce, 287 | 'api_key': api_key, 288 | }, 289 | function(response) { 290 | input = $('#embedly-api-key') 291 | 292 | if(response === 'removed') { 293 | console.log("Successfully removed Embedly API key") 294 | input.attr('class', 'default-input') 295 | } else if(response === 'true') { 296 | console.log("successfully saved API key") 297 | input.attr('class', 'success-input') 298 | } else { 299 | input.val('') 300 | console.log("Invalid Embedly API Key") 301 | input.attr('class', 'error-input') 302 | } 303 | }); 304 | }; 305 | 306 | //Uses the app.connect to try to auth the user. 307 | settings.connect = function(callback){ 308 | // cleans html for user select: 309 | // if the div is open already, close it., else continue: 310 | var $which = $('#embedly-which'), 311 | $list = $('#embedly-which-list'), 312 | $button = $('#connect-button'); 313 | 314 | if($which.is(":visible")) { 315 | $which.hide(); 316 | return; 317 | } 318 | // if the user clicks multiple times, make sure div is empty 319 | $list.empty(); 320 | 321 | app.connect(function (data) { 322 | if (data.error === false) { 323 | if (data.organizations.length === 1) { 324 | // single organization. easy. 325 | var org = data.organizations[0]; 326 | $button.text('CONNECTED'); 327 | settings.save(org.api_key, org.analytics_key, org.name); 328 | } else { 329 | $which.show(); 330 | 331 | var selected = function (org) { 332 | return function () { 333 | $button.text('CONNECTED'); 334 | settings.save(org.api_key, org.analytics_key, org.name); 335 | // clear html after selection in case of reselection 336 | $which.hide(); 337 | $list.empty(); 338 | }; 339 | }; 340 | 341 | data.organizations.forEach(function(org){ 342 | var $li = $('
  • '), 343 | $a = $(''); 344 | $a.text(org.name.toUpperCase()); 345 | 346 | $a.on('click', selected(org)); 347 | $li.append($a); 348 | $list.append($li); 349 | }); 350 | } 351 | } else { 352 | // user is not currently logged in 353 | if (callback){ 354 | callback({error: true}); 355 | } else { 356 | window.alert("Please log in to your Embedly account first"); 357 | } 358 | } 359 | }); 360 | }; 361 | 362 | settings.init = function(){ 363 | Object.keys(preview_map).forEach(function(key) { 364 | // current card is set globally server side. 365 | // contains a map of "card_chrome" => "1" for all set options 366 | // if set, update the template for the initial card. 367 | if(EMBEDLY_CONFIG.current[key]) { 368 | settings.preview(preview_map[key], EMBEDLY_CONFIG.current[key]); 369 | } 370 | }); 371 | 372 | settings.card(); 373 | }; 374 | 375 | $(document).ready(function($) { 376 | // Set up the iframe; 377 | app.init(); 378 | 379 | // Set up the analytics. 380 | //analytics.init(); 381 | 382 | // Set up the settings. 383 | settings.init(); 384 | 385 | // All the code to deal with the advanced options. 386 | $(".embedly-align-select-container a").click(function(){ 387 | $(this).parent().addClass("selected").siblings().removeClass("selected"); 388 | }); 389 | 390 | // When the alignment is selected, unselect other alignments 391 | $('.align-icon').mousedown(function() { 392 | $(this).children()[0].value = 'checked'; 393 | $(this).addClass('selected-align-select'); 394 | 395 | $.each($(this).parent().siblings(), function(name, obj) { 396 | var span = $(obj).children()[0]; 397 | var hidden = $(span).children()[0]; 398 | hidden.value = 'unchecked'; 399 | $(span).removeClass('selected-align-select'); 400 | }); 401 | 402 | var align = $(this).attr('align-value'); 403 | settings.update('card_align', align); 404 | }); 405 | 406 | // minimal checkbox at the moment 407 | $('.chrome-card-checkbox').click(function() { 408 | settings.update('card_chrome', $(this).is(':checked') ? 0 : 1); 409 | }); 410 | 411 | $('.embedly-social-checkbox').click(function() { 412 | settings.update('card_controls', $(this).is(':checked') ? 1 : 0); 413 | }); 414 | 415 | $('.embedly-dark-checkbox').click(function() { 416 | var checked = $(this).is(':checked'), 417 | value = checked ? 'dark' : 'light'; 418 | 419 | settings.update('card_theme', value); 420 | 421 | var $preview = $('.card-preview-container'); 422 | if(checked) { 423 | $preview.addClass('dark-theme'); 424 | } else { 425 | $preview.removeClass('dark-theme'); 426 | } 427 | }); 428 | 429 | $('#embedly-max-width').focusout(function() { 430 | settings.update('card_width', $(this).val()); 431 | }); 432 | 433 | $('#embedly-max-width').keypress(function(e) { 434 | if(e.which === 13) { 435 | settings.update('card_width', $(this).val()); 436 | return false; 437 | } 438 | }); 439 | 440 | $('#embedly-api-key').focusout(function() { 441 | console.log($(this).val()); 442 | settings.save_api_key($(this).val()); 443 | }); 444 | 445 | $('#embedly-api-key').keypress(function(e) { 446 | if(e.which === 13) { 447 | console.log($(this).val()); 448 | settings.save_api_key($(this).val()); 449 | return false; 450 | } 451 | }); 452 | 453 | // toggles dropdowns 454 | $('.dropdown-wrapper .dropdown-header a').click(function(){ 455 | var $wrapper = $(this).parents('.dropdown-wrapper'), 456 | $body = $wrapper.find('.dropdown-body'), 457 | $arrow = $wrapper.find('.dropdown-header a span'); 458 | 459 | if($body.is(":visible")) { 460 | $body.hide(); 461 | $arrow.removeClass('dashicons-arrow-down-alt2').addClass('dashicons-arrow-right-alt2'); 462 | } else { 463 | $body.show(); 464 | $arrow.removeClass('dashicons-arrow-right-alt2').addClass('dashicons-arrow-down-alt2'); 465 | } 466 | return false; 467 | }); 468 | 469 | // sets the back direct link on the create account button 470 | $('#create-account-btn').attr("href", "https://app.embed.ly/signup/wordpress?back=" + encodeURIComponent(window.location.toString())); 471 | 472 | 473 | // sets the back direct link for pre-existing users 474 | $('#preexisting-user').attr('href', 475 | 'https://app.embed.ly/wordpress?back=' + 476 | encodeURIComponent(window.location.toString())); 477 | 478 | 479 | $('#connect-button').click(function() { 480 | // First try to see if we are logged in, then move away from the plugin. 481 | settings.connect(function(){ 482 | $('#connect-button').html("VISITING APP.EMBED.LY..."); 483 | window.location = [ 484 | 'https://app.embed.ly/wordpress?back=', 485 | encodeURIComponent(window.location.toString()) 486 | ].join(''); 487 | }); 488 | return false; 489 | }); 490 | 491 | // checks if page was loaded after signing in from app.embed.ly/wordpress/* 492 | if(utils.unparam('embedly') === 'back' && !EMBEDLY_CONFIG.analyticsKey) { 493 | $('#embedly-connect-failed-refresh').show(); 494 | $('.embedly-create-account-btn-wrap').hide(); 495 | settings.connect(function(){ 496 | //I'm pretty sure this should fail silently. 497 | }); 498 | } 499 | }); 500 | })(jQuery); 501 | -------------------------------------------------------------------------------- /embedly.php: -------------------------------------------------------------------------------- 1 | api param name 42 | $settings_map = array( 43 | 'card_controls' => 'cards_controls', 44 | 'card_theme' => 'cards_theme', 45 | 'card_width' => 'cards_width', 46 | 'card_align' => 'cards_align', 47 | ); 48 | 49 | /** 50 | * Embedly WP Class 51 | */ 52 | class WP_Embedly 53 | { 54 | 55 | public $embedly_options; //embedly options array 56 | public $embedly_settings_page; //embedly settings page 57 | static $instance; //allows plugin to be called externally without re-constructing 58 | 59 | /** 60 | * Register hooks with WP Core 61 | */ 62 | function __construct() 63 | { 64 | global $wpdb; 65 | self::$instance = $this; 66 | 67 | // init settings array 68 | $this->embedly_options = array( 69 | 'active' => true, 70 | 'key' => '', 71 | 'analytics_key' => '', 72 | 'card_controls' => true, 73 | 'card_align' => 'center', 74 | 'card_width' => '', 75 | 'card_theme' => 'light', 76 | 'is_key_valid' => false, 77 | 'is_welcomed' => false, 78 | ); 79 | 80 | //i18n 81 | add_action('init', array( 82 | $this, 83 | 'i18n' 84 | )); 85 | 86 | //Write default options to database 87 | add_option('embedly_settings', $this->embedly_options); 88 | 89 | //Update options from database 90 | $this->embedly_options = get_option('embedly_settings'); 91 | 92 | register_deactivation_hook(__FILE__, array( 93 | $this, 94 | 'embedly_deactivate' 95 | )); 96 | 97 | 98 | /** 99 | * We have to check if a user's embedly api key is valid once in a while for 100 | * security. If their API key was compromised, or if their acct. 101 | * was deleted. This ensures plugin functionality, and proper analytics. 102 | * 103 | * But we don't need to do it every time the load the page. 104 | */ 105 | if( !wp_next_scheduled( 'embedly_revalidate_account' ) ) { 106 | wp_schedule_event( time(), 'hourly', 'embedly_revalidate_account' ); 107 | } 108 | 109 | //Admin settings page actions 110 | add_action('admin_menu', array( 111 | $this, 112 | 'embedly_add_settings_page' 113 | )); 114 | 115 | add_action('admin_print_styles', array( 116 | $this, 117 | 'embedly_enqueue_admin' 118 | )); 119 | 120 | add_action('admin_enqueue_scripts', array( 121 | $this, 122 | 'embedly_localize_config' 123 | )); 124 | 125 | // action notifies user on admin menu if they don't have a key 126 | //add_action( 'admin_menu', array( 127 | // $this, 128 | // 'embedly_notify_user_icon' 129 | //)); 130 | 131 | add_action('wp_ajax_embedly_update_option', array( 132 | $this, 133 | 'embedly_ajax_update_option' 134 | )); 135 | add_action('wp_ajax_embedly_save_account', array( 136 | $this, 137 | 'embedly_save_account', 138 | )); 139 | add_action('wp_ajax_embedly_save_api_key', array( 140 | $this, 141 | 'embedly_save_api_key', 142 | )); 143 | 144 | // Instead of checking for admin_init action 145 | // we created a custom cron action on plugin activation. 146 | // it will revalidate the acct every hour. 147 | // worst case if a user wants to revalidate immediately 148 | // just deactivate and reactivate the plugin 149 | //add_action('embedly_revalidate_account', array( 150 | // $this, 151 | // 'validate_api_key' 152 | //)); 153 | 154 | // action establishes embed.ly the provider of embeds 155 | add_action('plugins_loaded', array( 156 | $this, 157 | 'add_embedly_providers' 158 | )); 159 | } 160 | 161 | 162 | /** 163 | * makes sure the key is always valid (in case user, say, deletes their app acct) 164 | **/ 165 | function validate_api_key() 166 | { 167 | if($this->embedly_acct_has_feature('card_details', $this->embedly_options['key'])) { 168 | $this->embedly_save_option('is_key_valid', true); 169 | } else { 170 | $this->embedly_save_option('is_key_valid', false); 171 | } 172 | } 173 | 174 | /** 175 | * receives embedly account data from connection request 176 | **/ 177 | function embedly_save_account() 178 | { 179 | // check nonce 180 | if( ! wp_verify_nonce($_POST['security'], "embedly_save_account_nonce") ) { 181 | echo "security exception"; 182 | wp_die("security_exception"); 183 | } 184 | 185 | // verify permission to save account info on 'connect' click 186 | if(!current_user_can('manage_options')) { 187 | echo "invalid permissions"; 188 | wp_die("permission_exception"); 189 | } 190 | 191 | // not validating the analytics_key for security. 192 | // analytics calls will just fail if it's invalid. 193 | if(isset($_POST) && !empty($_POST)) { 194 | $api_key = $_POST['api_key']; 195 | $analytics_key=$_POST['analytics_key']; 196 | 197 | $this->embedly_save_option('key', $api_key); 198 | $this->embedly_save_option('analytics_key', $analytics_key); 199 | // need to validate the API key after signup since no longer plugin_load hook. 200 | $this->validate_api_key(); 201 | 202 | // better than returning some ambiguous boolean type 203 | echo 'true'; 204 | wp_die(); 205 | } 206 | echo 'false'; 207 | wp_die(); 208 | } 209 | 210 | /** 211 | * receives embedly api_key from plugin api key input, validates and saves it. 212 | **/ 213 | function embedly_save_api_key() 214 | { 215 | // check nonce 216 | if( ! wp_verify_nonce($_POST['security'], "embedly_save_account_nonce") ) { 217 | echo "security exception"; 218 | wp_die("security_exception"); 219 | } 220 | 221 | // verify permission to save account info on 'connect' click 222 | if(!current_user_can('manage_options')) { 223 | echo "invalid permissions"; 224 | wp_die("permission_exception"); 225 | } 226 | 227 | if(isset($_POST) && !empty($_POST)) { 228 | $api_key = $_POST['api_key']; 229 | if (empty($api_key)) { 230 | # assume removal intended. 231 | $this->embedly_save_option('key', ''); 232 | echo 'removed'; 233 | wp_die(); 234 | } else { 235 | # actually check the key: 236 | $valid = $this->embedly_acct_has_feature('card_details', $api_key); 237 | } 238 | 239 | if($valid) { 240 | $this->embedly_save_option('key', $api_key); 241 | // better than returning some ambiguous boolean type 242 | echo 'true'; 243 | wp_die(); 244 | } else { 245 | echo 'false'; 246 | wp_die(); 247 | } 248 | 249 | // need to validate the API key after signup since no longer plugin_load hook. 250 | #$this->validate_api_key(); 251 | 252 | } 253 | echo 'false'; 254 | wp_die(); 255 | } 256 | 257 | /** 258 | * handles request from frontend to update a card setting 259 | **/ 260 | function embedly_ajax_update_option() 261 | { 262 | // verify nonce 263 | if( ! wp_verify_nonce($_POST['security'], "embedly_update_option_nonce") ) { 264 | echo "security exception"; 265 | wp_die("security_exception"); 266 | } 267 | 268 | // verify permissions 269 | if(!current_user_can('manage_options')) { 270 | echo "invalid permissions"; 271 | wp_die("permission_exception"); 272 | } 273 | 274 | if(!isset($_POST) || empty($_POST)) { 275 | echo 'ajax-error'; 276 | wp_die("invalid_post"); 277 | } 278 | 279 | // access to the $_POST from the ajax call data object 280 | if ($_POST['key'] == 'card_width') { 281 | $this->embedly_save_option($_POST['key'], $this->handle_width_input($_POST['value'])); 282 | // return the width of the card (only back end validated input) 283 | echo $this->embedly_options['card_width']; 284 | } else { 285 | $this->embedly_save_option($_POST['key'], $_POST['value']); 286 | } 287 | 288 | wp_die(); 289 | } 290 | 291 | /** 292 | * Load plugin translation 293 | */ 294 | function i18n() 295 | { 296 | load_plugin_textdomain('embedly', false, dirname(plugin_basename(__FILE__)) . '/lang/'); 297 | } 298 | 299 | /** 300 | * Deactivation Hook 301 | **/ 302 | function embedly_deactivate() 303 | { 304 | wp_clear_scheduled_hook('embedly_revalidate_account'); 305 | delete_option('embedly_settings'); 306 | } 307 | 308 | 309 | /** 310 | * warns user if their key is not set in the settings 311 | * DEPRECATED 312 | **/ 313 | function embedly_notify_user_icon() 314 | { 315 | if( !empty($this->embedly_options['key'])) { 316 | return; 317 | } 318 | 319 | global $menu; 320 | if ( !$this->valid_key() ) { 321 | foreach ( $menu as $key => $value ) { 322 | if ($menu[$key][2] == 'embedly') { 323 | // accesses the menu item html 324 | $menu[$key][0] .= ' '. 325 | ''. 327 | '!'; 328 | return; 329 | } 330 | } 331 | } 332 | } 333 | 334 | /** 335 | * Adds top level Embedly settings page 336 | **/ 337 | function embedly_add_settings_page() 338 | { 339 | if(current_user_can('manage_options')) { 340 | $icon = 'dashicons-admin-generic'; 341 | if( version_compare( $GLOBALS['wp_version'], '4.1', '>' ) ) { 342 | $icon = 'dashicons-align-center'; 343 | } 344 | 345 | $this->embedly_settings_page = add_menu_page('Embedly', 'Embedly', 'activate_plugins', 'embedly', array( 346 | $this, 347 | 'embedly_settings_page' 348 | ), $icon); 349 | } 350 | 351 | } 352 | 353 | 354 | /** 355 | * Enqueue styles/scripts for embedly page(s) only 356 | **/ 357 | function embedly_enqueue_admin() 358 | { 359 | $screen = get_current_screen(); 360 | if ($screen->id == $this->embedly_settings_page) { 361 | wp_enqueue_style('dashicons'); 362 | wp_enqueue_style('embedly_admin_styles', EMBEDLY_URL . '/css/embedly-admin.css'); 363 | wp_enqueue_style('embedly-fonts', 'https://cdn.embed.ly/wordpress/static/styles/fontspring-stylesheet.css'); 364 | wp_enqueue_script('platform', '//cdn.embedly.com/widgets/platform.js', array(), '1.0', true); 365 | } 366 | return; 367 | } 368 | 369 | /** 370 | * Localizes the configuration settings for the user, making EMBEDLY_CONFIG available 371 | * prior to loading embedly.js 372 | **/ 373 | function embedly_localize_config() 374 | { 375 | global $settings_map; 376 | 377 | // DEPRECATED 378 | //if($this->valid_key()) { 379 | // $analytics_key = $this->embedly_options['analytics_key']; 380 | //} else { 381 | // $analytics_key = 'null'; 382 | // } 383 | 384 | $ajax_url = admin_url( 'admin-ajax.php', 'relative' ); 385 | 386 | $current = array(); 387 | foreach ($settings_map as $setting => $api_param) { 388 | if(isset($this->embedly_options[$setting])) { 389 | if( is_bool($this->embedly_options[$setting])) { 390 | $current[$setting] = $this->embedly_options[$setting] ? '1' : '0'; 391 | } else { 392 | $current[$setting] = $this->embedly_options[$setting]; 393 | } 394 | } 395 | } 396 | 397 | $embedly_config = array( 398 | 'updateOptionNonce' => wp_create_nonce("embedly_update_option_nonce"), 399 | 'saveAccountNonce' => wp_create_nonce("embedly_save_account_nonce"), 400 | #'analyticsKey' => $analytics_key, 401 | 'ajaxurl' => $ajax_url, 402 | 'current' => $current, 403 | ); 404 | 405 | wp_register_script('embedly_admin_scripts', EMBEDLY_URL . '/js/embedly.js', array( 406 | 'jquery' 407 | ), '1.0', true); 408 | wp_localize_script('embedly_admin_scripts', 'EMBEDLY_CONFIG', $embedly_config); 409 | wp_enqueue_script('embedly_admin_scripts'); 410 | } 411 | 412 | 413 | /** 414 | * Does the work of adding the Embedly providers to wp_oembed 415 | **/ 416 | function add_embedly_providers() 417 | { 418 | // if user entered valid key, override providers, else, do nothing 419 | //if ($this->valid_key()) { 420 | // delete all current oembed providers 421 | add_filter('oembed_providers', '__return_empty_array'); 422 | // add embedly provider 423 | $provider_uri = $this->build_uri_with_options(); 424 | wp_oembed_add_provider('#https?://[^\s]+#i', $provider_uri, true); 425 | //} 426 | } 427 | 428 | 429 | /** 430 | * construct's a oembed endpoint for cards using embedly_options settings 431 | * 432 | * If key is defined, use it. Else, don't. 433 | **/ 434 | function build_uri_with_options() 435 | { 436 | global $settings_map; 437 | // gets the subset of settings that are actually set in plugin 438 | $set_options = array(); 439 | if(!empty($settings_map)) { 440 | foreach ($settings_map as $setting => $api_param) { 441 | if(isset($this->embedly_options[$setting])) { 442 | $set_options[$setting] = $api_param; 443 | } 444 | } 445 | } 446 | 447 | // option params is a list of url_param => value 448 | // for the url string 449 | $first = true; 450 | $option_params = array(); # example: '&card_theme' => 'dark' 451 | foreach ($set_options as $option => $api_param) { 452 | $value = $this->embedly_options[$option]; 453 | 454 | $delimiter = '&'; 455 | if ( $first ) { 456 | $delimiter = '?'; 457 | $first = false; 458 | } 459 | 460 | if ( is_bool($value) ) { 461 | $whole_param = $delimiter . $api_param . '=' . ($value ? '1' : '0'); 462 | $option_params[$option] = $whole_param; 463 | } 464 | else { 465 | $whole_param = $delimiter . $api_param . '=' . $value; 466 | $option_params[$option] = $whole_param; 467 | } 468 | } 469 | 470 | $base = EMBEDLY_BASE_URI; 471 | $param_str = ''; 472 | 473 | foreach($option_params as $key => $value) { 474 | $param_str .= $value; # value is the actual uri parameter, at this point 475 | } 476 | 477 | # generic key w/o analytics, no premium features 478 | $key = EMBEDLY_WP_BASE_KEY; 479 | 480 | # unless overidden 481 | if ($this->embedly_options['key']) { 482 | $key = $this->embedly_options['key']; 483 | $cards_key_param = '&cards_key=' . $key; 484 | $param_str .= $cards_key_param; 485 | } 486 | 487 | $key_param = '&key=' . $key; 488 | $param_str .= $key_param; 489 | 490 | return $base . $param_str; 491 | } 492 | 493 | 494 | /** 495 | * legacy function to check if account has specific features enabled 496 | * but mainly, we care to check if the key is valid 497 | **/ 498 | function embedly_acct_has_feature($feature, $key = false) 499 | { 500 | if ($key) { 501 | $result = wp_remote_retrieve_body(wp_remote_get( 502 | 'http://api.embed.ly/1/feature?feature=' . 503 | $feature . 504 | '&key=' . 505 | $key)); 506 | } else { 507 | return false; 508 | } 509 | 510 | $error_code = 'error_code'; 511 | $feature_status = json_decode($result); 512 | if (isset($feature_status->$error_code)) { 513 | return false; 514 | } 515 | if ($feature_status) { 516 | return $feature_status->$feature; 517 | } else { 518 | return false; 519 | } 520 | } 521 | 522 | 523 | /** 524 | * update embedly_options with a given key: value pair 525 | **/ 526 | function embedly_save_option($key, $value) 527 | { 528 | if(current_user_can('manage_options')) { 529 | $key = sanitize_key( $key ); 530 | $value = sanitize_text_field( $value ); 531 | 532 | $this->embedly_options[$key] = $value; 533 | update_option('embedly_settings', $this->embedly_options); 534 | $this->embedly_options = get_option('embedly_settings'); 535 | 536 | } 537 | } 538 | 539 | /** 540 | * removes a setting 541 | **/ 542 | function embedly_delete_option($key) 543 | { 544 | if(current_user_can('manage_options')) { 545 | unset($this->embedly_options[$key]); 546 | update_option('embedly_settings', $this->embedly_options); 547 | $this->embedly_options = get_option('embedly_settings'); 548 | } 549 | } 550 | 551 | 552 | /** 553 | * handles 'max width' input for card defaults 554 | * returns the string corresponding to the correct cards_width 555 | * card parameter 556 | **/ 557 | function handle_width_input($input) 558 | { 559 | // width can be '%' or 'px' 560 | // first check if '100%', 561 | $percent = $this->int_before_substring($input, '%'); 562 | if ($percent != 0 && $percent <= 100) { 563 | return $percent . '%'; 564 | } 565 | 566 | // try for a value like 300px (platform can only handle >200px?) 567 | $pixels = $this->int_before_substring($input, 'px'); 568 | if ($pixels > 0) { 569 | return max($pixels, 200); 570 | } 571 | 572 | // try solitary int value. 573 | $int = intval($input); 574 | if ($int > 0) { 575 | return max($int, 200); 576 | } 577 | 578 | return ""; 579 | } 580 | 581 | 582 | /** 583 | * returns valid integer (not inclusive of 0, which indicates failure) 584 | * preceding a given token $substring. 585 | * given '100%', '%' returns 100 586 | * given 'asdf', '%', returns 0 587 | **/ 588 | function int_before_substring($whole, $substring) 589 | { 590 | $pos = strpos($whole, $substring); 591 | if($pos != false) { 592 | $preceding = substr($whole, 0, $pos); 593 | return $percent = intval($preceding); 594 | } 595 | } 596 | 597 | /** 598 | * waterfall failure checks on the key 599 | **/ 600 | function valid_key() 601 | { 602 | if (!isset($this->embedly_options['key'])) { 603 | return false; 604 | } 605 | if (empty($this->embedly_options['key'])) { 606 | return false; 607 | } 608 | if(!isset($this->embedly_options['is_key_valid'])) { 609 | return false; 610 | } 611 | if (!$this->embedly_options['is_key_valid']) { 612 | return false; 613 | } 614 | 615 | return true; 616 | } 617 | 618 | 619 | /////////////////////////// BEGIN TEMPLATE FUNCTIONS FOR FORM LOGIC 620 | 621 | 622 | /** 623 | * returns max_width setting as a html value attr 624 | **/ 625 | function get_value_embedly_max_width() 626 | { 627 | if(isset($this->embedly_options['card_width'])) { 628 | $value = 'value="'; 629 | $width = $this->embedly_options['card_width']; 630 | if(strpos($width, '%') !== false) { 631 | $value .= $width; 632 | } else if($width !== '') { 633 | // we remove for api call, but replace for user 634 | $value .= $width . "px"; 635 | } 636 | 637 | echo $value . '" '; 638 | } 639 | } 640 | 641 | /** 642 | * returns embedly api_key if it's set 643 | **/ 644 | function get_value_embedly_api_key() 645 | { 646 | if(isset($this->embedly_options['key'])) { 647 | $value = 'value="'; 648 | $key = $this->embedly_options['key']; 649 | $value = $value . $key; 650 | echo $value . '" '; 651 | } 652 | } 653 | 654 | /** 655 | * returns current card_align value 656 | **/ 657 | function get_current_align() 658 | { 659 | $current_align = 'center'; // default if not set 660 | if(isset($this->embedly_options['card_align'])) { 661 | $current_align = $this->embedly_options['card_align']; 662 | } 663 | return $current_align; 664 | } 665 | 666 | /** 667 | * Builds an href for the Realtime Analytics button 668 | * DEPRECATED 669 | */ 670 | function get_onclick_analytics_button() { 671 | if($this->valid_key()) { 672 | echo ' href="https://app.embed.ly/r' . '?api_key=' . $this->embedly_options['key'] . 673 | '&path=analytics' .'" '; 674 | } else { 675 | // how to fail gracefully here? (should always have key) 676 | echo ' href="http://app.embed.ly" '; 677 | } 678 | } 679 | 680 | /** 681 | * sets the class of the preview container.. if dark theme, add "dark-theme" class 682 | */ 683 | function get_class_card_preview_container() { 684 | $class = 'class="card-preview-container'; 685 | if($this->embedly_options['card_theme'] == 'dark') { 686 | $class .= ' dark-theme'; 687 | } 688 | echo $class . '" '; 689 | } 690 | 691 | /** 692 | * fallback for alignment icons (only change nec. to support 3.8, atm) 693 | **/ 694 | function get_compatible_dashicon($align) 695 | { 696 | $base = '"dashicons align-icon '; 697 | // WP 4.1 has the "new" align icon, else, use old one (until 3.8) 698 | if( version_compare( $GLOBALS['wp_version'], '4.1', '<' ) ) { 699 | if($align == 'left') { 700 | // left is being reversed to support di-none in 4.1+ 701 | echo $base . 'dashicons-editor-alignleft'; 702 | } else if($align == 'right') { 703 | echo $base . 'dashicons-editor-alignleft di-reverse'; 704 | } else { 705 | echo $base . 'dashicons-editor-aligncenter'; 706 | } 707 | } else { 708 | if($align == 'left') { 709 | echo $base . 'di-none'; 710 | } else if($align == 'right'){ 711 | echo $base . 'di-none di-reverse'; 712 | } else { 713 | echo $base . 'di-center'; 714 | } 715 | } 716 | } 717 | 718 | /** 719 | * Welcome the user one time. 720 | **/ 721 | function get_welcome_message() { 722 | if (isset($this->embedly_options['is_welcomed']) && !$this->embedly_options['is_welcomed']) { 723 | $this->embedly_save_option('is_welcomed', true); 724 | echo "

    You're ready to start embedding.

    ". 725 | "

    Paste a URL in a new post and it will automatically embed and measure analytics.

    ". 726 | "

    For more on getting started, check out the tutorial below.

    "; 727 | } else echo ""; 728 | } 729 | /////////////////////////// END TEMPLATE FUNCTIONS FOR FORM LOGIC 730 | 731 | /** 732 | * The Admin Page. Abandon all hope, all ye' who enter here. 733 | **/ 734 | function embedly_settings_page() 735 | { 736 | global $wpdb; 737 | ######## BEGIN FORM HTML ######### 738 | #debugging: 739 | #echo $this->build_uri_with_options(); 740 | 741 | ?> 742 |
    743 |
    744 |
    745 | 746 | 747 |
    748 |
    749 |
    750 |
    751 | 754 |
    755 |
    756 |
    757 | 758 |
    759 |
    760 | 761 |
    762 | get_welcome_message(); ?> 763 |
    764 | 765 | 778 | 779 | 780 |
    781 | 782 | 859 | 860 | 861 | 878 | 879 | 880 | 898 | 899 | 900 |
    901 |
    902 |
    903 |