Файловый менеджер - Редактировать - /var/www/xthruster/html/wp-content/uploads/flags/image.tar
Назад
editor-rtl.min.css 0000644 00000004557 14721530727 0010150 0 ustar 00 .wp-block-image.wp-block-image .block-editor-media-placeholder.is-small{min-height:60px}figure.wp-block-image:not(.wp-block){margin:0}.wp-block-image{position:relative}.wp-block-image .is-applying img,.wp-block-image.is-transient img{opacity:.3}.wp-block-image figcaption img{display:inline}.wp-block-image .components-spinner{margin:0;position:absolute;right:50%;top:50%;transform:translate(50%,-50%)}.wp-block-image__placeholder{aspect-ratio:4/3}.wp-block-image__placeholder.has-illustration:before{background:#fff;opacity:.8}.wp-block-image__placeholder .components-placeholder__illustration{opacity:.1}.wp-block-image .components-resizable-box__container{display:table}.wp-block-image .components-resizable-box__container img{display:block;height:inherit;width:inherit}.block-editor-block-list__block[data-type="core/image"] .block-editor-block-toolbar .block-editor-url-input__button-modal{left:0;margin:-1px 0;position:absolute;right:0}@media (min-width:600px){.block-editor-block-list__block[data-type="core/image"] .block-editor-block-toolbar .block-editor-url-input__button-modal{margin:-1px}}[data-align=full]>.wp-block-image img,[data-align=wide]>.wp-block-image img{height:auto;width:100%}.wp-block[data-align=center]>.wp-block-image,.wp-block[data-align=left]>.wp-block-image,.wp-block[data-align=right]>.wp-block-image{display:table}.wp-block[data-align=center]>.wp-block-image>figcaption,.wp-block[data-align=left]>.wp-block-image>figcaption,.wp-block[data-align=right]>.wp-block-image>figcaption{caption-side:bottom;display:table-caption}.wp-block[data-align=left]>.wp-block-image{margin:.5em 0 .5em 1em}.wp-block[data-align=right]>.wp-block-image{margin:.5em 1em .5em 0}.wp-block[data-align=center]>.wp-block-image{margin-left:auto;margin-right:auto;text-align:center}.wp-block[data-align]:has(>.wp-block-image){position:relative}.wp-block-image__crop-area{max-width:100%;overflow:hidden;position:relative;width:100%}.wp-block-image__crop-area .reactEasyCrop_Container{pointer-events:auto}.wp-block-image__crop-area .reactEasyCrop_Container .reactEasyCrop_Image{border:none;border-radius:0}.wp-block-image__crop-icon{align-items:center;display:flex;justify-content:center;min-width:48px;padding:0 8px}.wp-block-image__crop-icon svg{fill:currentColor}.wp-block-image__zoom .components-popover__content{min-width:260px;overflow:visible!important}.wp-block-image__toolbar_content_textarea{width:250px} block.json 0000644 00000005572 14721530727 0006552 0 ustar 00 { "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "core/image", "title": "Image", "category": "media", "usesContext": [ "allowResize", "imageCrop", "fixedHeight" ], "description": "Insert an image to make a visual statement.", "keywords": [ "img", "photo", "picture" ], "textdomain": "default", "attributes": { "blob": { "type": "string", "role": "local" }, "url": { "type": "string", "source": "attribute", "selector": "img", "attribute": "src", "role": "content" }, "alt": { "type": "string", "source": "attribute", "selector": "img", "attribute": "alt", "default": "", "role": "content" }, "caption": { "type": "rich-text", "source": "rich-text", "selector": "figcaption", "role": "content" }, "lightbox": { "type": "object", "enabled": { "type": "boolean" } }, "title": { "type": "string", "source": "attribute", "selector": "img", "attribute": "title", "role": "content" }, "href": { "type": "string", "source": "attribute", "selector": "figure > a", "attribute": "href", "role": "content" }, "rel": { "type": "string", "source": "attribute", "selector": "figure > a", "attribute": "rel" }, "linkClass": { "type": "string", "source": "attribute", "selector": "figure > a", "attribute": "class" }, "id": { "type": "number", "role": "content" }, "width": { "type": "string" }, "height": { "type": "string" }, "aspectRatio": { "type": "string" }, "scale": { "type": "string" }, "sizeSlug": { "type": "string" }, "linkDestination": { "type": "string" }, "linkTarget": { "type": "string", "source": "attribute", "selector": "figure > a", "attribute": "target" } }, "supports": { "interactivity": true, "align": [ "left", "center", "right", "wide", "full" ], "anchor": true, "color": { "text": false, "background": false }, "filter": { "duotone": true }, "spacing": { "margin": true }, "__experimentalBorder": { "color": true, "radius": true, "width": true, "__experimentalSkipSerialization": true, "__experimentalDefaultControls": { "color": true, "radius": true, "width": true } }, "shadow": { "__experimentalSkipSerialization": true } }, "selectors": { "border": ".wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder", "shadow": ".wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder", "filter": { "duotone": ".wp-block-image img, .wp-block-image .components-placeholder" } }, "styles": [ { "name": "default", "label": "Default", "isDefault": true }, { "name": "rounded", "label": "Rounded" } ], "editorStyle": "wp-block-image-editor", "style": "wp-block-image" } view.min.js 0000644 00000010763 14721530727 0006655 0 ustar 00 import*as t from"@wordpress/interactivity";var e={d:(t,n)=>{for(var o in n)e.o(n,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:n[o]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)};const n=(t=>{var n={};return e.d(n,t),n})({getContext:()=>t.getContext,getElement:()=>t.getElement,store:()=>t.store});let o=!1,a=0;const{state:r,actions:i,callbacks:l}=(0,n.store)("core/image",{state:{currentImageId:null,get currentImage(){return r.metadata[r.currentImageId]},get overlayOpened(){return null!==r.currentImageId},get roleAttribute(){return r.overlayOpened?"dialog":null},get ariaModal(){return r.overlayOpened?"true":null},get enlargedSrc(){return r.currentImage.uploadedSrc||"data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="},get figureStyles(){return r.overlayOpened&&`${r.currentImage.figureStyles?.replace(/margin[^;]*;?/g,"")};`},get imgStyles(){return r.overlayOpened&&`${r.currentImage.imgStyles?.replace(/;$/,"")}; object-fit:cover;`},get imageButtonRight(){const{imageId:t}=(0,n.getContext)();return r.metadata[t].imageButtonRight},get imageButtonTop(){const{imageId:t}=(0,n.getContext)();return r.metadata[t].imageButtonTop},get isContentHidden(){const t=(0,n.getContext)();return r.overlayEnabled&&r.currentImageId===t.imageId},get isContentVisible(){const t=(0,n.getContext)();return!r.overlayEnabled&&r.currentImageId===t.imageId}},actions:{showLightbox(){const{imageId:t}=(0,n.getContext)();r.metadata[t].imageRef?.complete&&(r.scrollTopReset=document.documentElement.scrollTop,r.scrollLeftReset=document.documentElement.scrollLeft,r.overlayEnabled=!0,r.currentImageId=t,l.setOverlayStyles())},hideLightbox(){r.overlayEnabled&&(r.showClosingAnimation=!0,r.overlayEnabled=!1,setTimeout((function(){r.currentImage.buttonRef.focus({preventScroll:!0}),r.currentImageId=null}),450))},handleKeydown(t){if(r.overlayEnabled){if("Tab"===t.key){t.preventDefault();const{ref:e}=(0,n.getElement)();e.querySelector("button").focus()}"Escape"===t.key&&i.hideLightbox()}},handleTouchMove(t){r.overlayEnabled&&t.preventDefault()},handleTouchStart(){o=!0},handleTouchEnd(){a=Date.now(),o=!1},handleScroll(){r.overlayOpened&&!o&&Date.now()-a>450&&window.scrollTo(r.scrollLeftReset,r.scrollTopReset)}},callbacks:{setOverlayStyles(){if(!r.overlayEnabled)return;let{naturalWidth:t,naturalHeight:e,offsetWidth:n,offsetHeight:o}=r.currentImage.imageRef,{x:a,y:i}=r.currentImage.imageRef.getBoundingClientRect();const l=t/e;let g=n/o;if("contain"===r.currentImage.scaleAttr)if(l>g){const t=n/l;i+=(o-t)/2,o=t}else{const t=o*l;a+=(n-t)/2,n=t}g=n/o;let c=parseFloat("none"!==r.currentImage.targetWidth?r.currentImage.targetWidth:t),s=parseFloat("none"!==r.currentImage.targetHeight?r.currentImage.targetHeight:e),d=c/s,u=c,m=s,h=c,p=s;if(l.toFixed(2)!==d.toFixed(2)){if(l>d){const t=c/l;s-t>c?(s=t,c=t*l):s=c/l}else{const t=s*l;c-t>s?(c=t,s=t/l):c=s*l}h=c,p=s,d=c/s,g>d?(u=c,m=u/g):(m=s,u=m*g)}(n>h||o>p)&&(h=n,p=o);let f=0;window.innerWidth>480?f=80:window.innerWidth>1920&&(f=160);const y=Math.min(window.innerWidth-f,h),b=Math.min(window.innerHeight-80,p);g>y/b?(h=y,p=h/g):(p=b,h=p*g);const w=n/h,I=c*(h/u),x=s*(p/m);r.overlayStyles=`\n\t\t\t\t:root {\n\t\t\t\t\t--wp--lightbox-initial-top-position: ${i}px;\n\t\t\t\t\t--wp--lightbox-initial-left-position: ${a}px;\n\t\t\t\t\t--wp--lightbox-container-width: ${h+1}px;\n\t\t\t\t\t--wp--lightbox-container-height: ${p+1}px;\n\t\t\t\t\t--wp--lightbox-image-width: ${I}px;\n\t\t\t\t\t--wp--lightbox-image-height: ${x}px;\n\t\t\t\t\t--wp--lightbox-scale: ${w};\n\t\t\t\t\t--wp--lightbox-scrollbar-width: ${window.innerWidth-document.documentElement.clientWidth}px;\n\t\t\t\t}\n\t\t\t`},setButtonStyles(){const{imageId:t}=(0,n.getContext)(),{ref:e}=(0,n.getElement)();r.metadata[t].imageRef=e,r.metadata[t].currentSrc=e.currentSrc;const{naturalWidth:o,naturalHeight:a,offsetWidth:i,offsetHeight:l}=e;if(0===o||0===a)return;const g=e.parentElement,c=e.parentElement.clientWidth;let s=e.parentElement.clientHeight;const d=g.querySelector("figcaption");if(d){const t=window.getComputedStyle(d);["absolute","fixed"].includes(t.position)||(s=s-d.offsetHeight-parseFloat(t.marginTop)-parseFloat(t.marginBottom))}const u=s-l,m=c-i;let h=u+16,p=m+16;if("contain"===r.metadata[t].scaleAttr){const t=o/a;if(t>=i/l){h=(l-i/t)/2+u+16,p=m+16}else{h=u+16,p=(i-l*t)/2+m+16}}r.metadata[t].imageButtonTop=h,r.metadata[t].imageButtonRight=p},setOverlayFocus(){if(r.overlayEnabled){const{ref:t}=(0,n.getElement)();t.focus()}},initTriggerButton(){const{imageId:t}=(0,n.getContext)(),{ref:e}=(0,n.getElement)();r.metadata[t].buttonRef=e}}},{lock:!0}); view.asset.php 0000644 00000000124 14721530727 0007352 0 ustar 00 <?php return array('dependencies' => array(), 'version' => '7500eb032759d407a71d'); editor.min.css 0000644 00000004557 14721530727 0007351 0 ustar 00 .wp-block-image.wp-block-image .block-editor-media-placeholder.is-small{min-height:60px}figure.wp-block-image:not(.wp-block){margin:0}.wp-block-image{position:relative}.wp-block-image .is-applying img,.wp-block-image.is-transient img{opacity:.3}.wp-block-image figcaption img{display:inline}.wp-block-image .components-spinner{left:50%;margin:0;position:absolute;top:50%;transform:translate(-50%,-50%)}.wp-block-image__placeholder{aspect-ratio:4/3}.wp-block-image__placeholder.has-illustration:before{background:#fff;opacity:.8}.wp-block-image__placeholder .components-placeholder__illustration{opacity:.1}.wp-block-image .components-resizable-box__container{display:table}.wp-block-image .components-resizable-box__container img{display:block;height:inherit;width:inherit}.block-editor-block-list__block[data-type="core/image"] .block-editor-block-toolbar .block-editor-url-input__button-modal{left:0;margin:-1px 0;position:absolute;right:0}@media (min-width:600px){.block-editor-block-list__block[data-type="core/image"] .block-editor-block-toolbar .block-editor-url-input__button-modal{margin:-1px}}[data-align=full]>.wp-block-image img,[data-align=wide]>.wp-block-image img{height:auto;width:100%}.wp-block[data-align=center]>.wp-block-image,.wp-block[data-align=left]>.wp-block-image,.wp-block[data-align=right]>.wp-block-image{display:table}.wp-block[data-align=center]>.wp-block-image>figcaption,.wp-block[data-align=left]>.wp-block-image>figcaption,.wp-block[data-align=right]>.wp-block-image>figcaption{caption-side:bottom;display:table-caption}.wp-block[data-align=left]>.wp-block-image{margin:.5em 1em .5em 0}.wp-block[data-align=right]>.wp-block-image{margin:.5em 0 .5em 1em}.wp-block[data-align=center]>.wp-block-image{margin-left:auto;margin-right:auto;text-align:center}.wp-block[data-align]:has(>.wp-block-image){position:relative}.wp-block-image__crop-area{max-width:100%;overflow:hidden;position:relative;width:100%}.wp-block-image__crop-area .reactEasyCrop_Container{pointer-events:auto}.wp-block-image__crop-area .reactEasyCrop_Container .reactEasyCrop_Image{border:none;border-radius:0}.wp-block-image__crop-icon{align-items:center;display:flex;justify-content:center;min-width:48px;padding:0 8px}.wp-block-image__crop-icon svg{fill:currentColor}.wp-block-image__zoom .components-popover__content{min-width:260px;overflow:visible!important}.wp-block-image__toolbar_content_textarea{width:250px} style-rtl.min.css 0000644 00000015076 14721530727 0010020 0 ustar 00 .wp-block-image a{display:inline-block}.wp-block-image img{box-sizing:border-box;height:auto;max-width:100%;vertical-align:bottom}@media (prefers-reduced-motion:no-preference){.wp-block-image img.hide{visibility:hidden}.wp-block-image img.show{animation:show-content-image .4s}}.wp-block-image[style*=border-radius] img,.wp-block-image[style*=border-radius]>a{border-radius:inherit}.wp-block-image.has-custom-border img{box-sizing:border-box}.wp-block-image.aligncenter{text-align:center}.wp-block-image.alignfull a,.wp-block-image.alignwide a{width:100%}.wp-block-image.alignfull img,.wp-block-image.alignwide img{height:auto;width:100%}.wp-block-image .aligncenter,.wp-block-image .alignleft,.wp-block-image .alignright,.wp-block-image.aligncenter,.wp-block-image.alignleft,.wp-block-image.alignright{display:table}.wp-block-image .aligncenter>figcaption,.wp-block-image .alignleft>figcaption,.wp-block-image .alignright>figcaption,.wp-block-image.aligncenter>figcaption,.wp-block-image.alignleft>figcaption,.wp-block-image.alignright>figcaption{caption-side:bottom;display:table-caption}.wp-block-image .alignleft{float:left;margin:.5em 1em .5em 0}.wp-block-image .alignright{float:right;margin:.5em 0 .5em 1em}.wp-block-image .aligncenter{margin-left:auto;margin-right:auto}.wp-block-image :where(figcaption){margin-bottom:1em;margin-top:.5em}.wp-block-image.is-style-circle-mask img{border-radius:9999px}@supports ((-webkit-mask-image:none) or (mask-image:none)) or (-webkit-mask-image:none){.wp-block-image.is-style-circle-mask img{border-radius:0;-webkit-mask-image:url('data:image/svg+xml;utf8,<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50"/></svg>');mask-image:url('data:image/svg+xml;utf8,<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50"/></svg>');mask-mode:alpha;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}}:root :where(.wp-block-image.is-style-rounded img,.wp-block-image .is-style-rounded img){border-radius:9999px}.wp-block-image figure{margin:0}.wp-lightbox-container{display:flex;flex-direction:column;position:relative}.wp-lightbox-container img{cursor:zoom-in}.wp-lightbox-container img:hover+button{opacity:1}.wp-lightbox-container button{align-items:center;-webkit-backdrop-filter:blur(16px) saturate(180%);backdrop-filter:blur(16px) saturate(180%);background-color:#5a5a5a40;border:none;border-radius:4px;cursor:zoom-in;display:flex;height:20px;justify-content:center;left:16px;opacity:0;padding:0;position:absolute;text-align:center;top:16px;transition:opacity .2s ease;width:20px;z-index:100}.wp-lightbox-container button:focus-visible{outline:3px auto #5a5a5a40;outline:3px auto -webkit-focus-ring-color;outline-offset:3px}.wp-lightbox-container button:hover{cursor:pointer;opacity:1}.wp-lightbox-container button:focus{opacity:1}.wp-lightbox-container button:focus,.wp-lightbox-container button:hover,.wp-lightbox-container button:not(:hover):not(:active):not(.has-background){background-color:#5a5a5a40;border:none}.wp-lightbox-overlay{box-sizing:border-box;cursor:zoom-out;height:100vh;overflow:hidden;position:fixed;right:0;top:0;visibility:hidden;width:100%;z-index:100000}.wp-lightbox-overlay .close-button{align-items:center;cursor:pointer;display:flex;justify-content:center;left:calc(env(safe-area-inset-left) + 16px);min-height:40px;min-width:40px;padding:0;position:absolute;top:calc(env(safe-area-inset-top) + 16px);z-index:5000000}.wp-lightbox-overlay .close-button:focus,.wp-lightbox-overlay .close-button:hover,.wp-lightbox-overlay .close-button:not(:hover):not(:active):not(.has-background){background:none;border:none}.wp-lightbox-overlay .lightbox-image-container{height:var(--wp--lightbox-container-height);overflow:hidden;position:absolute;right:50%;top:50%;transform:translate(50%,-50%);transform-origin:top right;width:var(--wp--lightbox-container-width);z-index:9999999999}.wp-lightbox-overlay .wp-block-image{align-items:center;box-sizing:border-box;display:flex;height:100%;justify-content:center;margin:0;position:relative;transform-origin:100% 0;width:100%;z-index:3000000}.wp-lightbox-overlay .wp-block-image img{height:var(--wp--lightbox-image-height);min-height:var(--wp--lightbox-image-height);min-width:var(--wp--lightbox-image-width);width:var(--wp--lightbox-image-width)}.wp-lightbox-overlay .wp-block-image figcaption{display:none}.wp-lightbox-overlay button{background:none;border:none}.wp-lightbox-overlay .scrim{background-color:#fff;height:100%;opacity:.9;position:absolute;width:100%;z-index:2000000}.wp-lightbox-overlay.active{animation:turn-on-visibility .25s both;visibility:visible}.wp-lightbox-overlay.active img{animation:turn-on-visibility .35s both}.wp-lightbox-overlay.show-closing-animation:not(.active){animation:turn-off-visibility .35s both}.wp-lightbox-overlay.show-closing-animation:not(.active) img{animation:turn-off-visibility .25s both}@media (prefers-reduced-motion:no-preference){.wp-lightbox-overlay.zoom.active{animation:none;opacity:1;visibility:visible}.wp-lightbox-overlay.zoom.active .lightbox-image-container{animation:lightbox-zoom-in .4s}.wp-lightbox-overlay.zoom.active .lightbox-image-container img{animation:none}.wp-lightbox-overlay.zoom.active .scrim{animation:turn-on-visibility .4s forwards}.wp-lightbox-overlay.zoom.show-closing-animation:not(.active){animation:none}.wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .lightbox-image-container{animation:lightbox-zoom-out .4s}.wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .lightbox-image-container img{animation:none}.wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .scrim{animation:turn-off-visibility .4s forwards}}@keyframes show-content-image{0%{visibility:hidden}99%{visibility:hidden}to{visibility:visible}}@keyframes turn-on-visibility{0%{opacity:0}to{opacity:1}}@keyframes turn-off-visibility{0%{opacity:1;visibility:visible}99%{opacity:0;visibility:visible}to{opacity:0;visibility:hidden}}@keyframes lightbox-zoom-in{0%{transform:translate(calc(((-100vw + var(--wp--lightbox-scrollbar-width))/2 + var(--wp--lightbox-initial-left-position))*-1),calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale))}to{transform:translate(50%,-50%) scale(1)}}@keyframes lightbox-zoom-out{0%{transform:translate(50%,-50%) scale(1);visibility:visible}99%{visibility:visible}to{transform:translate(calc(((-100vw + var(--wp--lightbox-scrollbar-width))/2 + var(--wp--lightbox-initial-left-position))*-1),calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale));visibility:hidden}} theme.min.css 0000644 00000000274 14721530727 0007155 0 ustar 00 :root :where(.wp-block-image figcaption){color:#555;font-size:13px;text-align:center}.is-dark-theme :root :where(.wp-block-image figcaption){color:#ffffffa6}.wp-block-image{margin:0 0 1em} theme-rtl.min.css 0000644 00000000274 14721530727 0007754 0 ustar 00 :root :where(.wp-block-image figcaption){color:#555;font-size:13px;text-align:center}.is-dark-theme :root :where(.wp-block-image figcaption){color:#ffffffa6}.wp-block-image{margin:0 0 1em} theme-rtl.css 0000644 00000000324 14721530727 0007166 0 ustar 00 :root :where(.wp-block-image figcaption){ color:#555; font-size:13px; text-align:center; } .is-dark-theme :root :where(.wp-block-image figcaption){ color:#ffffffa6; } .wp-block-image{ margin:0 0 1em; } style-rtl.css 0000644 00000016675 14721530727 0007244 0 ustar 00 .wp-block-image a{ display:inline-block; } .wp-block-image img{ box-sizing:border-box; height:auto; max-width:100%; vertical-align:bottom; } @media (prefers-reduced-motion:no-preference){ .wp-block-image img.hide{ visibility:hidden; } .wp-block-image img.show{ animation:show-content-image .4s; } } .wp-block-image[style*=border-radius] img,.wp-block-image[style*=border-radius]>a{ border-radius:inherit; } .wp-block-image.has-custom-border img{ box-sizing:border-box; } .wp-block-image.aligncenter{ text-align:center; } .wp-block-image.alignfull a,.wp-block-image.alignwide a{ width:100%; } .wp-block-image.alignfull img,.wp-block-image.alignwide img{ height:auto; width:100%; } .wp-block-image .aligncenter,.wp-block-image .alignleft,.wp-block-image .alignright,.wp-block-image.aligncenter,.wp-block-image.alignleft,.wp-block-image.alignright{ display:table; } .wp-block-image .aligncenter>figcaption,.wp-block-image .alignleft>figcaption,.wp-block-image .alignright>figcaption,.wp-block-image.aligncenter>figcaption,.wp-block-image.alignleft>figcaption,.wp-block-image.alignright>figcaption{ caption-side:bottom; display:table-caption; } .wp-block-image .alignleft{ float:left; margin:.5em 1em .5em 0; } .wp-block-image .alignright{ float:right; margin:.5em 0 .5em 1em; } .wp-block-image .aligncenter{ margin-left:auto; margin-right:auto; } .wp-block-image :where(figcaption){ margin-bottom:1em; margin-top:.5em; } .wp-block-image.is-style-circle-mask img{ border-radius:9999px; } @supports ((-webkit-mask-image:none) or (mask-image:none)) or (-webkit-mask-image:none){ .wp-block-image.is-style-circle-mask img{ border-radius:0; -webkit-mask-image:url('data:image/svg+xml;utf8,<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50"/></svg>'); mask-image:url('data:image/svg+xml;utf8,<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50"/></svg>'); mask-mode:alpha; -webkit-mask-position:center; mask-position:center; -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat; -webkit-mask-size:contain; mask-size:contain; } } :root :where(.wp-block-image.is-style-rounded img,.wp-block-image .is-style-rounded img){ border-radius:9999px; } .wp-block-image figure{ margin:0; } .wp-lightbox-container{ display:flex; flex-direction:column; position:relative; } .wp-lightbox-container img{ cursor:zoom-in; } .wp-lightbox-container img:hover+button{ opacity:1; } .wp-lightbox-container button{ align-items:center; -webkit-backdrop-filter:blur(16px) saturate(180%); backdrop-filter:blur(16px) saturate(180%); background-color:#5a5a5a40; border:none; border-radius:4px; cursor:zoom-in; display:flex; height:20px; justify-content:center; left:16px; opacity:0; padding:0; position:absolute; text-align:center; top:16px; transition:opacity .2s ease; width:20px; z-index:100; } .wp-lightbox-container button:focus-visible{ outline:3px auto #5a5a5a40; outline:3px auto -webkit-focus-ring-color; outline-offset:3px; } .wp-lightbox-container button:hover{ cursor:pointer; opacity:1; } .wp-lightbox-container button:focus{ opacity:1; } .wp-lightbox-container button:focus,.wp-lightbox-container button:hover,.wp-lightbox-container button:not(:hover):not(:active):not(.has-background){ background-color:#5a5a5a40; border:none; } .wp-lightbox-overlay{ box-sizing:border-box; cursor:zoom-out; height:100vh; overflow:hidden; position:fixed; right:0; top:0; visibility:hidden; width:100%; z-index:100000; } .wp-lightbox-overlay .close-button{ align-items:center; cursor:pointer; display:flex; justify-content:center; left:calc(env(safe-area-inset-left) + 16px); min-height:40px; min-width:40px; padding:0; position:absolute; top:calc(env(safe-area-inset-top) + 16px); z-index:5000000; } .wp-lightbox-overlay .close-button:focus,.wp-lightbox-overlay .close-button:hover,.wp-lightbox-overlay .close-button:not(:hover):not(:active):not(.has-background){ background:none; border:none; } .wp-lightbox-overlay .lightbox-image-container{ height:var(--wp--lightbox-container-height); overflow:hidden; position:absolute; right:50%; top:50%; transform:translate(50%, -50%); transform-origin:top right; width:var(--wp--lightbox-container-width); z-index:9999999999; } .wp-lightbox-overlay .wp-block-image{ align-items:center; box-sizing:border-box; display:flex; height:100%; justify-content:center; margin:0; position:relative; transform-origin:100% 0; width:100%; z-index:3000000; } .wp-lightbox-overlay .wp-block-image img{ height:var(--wp--lightbox-image-height); min-height:var(--wp--lightbox-image-height); min-width:var(--wp--lightbox-image-width); width:var(--wp--lightbox-image-width); } .wp-lightbox-overlay .wp-block-image figcaption{ display:none; } .wp-lightbox-overlay button{ background:none; border:none; } .wp-lightbox-overlay .scrim{ background-color:#fff; height:100%; opacity:.9; position:absolute; width:100%; z-index:2000000; } .wp-lightbox-overlay.active{ animation:turn-on-visibility .25s both; visibility:visible; } .wp-lightbox-overlay.active img{ animation:turn-on-visibility .35s both; } .wp-lightbox-overlay.show-closing-animation:not(.active){ animation:turn-off-visibility .35s both; } .wp-lightbox-overlay.show-closing-animation:not(.active) img{ animation:turn-off-visibility .25s both; } @media (prefers-reduced-motion:no-preference){ .wp-lightbox-overlay.zoom.active{ animation:none; opacity:1; visibility:visible; } .wp-lightbox-overlay.zoom.active .lightbox-image-container{ animation:lightbox-zoom-in .4s; } .wp-lightbox-overlay.zoom.active .lightbox-image-container img{ animation:none; } .wp-lightbox-overlay.zoom.active .scrim{ animation:turn-on-visibility .4s forwards; } .wp-lightbox-overlay.zoom.show-closing-animation:not(.active){ animation:none; } .wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .lightbox-image-container{ animation:lightbox-zoom-out .4s; } .wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .lightbox-image-container img{ animation:none; } .wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .scrim{ animation:turn-off-visibility .4s forwards; } } @keyframes show-content-image{ 0%{ visibility:hidden; } 99%{ visibility:hidden; } to{ visibility:visible; } } @keyframes turn-on-visibility{ 0%{ opacity:0; } to{ opacity:1; } } @keyframes turn-off-visibility{ 0%{ opacity:1; visibility:visible; } 99%{ opacity:0; visibility:visible; } to{ opacity:0; visibility:hidden; } } @keyframes lightbox-zoom-in{ 0%{ transform:translate(calc(((-100vw + var(--wp--lightbox-scrollbar-width))/2 + var(--wp--lightbox-initial-left-position))*-1), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); } to{ transform:translate(50%, -50%) scale(1); } } @keyframes lightbox-zoom-out{ 0%{ transform:translate(50%, -50%) scale(1); visibility:visible; } 99%{ visibility:visible; } to{ transform:translate(calc(((-100vw + var(--wp--lightbox-scrollbar-width))/2 + var(--wp--lightbox-initial-left-position))*-1), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); visibility:hidden; } } editor-rtl.css 0000644 00000005156 14721530727 0007362 0 ustar 00 .wp-block-image.wp-block-image .block-editor-media-placeholder.is-small{ min-height:60px; } figure.wp-block-image:not(.wp-block){ margin:0; } .wp-block-image{ position:relative; } .wp-block-image .is-applying img,.wp-block-image.is-transient img{ opacity:.3; } .wp-block-image figcaption img{ display:inline; } .wp-block-image .components-spinner{ margin:0; position:absolute; right:50%; top:50%; transform:translate(50%, -50%); } .wp-block-image__placeholder{ aspect-ratio:4/3; } .wp-block-image__placeholder.has-illustration:before{ background:#fff; opacity:.8; } .wp-block-image__placeholder .components-placeholder__illustration{ opacity:.1; } .wp-block-image .components-resizable-box__container{ display:table; } .wp-block-image .components-resizable-box__container img{ display:block; height:inherit; width:inherit; } .block-editor-block-list__block[data-type="core/image"] .block-editor-block-toolbar .block-editor-url-input__button-modal{ left:0; margin:-1px 0; position:absolute; right:0; } @media (min-width:600px){ .block-editor-block-list__block[data-type="core/image"] .block-editor-block-toolbar .block-editor-url-input__button-modal{ margin:-1px; } } [data-align=full]>.wp-block-image img,[data-align=wide]>.wp-block-image img{ height:auto; width:100%; } .wp-block[data-align=center]>.wp-block-image,.wp-block[data-align=left]>.wp-block-image,.wp-block[data-align=right]>.wp-block-image{ display:table; } .wp-block[data-align=center]>.wp-block-image>figcaption,.wp-block[data-align=left]>.wp-block-image>figcaption,.wp-block[data-align=right]>.wp-block-image>figcaption{ caption-side:bottom; display:table-caption; } .wp-block[data-align=left]>.wp-block-image{ margin:.5em 0 .5em 1em; } .wp-block[data-align=right]>.wp-block-image{ margin:.5em 1em .5em 0; } .wp-block[data-align=center]>.wp-block-image{ margin-left:auto; margin-right:auto; text-align:center; } .wp-block[data-align]:has(>.wp-block-image){ position:relative; } .wp-block-image__crop-area{ max-width:100%; overflow:hidden; position:relative; width:100%; } .wp-block-image__crop-area .reactEasyCrop_Container{ pointer-events:auto; } .wp-block-image__crop-area .reactEasyCrop_Container .reactEasyCrop_Image{ border:none; border-radius:0; } .wp-block-image__crop-icon{ align-items:center; display:flex; justify-content:center; min-width:48px; padding:0 8px; } .wp-block-image__crop-icon svg{ fill:currentColor; } .wp-block-image__zoom .components-popover__content{ min-width:260px; overflow:visible !important; } .wp-block-image__toolbar_content_textarea{ width:250px; } view.js 0000644 00000043201 14721530727 0006064 0 ustar 00 import * as __WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__ from "@wordpress/interactivity"; /******/ // The require scope /******/ var __webpack_require__ = {}; /******/ /************************************************************************/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; ;// CONCATENATED MODULE: external "@wordpress/interactivity" var x = (y) => { var x = {}; __webpack_require__.d(x, y); return x } var y = (x) => (() => (x)) const interactivity_namespaceObject = x({ ["getContext"]: () => (__WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__.getContext), ["getElement"]: () => (__WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__.getElement), ["store"]: () => (__WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__.store) }); ;// CONCATENATED MODULE: ./node_modules/@wordpress/block-library/build-module/image/view.js /** * WordPress dependencies */ /** * Tracks whether user is touching screen; used to differentiate behavior for * touch and mouse input. * * @type {boolean} */ let isTouching = false; /** * Tracks the last time the screen was touched; used to differentiate behavior * for touch and mouse input. * * @type {number} */ let lastTouchTime = 0; const { state, actions, callbacks } = (0,interactivity_namespaceObject.store)('core/image', { state: { currentImageId: null, get currentImage() { return state.metadata[state.currentImageId]; }, get overlayOpened() { return state.currentImageId !== null; }, get roleAttribute() { return state.overlayOpened ? 'dialog' : null; }, get ariaModal() { return state.overlayOpened ? 'true' : null; }, get enlargedSrc() { return state.currentImage.uploadedSrc || 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; }, get figureStyles() { return state.overlayOpened && `${state.currentImage.figureStyles?.replace(/margin[^;]*;?/g, '')};`; }, get imgStyles() { return state.overlayOpened && `${state.currentImage.imgStyles?.replace(/;$/, '')}; object-fit:cover;`; }, get imageButtonRight() { const { imageId } = (0,interactivity_namespaceObject.getContext)(); return state.metadata[imageId].imageButtonRight; }, get imageButtonTop() { const { imageId } = (0,interactivity_namespaceObject.getContext)(); return state.metadata[imageId].imageButtonTop; }, get isContentHidden() { const ctx = (0,interactivity_namespaceObject.getContext)(); return state.overlayEnabled && state.currentImageId === ctx.imageId; }, get isContentVisible() { const ctx = (0,interactivity_namespaceObject.getContext)(); return !state.overlayEnabled && state.currentImageId === ctx.imageId; } }, actions: { showLightbox() { const { imageId } = (0,interactivity_namespaceObject.getContext)(); // Bails out if the image has not loaded yet. if (!state.metadata[imageId].imageRef?.complete) { return; } // Stores the positions of the scroll to fix it until the overlay is // closed. state.scrollTopReset = document.documentElement.scrollTop; state.scrollLeftReset = document.documentElement.scrollLeft; // Sets the current expanded image in the state and enables the overlay. state.overlayEnabled = true; state.currentImageId = imageId; // Computes the styles of the overlay for the animation. callbacks.setOverlayStyles(); }, hideLightbox() { if (state.overlayEnabled) { // Starts the overlay closing animation. The showClosingAnimation // class is used to avoid showing it on page load. state.showClosingAnimation = true; state.overlayEnabled = false; // Waits until the close animation has completed before allowing a // user to scroll again. The duration of this animation is defined in // the `styles.scss` file, but in any case we should wait a few // milliseconds longer than the duration, otherwise a user may scroll // too soon and cause the animation to look sloppy. setTimeout(function () { // Delays before changing the focus. Otherwise the focus ring will // appear on Firefox before the image has finished animating, which // looks broken. state.currentImage.buttonRef.focus({ preventScroll: true }); // Resets the current image id to mark the overlay as closed. state.currentImageId = null; }, 450); } }, handleKeydown(event) { if (state.overlayEnabled) { // Focuses the close button when the user presses the tab key. if (event.key === 'Tab') { event.preventDefault(); const { ref } = (0,interactivity_namespaceObject.getElement)(); ref.querySelector('button').focus(); } // Closes the lightbox when the user presses the escape key. if (event.key === 'Escape') { actions.hideLightbox(); } } }, handleTouchMove(event) { // On mobile devices, prevents triggering the scroll event because // otherwise the page jumps around when it resets the scroll position. // This also means that closing the lightbox requires that a user // perform a simple tap. This may be changed in the future if there is a // better alternative to override or reset the scroll position during // swipe actions. if (state.overlayEnabled) { event.preventDefault(); } }, handleTouchStart() { isTouching = true; }, handleTouchEnd() { // Waits a few milliseconds before resetting to ensure that pinch to // zoom works consistently on mobile devices when the lightbox is open. lastTouchTime = Date.now(); isTouching = false; }, handleScroll() { // Prevents scrolling behaviors that trigger content shift while the // lightbox is open. It would be better to accomplish through CSS alone, // but using overflow: hidden is currently the only way to do so and // that causes a layout to shift and prevents the zoom animation from // working in some cases because it's not possible to account for the // layout shift when doing the animation calculations. Instead, it uses // JavaScript to prevent and reset the scrolling behavior. if (state.overlayOpened) { // Avoids overriding the scroll behavior on mobile devices because // doing so breaks the pinch to zoom functionality, and users should // be able to zoom in further on the high-res image. if (!isTouching && Date.now() - lastTouchTime > 450) { // It doesn't rely on `event.preventDefault()` to prevent scrolling // because the scroll event can't be canceled, so it resets the // position instead. window.scrollTo(state.scrollLeftReset, state.scrollTopReset); } } } }, callbacks: { setOverlayStyles() { if (!state.overlayEnabled) { return; } let { naturalWidth, naturalHeight, offsetWidth: originalWidth, offsetHeight: originalHeight } = state.currentImage.imageRef; let { x: screenPosX, y: screenPosY } = state.currentImage.imageRef.getBoundingClientRect(); // Natural ratio of the image clicked to open the lightbox. const naturalRatio = naturalWidth / naturalHeight; // Original ratio of the image clicked to open the lightbox. let originalRatio = originalWidth / originalHeight; // If it has object-fit: contain, recalculates the original sizes // and the screen position without the blank spaces. if (state.currentImage.scaleAttr === 'contain') { if (naturalRatio > originalRatio) { const heightWithoutSpace = originalWidth / naturalRatio; // Recalculates screen position without the top space. screenPosY += (originalHeight - heightWithoutSpace) / 2; originalHeight = heightWithoutSpace; } else { const widthWithoutSpace = originalHeight * naturalRatio; // Recalculates screen position without the left space. screenPosX += (originalWidth - widthWithoutSpace) / 2; originalWidth = widthWithoutSpace; } } originalRatio = originalWidth / originalHeight; // Typically, it uses the image's full-sized dimensions. If those // dimensions have not been set (i.e. an external image with only one // size), the image's dimensions in the lightbox are the same // as those of the image in the content. let imgMaxWidth = parseFloat(state.currentImage.targetWidth !== 'none' ? state.currentImage.targetWidth : naturalWidth); let imgMaxHeight = parseFloat(state.currentImage.targetHeight !== 'none' ? state.currentImage.targetHeight : naturalHeight); // Ratio of the biggest image stored in the database. let imgRatio = imgMaxWidth / imgMaxHeight; let containerMaxWidth = imgMaxWidth; let containerMaxHeight = imgMaxHeight; let containerWidth = imgMaxWidth; let containerHeight = imgMaxHeight; // Checks if the target image has a different ratio than the original // one (thumbnail). Recalculates the width and height. if (naturalRatio.toFixed(2) !== imgRatio.toFixed(2)) { if (naturalRatio > imgRatio) { // If the width is reached before the height, it keeps the maxWidth // and recalculates the height unless the difference between the // maxHeight and the reducedHeight is higher than the maxWidth, // where it keeps the reducedHeight and recalculate the width. const reducedHeight = imgMaxWidth / naturalRatio; if (imgMaxHeight - reducedHeight > imgMaxWidth) { imgMaxHeight = reducedHeight; imgMaxWidth = reducedHeight * naturalRatio; } else { imgMaxHeight = imgMaxWidth / naturalRatio; } } else { // If the height is reached before the width, it keeps the maxHeight // and recalculate the width unlesss the difference between the // maxWidth and the reducedWidth is higher than the maxHeight, where // it keeps the reducedWidth and recalculate the height. const reducedWidth = imgMaxHeight * naturalRatio; if (imgMaxWidth - reducedWidth > imgMaxHeight) { imgMaxWidth = reducedWidth; imgMaxHeight = reducedWidth / naturalRatio; } else { imgMaxWidth = imgMaxHeight * naturalRatio; } } containerWidth = imgMaxWidth; containerHeight = imgMaxHeight; imgRatio = imgMaxWidth / imgMaxHeight; // Calculates the max size of the container. if (originalRatio > imgRatio) { containerMaxWidth = imgMaxWidth; containerMaxHeight = containerMaxWidth / originalRatio; } else { containerMaxHeight = imgMaxHeight; containerMaxWidth = containerMaxHeight * originalRatio; } } // If the image has been pixelated on purpose, it keeps that size. if (originalWidth > containerWidth || originalHeight > containerHeight) { containerWidth = originalWidth; containerHeight = originalHeight; } // Calculates the final lightbox image size and the scale factor. // MaxWidth is either the window container (accounting for padding) or // the image resolution. let horizontalPadding = 0; if (window.innerWidth > 480) { horizontalPadding = 80; } else if (window.innerWidth > 1920) { horizontalPadding = 160; } const verticalPadding = 80; const targetMaxWidth = Math.min(window.innerWidth - horizontalPadding, containerWidth); const targetMaxHeight = Math.min(window.innerHeight - verticalPadding, containerHeight); const targetContainerRatio = targetMaxWidth / targetMaxHeight; if (originalRatio > targetContainerRatio) { // If targetMaxWidth is reached before targetMaxHeight. containerWidth = targetMaxWidth; containerHeight = containerWidth / originalRatio; } else { // If targetMaxHeight is reached before targetMaxWidth. containerHeight = targetMaxHeight; containerWidth = containerHeight * originalRatio; } const containerScale = originalWidth / containerWidth; const lightboxImgWidth = imgMaxWidth * (containerWidth / containerMaxWidth); const lightboxImgHeight = imgMaxHeight * (containerHeight / containerMaxHeight); // As of this writing, using the calculations above will render the // lightbox with a small, erroneous whitespace on the left side of the // image in iOS Safari, perhaps due to an inconsistency in how browsers // handle absolute positioning and CSS transformation. In any case, // adding 1 pixel to the container width and height solves the problem, // though this can be removed if the issue is fixed in the future. state.overlayStyles = ` :root { --wp--lightbox-initial-top-position: ${screenPosY}px; --wp--lightbox-initial-left-position: ${screenPosX}px; --wp--lightbox-container-width: ${containerWidth + 1}px; --wp--lightbox-container-height: ${containerHeight + 1}px; --wp--lightbox-image-width: ${lightboxImgWidth}px; --wp--lightbox-image-height: ${lightboxImgHeight}px; --wp--lightbox-scale: ${containerScale}; --wp--lightbox-scrollbar-width: ${window.innerWidth - document.documentElement.clientWidth}px; } `; }, setButtonStyles() { const { imageId } = (0,interactivity_namespaceObject.getContext)(); const { ref } = (0,interactivity_namespaceObject.getElement)(); state.metadata[imageId].imageRef = ref; state.metadata[imageId].currentSrc = ref.currentSrc; const { naturalWidth, naturalHeight, offsetWidth, offsetHeight } = ref; // If the image isn't loaded yet, it can't calculate where the button // should be. if (naturalWidth === 0 || naturalHeight === 0) { return; } const figure = ref.parentElement; const figureWidth = ref.parentElement.clientWidth; // It needs special handling for the height because a caption will cause // the figure to be taller than the image, which means it needs to // account for that when calculating the placement of the button in the // top right corner of the image. let figureHeight = ref.parentElement.clientHeight; const caption = figure.querySelector('figcaption'); if (caption) { const captionComputedStyle = window.getComputedStyle(caption); if (!['absolute', 'fixed'].includes(captionComputedStyle.position)) { figureHeight = figureHeight - caption.offsetHeight - parseFloat(captionComputedStyle.marginTop) - parseFloat(captionComputedStyle.marginBottom); } } const buttonOffsetTop = figureHeight - offsetHeight; const buttonOffsetRight = figureWidth - offsetWidth; let imageButtonTop = buttonOffsetTop + 16; let imageButtonRight = buttonOffsetRight + 16; // In the case of an image with object-fit: contain, the size of the // <img> element can be larger than the image itself, so it needs to // calculate where to place the button. if (state.metadata[imageId].scaleAttr === 'contain') { // Natural ratio of the image. const naturalRatio = naturalWidth / naturalHeight; // Offset ratio of the image. const offsetRatio = offsetWidth / offsetHeight; if (naturalRatio >= offsetRatio) { // If it reaches the width first, it keeps the width and compute the // height. const referenceHeight = offsetWidth / naturalRatio; imageButtonTop = (offsetHeight - referenceHeight) / 2 + buttonOffsetTop + 16; imageButtonRight = buttonOffsetRight + 16; } else { // If it reaches the height first, it keeps the height and compute // the width. const referenceWidth = offsetHeight * naturalRatio; imageButtonTop = buttonOffsetTop + 16; imageButtonRight = (offsetWidth - referenceWidth) / 2 + buttonOffsetRight + 16; } } state.metadata[imageId].imageButtonTop = imageButtonTop; state.metadata[imageId].imageButtonRight = imageButtonRight; }, setOverlayFocus() { if (state.overlayEnabled) { // Moves the focus to the dialog when it opens. const { ref } = (0,interactivity_namespaceObject.getElement)(); ref.focus(); } }, initTriggerButton() { const { imageId } = (0,interactivity_namespaceObject.getContext)(); const { ref } = (0,interactivity_namespaceObject.getElement)(); state.metadata[imageId].buttonRef = ref; } } }, { lock: true }); view.min.asset.php 0000644 00000000124 14721530727 0010134 0 ustar 00 <?php return array('dependencies' => array(), 'version' => 'ff354d5368d64857fef0'); theme.css 0000644 00000000324 14721530727 0006367 0 ustar 00 :root :where(.wp-block-image figcaption){ color:#555; font-size:13px; text-align:center; } .is-dark-theme :root :where(.wp-block-image figcaption){ color:#ffffffa6; } .wp-block-image{ margin:0 0 1em; } editor.css 0000644 00000005156 14721530727 0006563 0 ustar 00 .wp-block-image.wp-block-image .block-editor-media-placeholder.is-small{ min-height:60px; } figure.wp-block-image:not(.wp-block){ margin:0; } .wp-block-image{ position:relative; } .wp-block-image .is-applying img,.wp-block-image.is-transient img{ opacity:.3; } .wp-block-image figcaption img{ display:inline; } .wp-block-image .components-spinner{ left:50%; margin:0; position:absolute; top:50%; transform:translate(-50%, -50%); } .wp-block-image__placeholder{ aspect-ratio:4/3; } .wp-block-image__placeholder.has-illustration:before{ background:#fff; opacity:.8; } .wp-block-image__placeholder .components-placeholder__illustration{ opacity:.1; } .wp-block-image .components-resizable-box__container{ display:table; } .wp-block-image .components-resizable-box__container img{ display:block; height:inherit; width:inherit; } .block-editor-block-list__block[data-type="core/image"] .block-editor-block-toolbar .block-editor-url-input__button-modal{ left:0; margin:-1px 0; position:absolute; right:0; } @media (min-width:600px){ .block-editor-block-list__block[data-type="core/image"] .block-editor-block-toolbar .block-editor-url-input__button-modal{ margin:-1px; } } [data-align=full]>.wp-block-image img,[data-align=wide]>.wp-block-image img{ height:auto; width:100%; } .wp-block[data-align=center]>.wp-block-image,.wp-block[data-align=left]>.wp-block-image,.wp-block[data-align=right]>.wp-block-image{ display:table; } .wp-block[data-align=center]>.wp-block-image>figcaption,.wp-block[data-align=left]>.wp-block-image>figcaption,.wp-block[data-align=right]>.wp-block-image>figcaption{ caption-side:bottom; display:table-caption; } .wp-block[data-align=left]>.wp-block-image{ margin:.5em 1em .5em 0; } .wp-block[data-align=right]>.wp-block-image{ margin:.5em 0 .5em 1em; } .wp-block[data-align=center]>.wp-block-image{ margin-left:auto; margin-right:auto; text-align:center; } .wp-block[data-align]:has(>.wp-block-image){ position:relative; } .wp-block-image__crop-area{ max-width:100%; overflow:hidden; position:relative; width:100%; } .wp-block-image__crop-area .reactEasyCrop_Container{ pointer-events:auto; } .wp-block-image__crop-area .reactEasyCrop_Container .reactEasyCrop_Image{ border:none; border-radius:0; } .wp-block-image__crop-icon{ align-items:center; display:flex; justify-content:center; min-width:48px; padding:0 8px; } .wp-block-image__crop-icon svg{ fill:currentColor; } .wp-block-image__zoom .components-popover__content{ min-width:260px; overflow:visible !important; } .wp-block-image__toolbar_content_textarea{ width:250px; } style.css 0000644 00000016663 14721530727 0006442 0 ustar 00 .wp-block-image a{ display:inline-block; } .wp-block-image img{ box-sizing:border-box; height:auto; max-width:100%; vertical-align:bottom; } @media (prefers-reduced-motion:no-preference){ .wp-block-image img.hide{ visibility:hidden; } .wp-block-image img.show{ animation:show-content-image .4s; } } .wp-block-image[style*=border-radius] img,.wp-block-image[style*=border-radius]>a{ border-radius:inherit; } .wp-block-image.has-custom-border img{ box-sizing:border-box; } .wp-block-image.aligncenter{ text-align:center; } .wp-block-image.alignfull a,.wp-block-image.alignwide a{ width:100%; } .wp-block-image.alignfull img,.wp-block-image.alignwide img{ height:auto; width:100%; } .wp-block-image .aligncenter,.wp-block-image .alignleft,.wp-block-image .alignright,.wp-block-image.aligncenter,.wp-block-image.alignleft,.wp-block-image.alignright{ display:table; } .wp-block-image .aligncenter>figcaption,.wp-block-image .alignleft>figcaption,.wp-block-image .alignright>figcaption,.wp-block-image.aligncenter>figcaption,.wp-block-image.alignleft>figcaption,.wp-block-image.alignright>figcaption{ caption-side:bottom; display:table-caption; } .wp-block-image .alignleft{ float:left; margin:.5em 1em .5em 0; } .wp-block-image .alignright{ float:right; margin:.5em 0 .5em 1em; } .wp-block-image .aligncenter{ margin-left:auto; margin-right:auto; } .wp-block-image :where(figcaption){ margin-bottom:1em; margin-top:.5em; } .wp-block-image.is-style-circle-mask img{ border-radius:9999px; } @supports ((-webkit-mask-image:none) or (mask-image:none)) or (-webkit-mask-image:none){ .wp-block-image.is-style-circle-mask img{ border-radius:0; -webkit-mask-image:url('data:image/svg+xml;utf8,<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50"/></svg>'); mask-image:url('data:image/svg+xml;utf8,<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50"/></svg>'); mask-mode:alpha; -webkit-mask-position:center; mask-position:center; -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat; -webkit-mask-size:contain; mask-size:contain; } } :root :where(.wp-block-image.is-style-rounded img,.wp-block-image .is-style-rounded img){ border-radius:9999px; } .wp-block-image figure{ margin:0; } .wp-lightbox-container{ display:flex; flex-direction:column; position:relative; } .wp-lightbox-container img{ cursor:zoom-in; } .wp-lightbox-container img:hover+button{ opacity:1; } .wp-lightbox-container button{ align-items:center; -webkit-backdrop-filter:blur(16px) saturate(180%); backdrop-filter:blur(16px) saturate(180%); background-color:#5a5a5a40; border:none; border-radius:4px; cursor:zoom-in; display:flex; height:20px; justify-content:center; opacity:0; padding:0; position:absolute; right:16px; text-align:center; top:16px; transition:opacity .2s ease; width:20px; z-index:100; } .wp-lightbox-container button:focus-visible{ outline:3px auto #5a5a5a40; outline:3px auto -webkit-focus-ring-color; outline-offset:3px; } .wp-lightbox-container button:hover{ cursor:pointer; opacity:1; } .wp-lightbox-container button:focus{ opacity:1; } .wp-lightbox-container button:focus,.wp-lightbox-container button:hover,.wp-lightbox-container button:not(:hover):not(:active):not(.has-background){ background-color:#5a5a5a40; border:none; } .wp-lightbox-overlay{ box-sizing:border-box; cursor:zoom-out; height:100vh; left:0; overflow:hidden; position:fixed; top:0; visibility:hidden; width:100%; z-index:100000; } .wp-lightbox-overlay .close-button{ align-items:center; cursor:pointer; display:flex; justify-content:center; min-height:40px; min-width:40px; padding:0; position:absolute; right:calc(env(safe-area-inset-right) + 16px); top:calc(env(safe-area-inset-top) + 16px); z-index:5000000; } .wp-lightbox-overlay .close-button:focus,.wp-lightbox-overlay .close-button:hover,.wp-lightbox-overlay .close-button:not(:hover):not(:active):not(.has-background){ background:none; border:none; } .wp-lightbox-overlay .lightbox-image-container{ height:var(--wp--lightbox-container-height); left:50%; overflow:hidden; position:absolute; top:50%; transform:translate(-50%, -50%); transform-origin:top left; width:var(--wp--lightbox-container-width); z-index:9999999999; } .wp-lightbox-overlay .wp-block-image{ align-items:center; box-sizing:border-box; display:flex; height:100%; justify-content:center; margin:0; position:relative; transform-origin:0 0; width:100%; z-index:3000000; } .wp-lightbox-overlay .wp-block-image img{ height:var(--wp--lightbox-image-height); min-height:var(--wp--lightbox-image-height); min-width:var(--wp--lightbox-image-width); width:var(--wp--lightbox-image-width); } .wp-lightbox-overlay .wp-block-image figcaption{ display:none; } .wp-lightbox-overlay button{ background:none; border:none; } .wp-lightbox-overlay .scrim{ background-color:#fff; height:100%; opacity:.9; position:absolute; width:100%; z-index:2000000; } .wp-lightbox-overlay.active{ animation:turn-on-visibility .25s both; visibility:visible; } .wp-lightbox-overlay.active img{ animation:turn-on-visibility .35s both; } .wp-lightbox-overlay.show-closing-animation:not(.active){ animation:turn-off-visibility .35s both; } .wp-lightbox-overlay.show-closing-animation:not(.active) img{ animation:turn-off-visibility .25s both; } @media (prefers-reduced-motion:no-preference){ .wp-lightbox-overlay.zoom.active{ animation:none; opacity:1; visibility:visible; } .wp-lightbox-overlay.zoom.active .lightbox-image-container{ animation:lightbox-zoom-in .4s; } .wp-lightbox-overlay.zoom.active .lightbox-image-container img{ animation:none; } .wp-lightbox-overlay.zoom.active .scrim{ animation:turn-on-visibility .4s forwards; } .wp-lightbox-overlay.zoom.show-closing-animation:not(.active){ animation:none; } .wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .lightbox-image-container{ animation:lightbox-zoom-out .4s; } .wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .lightbox-image-container img{ animation:none; } .wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .scrim{ animation:turn-off-visibility .4s forwards; } } @keyframes show-content-image{ 0%{ visibility:hidden; } 99%{ visibility:hidden; } to{ visibility:visible; } } @keyframes turn-on-visibility{ 0%{ opacity:0; } to{ opacity:1; } } @keyframes turn-off-visibility{ 0%{ opacity:1; visibility:visible; } 99%{ opacity:0; visibility:visible; } to{ opacity:0; visibility:hidden; } } @keyframes lightbox-zoom-in{ 0%{ transform:translate(calc((-100vw + var(--wp--lightbox-scrollbar-width))/2 + var(--wp--lightbox-initial-left-position)), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); } to{ transform:translate(-50%, -50%) scale(1); } } @keyframes lightbox-zoom-out{ 0%{ transform:translate(-50%, -50%) scale(1); visibility:visible; } 99%{ visibility:visible; } to{ transform:translate(calc((-100vw + var(--wp--lightbox-scrollbar-width))/2 + var(--wp--lightbox-initial-left-position)), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); visibility:hidden; } } style.min.css 0000644 00000015064 14721530727 0007216 0 ustar 00 .wp-block-image a{display:inline-block}.wp-block-image img{box-sizing:border-box;height:auto;max-width:100%;vertical-align:bottom}@media (prefers-reduced-motion:no-preference){.wp-block-image img.hide{visibility:hidden}.wp-block-image img.show{animation:show-content-image .4s}}.wp-block-image[style*=border-radius] img,.wp-block-image[style*=border-radius]>a{border-radius:inherit}.wp-block-image.has-custom-border img{box-sizing:border-box}.wp-block-image.aligncenter{text-align:center}.wp-block-image.alignfull a,.wp-block-image.alignwide a{width:100%}.wp-block-image.alignfull img,.wp-block-image.alignwide img{height:auto;width:100%}.wp-block-image .aligncenter,.wp-block-image .alignleft,.wp-block-image .alignright,.wp-block-image.aligncenter,.wp-block-image.alignleft,.wp-block-image.alignright{display:table}.wp-block-image .aligncenter>figcaption,.wp-block-image .alignleft>figcaption,.wp-block-image .alignright>figcaption,.wp-block-image.aligncenter>figcaption,.wp-block-image.alignleft>figcaption,.wp-block-image.alignright>figcaption{caption-side:bottom;display:table-caption}.wp-block-image .alignleft{float:left;margin:.5em 1em .5em 0}.wp-block-image .alignright{float:right;margin:.5em 0 .5em 1em}.wp-block-image .aligncenter{margin-left:auto;margin-right:auto}.wp-block-image :where(figcaption){margin-bottom:1em;margin-top:.5em}.wp-block-image.is-style-circle-mask img{border-radius:9999px}@supports ((-webkit-mask-image:none) or (mask-image:none)) or (-webkit-mask-image:none){.wp-block-image.is-style-circle-mask img{border-radius:0;-webkit-mask-image:url('data:image/svg+xml;utf8,<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50"/></svg>');mask-image:url('data:image/svg+xml;utf8,<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50"/></svg>');mask-mode:alpha;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}}:root :where(.wp-block-image.is-style-rounded img,.wp-block-image .is-style-rounded img){border-radius:9999px}.wp-block-image figure{margin:0}.wp-lightbox-container{display:flex;flex-direction:column;position:relative}.wp-lightbox-container img{cursor:zoom-in}.wp-lightbox-container img:hover+button{opacity:1}.wp-lightbox-container button{align-items:center;-webkit-backdrop-filter:blur(16px) saturate(180%);backdrop-filter:blur(16px) saturate(180%);background-color:#5a5a5a40;border:none;border-radius:4px;cursor:zoom-in;display:flex;height:20px;justify-content:center;opacity:0;padding:0;position:absolute;right:16px;text-align:center;top:16px;transition:opacity .2s ease;width:20px;z-index:100}.wp-lightbox-container button:focus-visible{outline:3px auto #5a5a5a40;outline:3px auto -webkit-focus-ring-color;outline-offset:3px}.wp-lightbox-container button:hover{cursor:pointer;opacity:1}.wp-lightbox-container button:focus{opacity:1}.wp-lightbox-container button:focus,.wp-lightbox-container button:hover,.wp-lightbox-container button:not(:hover):not(:active):not(.has-background){background-color:#5a5a5a40;border:none}.wp-lightbox-overlay{box-sizing:border-box;cursor:zoom-out;height:100vh;left:0;overflow:hidden;position:fixed;top:0;visibility:hidden;width:100%;z-index:100000}.wp-lightbox-overlay .close-button{align-items:center;cursor:pointer;display:flex;justify-content:center;min-height:40px;min-width:40px;padding:0;position:absolute;right:calc(env(safe-area-inset-right) + 16px);top:calc(env(safe-area-inset-top) + 16px);z-index:5000000}.wp-lightbox-overlay .close-button:focus,.wp-lightbox-overlay .close-button:hover,.wp-lightbox-overlay .close-button:not(:hover):not(:active):not(.has-background){background:none;border:none}.wp-lightbox-overlay .lightbox-image-container{height:var(--wp--lightbox-container-height);left:50%;overflow:hidden;position:absolute;top:50%;transform:translate(-50%,-50%);transform-origin:top left;width:var(--wp--lightbox-container-width);z-index:9999999999}.wp-lightbox-overlay .wp-block-image{align-items:center;box-sizing:border-box;display:flex;height:100%;justify-content:center;margin:0;position:relative;transform-origin:0 0;width:100%;z-index:3000000}.wp-lightbox-overlay .wp-block-image img{height:var(--wp--lightbox-image-height);min-height:var(--wp--lightbox-image-height);min-width:var(--wp--lightbox-image-width);width:var(--wp--lightbox-image-width)}.wp-lightbox-overlay .wp-block-image figcaption{display:none}.wp-lightbox-overlay button{background:none;border:none}.wp-lightbox-overlay .scrim{background-color:#fff;height:100%;opacity:.9;position:absolute;width:100%;z-index:2000000}.wp-lightbox-overlay.active{animation:turn-on-visibility .25s both;visibility:visible}.wp-lightbox-overlay.active img{animation:turn-on-visibility .35s both}.wp-lightbox-overlay.show-closing-animation:not(.active){animation:turn-off-visibility .35s both}.wp-lightbox-overlay.show-closing-animation:not(.active) img{animation:turn-off-visibility .25s both}@media (prefers-reduced-motion:no-preference){.wp-lightbox-overlay.zoom.active{animation:none;opacity:1;visibility:visible}.wp-lightbox-overlay.zoom.active .lightbox-image-container{animation:lightbox-zoom-in .4s}.wp-lightbox-overlay.zoom.active .lightbox-image-container img{animation:none}.wp-lightbox-overlay.zoom.active .scrim{animation:turn-on-visibility .4s forwards}.wp-lightbox-overlay.zoom.show-closing-animation:not(.active){animation:none}.wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .lightbox-image-container{animation:lightbox-zoom-out .4s}.wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .lightbox-image-container img{animation:none}.wp-lightbox-overlay.zoom.show-closing-animation:not(.active) .scrim{animation:turn-off-visibility .4s forwards}}@keyframes show-content-image{0%{visibility:hidden}99%{visibility:hidden}to{visibility:visible}}@keyframes turn-on-visibility{0%{opacity:0}to{opacity:1}}@keyframes turn-off-visibility{0%{opacity:1;visibility:visible}99%{opacity:0;visibility:visible}to{opacity:0;visibility:hidden}}@keyframes lightbox-zoom-in{0%{transform:translate(calc((-100vw + var(--wp--lightbox-scrollbar-width))/2 + var(--wp--lightbox-initial-left-position)),calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale))}to{transform:translate(-50%,-50%) scale(1)}}@keyframes lightbox-zoom-out{0%{transform:translate(-50%,-50%) scale(1);visibility:visible}99%{visibility:visible}to{transform:translate(calc((-100vw + var(--wp--lightbox-scrollbar-width))/2 + var(--wp--lightbox-initial-left-position)),calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale));visibility:hidden}} image-status.php 0000644 00000001240 14721542123 0007656 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; use ImageOptimization\Classes\Basic_Enum; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } final class Image_Status extends Basic_Enum { public const NOT_OPTIMIZED = 'not-optimized'; public const OPTIMIZED = 'optimized'; public const OPTIMIZATION_IN_PROGRESS = 'optimization-in-progress'; public const OPTIMIZATION_FAILED = 'optimization-failed'; public const RESTORING_IN_PROGRESS = 'restoring-in-progress'; public const RESTORING_FAILED = 'restoring-failed'; public const REOPTIMIZING_IN_PROGRESS = 'reoptimizing-in-progress'; public const REOPTIMIZING_FAILED = 'reoptimizing-failed'; } image.php 0000644 00000010452 14721542123 0006342 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; use ImageOptimization\Classes\Image\Exceptions\Invalid_Image_Exception; use WP_Post; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Image { public const SIZE_FULL = 'full'; private const SUPPORTED_MIME_TYPES = [ 'image/jpeg', 'image/png', 'image/webp', 'image/gif', 'image/avif' ]; // Used for error messages private const SUPPORTED_FORMATS = [ 'jpeg', 'png', 'webp', 'gif', 'avif' ]; private const MIME_TYPES_CANNOT_BE_OPTIMIZED = [ 'image/avif' ]; private const FORMATS_CANNOT_BE_OPTIMIZED = [ 'avif' ]; protected int $image_id; protected $attachment_object; /** * Returns attachment post id. * * @return int */ public function get_id(): int { return $this->image_id; } /** * Returns file URL for a specific image size. * * @param string $image_size Image size (e. g. 'full', 'thumbnail', etc) * @return string|null */ public function get_url( string $image_size ): ?string { $image_data = wp_get_attachment_image_src( $this->image_id, $image_size ); if ( empty( $image_data ) ) { return null; } return $image_data[0]; } /** * Returns absolute file path for a specific image size. * * @param string $image_size Image size (e. g. 'full', 'thumbnail', etc) * @return string|null */ public function get_file_path( string $image_size ): ?string { if ( 'full' === $image_size ) { $path = get_attached_file( $this->image_id ); return $path ?? null; } $path_data = image_get_intermediate_size( $this->image_id, $image_size ); if ( empty( $path_data ) ) { return null; } return sprintf( '%s/%s', wp_get_upload_dir()['basedir'], $path_data['path'] ); } /** * Returns true if an image marked as optimized. * * @return bool */ public function is_optimized(): bool { $meta = new Image_Meta( $this->image_id ); return $meta->get_status() === Image_Status::OPTIMIZED; } /** * Returns true if an image can be restored from the backups. * * @return bool */ public function can_be_restored(): bool { $meta = new Image_Meta( $this->image_id ); return (bool) count( $meta->get_image_backup_paths() ); } /** * Returns image's mime type. * * @return string */ public function get_mime_type(): string { return $this->attachment_object->post_mime_type; } /** * Returns an original attachment WP_Post object. * * @return WP_Post */ public function get_attachment_object(): WP_Post { return $this->attachment_object; } /** * Updates WP_Post fields of the attachment. * * @return bool True if the post was updated successfully, false otherwise. */ public function update_attachment( array $update_query ): bool { global $wpdb; // Must use $wpdb here as `wp_update_post()` doesn't allow to rewrite guid. $result = $wpdb->update( $wpdb->posts, $update_query, [ 'ID' => $this->image_id ] ); if ( 0 !== $result ) { $this->attachment_object = get_post( $this->image_id ); return true; } return false; } /** * Returns the list of mime types supported by the plugin. * * @return string[] */ public static function get_supported_mime_types(): array { return self::SUPPORTED_MIME_TYPES; } /** * Returns the list of formats types supported by the plugin. * * @return string[] */ public static function get_supported_formats(): array { return self::SUPPORTED_FORMATS; } /** * Returns the list of mime types that are supported by the plugin, but cannot be optimized * * @return string[] */ public static function get_mime_types_cannot_be_optimized(): array { return self::MIME_TYPES_CANNOT_BE_OPTIMIZED; } /** * Returns the list of formats that are supported by the plugin, but cannot be optimized * * @return string[] */ public static function get_formats_cannot_be_optimized(): array { return self::FORMATS_CANNOT_BE_OPTIMIZED; } /** * @throws Invalid_Image_Exception */ public function __construct( int $image_id ) { $this->image_id = $image_id; $this->attachment_object = get_post( $image_id ); if ( ! $this->attachment_object ) { throw new Invalid_Image_Exception( "There is no entity with id '$image_id'" ); } if ( ! wp_attachment_is_image( $this->attachment_object ) ) { throw new Invalid_Image_Exception( "Post '$image_id' is not an image" ); } } } image-db-update.php 0000644 00000001217 14721542123 0010204 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; use WP_Query; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Image_DB_Update { public static function update_posts_table_urls( string $old_url, string $new_url ) { $query = new WP_Query( [ 'post_type' => 'any', 'post_status' => 'any', 's' => $old_url, 'search_columns' => [ 'post_content' ], ] ); if ( ! $query->post_count ) { return; } foreach ( $query->posts as $post ) { $new_content = str_replace( $old_url, $new_url, $post->post_content ); wp_update_post([ 'ID' => $post->ID, 'post_content' => $new_content, ]); } } } image-backup.php 0000644 00000007766 14721542123 0007623 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; use ImageOptimization\Classes\File_System\Exceptions\File_System_Operation_Error; use ImageOptimization\Classes\File_System\File_System; use ImageOptimization\Classes\File_Utils; use ImageOptimization\Classes\Image\Exceptions\Image_Backup_Creation_Error; use ImageOptimization\Classes\Logger; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * We're saving backup paths in meta even though the backup path could be dynamically generated. * The next reasons affected this decision: * * 1. Possible path conflicts with other plugins and/or custom user logic. We can't guarantee that the image * we find using the dynamically created path will be the same image we saved. * 2. If a backup doesn't exist, but stored in our meta -- we can be almost sure it's not because of us. * Probably, some other plugin removed it or even user manually did it, but it's not our fault. Makes this logic * easier to debug. * 3. We can change backup file name using `wp_unique_filename()` if needed and easily point a backup path to an * image. */ class Image_Backup { /** * Creates a backup of a file by copying it to a new file with the backup extension. * Also, attaches a newly created backup to image's meta. * * @param int $image_id Attachment id. * @param string $image_size Image size (e.g. 'full', 'thumbnail', etc.). * @param string $image_path Path to an image we plan to back up. * * @return string Backup path if successfully created, false otherwise. * * @throws Image_Backup_Creation_Error */ public static function create( int $image_id, string $image_size, string $image_path ): string { $extension = File_Utils::get_extension( $image_path ); $backup_path = File_Utils::replace_extension( $image_path, "backup.$extension" ); try { File_System::copy( $image_path, $backup_path, true ); } catch ( File_System_Operation_Error $e ) { Logger::log( Logger::LEVEL_ERROR, "Error while creating a backup for image {$image_id} and size {$image_size}" ); throw new Image_Backup_Creation_Error( "Error while creating a backup for image {$image_id} and size {$image_size}" ); } $meta = new Image_Meta( $image_id ); $meta->set_image_backup_path( $image_size, $backup_path ); $meta->save(); return $backup_path; } /** * Looks for registered backups and remove all files found. * Also, wipes removed files from image meta. * * @param int[] $image_ids Array of attachment ids. * @return void */ public static function remove_many( array $image_ids ): void { foreach ( $image_ids as $image_id ) { self::remove( $image_id ); } } /** * Removes one or all backups for a specific image. * Also, wipes removed files from image meta. * * @param int $image_id Attachment id. * @param string|null $image_size Image size (e.g. 'full', 'thumbnail', etc.). All backups will be removed if no size provided. * * @return bool Returns true if backups were removed successfully, false otherwise. */ public static function remove( int $image_id, ?string $image_size = null ): bool { $meta = new Image_Meta( $image_id ); $backups = $meta->get_image_backup_paths(); if ( empty( $backups ) ) { return false; } if ( $image_size ) { if ( ! key_exists( $image_size, $backups ) ) { return false; } try { File_System::delete( $backups[ $image_size ], false, 'f' ); } catch ( File_System_Operation_Error $e ) { Logger::log( Logger::LEVEL_ERROR, "Error while removing a backup for image {$image_id} and size {$image_size}" ); } $meta->remove_image_backup_path( $image_size ); $meta->save(); return true; } foreach ( $backups as $image_size => $backup_path ) { try { File_System::delete( $backup_path, false, 'f' ); } catch ( File_System_Operation_Error $e ) { Logger::log( Logger::LEVEL_ERROR, "Error while removing backups {$image_id}" ); } $meta->remove_image_backup_path( $image_size ); } $meta->save(); return true; } } image-query-builder.php 0000644 00000004547 14721542123 0011141 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; use WP_Query; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Image_Query_Builder { private array $query; public function return_images_only_with_backups(): self { $this->query['meta_query'][] = [ 'compare' => 'NOT LIKE', 'value' => '"backups";a:0', // Serialized empty array of backups 'key' => Image_Meta::IMAGE_OPTIMIZER_METADATA_KEY, ]; return $this; } public function return_not_optimized_images(): self { $this->query['meta_query'][] = [ 'relation' => 'OR', [ 'key' => Image_Meta::IMAGE_OPTIMIZER_METADATA_KEY, 'compare' => 'NOT EXISTS', ], [ 'compare' => 'LIKE', 'value' => '-failed";', 'key' => Image_Meta::IMAGE_OPTIMIZER_METADATA_KEY, ], [ 'compare' => 'LIKE', 'value' => ':"not-optimized";', 'key' => Image_Meta::IMAGE_OPTIMIZER_METADATA_KEY, ], ]; return $this; } public function return_optimized_images(): self { $this->query['meta_query'][] = [ 'compare' => 'LIKE', 'value' => '"status";s:9:"optimized"', 'key' => Image_Meta::IMAGE_OPTIMIZER_METADATA_KEY, ]; return $this; } public function return_images_with_non_empty_meta(): self { $this->query['meta_query'][] = [ 'key' => Image_Meta::IMAGE_OPTIMIZER_METADATA_KEY, 'compare' => 'EXISTS', ]; return $this; } public function set_paging_size( int $paging_size ): self { $this->query['posts_per_page'] = $paging_size; return $this; } public function set_current_page( int $current_page ): self { $this->query['paged'] = $current_page; return $this; } public function set_image_ids( array $image_ids ): self { $this->query['post__in'] = $image_ids; return $this; } public function set_mime_types( array $mime_types ): self { $this->query['post_mime_type'] = $mime_types; return $this; } public function execute(): WP_Query { return new WP_Query( $this->query ); } public function __construct() { $basic_query = [ 'post_type' => 'attachment', 'post_mime_type' => Image::get_supported_mime_types(), 'post_status' => 'any', 'fields' => 'ids', 'posts_per_page' => -1, 'meta_query' => [ 'relation' => 'AND', [ 'key' => '_wp_attachment_metadata', // Images without this field considered invalid 'compare' => 'EXISTS', ], ], ]; $this->query = $basic_query; } } image-optimization-error-type.php 0000644 00000000566 14721542123 0013201 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; use ImageOptimization\Classes\Basic_Enum; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } final class Image_Optimization_Error_Type extends Basic_Enum { public const QUOTA_EXCEEDED = 'quota-exceeded'; public const FILE_ALREADY_EXISTS = 'file-already-exists'; public const GENERIC = 'generic'; } image-meta.php 0000644 00000010566 14721542123 0007274 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Image_Meta { public const IMAGE_OPTIMIZER_METADATA_KEY = 'image_optimizer_metadata'; private const INITIAL_META_VALUE = [ 'status' => Image_Status::NOT_OPTIMIZED, 'error_type' => null, 'compression_level' => null, 'sizes_optimized' => [], 'backups' => [], 'original_data' => [ 'sizes' => [], ], ]; private int $image_id; private array $image_meta; public function get_status(): string { return $this->image_meta['status']; } public function set_status( string $status ): Image_Meta { $this->image_meta['status'] = $status; return $this; } public function get_error_type(): ?string { return $this->image_meta['error_type']; } public function set_error_type( ?string $type ): Image_Meta { $this->image_meta['error_type'] = $type; return $this; } public function get_compression_level(): ?string { return $this->image_meta['compression_level']; } public function set_compression_level( string $compression_level ): Image_Meta { $this->image_meta['compression_level'] = $compression_level; return $this; } public function get_optimized_sizes(): array { return $this->image_meta['sizes_optimized']; } public function add_optimized_size( string $optimized_size ): Image_Meta { if ( ! in_array( $optimized_size, $this->image_meta['sizes_optimized'], true ) ) { $this->image_meta['sizes_optimized'][] = $optimized_size; } return $this; } public function clear_optimized_sizes(): Image_Meta { $this->image_meta['sizes_optimized'] = []; return $this; } public function set_optimized_size( array $optimized_size ): Image_Meta { $this->image_meta['sizes_optimized'] = $optimized_size; return $this; } public function clear_backups(): Image_Meta { $this->image_meta['backups'] = []; return $this; } public function get_image_backup_paths(): array { return $this->image_meta['backups']; } public function get_image_backup_path( string $image_size ): ?string { return $this->image_meta['backups'][ $image_size ] ?? null; } public function set_image_backup_path( string $image_size, string $backup_path ): Image_Meta { $this->image_meta['backups'][ $image_size ] = $backup_path; return $this; } public function remove_image_backup_path( string $image_size ): Image_Meta { unset( $this->image_meta['backups'][ $image_size ] ); return $this; } public function get_original_file_size( string $image_size ): ?int { if ( ! isset( $this->image_meta['original_data']['sizes'][ $image_size ]['filesize'] ) ) { return null; } return $this->image_meta['original_data']['sizes'][ $image_size ]['filesize']; } public function get_original_mime_type( string $image_size ): ?string { if ( ! isset( $this->image_meta['original_data']['sizes'][ $image_size ] ) ) { return null; } return $this->image_meta['original_data']['sizes'][ $image_size ]['mime-type']; } public function get_original_width( string $image_size ): ?string { if ( ! isset( $this->image_meta['original_data']['sizes'][ $image_size ] ) ) { return null; } return $this->image_meta['original_data']['sizes'][ $image_size ]['width']; } public function get_original_height( string $image_size ): ?string { if ( ! isset( $this->image_meta['original_data']['sizes'][ $image_size ] ) ) { return null; } return $this->image_meta['original_data']['sizes'][ $image_size ]['height']; } public function add_original_data( string $size, array $data ): Image_Meta { $this->image_meta['original_data']['sizes'][ $size ] = $data; return $this; } public function clear_original_data(): Image_Meta { $this->image_meta['original_data'] = [ 'sizes' => [] ]; return $this; } public function delete(): bool { return delete_post_meta( $this->image_id, self::IMAGE_OPTIMIZER_METADATA_KEY ); } public function save(): Image_Meta { update_post_meta( $this->image_id, self::IMAGE_OPTIMIZER_METADATA_KEY, $this->image_meta ); $this->query_meta(); return $this; } private function query_meta(): void { $meta = get_post_meta( $this->image_id, self::IMAGE_OPTIMIZER_METADATA_KEY, true ); $this->image_meta = $meta ? array_replace_recursive( self::INITIAL_META_VALUE, $meta ) : self::INITIAL_META_VALUE; } public function __construct( int $image_id ) { $this->image_id = $image_id; $this->query_meta(); } } image-conversion-option.php 0000644 00000000500 14721542123 0012024 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; use ImageOptimization\Classes\Basic_Enum; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } final class Image_Conversion_Option extends Basic_Enum { public const ORIGINAL = 'original'; public const WEBP = 'webp'; public const AVIF = 'avif'; } exceptions/invalid-image-exception.php 0000644 00000000361 14721542123 0014141 0 ustar 00 <?php namespace ImageOptimization\Classes\Image\Exceptions; use Exception; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Invalid_Image_Exception extends Exception { protected $message = 'Invalid image'; } exceptions/image-backup-creation-error.php 0000644 00000000375 14721542123 0014722 0 ustar 00 <?php namespace ImageOptimization\Classes\Image\Exceptions; use Exception; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Image_Backup_Creation_Error extends Exception { protected $message = 'Backup creation error'; } exceptions/image-restoring-exception.php 0000644 00000000376 14721542123 0014535 0 ustar 00 <?php namespace ImageOptimization\Classes\Image\Exceptions; use Exception; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Image_Restoring_Exception extends Exception { protected $message = 'Image cannot be restored'; } wp-image-meta.php 0000644 00000016433 14721542123 0007717 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; use ImageOptimization\Classes\File_Utils; use ImageOptimization\Classes\Image\Exceptions\Invalid_Image_Exception; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Class WP_Image_Meta * * This class is used to manage the metadata of an image in WordPress. */ class WP_Image_Meta { private int $image_id; private array $image_meta; private Image $image; /** * Get the size data of the image. * * @param string $image_size The size of the image. * @return array|null The size data of the image or null if the size does not exist. */ public function get_size_data( string $image_size ): ?array { if ( Image::SIZE_FULL === $image_size ) { $output = []; $output['file'] = $this->image_meta['file']; $output['filesize'] = $this->image_meta['filesize']; $output['width'] = $this->image_meta['width']; $output['height'] = $this->image_meta['height']; $output['mime-type'] = $this->image->get_attachment_object()->post_mime_type; return $output; } if ( ! isset( $this->image_meta['sizes'][ $image_size ] ) ) { return null; } return $this->image_meta['sizes'][ $image_size ]; } /** * Get the keys of the image sizes. * * @return array The keys of the image sizes. */ public function get_size_keys(): array { return [ Image::SIZE_FULL, ...array_keys( $this->image_meta['sizes'] ) ]; } /** * Returns keys of sizes that have the same dimensions as the one provided. * * @param string $image_size The size of the image. * * @return array */ public function get_size_duplicates( string $image_size ): array { $duplicates = []; $width = $this->get_width( $image_size ); $height = $this->get_height( $image_size ); foreach ( $this->image_meta['sizes'] as $size_key => $size_data ) { if ( $size_data['width'] === $width && $size_data['height'] === $height && $image_size !== $size_key ) { $duplicates[] = $size_key; } } return array_unique( $duplicates ); } /** * Get the file size of the image. * * @param string $image_size The size of the image. * @return int|null The file size of the image or null if the size does not exist. */ public function get_file_size( string $image_size ): ?int { if ( Image::SIZE_FULL === $image_size ) { return $this->image_meta['filesize'] ?? null; } if ( ! isset( $this->image_meta['sizes'][ $image_size ]['filesize'] ) ) { return null; } return $this->image_meta['sizes'][ $image_size ]['filesize']; } /** * Set the file size of the image. * * @param string $image_size The size of the image. * @param int $file_size The file size to set. * @return WP_Image_Meta The current instance. */ public function set_file_size( string $image_size, int $file_size ): WP_Image_Meta { if ( Image::SIZE_FULL === $image_size ) { $this->image_meta['filesize'] = $file_size; return $this; } $this->maybe_add_new_size( $image_size ); $this->image_meta['sizes'][ $image_size ]['filesize'] = $file_size; return $this; } /** * Set the file path of the image. * * @param string $image_size The size of the image. * @param string $full_path The full path to set. * @return WP_Image_Meta The current instance. */ public function set_file_path( string $image_size, string $full_path ): WP_Image_Meta { if ( Image::SIZE_FULL === $image_size ) { $this->image_meta['file'] = File_Utils::get_relative_upload_path( $full_path ); return $this; } $this->maybe_add_new_size( $image_size ); $this->image_meta['sizes'][ $image_size ]['file'] = File_Utils::get_basename( $full_path ); return $this; } /** * Get the width of the image. * * @param string $image_size The size of the image. * * @return int|null */ public function get_width( string $image_size ): ?int { if ( Image::SIZE_FULL === $image_size ) { return $this->image_meta['width']; } if ( ! isset( $this->image_meta['sizes'][ $image_size ]['width'] ) ) { return null; } return $this->image_meta['sizes'][ $image_size ]['width']; } /** * Set the width of the image. * * @param string $image_size The size of the image. * @param int $width The width to set. * @return WP_Image_Meta The current instance. */ public function set_width( string $image_size, int $width ): WP_Image_Meta { if ( Image::SIZE_FULL === $image_size ) { $this->image_meta['width'] = $width; return $this; } $this->maybe_add_new_size( $image_size ); $this->image_meta['sizes'][ $image_size ]['width'] = $width; return $this; } /** * Get the height of the image. * * @param string $image_size The size of the image. * * @return int|null */ public function get_height( string $image_size ): ?int { if ( Image::SIZE_FULL === $image_size ) { return $this->image_meta['height']; } if ( ! isset( $this->image_meta['sizes'][ $image_size ]['height'] ) ) { return null; } return $this->image_meta['sizes'][ $image_size ]['height']; } /** * Set the height of the image. * * @param string $image_size The size of the image. * @param int $height The height to set. * @return WP_Image_Meta The current instance. */ public function set_height( string $image_size, int $height ): WP_Image_Meta { if ( Image::SIZE_FULL === $image_size ) { $this->image_meta['height'] = $height; return $this; } $this->maybe_add_new_size( $image_size ); $this->image_meta['sizes'][ $image_size ]['height'] = $height; return $this; } /** * Set the mime type of the image. * * @param string $image_size The size of the image. * @param string $mime_type The mime type to set. * @return WP_Image_Meta The current instance. */ public function set_mime_type( string $image_size, string $mime_type ): WP_Image_Meta { if ( Image::SIZE_FULL === $image_size ) { // WP doesn't store it in meta for the original image return $this; } $this->maybe_add_new_size( $image_size ); $this->image_meta['sizes'][ $image_size ]['mime-type'] = $mime_type; return $this; } /** * Add a new size to the image if it does not exist. * * @param string $image_size The size of the image. */ private function maybe_add_new_size( $image_size ): void { if ( ! isset( $this->image_meta['sizes'][ $image_size ] ) ) { $this->image_meta['sizes'][ $image_size ] = []; } } /** * Save the image metadata. * * @return WP_Image_Meta The current instance. */ public function save(): WP_Image_Meta { wp_update_attachment_metadata( $this->image_id, $this->image_meta ); return $this; } /** * Query the image metadata. * * @throws Invalid_Image_Exception */ private function query_meta(): void { $meta = wp_get_attachment_metadata( $this->image_id ); if ( ! $meta ) { throw new Invalid_Image_Exception( 'Invalid WP image meta' ); } // Handle unsupported formats that WP doesn't create thumbnails for if ( ! isset( $meta['sizes'] ) ) { $meta['sizes'] = []; } $this->image_meta = $meta; } /** * WP_Image_Meta constructor. * * @param int $image_id The ID of the image. * @param Image|null $image The image object. * @throws Invalid_Image_Exception If the image metadata is invalid. */ public function __construct( int $image_id, ?Image $image = null ) { $this->image_id = $image_id; $this->image = $image ?? new Image( $image_id ); $this->query_meta(); } } image-restore.php 0000644 00000007736 14721542123 0010036 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; use ImageOptimization\Classes\File_System\{ Exceptions\File_System_Operation_Error, File_System, }; use ImageOptimization\Classes\File_Utils; use ImageOptimization\Classes\Image\Exceptions\{ Image_Restoring_Exception, Invalid_Image_Exception, }; use ImageOptimization\Classes\Logger; use Throwable; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Image_Restore { public static function restore_many( array $image_ids, bool $keep_image_meta = false ): void { foreach ( $image_ids as $image_id ) { try { self::restore( $image_id, $keep_image_meta ); } catch ( Throwable $t ) { Logger::log( Logger::LEVEL_ERROR, 'Bulk images restoring error: ' . $t->getMessage() ); ( new Image_Meta( $image_id ) ) ->set_status( Image_Status::RESTORING_FAILED ) ->save(); continue; } } } /** * @throws Invalid_Image_Exception|Image_Restoring_Exception|File_System_Operation_Error */ public static function restore( int $image_id, bool $keep_image_meta = false ): void { $image = new Image( $image_id ); if ( ! $image->can_be_restored() ) { throw new Image_Restoring_Exception( "Image $image_id cannot be restored" ); } $meta = new Image_Meta( $image_id ); $wp_meta = new WP_Image_Meta( $image_id ); foreach ( $meta->get_optimized_sizes() as $image_size ) { $backup_path = $meta->get_image_backup_path( $image_size ); $current_path = $image->get_file_path( $image_size ); if ( $backup_path && $current_path ) { $original_path = self::get_path_from_backup_path( $backup_path ); if ( $original_path === $backup_path ) { File_System::delete( $current_path, false, 'f' ); self::update_posts( $current_path, $original_path ); } else { File_System::move( $backup_path, $original_path, $original_path === $current_path ); if ( $original_path !== $current_path ) { File_System::delete( $current_path, false, 'f' ); self::update_posts( $current_path, $original_path ); } } $file_size = $meta->get_original_file_size( $image_size ) ?? File_System::size( $original_path ); $wp_meta ->set_file_path( $image_size, $original_path ) ->set_mime_type( $image_size, $meta->get_original_mime_type( $image_size ) ) ->set_width( $image_size, $meta->get_original_width( $image_size ) ) ->set_height( $image_size, $meta->get_original_height( $image_size ) ) ->set_file_size( $image_size, $file_size ); if ( Image::SIZE_FULL === $image_size ) { self::update_image_post( $image, $original_path, $meta->get_original_mime_type( Image::SIZE_FULL ) ); } } } $wp_meta->save(); if ( $keep_image_meta ) { $meta ->clear_optimized_sizes() ->clear_backups() ->clear_original_data() ->save(); return; } $meta->delete(); } private static function get_path_from_backup_path( string $backup_path ): string { $extension = File_Utils::get_extension( $backup_path ); return str_replace( ".backup.$extension", ".$extension", $backup_path ); } private static function update_image_post( Image $image, string $image_path, string $mime_type ): void { $post_update_query = [ 'post_modified' => current_time( 'mysql' ), 'post_modified_gmt' => current_time( 'mysql', true ), 'post_mime_type' => $mime_type, 'guid' => File_Utils::get_url_from_path( $image_path ), ]; $image->update_attachment( $post_update_query ); update_attached_file( $image->get_id(), $image_path ); } /** * If we change an image extension, we should walk through the wp_posts table and update all the * hardcoded image links to prevent 404s. * * @param string $old_path Previous image path * @param string $new_path Current image path * * @return void */ private static function update_posts( string $old_path, string $new_path ) { Image_DB_Update::update_posts_table_urls( File_Utils::get_url_from_path( $old_path ), File_Utils::get_url_from_path( $new_path ) ); } } image-conversion.php 0000644 00000002263 14721542123 0010526 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; use ImageOptimization\Modules\Settings\Classes\Settings; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Image_Conversion { protected ?string $convert_to_format; protected array $options; public function is_enabled(): bool { return Image_Conversion_Option::ORIGINAL !== $this->convert_to_format; } public function get_current_conversion_option(): string { return $this->convert_to_format; } public function get_current_file_extension(): ?string { if ( ! $this->is_enabled() ) { return null; } return $this->options[ $this->convert_to_format ]['extension']; } public function get_current_mime_type(): ?string { if ( ! $this->is_enabled() ) { return null; } return $this->options[ $this->convert_to_format ]['mime_type']; } public function __construct() { $this->convert_to_format = Settings::get( Settings::CONVERT_TO_FORMAT_OPTION_NAME ); $this->options = [ Image_Conversion_Option::WEBP => [ 'extension' => 'webp', 'mime_type' => 'image/webp', ], Image_Conversion_Option::AVIF => [ 'extension' => 'avif', 'mime_type' => 'image/avif', ], ]; } } image-dimensions.php 0000644 00000002041 14721542123 0010503 0 ustar 00 <?php namespace ImageOptimization\Classes\Image; use ImageOptimization\Classes\Logger; use Imagick; use stdClass; use Throwable; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Image_Dimensions { /** * @param string $file_path * * @return stdClass{width: int, height: int} */ public static function get_by_path( string $file_path ): stdClass { $dimensions = wp_getimagesize( $file_path ); $output = new stdClass(); $output->width = 0; $output->height = 0; if ( $dimensions ) { $output->width = $dimensions[0]; $output->height = $dimensions[1]; return $output; } if ( class_exists( 'Imagick' ) ) { try { $im = new Imagick( $file_path ); $image_geometry = $im->getImageGeometry(); $im->clear(); $output->width = $image_geometry['width']; $output->height = $image_geometry['height']; } catch ( Throwable $t ) { Logger::log( Logger::LEVEL_ERROR, 'AVIF image dimensions calculation error: ' . $t->getMessage() ); } } return $output; } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.3-4ubuntu2.24 | Генерация страницы: 0.01 |
proxy
|
phpinfo
|
Настройка