Version Description
Download this release
Release Info
Developer | rocwing |
Plugin | Web Recipe Clipper |
Version | 1.0 |
Comparing to | |
See all releases |
Version 1.0
- README.md +39 -0
- dist/blocks.build.js +1 -0
- dist/blocks.editor.build.css +1 -0
- dist/blocks.style.build.css +1 -0
- plugin.php +22 -0
- src/block/block.js +223 -0
- src/block/editor.scss +19 -0
- src/block/style.scss +13 -0
- src/blocks.js +12 -0
- src/common.scss +13 -0
- src/init.php +64 -0
README.md
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Web Recipe Clipper ===
|
2 |
+
Contributors: rocwing
|
3 |
+
Tags: recipe, gutenberg block, recipe generator, food, cooking, food
|
4 |
+
Donate link: https://www.leancodes.com/product/web-recipe-clipper/
|
5 |
+
Requires at least: 5.0.0
|
6 |
+
Tested up to: 5.1
|
7 |
+
Requires PHP: 5.2.4
|
8 |
+
Stable tag: 1.0
|
9 |
+
License: GPLv2 or later
|
10 |
+
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
11 |
+
|
12 |
+
The plugin will add a block to gutenberg editor, you can paste a web recipe link, it will clip the content to generate the recipe in the editor.
|
13 |
+
|
14 |
+
== Description ==
|
15 |
+
The plugin will clip the recipe title, photo, description, instructions to your gutenberg editor, you can upload your own photos, edit the content, you can also add other contents.
|
16 |
+
When you save your post, it will show a well-formatted recipe on your post.
|
17 |
+
Sites we support, continuously added:
|
18 |
+
* [Allrecipes](http://www.allrecipes.com/)
|
19 |
+
* [Cooking](http://cooking.nytimes.com/)
|
20 |
+
* [PeachDish](https://www.peachdish.com/recipes)
|
21 |
+
* [Myrecipes](https://www.myrecipes.com)
|
22 |
+
|
23 |
+
== Installation ==
|
24 |
+
1.Install the plugin through the WordPress plugins screen.
|
25 |
+
2.Activate the plugin through the ‘Plugins’ screen in WordPress.
|
26 |
+
3.Search Web Recipe Clipper in your editor when you want to clip a recipe
|
27 |
+
|
28 |
+
== Frequently Asked Questions ==
|
29 |
+
|
30 |
+
|
31 |
+
== Screenshots ==
|
32 |
+
1. Find web recipe clipper block in your editor
|
33 |
+
2. Paste a web recipe link
|
34 |
+
3. It will generate recipe in your editor
|
35 |
+
|
36 |
+
== Changelog ==
|
37 |
+
|
38 |
+
|
39 |
+
== Upgrade Notice ==
|
dist/blocks.build.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
!function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=8)}([function(e,t,n){"use strict";function r(e){return"[object Array]"===C.call(e)}function o(e){return"[object ArrayBuffer]"===C.call(e)}function i(e){return"undefined"!==typeof FormData&&e instanceof FormData}function s(e){return"undefined"!==typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function a(e){return"string"===typeof e}function u(e){return"number"===typeof e}function c(e){return"undefined"===typeof e}function l(e){return null!==e&&"object"===typeof e}function f(e){return"[object Date]"===C.call(e)}function p(e){return"[object File]"===C.call(e)}function d(e){return"[object Blob]"===C.call(e)}function m(e){return"[object Function]"===C.call(e)}function h(e){return l(e)&&m(e.pipe)}function g(e){return"undefined"!==typeof URLSearchParams&&e instanceof URLSearchParams}function w(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function y(){return("undefined"===typeof navigator||"ReactNative"!==navigator.product)&&("undefined"!==typeof window&&"undefined"!==typeof document)}function v(e,t){if(null!==e&&"undefined"!==typeof e)if("object"!==typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&t.call(null,e[i],i,e)}function E(){function e(e,n){"object"===typeof t[n]&&"object"===typeof e?t[n]=E(t[n],e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function x(e,t,n){return v(t,function(t,r){e[r]=n&&"function"===typeof t?b(t,n):t}),e}var b=n(2),T=n(14),C=Object.prototype.toString;e.exports={isArray:r,isArrayBuffer:o,isBuffer:T,isFormData:i,isArrayBufferView:s,isString:a,isNumber:u,isObject:l,isUndefined:c,isDate:f,isFile:p,isBlob:d,isFunction:m,isStream:h,isURLSearchParams:g,isStandardBrowserEnv:y,forEach:v,merge:E,extend:x,trim:w}},function(e,t,n){"use strict";(function(t){function r(e,t){!o.isUndefined(e)&&o.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}var o=n(0),i=n(16),s={"Content-Type":"application/x-www-form-urlencoded"},a={adapter:function(){var e;return"undefined"!==typeof XMLHttpRequest?e=n(4):"undefined"!==typeof t&&(e=n(4)),e}(),transformRequest:[function(e,t){return i(t,"Content-Type"),o.isFormData(e)||o.isArrayBuffer(e)||o.isBuffer(e)||o.isStream(e)||o.isFile(e)||o.isBlob(e)?e:o.isArrayBufferView(e)?e.buffer:o.isURLSearchParams(e)?(r(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):o.isObject(e)?(r(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"===typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(e){return e>=200&&e<300}};a.headers={common:{Accept:"application/json, text/plain, */*"}},o.forEach(["delete","get","head"],function(e){a.headers[e]={}}),o.forEach(["post","put","patch"],function(e){a.headers[e]=o.merge(s)}),e.exports=a}).call(t,n(3))},function(e,t,n){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function o(e){if(l===setTimeout)return setTimeout(e,0);if((l===n||!l)&&setTimeout)return l=setTimeout,setTimeout(e,0);try{return l(e,0)}catch(t){try{return l.call(null,e,0)}catch(t){return l.call(this,e,0)}}}function i(e){if(f===clearTimeout)return clearTimeout(e);if((f===r||!f)&&clearTimeout)return f=clearTimeout,clearTimeout(e);try{return f(e)}catch(t){try{return f.call(null,e)}catch(t){return f.call(this,e)}}}function s(){h&&d&&(h=!1,d.length?m=d.concat(m):g=-1,m.length&&a())}function a(){if(!h){var e=o(s);h=!0;for(var t=m.length;t;){for(d=m,m=[];++g<t;)d&&d[g].run();g=-1,t=m.length}d=null,h=!1,i(e)}}function u(e,t){this.fun=e,this.array=t}function c(){}var l,f,p=e.exports={};!function(){try{l="function"===typeof setTimeout?setTimeout:n}catch(e){l=n}try{f="function"===typeof clearTimeout?clearTimeout:r}catch(e){f=r}}();var d,m=[],h=!1,g=-1;p.nextTick=function(e){var t=new Array(arguments.length-1);if(arguments.length>1)for(var n=1;n<arguments.length;n++)t[n-1]=arguments[n];m.push(new u(e,t)),1!==m.length||h||o(a)},u.prototype.run=function(){this.fun.apply(null,this.array)},p.title="browser",p.browser=!0,p.env={},p.argv=[],p.version="",p.versions={},p.on=c,p.addListener=c,p.once=c,p.off=c,p.removeListener=c,p.removeAllListeners=c,p.emit=c,p.prependListener=c,p.prependOnceListener=c,p.listeners=function(e){return[]},p.binding=function(e){throw new Error("process.binding is not supported")},p.cwd=function(){return"/"},p.chdir=function(e){throw new Error("process.chdir is not supported")},p.umask=function(){return 0}},function(e,t,n){"use strict";(function(t){var r=n(0),o=n(17),i=n(19),s=n(20),a=n(21),u=n(5),c="undefined"!==typeof window&&window.btoa&&window.btoa.bind(window)||n(22);e.exports=function(e){return new Promise(function(l,f){var p=e.data,d=e.headers;r.isFormData(p)&&delete d["Content-Type"];var m=new XMLHttpRequest,h="onreadystatechange",g=!1;if("test"===t.env.NODE_ENV||"undefined"===typeof window||!window.XDomainRequest||"withCredentials"in m||a(e.url)||(m=new window.XDomainRequest,h="onload",g=!0,m.onprogress=function(){},m.ontimeout=function(){}),e.auth){var w=e.auth.username||"",y=e.auth.password||"";d.Authorization="Basic "+c(w+":"+y)}if(m.open(e.method.toUpperCase(),i(e.url,e.params,e.paramsSerializer),!0),m.timeout=e.timeout,m[h]=function(){if(m&&(4===m.readyState||g)&&(0!==m.status||m.responseURL&&0===m.responseURL.indexOf("file:"))){var t="getAllResponseHeaders"in m?s(m.getAllResponseHeaders()):null,n=e.responseType&&"text"!==e.responseType?m.response:m.responseText,r={data:n,status:1223===m.status?204:m.status,statusText:1223===m.status?"No Content":m.statusText,headers:t,config:e,request:m};o(l,f,r),m=null}},m.onerror=function(){f(u("Network Error",e,null,m)),m=null},m.ontimeout=function(){f(u("timeout of "+e.timeout+"ms exceeded",e,"ECONNABORTED",m)),m=null},r.isStandardBrowserEnv()){var v=n(23),E=(e.withCredentials||a(e.url))&&e.xsrfCookieName?v.read(e.xsrfCookieName):void 0;E&&(d[e.xsrfHeaderName]=E)}if("setRequestHeader"in m&&r.forEach(d,function(e,t){"undefined"===typeof p&&"content-type"===t.toLowerCase()?delete d[t]:m.setRequestHeader(t,e)}),e.withCredentials&&(m.withCredentials=!0),e.responseType)try{m.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"===typeof e.onDownloadProgress&&m.addEventListener("progress",e.onDownloadProgress),"function"===typeof e.onUploadProgress&&m.upload&&m.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){m&&(m.abort(),f(e),m=null)}),void 0===p&&(p=null),m.send(p)})}}).call(t,n(3))},function(e,t,n){"use strict";var r=n(18);e.exports=function(e,t,n,o,i){var s=new Error(e);return r(s,t,n,o,i)}},function(e,t,n){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t,n){"use strict";function r(e){this.message=e}r.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},r.prototype.__CANCEL__=!0,e.exports=r},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});n(9)},function(e,t,n){"use strict";var r=n(10),o=(n.n(r),n(11)),i=(n.n(o),n(12)),s=n.n(i),a=wp.i18n.__,u=wp.blocks.registerBlockType,c=wp.editor,l=(c.PlainText,c.RichText),f=c.MediaUpload,p=(c.URLInputButton,c.URLInput),d=wp.components,m=d.Button,h=d.Spinner;u("cgb/block-web-recipe-clipper",{title:a("Web Recipe Clipper"),icon:"carrot",category:"common",keywords:[a("web recipe clipper"),a("wordpress recipe builder")],attributes:{url:{type:"string"},title:{type:"string",selector:"h2"},description:{type:"string",selector:"p"},image:{type:"string"},ingredients:{type:"string",source:"html",multiline:"li",selector:"ul"},instructions:{type:"string",source:"html",multiline:"p",selector:".wrc-instructions"},fetching:{type:"string"}},edit:function(e){var t=e.className,n=e.attributes,r=n.url,o=n.title,i=n.description,u=n.image,c=n.ingredients,d=n.instructions,g=n.fetching,w=e.setAttributes,y=function(e){w({fetching:!0}),s()({method:"get",url:"https://www.leancodes.com/recipe-api/RecipeParser-master/parse.php?link="+e}).then(function(t){w({url:e,title:t.data.title,description:t.data.description,image:t.data.photo_url,ingredients:t.data.ingredients[0].list.map(function(e){return"<li>"+e+"</li>"}).join(""),instructions:t.data.instructions[0].list.map(function(e){return"<p>"+e+"</p>"}).join(""),fetching:!1})})},v=function(e){w({image:e.url})},E=function(e){w({ingredients:e})},x=function(e){w({instructions:e})};return null==o||g?g?wp.element.createElement("div",{className:"web-recipe-clipper is-loading"},wp.element.createElement(h,null),wp.element.createElement("p",null,a("Loading\u2026"))):wp.element.createElement(p,{className:t,value:r,onChange:y,placeholder:"Paste a web recipe URL"}):wp.element.createElement("div",{className:"wrc-edit"},wp.element.createElement(l,{tagName:"h2",value:o,placeholder:"Recipe title\u2026",onChange:function(e){return w({title:e})}}),wp.element.createElement("div",{className:"wrc-recipe-image-edit"},wp.element.createElement(f,{onSelect:v,allowedTypes:"image",value:u,render:function(e){var t=e.open;return wp.element.createElement(m,{className:u?"image-button":"button button-large",onClick:t},u?wp.element.createElement("img",{src:u,alt:a("Upload Recipe Image","gutenberg-examples")}):a("Upload Image","gutenberg-examples"))}})),wp.element.createElement(l,{value:i,onChange:function(e){return w({description:e})}}),wp.element.createElement("h3",null,"Ingredients"),wp.element.createElement(l,{tagName:"ul",multiline:"li",value:c,onChange:E,className:"wrc-ingredients-edit"}),wp.element.createElement("h3",null,"Instructions"),wp.element.createElement(l,{tagName:"div",multiline:"p",className:"wrc-instructions-edit",placeholder:"Write the instructions\u2026",value:d,onChange:x}))},save:function(e){var t=(e.className,e.attributes),n=(t.url,t.title),r=t.description,o=t.image,i=t.ingredients,s=t.instructions;t.fetching,e.setAttributes;return wp.element.createElement("div",{className:"wrc"},wp.element.createElement("h2",null,n),wp.element.createElement("div",{className:"recipe-image"},wp.element.createElement("img",{src:o})),wp.element.createElement("p",null,r),wp.element.createElement("h3",null,"Ingredients"),wp.element.createElement("div",{className:"wrc-ingredients"},wp.element.createElement("ul",{dangerouslySetInnerHTML:{__html:i}})),wp.element.createElement("h3",null,"Instructions"),wp.element.createElement("div",{className:"wrc-instructions",dangerouslySetInnerHTML:{__html:s}}))}})},function(e,t){},function(e,t){},function(e,t,n){e.exports=n(13)},function(e,t,n){"use strict";function r(e){var t=new s(e),n=i(s.prototype.request,t);return o.extend(n,s.prototype,t),o.extend(n,t),n}var o=n(0),i=n(2),s=n(15),a=n(1),u=r(a);u.Axios=s,u.create=function(e){return r(o.merge(a,e))},u.Cancel=n(7),u.CancelToken=n(29),u.isCancel=n(6),u.all=function(e){return Promise.all(e)},u.spread=n(30),e.exports=u,e.exports.default=u},function(e,t){function n(e){return!!e.constructor&&"function"===typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}function r(e){return"function"===typeof e.readFloatLE&&"function"===typeof e.slice&&n(e.slice(0,0))}e.exports=function(e){return null!=e&&(n(e)||r(e)||!!e._isBuffer)}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new s,response:new s}}var o=n(1),i=n(0),s=n(24),a=n(25);r.prototype.request=function(e){"string"===typeof e&&(e=i.merge({url:arguments[0]},arguments[1])),e=i.merge(o,{method:"get"},this.defaults,e),e.method=e.method.toLowerCase();var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},i.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(i.merge(n||{},{method:e,url:t}))}}),i.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(i.merge(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";var r=n(0);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(5);e.exports=function(e,t,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?t(r("Request failed with status code "+n.status,n.config,null,n.request,n)):e(n)}},function(e,t,n){"use strict";e.exports=function(e,t,n,r,o){return e.config=t,n&&(e.code=n),e.request=r,e.response=o,e}},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(0);e.exports=function(e,t,n){if(!t)return e;var i;if(n)i=n(t);else if(o.isURLSearchParams(t))i=t.toString();else{var s=[];o.forEach(t,function(e,t){null!==e&&"undefined"!==typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),s.push(r(t)+"="+r(e))}))}),i=s.join("&")}return i&&(e+=(-1===e.indexOf("?")?"?":"&")+i),e}},function(e,t,n){"use strict";var r=n(0),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,i,s={};return e?(r.forEach(e.split("\n"),function(e){if(i=e.indexOf(":"),t=r.trim(e.substr(0,i)).toLowerCase(),n=r.trim(e.substr(i+1)),t){if(s[t]&&o.indexOf(t)>=0)return;s[t]="set-cookie"===t?(s[t]?s[t]:[]).concat([n]):s[t]?s[t]+", "+n:n}}),s):s}},function(e,t,n){"use strict";var r=n(0);e.exports=r.isStandardBrowserEnv()?function(){function e(e){var t=e;return n&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(n){var o=r.isString(n)?e(n):n;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t,n){"use strict";function r(){this.message="String contains an invalid character"}function o(e){for(var t,n,o=String(e),s="",a=0,u=i;o.charAt(0|a)||(u="=",a%1);s+=u.charAt(63&t>>8-a%1*8)){if((n=o.charCodeAt(a+=.75))>255)throw new r;t=t<<8|n}return s}var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";r.prototype=new Error,r.prototype.code=5,r.prototype.name="InvalidCharacterError",e.exports=o},function(e,t,n){"use strict";var r=n(0);e.exports=r.isStandardBrowserEnv()?function(){return{write:function(e,t,n,o,i,s){var a=[];a.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(i)&&a.push("domain="+i),!0===s&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(0);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(0),i=n(26),s=n(6),a=n(1),u=n(27),c=n(28);e.exports=function(e){return r(e),e.baseURL&&!u(e.url)&&(e.url=c(e.baseURL,e.url)),e.headers=e.headers||{},e.data=i(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]}),(e.adapter||a.adapter)(e).then(function(t){return r(e),t.data=i(t.data,t.headers,e.transformResponse),t},function(t){return s(t)||(r(e),t&&t.response&&(t.response.data=i(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(0);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t,n){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t,n){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t,n){"use strict";function r(e){if("function"!==typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new o(e),t(n.reason))})}var o=n(7);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var e;return{token:new r(function(t){e=t}),cancel:e}},e.exports=r},function(e,t,n){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}}]);
|
dist/blocks.editor.build.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
.wp-block-cgb-block-web-recipe-clipper{background:#bada55;border:0.2rem solid #292929;color:#292929;margin:0 auto;max-width:740px;padding:2rem}.wrc-ingredients-edit{padding-left:1.3em !important;margin-left:1.3em !important}
|
dist/blocks.style.build.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
.wp-block-cgb-block-web-recipe-clipper{background:#f4f4f4;color:#292929;margin:0 auto;max-width:740px;padding:2rem}
|
plugin.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Plugin Name: Web Recipe Clipper
|
4 |
+
* Description: Web Recipe Clipper — Sometimes we want to save a recipe that we find on the web in our own blog post, you can use this plugin to add a block to gutenberg editor, then you can paste the web recipe url. It will generate a recipe in your editor based on the web recipe title, photo, description, ingredients and instructions, you can edit it, change it to your own version then publish it.
|
5 |
+
* Author: LeanCodes
|
6 |
+
* Author URI: https://www.leancodes.com
|
7 |
+
* Version: 1.0.0
|
8 |
+
* License: GPL2+
|
9 |
+
* License URI: https://www.gnu.org/licenses/gpl-2.0.txt
|
10 |
+
*
|
11 |
+
* @package CGB
|
12 |
+
*/
|
13 |
+
|
14 |
+
// Exit if accessed directly.
|
15 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
16 |
+
exit;
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Block Initializer.
|
21 |
+
*/
|
22 |
+
require_once plugin_dir_path( __FILE__ ) . 'src/init.php';
|
src/block/block.js
ADDED
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* BLOCK: web-recipe-clipper
|
3 |
+
*
|
4 |
+
* Registering a basic block with Gutenberg.
|
5 |
+
* Simple block, renders and saves the same content without any interactivity.
|
6 |
+
*/
|
7 |
+
|
8 |
+
// Import CSS.
|
9 |
+
import './style.scss';
|
10 |
+
import './editor.scss';
|
11 |
+
import axios from 'axios';
|
12 |
+
|
13 |
+
const { __ } = wp.i18n; // Import __() from wp.i18n
|
14 |
+
const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks
|
15 |
+
const { PlainText,RichText,MediaUpload,URLInputButton,URLInput } = wp.editor;
|
16 |
+
const { Button,Spinner } = wp.components;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Register: aa Gutenberg Block.
|
20 |
+
*
|
21 |
+
* Registers a new block provided a unique name and an object defining its
|
22 |
+
* behavior. Once registered, the block is made editor as an option to any
|
23 |
+
* editor interface where blocks are implemented.
|
24 |
+
*
|
25 |
+
* @link https://wordpress.org/gutenberg/handbook/block-api/
|
26 |
+
* @param {string} name Block name.
|
27 |
+
* @param {Object} settings Block settings.
|
28 |
+
* @return {?WPBlock} The block, if it has been successfully
|
29 |
+
* registered; otherwise `undefined`.
|
30 |
+
*/
|
31 |
+
registerBlockType( 'cgb/block-web-recipe-clipper', {
|
32 |
+
// Block name. Block names must be string that contains a namespace prefix. Example: my-plugin/my-custom-block.
|
33 |
+
title: __( 'Web Recipe Clipper' ), // Block title.
|
34 |
+
icon: 'carrot', // Block icon from Dashicons → https://developer.wordpress.org/resource/dashicons/.
|
35 |
+
category: 'common', // Block category — Group blocks together based on common traits E.g. common, formatting, layout widgets, embed.
|
36 |
+
keywords: [
|
37 |
+
__( 'web recipe clipper' ),
|
38 |
+
__( 'wordpress recipe builder' ),
|
39 |
+
],
|
40 |
+
attributes: {
|
41 |
+
url: {
|
42 |
+
type: 'string',
|
43 |
+
},
|
44 |
+
title: {
|
45 |
+
type: 'string',
|
46 |
+
selector: 'h2',
|
47 |
+
},
|
48 |
+
description: {
|
49 |
+
type: 'string',
|
50 |
+
selector:'p',
|
51 |
+
},
|
52 |
+
image: {
|
53 |
+
type: 'string',
|
54 |
+
},
|
55 |
+
ingredients: {
|
56 |
+
type: 'string',
|
57 |
+
source: 'html',
|
58 |
+
multiline: 'li',
|
59 |
+
selector: 'ul',
|
60 |
+
},
|
61 |
+
instructions: {
|
62 |
+
type: 'string',
|
63 |
+
source: 'html',
|
64 |
+
multiline: 'p',
|
65 |
+
selector: '.wrc-instructions',
|
66 |
+
},
|
67 |
+
fetching: {
|
68 |
+
type: 'string',
|
69 |
+
},
|
70 |
+
},
|
71 |
+
|
72 |
+
/**
|
73 |
+
* The edit function describes the structure of your block in the context of the editor.
|
74 |
+
* This represents what the editor will render when the block is used.
|
75 |
+
*
|
76 |
+
* The "edit" property must be a valid function.
|
77 |
+
*
|
78 |
+
* @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/
|
79 |
+
*/
|
80 |
+
edit: ( props ) => {
|
81 |
+
const {
|
82 |
+
className,
|
83 |
+
attributes: {
|
84 |
+
url,
|
85 |
+
title,
|
86 |
+
description,
|
87 |
+
image,
|
88 |
+
ingredients,
|
89 |
+
instructions,
|
90 |
+
fetching,
|
91 |
+
},
|
92 |
+
setAttributes,
|
93 |
+
} = props;
|
94 |
+
|
95 |
+
const onChangeURL = ( value ) => {
|
96 |
+
|
97 |
+
setAttributes({fetching: true});
|
98 |
+
axios({
|
99 |
+
method: 'get',
|
100 |
+
url: `https://www.leancodes.com/recipe-api/RecipeParser-master/parse.php?link=${ value }`
|
101 |
+
}).then(response => {
|
102 |
+
|
103 |
+
setAttributes( { url: value, title: response.data.title, description: response.data.description, image: response.data.photo_url, ingredients: response.data.ingredients[0].list.map(function(ingredient){
|
104 |
+
return '<li>'+ingredient+'</li>';
|
105 |
+
}).join(''), instructions: response.data.instructions[0].list.map(function(instruction){
|
106 |
+
return '<p>'+instruction+'</p>';
|
107 |
+
}).join(''), fetching: false} );
|
108 |
+
});
|
109 |
+
|
110 |
+
};
|
111 |
+
const onSelectImage = ( media ) => {
|
112 |
+
setAttributes( {
|
113 |
+
image: media.url
|
114 |
+
} );
|
115 |
+
};
|
116 |
+
const onChangeIngredients = ( value ) => {
|
117 |
+
setAttributes( { ingredients: value } );
|
118 |
+
};
|
119 |
+
const onChangeInstructions = ( value ) => {
|
120 |
+
setAttributes( { instructions: value } );
|
121 |
+
};
|
122 |
+
if(title != null && !fetching){
|
123 |
+
|
124 |
+
return (<div className="wrc-edit">
|
125 |
+
<RichText
|
126 |
+
tagName="h2"
|
127 |
+
value={ title }
|
128 |
+
placeholder="Recipe title…"
|
129 |
+
onChange={ ( content ) => setAttributes( { title: content } ) }
|
130 |
+
/>
|
131 |
+
<div className="wrc-recipe-image-edit">
|
132 |
+
<MediaUpload
|
133 |
+
onSelect={ onSelectImage }
|
134 |
+
allowedTypes="image"
|
135 |
+
value={ image }
|
136 |
+
render={ ( { open } ) => (
|
137 |
+
<Button className={ image ? 'image-button' : 'button button-large' } onClick={ open }>
|
138 |
+
{ ! image ? __( 'Upload Image', 'gutenberg-examples' ) : <img src={ image } alt={ __( 'Upload Recipe Image', 'gutenberg-examples' ) } /> }
|
139 |
+
</Button>
|
140 |
+
) }
|
141 |
+
/>
|
142 |
+
</div>
|
143 |
+
<RichText
|
144 |
+
value={ description }
|
145 |
+
onChange={ ( content ) => setAttributes( { description: content } ) }
|
146 |
+
/>
|
147 |
+
<h3>Ingredients</h3>
|
148 |
+
<RichText
|
149 |
+
tagName="ul"
|
150 |
+
multiline="li"
|
151 |
+
value={ ingredients }
|
152 |
+
onChange={ onChangeIngredients }
|
153 |
+
className="wrc-ingredients-edit"
|
154 |
+
/>
|
155 |
+
<h3>Instructions</h3>
|
156 |
+
<RichText
|
157 |
+
tagName="div"
|
158 |
+
multiline="p"
|
159 |
+
className="wrc-instructions-edit"
|
160 |
+
placeholder="Write the instructions…"
|
161 |
+
value={ instructions }
|
162 |
+
onChange={ onChangeInstructions }
|
163 |
+
/>
|
164 |
+
</div>
|
165 |
+
|
166 |
+
);
|
167 |
+
}else{
|
168 |
+
if(fetching){
|
169 |
+
return <div className="web-recipe-clipper is-loading">
|
170 |
+
<Spinner />
|
171 |
+
<p>{ __( 'Loading…' ) }</p>
|
172 |
+
</div>
|
173 |
+
}else{
|
174 |
+
return (
|
175 |
+
<URLInput
|
176 |
+
className={ className }
|
177 |
+
value={ url }
|
178 |
+
onChange={onChangeURL}
|
179 |
+
placeholder="Paste a web recipe URL"
|
180 |
+
/>
|
181 |
+
);
|
182 |
+
}
|
183 |
+
}
|
184 |
+
},
|
185 |
+
|
186 |
+
|
187 |
+
/**
|
188 |
+
* The save function defines the way in which the different attributes should be combined
|
189 |
+
* into the final markup, which is then serialized by Gutenberg into post_content.
|
190 |
+
*
|
191 |
+
* The "save" property must be specified and must be a valid function.
|
192 |
+
*
|
193 |
+
* @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/
|
194 |
+
*/
|
195 |
+
save: ( props ) => {
|
196 |
+
const {
|
197 |
+
className,
|
198 |
+
attributes: {
|
199 |
+
url,
|
200 |
+
title,
|
201 |
+
description,
|
202 |
+
image,
|
203 |
+
ingredients,
|
204 |
+
instructions,
|
205 |
+
fetching,
|
206 |
+
},
|
207 |
+
setAttributes,
|
208 |
+
} = props;
|
209 |
+
return <div className="wrc">
|
210 |
+
<h2>{title}</h2>
|
211 |
+
<div className="recipe-image">
|
212 |
+
<img src={image}></img>
|
213 |
+
</div>
|
214 |
+
<p>{description}</p>
|
215 |
+
<h3>Ingredients</h3>
|
216 |
+
<div className="wrc-ingredients">
|
217 |
+
<ul dangerouslySetInnerHTML={{__html: ingredients}} />
|
218 |
+
</div>
|
219 |
+
<h3>Instructions</h3>
|
220 |
+
<div className="wrc-instructions" dangerouslySetInnerHTML={{__html: instructions}} />
|
221 |
+
</div>;
|
222 |
+
}
|
223 |
+
} );
|
src/block/editor.scss
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* #.# Editor Styles
|
3 |
+
*
|
4 |
+
* CSS for just Backend enqueued after style.scss
|
5 |
+
* which makes it higher in priority.
|
6 |
+
*/
|
7 |
+
|
8 |
+
.wp-block-cgb-block-web-recipe-clipper {
|
9 |
+
background: $green;
|
10 |
+
border: 0.2rem solid $black;
|
11 |
+
color: $black;
|
12 |
+
margin: 0 auto;
|
13 |
+
max-width: 740px;
|
14 |
+
padding: 2rem;
|
15 |
+
}
|
16 |
+
.wrc-ingredients-edit {
|
17 |
+
padding-left: 1.3em !important;
|
18 |
+
margin-left: 1.3em !important;
|
19 |
+
}
|
src/block/style.scss
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* #.# Styles
|
3 |
+
*
|
4 |
+
* CSS for both Frontend+Backend.
|
5 |
+
*/
|
6 |
+
|
7 |
+
.wp-block-cgb-block-web-recipe-clipper {
|
8 |
+
background: $white;
|
9 |
+
color: $black;
|
10 |
+
margin: 0 auto;
|
11 |
+
max-width: 740px;
|
12 |
+
padding: 2rem;
|
13 |
+
}
|
src/blocks.js
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Gutenberg Blocks
|
3 |
+
*
|
4 |
+
* All blocks related JavaScript files should be imported here.
|
5 |
+
* You can create a new block folder in this dir and include code
|
6 |
+
* for that block here as well.
|
7 |
+
*
|
8 |
+
* All blocks should be included here since this is the file that
|
9 |
+
* Webpack is compiling as the input file.
|
10 |
+
*/
|
11 |
+
|
12 |
+
import './block/block.js';
|
src/common.scss
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* #.# Common SCSS
|
3 |
+
*
|
4 |
+
* Can include things like variables and mixins
|
5 |
+
* that are used across the project.
|
6 |
+
*/
|
7 |
+
|
8 |
+
// Colors.
|
9 |
+
$black: rgb(41, 41, 41);
|
10 |
+
$white: #f4f4f4;
|
11 |
+
$gray: #dedede;
|
12 |
+
$green: #bada55;
|
13 |
+
$red: orangered;
|
src/init.php
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Blocks Initializer
|
4 |
+
*
|
5 |
+
* Enqueue CSS/JS of all the blocks.
|
6 |
+
*
|
7 |
+
* @since 1.0.0
|
8 |
+
* @package CGB
|
9 |
+
*/
|
10 |
+
|
11 |
+
// Exit if accessed directly.
|
12 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
13 |
+
exit;
|
14 |
+
}
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Enqueue Gutenberg block assets for both frontend + backend.
|
18 |
+
*
|
19 |
+
* @uses {wp-editor} for WP editor styles.
|
20 |
+
* @since 1.0.0
|
21 |
+
*/
|
22 |
+
function web_recipe_clipper_cgb_block_assets() { // phpcs:ignore
|
23 |
+
// Styles.
|
24 |
+
wp_enqueue_style(
|
25 |
+
'web_recipe_clipper-cgb-style-css', // Handle.
|
26 |
+
plugins_url( 'dist/blocks.style.build.css', dirname( __FILE__ ) ), // Block style CSS.
|
27 |
+
array( 'wp-editor' ) // Dependency to include the CSS after it.
|
28 |
+
// filemtime( plugin_dir_path( __DIR__ ) . 'dist/blocks.style.build.css' ) // Version: File modification time.
|
29 |
+
);
|
30 |
+
}
|
31 |
+
|
32 |
+
// Hook: Frontend assets.
|
33 |
+
add_action( 'enqueue_block_assets', 'web_recipe_clipper_cgb_block_assets' );
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Enqueue Gutenberg block assets for backend editor.
|
37 |
+
*
|
38 |
+
* @uses {wp-blocks} for block type registration & related functions.
|
39 |
+
* @uses {wp-element} for WP Element abstraction — structure of blocks.
|
40 |
+
* @uses {wp-i18n} to internationalize the block's text.
|
41 |
+
* @uses {wp-editor} for WP editor styles.
|
42 |
+
* @since 1.0.0
|
43 |
+
*/
|
44 |
+
function web_recipe_clipper_cgb_editor_assets() { // phpcs:ignore
|
45 |
+
// Scripts.
|
46 |
+
wp_enqueue_script(
|
47 |
+
'web_recipe_clipper-cgb-block-js', // Handle.
|
48 |
+
plugins_url( '/dist/blocks.build.js', dirname( __FILE__ ) ), // Block.build.js: We register the block here. Built with Webpack.
|
49 |
+
array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' ), // Dependencies, defined above.
|
50 |
+
// filemtime( plugin_dir_path( __DIR__ ) . 'dist/blocks.build.js' ), // Version: File modification time.
|
51 |
+
true // Enqueue the script in the footer.
|
52 |
+
);
|
53 |
+
|
54 |
+
// Styles.
|
55 |
+
wp_enqueue_style(
|
56 |
+
'web_recipe_clipper-cgb-block-editor-css', // Handle.
|
57 |
+
plugins_url( 'dist/blocks.editor.build.css', dirname( __FILE__ ) ), // Block editor CSS.
|
58 |
+
array( 'wp-edit-blocks' ) // Dependency to include the CSS after it.
|
59 |
+
// filemtime( plugin_dir_path( __DIR__ ) . 'dist/blocks.editor.build.css' ) // Version: File modification time.
|
60 |
+
);
|
61 |
+
}
|
62 |
+
|
63 |
+
// Hook: Editor assets.
|
64 |
+
add_action( 'enqueue_block_editor_assets', 'web_recipe_clipper_cgb_editor_assets' );
|