Web Recipe Clipper - Version 1.0

Version Description

Download this release

Release Info

Developer rocwing
Plugin Icon 128x128 Web Recipe Clipper
Version 1.0
Comparing to
See all releases

Version 1.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' );