Plugin Directory

Changeset 3040365


Ignore:
Timestamp:
02/23/2024 06:04:25 PM (2 years ago)
Author:
codealfa
Message:

Committing changes for version 4.2.0

Location:
jch-optimize/trunk
Files:
3 added
66 edited

Legend:

Unmodified
Added
Removed
  • jch-optimize/trunk/jch-optimize.php

    r3007001 r3040365  
    55 * Plugin URI: http://www.jch-optimize.net/
    66 * Description: Boost your WordPress site's performance with JCH Optimize as measured on PageSpeed
    7  * Version: 4.1.1
     7 * Version: 4.2.0
    88 * Author: Samuel Marshall
    99 * License: GNU/GPLv3
  • jch-optimize/trunk/lib/src/Admin/AbstractHtml.php

    r3007001 r3040365  
    1818use _JchOptimizeVendor\Joomla\DI\Container;
    1919use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    20 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    2120use _JchOptimizeVendor\Psr\Http\Client\ClientInterface;
    2221use _JchOptimizeVendor\Psr\Log\LoggerAwareInterface;
     
    2625use _JchOptimizeVendor\Spatie\Crawler\CrawlProfiles\CrawlInternalUrls;
    2726use JchOptimize\Core\Admin\API\MessageEventInterface;
     27use JchOptimize\Core\Container\ContainerAwareTrait;
    2828use JchOptimize\Core\Interfaces\Html;
    2929use JchOptimize\Core\Registry;
  • jch-optimize/trunk/lib/src/Admin/Ajax/Ajax.php

    r3007001 r3040365  
    1414
    1515use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    16 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1716use _JchOptimizeVendor\Joomla\Input\Input;
    1817use _JchOptimizeVendor\Psr\Log\LoggerAwareInterface;
     
    2120use JchOptimize\ContainerFactory;
    2221use JchOptimize\Core\Admin\Json;
     22use JchOptimize\Core\Container\ContainerAwareTrait;
    2323
    2424\defined('_JCH_EXEC') or exit('Restricted access');
  • jch-optimize/trunk/lib/src/Admin/Ajax/FileTree.php

    r2997317 r3040365  
    3636        $j = 0;
    3737        foreach ($files as $file) {
    38             if (\is_dir($root.$dir.$file) && 'jch_optimize_backup_images' != $file && '.jch' != $file) {
    39                 /*if ($i > 500) {
    40                                     if ($j > 1000) {
    41                                         break;
    42                                     }
    43 
    44                                     continue;
    45                                 }*/
     38            if (\is_dir($root.$dir.$file) && !\in_array($file, ['jch_optimize_backup_images', '.jch', 'jch-optimize'])) {
    4639                $directories[$i]['name'] = $file;
    4740                $directories[$i]['file_path'] = $dir.$file;
    4841                ++$i;
    49             } elseif ('tree' != $view && \preg_match('#\\.(?:gif|jpe?g|png)$#i', $file) && @\file_exists($root.$dir.$file)) {
    50                 /*  if ($j > 1000) {
    51                                       if ($i > 500) {
    52                                           break;
    53                                       }
    54 
    55                                       continue;
    56                                   } */
     42            } elseif ('tree' != $view && \preg_match('#'.\JchOptimize\Core\Admin\Ajax\OptimizeImage::$fileExtRegex.'#i', $file) && @\file_exists($root.$dir.$file)) {
    5743                $imageFiles[$j]['ext'] = \preg_replace('/^.*\\./', '', $file);
    5844                $imageFiles[$j]['name'] = $file;
  • jch-optimize/trunk/lib/src/Admin/Helper.php

    r3007001 r3040365  
    3434     * @deprecated
    3535     */
    36     public static function expandFileNameLegacy($sFile)
     36    public static function expandFileNameLegacy(string $sFile)
    3737    {
    3838        $sSanitizedFile = \str_replace('//', '/', $sFile);
     
    5252    }
    5353
    54     /**
    55      * @param null|(mixed|string)[]|string $dest
    56      *
    57      * @psalm-param array<mixed|string>|null|string $dest
    58      */
    59     public static function copyImage(string $src, $dest): bool
     54    public static function copyImage(string $src, string $dest): bool
    6055    {
    6156        try {
  • jch-optimize/trunk/lib/src/Admin/Icons.php

    r2997317 r3040365  
    1515use _JchOptimizeVendor\Joomla\CMS\Language\Text;
    1616use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    17 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
     17use JchOptimize\Core\Container\ContainerAwareTrait;
    1818use JchOptimize\Core\Registry;
    1919use JchOptimize\Model\ModeSwitcher;
     
    164164        $pageCacheTooltip .= Utility::translate('Toggles on/off the Page Cache feature.');
    165165
    166         return [['name' => 'Add Image Attributes', 'setting' => $setting = 'img_attributes_enable', 'icon' => 'img_attributes.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Adds \'height\' and/or \'width\' attributes to &lt:img&gt;\'s, if missing, to reduce CLS.')], ['name' => 'Sprite Generator', 'setting' => $setting = 'csg_enable', 'icon' => 'sprite_gen.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Combines select background images into a sprite.')], ['name' => 'Http/2 Push', 'setting' => $setting = 'http2_push_enable', 'icon' => 'http2_push.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Preloads critical assets using the http/2 protocol to improve LCP.')], ['name' => 'Lazy Load Images', 'setting' => $setting = 'lazyload_enable', 'icon' => 'lazyload.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Defer images that fall below the fold.')], ['name' => 'Optimize CSS Delivery', 'setting' => $setting = 'optimizeCssDelivery_enable', 'icon' => 'optimize_css_delivery.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Eliminates CSS render-blocking')], ['name' => 'Optimize Fonts', 'setting' => $setting = 'pro_optimizeFonts_enable', 'icon' => 'optimize_gfont.png', 'enabled' => $this->params->get($setting, '0'), 'proonly' => \true, 'tooltip' => Utility::translate('Optimizes the loading of fonts, including Google Fonts.')], ['name' => 'CDN', 'setting' => $setting = 'cookielessdomain_enable', 'icon' => 'cdn.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Loads static assets from a CDN server. Requires the CDN domain(s) to be configured on the Configuration tab.')], ['name' => 'Smart Combine', 'setting' => $setting = 'pro_smart_combine', 'icon' => 'smart_combine.png', 'enabled' => $this->params->get($setting, '0'), 'proonly' => \true, 'tooltip' => Utility::translate('Intelligently combines files in a number of smaller files, instead of one large file for better http2 delivery.')], ['name' => 'Load Webp', 'setting' => $setting = 'pro_load_webp_images', 'icon' => 'webp.png', 'enabled' => $this->params->get($setting, '0'), 'proonly' => \true, 'tooltip' => Utility::translate('Loads generated WEBP images in place of the original ones. These images must be generated on the Optimize Image tab first.')], ['name' => 'LCP Images', 'setting' => $setting = 'pro_lcp_images_enable', 'icon' => 'lcp_images.png', 'enabled' => $this->params->get($setting, '0'), 'proonly' => \true, 'tooltip' => Utility::translate('Preload LCP images with a high fetch priority. These images must be added on the Options page to be discovered.')], ['name' => 'Preconnects', 'setting' => $setting = 'pro_preconnect_domains_enable', 'icon' => 'preconnect.png', 'enabled' => $this->params->get($setting, '0'), 'proonly' => \true, 'tooltip' => Utility::translate('Preconnect external origins to reduce the impact of third-party domains.')], ['name' => 'Page Cache', 'setting' => 'integrated_page_cache_enable', 'icon' => 'cache.png', 'enabled' => Cache::isPageCacheEnabled($this->params), 'tooltip' => $pageCacheTooltip]];
     166        return [['name' => 'Add Image Attributes', 'setting' => $setting = 'img_attributes_enable', 'icon' => 'img_attributes.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Adds \'height\' and/or \'width\' attributes to &lt:img&gt;\'s, if missing, to reduce CLS.')], ['name' => 'Sprite Generator', 'setting' => $setting = 'csg_enable', 'icon' => 'sprite_gen.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Combines select background images into a sprite.')], ['name' => 'Http/2 Push', 'setting' => $setting = 'http2_push_enable', 'icon' => 'http2_push.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Preloads critical assets using the http/2 protocol to improve LCP.')], ['name' => 'Lazy Load Images', 'setting' => $setting = 'lazyload_enable', 'icon' => 'lazyload.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Defer images that fall below the fold.')], ['name' => 'Optimize CSS Delivery', 'setting' => $setting = 'optimizeCssDelivery_enable', 'icon' => 'optimize_css_delivery.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Eliminates CSS render-blocking')], ['name' => 'Optimize Fonts', 'setting' => $setting = 'pro_optimizeFonts_enable', 'icon' => 'optimize_gfont.png', 'enabled' => $this->params->get($setting, '0'), 'proonly' => \true, 'tooltip' => Utility::translate('Optimizes the loading of fonts, including Google Fonts.')], ['name' => 'CDN', 'setting' => $setting = 'cookielessdomain_enable', 'icon' => 'cdn.png', 'enabled' => $this->params->get($setting, '0'), 'tooltip' => Utility::translate('Loads static assets from a CDN server. Requires the CDN domain(s) to be configured on the Configuration tab.')], ['name' => 'Smart Combine', 'setting' => $setting = 'pro_smart_combine', 'icon' => 'smart_combine.png', 'enabled' => $this->params->get($setting, '0'), 'proonly' => \true, 'tooltip' => Utility::translate('Intelligently combines files in a number of smaller files, instead of one large file for better http2 delivery.')], ['name' => 'Load Webp', 'setting' => $setting = 'pro_load_webp_images', 'icon' => 'webp.png', 'enabled' => $this->params->get($setting, '0'), 'proonly' => \true, 'tooltip' => Utility::translate('Loads generated WEBP images in place of the original ones. These images must be generated on the Optimize Image tab first.')], ['name' => 'Load Responsive', 'setting' => $setting = 'pro_load_responsive_images', 'icon' => 'responsive_images.png', 'enabled' => $this->params->get($setting, '0'), 'proonly' => \true, 'tooltip' => Utility::translate('Use responsive images where available. These images must be generated on the Optimize Image tab first.')], ['name' => 'LCP Images', 'setting' => $setting = 'pro_lcp_images_enable', 'icon' => 'lcp_images.png', 'enabled' => $this->params->get($setting, '0'), 'proonly' => \true, 'tooltip' => Utility::translate('Preload LCP images with a high fetch priority. These images must be added on the Options page to be discovered.')], ['name' => 'Preconnects', 'setting' => $setting = 'pro_preconnect_domains_enable', 'icon' => 'preconnect.png', 'enabled' => $this->params->get($setting, '0'), 'proonly' => \true, 'tooltip' => Utility::translate('Preconnect external origins to reduce the impact of third-party domains.')], ['name' => 'Page Cache', 'setting' => 'integrated_page_cache_enable', 'icon' => 'cache.png', 'enabled' => Cache::isPageCacheEnabled($this->params), 'tooltip' => $pageCacheTooltip]];
    167167    }
    168168
  • jch-optimize/trunk/lib/src/Admin/Tasks.php

    r2997317 r3040365  
    172172    }
    173173
    174     /**
    175      * @return string|true
    176      *
    177      * @psalm-return 'BACKUPPATHDOESNTEXIST'|'SOMEIMAGESDIDNTRESTORE'|true
    178      */
    179     public static function restoreBackupImages(?LoggerInterface $logger = null)
     174    public static function restoreBackupImages(?LoggerInterface $logger = null): bool|string
    180175    {
    181176        if (\is_null($logger)) {
     
    190185        foreach ($aFiles as $backupContractedFile) {
    191186            $success = \false;
     187
     188            /** @var string[] $aPotentialOriginalFilePaths */
    192189            $aPotentialOriginalFilePaths = [AdminHelper::expandFileName($backupContractedFile), AdminHelper::expandFileNameLegacy($backupContractedFile)];
    193190            foreach ($aPotentialOriginalFilePaths as $originalFilePath) {
  • jch-optimize/trunk/lib/src/Cdn.php

    r2997317 r3040365  
    1616use _JchOptimizeVendor\GuzzleHttp\Psr7\UriResolver;
    1717use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    18 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1918use _JchOptimizeVendor\Psr\Http\Message\UriInterface;
     19use JchOptimize\Core\Container\ContainerAwareTrait;
    2020use JchOptimize\Core\Exception\RuntimeException;
    2121use JchOptimize\Core\FeatureHelpers\CdnDomains;
     
    4747        $this->params = $params;
    4848        $this->enabled = (bool) $this->params->get('cookielessdomain_enable', '0');
    49 
    50         switch ($params->get('cdn_scheme', '0')) {
    51             case '1':
    52                 $this->scheme = 'http';
    53 
    54                 break;
    55 
    56             case '2':
    57                 $this->scheme = 'https';
    58 
    59                 break;
    60 
    61             case '0':
    62             default:
    63                 $this->scheme = '';
    64 
    65                 break;
    66         }
     49        $this->scheme = match ((string) $params->get('cdn_scheme', '0')) {
     50            '1' => 'http',
     51            '2' => 'https',
     52            default => '',
     53        };
    6754    }
    6855
  • jch-optimize/trunk/lib/src/Combiner.php

    r2997317 r3040365  
    1919use _JchOptimizeVendor\GuzzleHttp\RequestOptions;
    2020use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    21 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    2221use _JchOptimizeVendor\Laminas\Cache\Pattern\CallbackCache;
    2322use _JchOptimizeVendor\Laminas\Cache\Storage\IterableInterface;
     
    3130use CodeAlfa\Minify\Js;
    3231use CodeAlfa\RegexTokenizer\Debug\Debug;
     32use JchOptimize\Core\Container\ContainerAwareTrait;
    3333use JchOptimize\Core\Css\Processor as CssProcessor;
    3434use JchOptimize\Core\Css\Sprite\Generator;
  • jch-optimize/trunk/lib/src/Css/Callbacks/AbstractCallback.php

    r2997317 r3040365  
    1414
    1515use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    16 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1716use JchOptimize\Core\Container\Container;
     17use JchOptimize\Core\Container\ContainerAwareTrait;
    1818use JchOptimize\Core\Registry;
    1919
  • jch-optimize/trunk/lib/src/Css/Callbacks/CorrectUrls.php

    r2997317 r3040365  
    1919use JchOptimize\Core\Css\Parser;
    2020use JchOptimize\Core\FeatureHelpers\LazyLoadExtended;
     21use JchOptimize\Core\FeatureHelpers\ResponsiveImages;
    2122use JchOptimize\Core\FeatureHelpers\Webp;
    2223use JchOptimize\Core\Helper;
     
    4445    private array $preconnects = [];
    4546
    46     private array $cssInfos;
     47    private array $cssInfos = [];
    4748    private array $lcpImages = [];
     49    private array $responsiveImages = [];
    4850
    4951    public function __construct(Container $container, Registry $params, Cdn $cdn, Http2Preload $http2Preload)
     
    6870            return $this->getContainer()->get(LazyLoadExtended::class)->handleCssBgImages($this, $css);
    6971        }
     72        $rsCss = '';
     73        if (JCH_PRO && !empty($this->responsiveImages)) {
     74            $rsImages = \array_reverse($this->responsiveImages, \true);
     75            foreach ($rsImages as $breakpoint => $rsImage) {
     76                $tmpCss = \preg_replace_callback('#'.Parser::cssUrlWithCaptureValueToken(\true).'#', fn ($match) => \str_replace($match[1], $rsImage, $match[0]), $css);
     77                $rsCss .= "@media (max-width: {$breakpoint}px){{$tmpCss}}";
     78            }
     79        }
    7080
    71         return $css;
     81        return $css.$rsCss;
    7282    }
    7383
    74     public function setCssInfos($cssInfos): void
     84    public function setCssInfos(array $cssInfos): void
    7585    {
    7686        $this->cssInfos = $cssInfos;
     
    99109    /**
    100110     * @param string[] $matches
    101      * @param mixed    $context
    102      *
    103      * @psalm-param array<string> $matches
    104111     */
    105     protected function processInnerMatches(array $matches, $context)
     112    protected function processInnerMatches(array $matches, string $context): string|bool
    106113    {
    107114        if (empty($matches[0])) {
     
    111118        if ('data' !== $originalUri->getScheme() && '' != $originalUri->getPath() && '/' != $originalUri->getPath()) {
    112119            if ($this->isHttp2) {
    113                 // The urls were already corrected on a previous run, we're only preloading assets in critical CSS and return
     120                // The urls were already corrected on a previous run,
     121                // we're only preloading assets in critical CSS and return
    114122                $fileType = 'font-face' == $context ? 'font' : 'image';
    115123                // LCP Images would have already been processed, we can skip those
     
    117125                    $lcpImages = Helper::getArray($this->params->get('pro_lcp_images', []));
    118126                    if (Helper::findMatches($lcpImages, $originalUri)) {
     127                        return \true;
     128                    }
     129                    // Don't preload responsive images
     130                    if (\str_contains((string) $originalUri, 'jch-optimize/rs')) {
    119131                        return \true;
    120132                    }
     
    142154            }
    143155            if ('font-face' != $context && 'import' != $context) {
     156                if (JCH_PRO && $this->params->get('pro_load_responsive_images', '0')) {
     157                    $this->responsiveImages = $this->getContainer()->get(ResponsiveImages::class)->getResponsiveImages($imageUri);
     158                }
    144159                if (JCH_PRO && $this->params->get('pro_load_webp_images', '0')) {
    145160                    /** @see Webp::getWebpImages() */
     
    149164                    $lcpImages = Helper::getArray($this->params->get('pro_lcp_images', []));
    150165                    if (Helper::findMatches($lcpImages, $imageUri)) {
    151                         $this->lcpImages[] = $imageUri;
     166                        $this->lcpImages[] = ['src' => $imageUri, 'srcset' => $this->responsiveImages ? $this->getContainer()->get(ResponsiveImages::class)->createSrcsetString($this->responsiveImages, $imageUri) : ''];
    152167                    }
    153168                }
  • jch-optimize/trunk/lib/src/Css/Callbacks/ExtractCriticalCss.php

    r2997317 r3040365  
    1515use CodeAlfa\RegexTokenizer\Debug\Debug;
    1616use JchOptimize\Core\Css\Parser;
     17use JchOptimize\Core\Exception\PropertyNotFoundException;
    1718use JchOptimize\Core\FeatureHelpers\DynamicSelectors;
    1819
     
    2324{
    2425    use Debug;
    25     public string $sHtmlAboveFold;
    26     public string $sFullHtml;
    27     public \DOMXPath $oXPath;
     26    public string $htmlAboveFold = '';
     27    public string $fullHtml = '';
    2828    public string $postCss = '';
    2929    public string $preCss = '';
    3030    public bool $isPostProcessing = \false;
    3131    protected string $criticalCss = '';
     32    private ?\DOMXPath $xPath = null;
    3233
    3334    public function processMatches(array $matches, string $context): string
     
    3637        if ('font-face' == $context || 'keyframes' == $context) {
    3738            if (!$this->isPostProcessing) {
    38                 // If we're not processing font-face or keyframes yet let's just save them for later until after we've done getting all the
    39                 // critical css
     39                // If we're not processing font-face or keyframes yet, let's just save them for later until
     40                // after we've done getting all the // critical css
    4041                $this->postCss .= $matches[0];
    4142
     
    99100            }
    100101            // Check CSS selector chain against HTMl above the fold to find a match
    101             if ($this->checkCssAgainstHtml($sSelectorChain, $this->sHtmlAboveFold)) {
     102            if ($this->checkCssAgainstHtml($sSelectorChain, $this->htmlAboveFold)) {
    102103                // Match found, add selector chain to array
    103104                $aFoundSelectorChains[] = $sSelectorChain;
     
    122123            $aXPaths = \array_unique(\explode(' | ', \str_replace('\\', '', $sXPath)));
    123124            foreach ($aXPaths as $sXPathValue) {
    124                 $oElement = $this->oXPath->query($sXPathValue);
    125                 //                                if ($oElement === FALSE)
     125                $element = $this->getDOMXPath()->query($sXPathValue);
     126                //                                if ($element === FALSE)
    126127                //                                {
    127128                //                                        echo $aMatches[1] . "\n";
     
    131132                //                                }
    132133                // Match found! Add to critical CSS
    133                 if (\false !== $oElement && $oElement->length) {
     134                if (\false !== $element && $element->length) {
    134135                    $this->appendToCriticalCss($matches[0]);
    135136                    $this->_debug($sXPathValue, $matches[0], 'afterCriticalCssFound');
     
    149150    }
    150151
    151     /**
    152      * @return string
    153      */
    154152    public function convertCss2XPath(string $sSelector, ?bool &$success = null): ?string
    155153    {
     
    163161        }
    164162        $sSelectorRegex = '#(?!$)([>+~, ]?)([*_a-z0-9-]*)(?:(([.\\#])((?:[_a-z0-9-]|\\\\[^\\r\\n\\f0-9a-z])+))(([.\\#])((?:[_a-z0-9-]|\\\\[^\\r\\n\\f0-9a-z])+))?|(\\[((?:[_a-z0-9-]|\\\\[^\\r\\n\\f0-9a-z])+)(([~|^$*]?=)["\']?([^\\]"\']+)["\']?)?\\]))*#i';
    165         $result = \preg_replace_callback($sSelectorRegex, [$this, '_tokenizer'], $sSelector).'[1]';
    166         if (null === $result) {
     163        $result = \preg_replace_callback($sSelectorRegex, [$this, 'tokenizer'], $sSelector).'[1]';
     164        if (\PREG_NO_ERROR !== \preg_last_error()) {
    167165            $success = \false;
    168166
     
    171169
    172170        return $result;
     171    }
     172
     173    public function setDOMXPath(\DOMXPath $xPath): void
     174    {
     175        $this->xPath = $xPath;
    173176    }
    174177
     
    236239     * @param string[] $aM
    237240     */
    238     protected function _tokenizer(array $aM): string
     241    protected function tokenizer(array $aM): string
    239242    {
    240243        $sXPath = '';
     
    341344        return $sXPath;
    342345    }
     346
     347    protected function getDOMXPath(): \DOMXPath
     348    {
     349        if ($this->xPath instanceof \DOMXPath) {
     350            return $this->xPath;
     351        }
     352
     353        throw new PropertyNotFoundException('DOMXPath not found in '.\get_class($this));
     354    }
    343355}
  • jch-optimize/trunk/lib/src/Css/Callbacks/FormatCss.php

    r2997317 r3040365  
    1616class FormatCss extends \JchOptimize\Core\Css\Callbacks\AbstractCallback
    1717{
    18     public string $validCssRules;
     18    public string $validCssRules = '';
    1919
    2020    public function processMatches(array $matches, string $context): string
  • jch-optimize/trunk/lib/src/Css/Callbacks/HandleAtRules.php

    r2997317 r3040365  
    2424    private array $fontFace = [];
    2525
    26     private array $cssInfos;
     26    private array $cssInfos = [];
    2727
    2828    public function processMatches(array $matches, string $context): string
     
    3535                $matches[0] = \preg_replace('#;?\\s*}$#', ';font-display:swap;}', $matches[0]);
    3636            } elseif (\preg_match('#font-display#i', $matches[0]) && $this->params->get('pro_force_swap_policy', '1')) {
    37                 $matches[0] = \preg_replace('#font-display[^;}]++#i', 'font-display:swap', $matches[0]);
     37                $matches[0] = \preg_replace('#font-display[^;}/\'"]++([;}])#i', '_JchOptimizeVendor\\font-display:swap\\1', $matches[0]);
    3838            }
    3939            /*if ($this->params->get('pro_optimizeFonts_enable', '0') && empty($this->cssInfos['combining-fontface'])) {
  • jch-optimize/trunk/lib/src/Css/Parser.php

    r2997317 r3040365  
    1414
    1515use CodeAlfa\RegexTokenizer\Css;
     16use JchOptimize\Core\Css\Callbacks\AbstractCallback;
    1617use JchOptimize\Core\Exception;
     18use JchOptimize\Core\Exception\PregErrorException;
    1719
    1820\defined('_JCH_EXEC') or exit('Restricted access');
     
    2123    use Css;
    2224    protected array $aExcludes = [];
    23 
    24     /** @var CssSearchObject */
    25     protected \JchOptimize\Core\Css\CssSearchObject $oCssSearchObject;
     25    protected ?\JchOptimize\Core\Css\CssSearchObject $cssSearchObject = null;
    2626    protected bool $bBranchReset = \true;
    2727    protected string $sParseTerm = '\\s*+';
     28    protected static int $subroutines = 0;
    2829
    2930    public function __construct()
     
    5758    // language=RegExp
    5859    /**
    59      * @param (mixed|string)[] $aAtRules
     60     * @param (mixed|string)[] $atRulesArray
    6061     *
    61      * @psalm-param list{0?: 'font-face'|'media'|mixed, 1?: 'keyframes'|mixed, 2?: 'page'|mixed, 3?: 'font-feature-values'|mixed, 4?: 'counter-style'|mixed, 5?: 'viewport'|mixed, 6?: 'property'|mixed,...} $aAtRules
     62     * @psalm-param list{0?: 'font-face'|'media'|mixed, 1?: 'keyframes'|mixed, 2?: 'page'|mixed, 3?: 'font-feature-values'|mixed, 4?: 'counter-style'|mixed, 5?: 'viewport'|mixed, 6?: 'property'|mixed,...} $atRulesArray
    6263     */
    63     public static function cssNestedAtRulesWithCaptureValueToken(array $aAtRules = [], bool $bCV = \false, bool $bEmpty = \false): string
    64     {
    65         $sAtRules = !empty($aAtRules) ? '(?>'.\implode('|', $aAtRules).')' : '';
    66         $iN = $bCV ? 2 : 1;
    67         $sValue = $bEmpty ? '\\s*+' : '(?>'.self::parse('', \true).'|(?-'.$iN.'))*+';
    68         $sAtRules = '<<@(?:-[^-]++-)??'.$sAtRules.'[^{};]*+>>(\\{<<'.$sValue.'>>\\})';
    69 
    70         return self::prepare($sAtRules, $bCV);
     64    public static function cssNestedAtRulesWithCaptureValueToken(array $atRulesArray = [], bool $shouldCaptureValue = \false, bool $empty = \false): string
     65    {
     66        $atRulesString = !empty($atRulesArray) ? '(?>'.\implode('|', $atRulesArray).')' : '';
     67        $i = self::$subroutines++;
     68        $sValue = $empty ? '\\s*+' : '(?>'.self::parse('', \true)."|(?P>css{$i}))*+";
     69        $atRulesString = "<<@(?:-[^-]++-)??{$atRulesString}[^{};]*+>>(?P<css{$i}>\\{<<{$sValue}>>\\})";
     70
     71        return self::prepare($atRulesString, $shouldCaptureValue);
    7172    }
    7273
     
    132133
    133134    /**
    134      * @param Callbacks\CombineMediaQueries|Callbacks\CorrectUrls|Callbacks\ExtractCriticalCss|Callbacks\FormatCss|Callbacks\HandleAtRules $oCallback
    135      *
    136135     * @throws Exception\PregErrorException
    137136     */
    138     public function processMatchesWithCallback(string $sCss, $oCallback, string $sContext = 'global'): ?string
     137    public function processMatchesWithCallback(string $sCss, AbstractCallback $oCallback, string $sContext = 'global'): ?string
    139138    {
    140139        $sRegex = $this->getCssSearchRegex();
     
    143142                return $aMatches[0];
    144143            }
    145             if ('@' == \substr($aMatches[0], 0, 1)) {
     144            if (\str_starts_with($aMatches[0], '@')) {
    146145                $sContext = $this->getContext($aMatches[0]);
    147                 foreach ($this->oCssSearchObject->getCssNestedRuleNames() as $aAtRule) {
     146                foreach ($this->getCssSearchObject()->getCssNestedRuleNames() as $aAtRule) {
    148147                    if ($aAtRule['name'] == $sContext) {
    149148                        if ($aAtRule['recurse']) {
     
    169168
    170169    /**
    171      * @psalm-param '' $sReplace
    172      *
    173      * @param mixed $sCss
    174      *
    175      * @throws Exception\PregErrorException
     170     * @throws PregErrorException
    176171     */
    177     public function replaceMatches($sCss, string $sReplace): ?string
    178     {
    179         $sProcessedCss = \preg_replace('#'.$this->getCssSearchRegex().'#i', $sReplace, $sCss);
     172    public function replaceMatches(string $css, string $replace): ?string
     173    {
     174        $processedCss = \preg_replace('#'.$this->getCssSearchRegex().'#i', $replace, $css);
    180175
    181176        try {
     
    184179            throw new Exception\PregErrorException($exception->getMessage());
    185180        }
    186 
    187         return $sProcessedCss;
    188     }
    189 
    190     public function setCssSearchObject(CssSearchObject $oCssSearchObject): void
    191     {
    192         $this->oCssSearchObject = $oCssSearchObject;
     181        if (\is_string($processedCss)) {
     182            return $processedCss;
     183        }
     184
     185        throw new PregErrorException('Unknown error processing regex');
     186    }
     187
     188    public function setCssSearchObject(CssSearchObject $cssSearchObject): void
     189    {
     190        $this->cssSearchObject = $cssSearchObject;
    193191    }
    194192
     
    212210    // language=RegExp
    213211    /**
    214      * @psalm-param '' $sInclude
     212     * @psalm-param '' $include
    215213     */
    216     protected static function parse(string $sInclude = '', bool $bNoEmpty = \false): string
    217     {
    218         $sRepeat = $bNoEmpty ? '+' : '*';
    219 
    220         return '(?>(?:[^{}"\'/'.$sInclude.']++|/)(?>'.self::blockCommentToken().'|'.self::stringWithCaptureValueToken().')?)'.$sRepeat.'?';
     214    protected static function parse(string $include = '', bool $noEmpty = \false): string
     215    {
     216        $repeat = $noEmpty ? '+' : '*';
     217
     218        return "(?>[^{}\"'/{$include}]{$repeat}+(?>".self::blockCommentToken().'|'.self::stringWithCaptureValueToken()."|/)*+){$repeat}?";
    221219    }
    222220
     
    250248    protected function getCriteria(): string
    251249    {
    252         $oObj = $this->oCssSearchObject;
     250        $oObj = $this->getCssSearchObject();
    253251        $aCriteria = [];
    254252        // We need to add Nested Rules criteria first to avoid trouble with recursion and branch capture reset
     
    309307        return !empty($aMatches[1]) ? \strtolower($aMatches[1]) : 'global';
    310308    }
     309
     310    protected function getCssSearchObject(): CssSearchObject
     311    {
     312        if ($this->cssSearchObject instanceof \JchOptimize\Core\Css\CssSearchObject) {
     313            return $this->cssSearchObject;
     314        }
     315
     316        throw new Exception\PropertyNotFoundException('CssSearchObject not set in '.\get_class($this));
     317    }
    311318}
  • jch-optimize/trunk/lib/src/Css/Processor.php

    r2997317 r3040365  
    1414
    1515use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    16 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1716use _JchOptimizeVendor\Psr\Log\LoggerAwareInterface;
    1817use _JchOptimizeVendor\Psr\Log\LoggerAwareTrait;
    1918use CodeAlfa\RegexTokenizer\Debug\Debug;
     19use JchOptimize\Core\Container\ContainerAwareTrait;
    2020use JchOptimize\Core\Css\Callbacks\CombineMediaQueries;
    2121use JchOptimize\Core\Css\Callbacks\CorrectUrls;
     
    3939    use FileInfosUtilsTrait;
    4040    use SerializableTrait;
    41     protected string $css;
     41    protected string $css = '';
    4242
    4343    private Registry $params;
     
    254254        $oCssSearchObject->setCssAtRuleCriteria(\JchOptimize\Core\Css\Parser::cssAtNameSpaceToken());
    255255        $oCssSearchObject->setCssRuleCriteria('.');
    256         $this->extractCriticalCss->sHtmlAboveFold = $sHtmlAboveFold;
    257         $this->extractCriticalCss->sFullHtml = $sFullHtml;
    258         $this->extractCriticalCss->oXPath = $oXPath;
     256        $this->extractCriticalCss->htmlAboveFold = $sHtmlAboveFold;
     257        $this->extractCriticalCss->fullHtml = $sFullHtml;
     258        $this->extractCriticalCss->setDOMXPath($oXPath);
    259259        $oParser->setCssSearchObject($oCssSearchObject);
    260260        $sCriticalCss = $oParser->processMatchesWithCallback($css, $this->extractCriticalCss);
  • jch-optimize/trunk/lib/src/Css/Sprite/Controller.php

    r2997317 r3040365  
    1515use _JchOptimizeVendor\GuzzleHttp\Psr7\UriResolver;
    1616use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    17 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1817use _JchOptimizeVendor\Joomla\Filesystem\Folder;
    1918use _JchOptimizeVendor\Psr\Log\LoggerAwareInterface;
     
    2120use _JchOptimizeVendor\Psr\Log\LoggerInterface;
    2221use Exception;
     22use JchOptimize\Core\Container\ContainerAwareTrait;
    2323use JchOptimize\Core\Exception\MissingDependencyException;
    2424use JchOptimize\Core\Registry;
     
    3838    use LoggerAwareTrait;
    3939    public array $options = [];
    40     public bool $bTransparent;
     40    public bool $bTransparent = \false;
    4141    protected array $imageTypes = [];
    4242    protected array $aFormErrors = [];
     
    4444    protected $sCss;
    4545    protected string $sTempSpriteName = '';
    46     protected bool $bValidImages;
     46    protected bool $bValidImages = \false;
    4747    protected array $aBackground = [];
    4848    protected array $aPosition = [];
     
    109109    public function GetSpriteFormats()
    110110    {
     111        // @phpstan-ignore-next-line
    111112        return $this->imageHandler->spriteFormats;
    112113    }
     
    154155            $fileUri = UriResolver::resolve(SystemUri::currentUri(), $fileUri);
    155156            $filePath = \str_replace(SystemUri::baseFull(), '', (string) $fileUri);
    156             $sFilePath = Paths::rootPath().\DIRECTORY_SEPARATOR.$filePath;
    157             $bFileExists = \true;
    158             if (@\file_exists($sFilePath)) {
     157            $filePath = Paths::rootPath().\DIRECTORY_SEPARATOR.$filePath;
     158            $aPathParts = \pathinfo($filePath);
     159            $fileBaseName = $aPathParts['basename'];
     160            $width = 0;
     161            $height = 0;
     162            $imageTypes = [];
     163            $bFileExists = \false;
     164            if (@\file_exists($filePath)) {
     165                $bFileExists = \true;
    159166                // do we want to scale down the source images
    160167                // scaling up isn't supported as that would result in poorer quality images
    161168                $bResize = 100 != $this->options['width-resize'] && 100 != $this->options['height-resize'];
    162169                // grab path information
    163                 // $sFilePath = $sFolderMD5.$sFile;
    164                 $aPathParts = \pathinfo($sFilePath);
    165                 $sFileBaseName = $aPathParts['basename'];
    166                 $aImageInfo = @\getimagesize($sFilePath);
     170                // $filePath = $sFolderMD5.$sFile;
     171                $aImageInfo = @\getimagesize($filePath);
    167172                if ($aImageInfo) {
    168                     $iWidth = $aImageInfo[0];
    169                     $iHeight = $aImageInfo[1];
    170                     $iImageType = $aImageInfo[2];
     173                    $width = $aImageInfo[0];
     174                    $height = $aImageInfo[1];
     175                    $imageTypes = $aImageInfo[2];
    171176                    // are we matching filenames against a regular expression
    172177                    // if so it's likely not all images from the ZIP file will end up in the generated sprite image
     
    176181                        $this->options['file-regex'] = \str_replace('/', '\\/', $this->options['file-regex']);
    177182                        // if the regular expression matches grab the first match and store for use as the class name
    178                         if (\preg_match('/^'.$this->options['file-regex'].'$/i', $sFileBaseName, $aMatches)) {
    179                             $sFileClass = $aMatches[1];
     183                        if (\preg_match('/^'.$this->options['file-regex'].'$/i', $fileBaseName, $aMatches)) {
     184                            $fileClass = $aMatches[1];
    180185                        } else {
    181                             $sFileClass = '';
     186                            $fileClass = '';
    182187                        }
    183188                    } else {
    184                         // not using regular expressions - set the class name to the base part of the filename (excluding extension)
    185                         $sFileClass = $aPathParts['basename'];
     189                        // not using regular expressions - set the class name to the base part of the
     190                        // filename (excluding extension)
     191                        $fileClass = $aPathParts['basename'];
    186192                    }
    187193                    // format the class name - it should only contain certain characters
    188194                    // this strips out any which aren't
    189                     $sFileClass = $this->FormatClassName($sFileClass);
     195                    $fileClass = $this->formatClassName($fileClass);
    190196                } else {
    191197                    $bFileExists = \false;
    192198                }
    193             } else {
    194                 $bFileExists = \false;
    195199            }
    196200            // the file also isn't valid if its extension doesn't match one of the image formats supported by the tool
    197201            // discard images whose height or width is greater than 50px
    198             if ($bFileExists && !empty($sFileClass) && \in_array(\strtoupper($aPathParts['extension']), $this->imageTypes) && \in_array($iImageType, [\IMAGETYPE_GIF, \IMAGETYPE_JPEG, \IMAGETYPE_PNG]) && '.' != \substr($sFileBaseName, 0, 1) && $iWidth < 50 && $iHeight < 50 && $iWidth > 0 && $iHeight > 0) {
     202            if ($bFileExists && !empty($fileClass) && \in_array(\strtoupper($aPathParts['extension']), $this->imageTypes) && \in_array($imageTypes, [\IMAGETYPE_GIF, \IMAGETYPE_JPEG, \IMAGETYPE_PNG]) && !\str_starts_with($fileBaseName, '.') && $width < 50 && $height < 50 && $width > 0 && $height > 0) {
    199203                // grab the file extension
    200204                $sExtension = $aPathParts['extension'];
    201205                // get MD5 of file (this can be used to compare if a file's content is exactly the same as another's)
    202                 $sFileMD5 = \md5(\file_get_contents($sFilePath));
     206                $sFileMD5 = \md5(\file_get_contents($filePath));
    203207                // check if this file's MD5 already exists in array of MD5s recorded so far
    204208                // if so it's a duplicate of another file in the ZIP
     
    208212                    if ('merge' == $this->options['ignore-duplicates']) {
    209213                        if (isset($aFilesInfo[$sKey]['class'])) {
    210                             $aFilesInfo[$sKey]['class'] = $aFilesInfo[$sKey]['class'].$this->options['selector-suffix'].', '.$this->options['selector-prefix'].'.'.$this->options['class-prefix'].$sFileClass;
     214                            $aFilesInfo[$sKey]['class'] = $aFilesInfo[$sKey]['class'].$this->options['selector-suffix'].', '.$this->options['selector-prefix'].'.'.$this->options['class-prefix'].$fileClass;
    211215                        }
    212216                        $this->aBackground[$k] = $sKey;
     
    222226                $aFilesMD5[$i] = $sFileMD5;
    223227                // store generated class selector details
    224                 // $aFilesInfo[$i]['class'] = ".{$this->aFormValues['class-prefix']}$sFileClass";
     228                // $aFilesInfo[$i]['class'] = ".{$this->aFormValues['class-prefix']}$fileClass";
    225229                // store file path information and extension
    226                 $aFilesInfo[$i]['path'] = $sFilePath;
     230                $aFilesInfo[$i]['path'] = $filePath;
    227231                $aFilesInfo[$i]['ext'] = $sExtension;
    228232                if ('horizontal' == $this->options['build-direction']) {
    229233                    // get the current width of the sprite image - after images processed so far
    230                     $iCurrentWidth = $iTotalWidth + $this->options['horizontal-offset'] + $iWidth;
     234                    $iCurrentWidth = $iTotalWidth + $this->options['horizontal-offset'] + $width;
    231235                    // store the maximum width reached so far
    232236                    // if we're on a new column current height might be less than the maximum
     
    236240                } else {
    237241                    // get the current height of the sprite image - after images processed so far
    238                     $iCurrentHeight = $iTotalHeight + $this->options['vertical-offset'] + $iHeight;
     242                    $iCurrentHeight = $iTotalHeight + $this->options['vertical-offset'] + $height;
    239243                    // store the maximum height reached so far
    240244                    // if we're on a new column current height might be less than the maximum
     
    245249                // store the original width and height of the image
    246250                // we'll need this later if the image is to be resized
    247                 $aFilesInfo[$i]['original-width'] = $iWidth;
    248                 $aFilesInfo[$i]['original-height'] = $iHeight;
     251                $aFilesInfo[$i]['original-width'] = $width;
     252                $aFilesInfo[$i]['original-height'] = $height;
    249253                // store the width and height of the image
    250254                // if we're resizing they'll be less than the original
    251                 $aFilesInfo[$i]['width'] = $bResize ? \round($iWidth / 100 * $this->options['width-resize']) : $iWidth;
    252                 $aFilesInfo[$i]['height'] = $bResize ? \round($iHeight / 100 * $this->options['height-resize']) : $iHeight;
     255                $aFilesInfo[$i]['width'] = $bResize ? \round($width / 100 * $this->options['width-resize']) : $width;
     256                $aFilesInfo[$i]['height'] = $bResize ? \round($height / 100 * $this->options['height-resize']) : $height;
    253257                if ('horizontal' == $this->options['build-direction']) {
    254258                    // opera (9.0 and below) has a bug which prevents it recognising  offsets of less than -2042px
     
    260264                        $iTotalWidth = 0;
    261265                    }
    262                     // if the current image is higher than any other in the current row then set the maximum height to that
     266                    // if the current image is higher than any other in the current row then set
     267                    // the maximum height to that
    263268                    // it will be used to set the height of the current row
    264269                    if ($aFilesInfo[$i]['height'] > $iMaxHeight) {
     
    285290                        $iTotalHeight = 0;
    286291                    }
    287                     // if the current image is wider than any other in the current column then set the maximum width to that
     292                    // if the current image is wider than any other in the current column then set
     293                    // the maximum width to that
    288294                    // it will be used to set the width of the current column
    289295                    if ($aFilesInfo[$i]['width'] > $iMaxWidth) {
     
    405411            JCH_DEBUG ? Profiler::stop('CreateSprite', \true) : null;
    406412        }
    407     }
    408 
    409     public function ValidImages(): bool
     413
     414        return null;
     415    }
     416
     417    public function validImages(): bool
    410418    {
    411419        return $this->bValidImages;
    412420    }
    413421
    414     public function GetSpriteFilename(): string
     422    public function getSpriteFileName(): string
    415423    {
    416424        $aFileParts = \pathinfo($this->sTempSpriteName);
     
    419427    }
    420428
    421     public function GetSpriteHash(): void
     429    public function getSpriteHash(): void
    422430    {
    423431        // return md5($this->GetSpriteFilename().ConfigHelper::Get('/checksum'));
    424432    }
    425433
    426     public function GetCss(): array
     434    public function getCss(): array
    427435    {
    428436        return $this->aCss;
    429437    }
    430438
    431     public function GetAllErrors(): array
     439    public function getAllErrors(): array
    432440    {
    433441        return $this->aFormErrors;
    434442    }
    435443
    436     public function GetZipFolder(): string
     444    public function getZipFolder(): string
    437445    {
    438446        return $this->sZipFolder;
    439447    }
    440448
    441     public function GetCssBackground(): array
     449    public function getCssBackground(): array
    442450    {
    443451        $aCssBackground = [];
     
    452460    }
    453461
    454     protected function FormatClassName(string $sClassName): ?string
     462    protected function formatClassName(string $sClassName): ?string
    455463    {
    456464        $aExtensions = [];
  • jch-optimize/trunk/lib/src/Css/Sprite/Generator.php

    r2997317 r3040365  
    1414
    1515use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    16 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1716use _JchOptimizeVendor\Psr\Log\LoggerAwareInterface;
    1817use _JchOptimizeVendor\Psr\Log\LoggerAwareTrait;
    1918use JchOptimize\Core\Cdn;
     19use JchOptimize\Core\Container\ContainerAwareTrait;
    2020use JchOptimize\Core\Exception;
    2121use JchOptimize\Core\Helper;
     
    170170        $aImages = $matches[1];
    171171        $this->spriteController->CreateSprite($aImages);
    172         $aSpriteCss = $this->spriteController->GetCssBackground();
     172        $aSpriteCss = $this->spriteController->getCssBackground();
    173173        $aPatterns = [];
    174174        $aPatterns[0] = '#background-position:[^;}]+;?#i';
     
    179179        $aPatterns[3] = '#(background:[^;}]*)\\burl\\((?=[^\\)]+\\.(?:png|gif|jpe?g))[^\\)]+\\)([^;}]*[;}])#i';
    180180        // Background image regex
    181         $sSpriteName = $this->spriteController->GetSpriteFilename();
     181        $sSpriteName = $this->spriteController->getSpriteFileName();
    182182        $aSearch = [];
    183183        $sRelSpritePath = Paths::spritePath(\true).\DIRECTORY_SEPARATOR.$sSpriteName;
  • jch-optimize/trunk/lib/src/Css/Sprite/Handler/Gd.php

    r2997317 r3040365  
    3636    }
    3737
    38     /**
    39      * @param mixed $spriteWidth
    40      * @param mixed $spriteHeight
    41      * @param mixed $bgColour
    42      * @param mixed $outputFormat
    43      *
    44      * @return false|resource
    45      */
    46     public function createSprite($spriteWidth, $spriteHeight, $bgColour, $outputFormat)
     38    public function createSprite($spriteWidth, $spriteHeight, $bgColour, $outputFormat): \GdImage|false
    4739    {
    4840        if ($this->options['is-transparent'] && !empty($this->options['background'])) {
     
    7466    }
    7567
    76     /**
    77      * @param mixed $fileInfos
    78      *
    79      * @return false|resource
    80      */
    81     public function createBlankImage($fileInfos)
     68    public function createBlankImage($fileInfos): \GdImage|false
    8269    {
    8370        $oCurrentImage = \imagecreatetruecolor($fileInfos['original-width'], $fileInfos['original-height']);
     
    8774    }
    8875
    89     /**
    90      * @param mixed $spriteObject
    91      * @param mixed $currentImage
    92      * @param mixed $fileInfos
    93      */
    94     public function resizeImage($spriteObject, $currentImage, $fileInfos)
     76    public function resizeImage($spriteObject, $currentImage, $fileInfos): void
    9577    {
    9678        \imagecopyresampled($spriteObject, $currentImage, $fileInfos['x'], $fileInfos['y'], 0, 0, $fileInfos['width'], $fileInfos['height'], $fileInfos['original-width'], $fileInfos['original-height']);
    9779    }
    9880
    99     /**
    100      * @param mixed $spriteObject
    101      * @param mixed $currentImage
    102      * @param mixed $fileInfos
    103      * @param mixed $resize
    104      */
    105     public function copyImageToSprite($spriteObject, $currentImage, $fileInfos, $resize)
     81    public function copyImageToSprite($spriteObject, $currentImage, $fileInfos, $resize): void
    10682    {
    10783        // if already resized the image will have been copied as part of the resize
     
    11187    }
    11288
    113     /**
    114      * @param mixed $imageObject
    115      */
    116     public function destroy($imageObject)
     89    public function destroy($imageObject): void
    11790    {
    11891        \imagedestroy($imageObject);
    11992    }
    12093
    121     /**
    122      * @param mixed $fileInfos
    123      *
    124      * @return false|resource
    125      */
    126     public function createImage($fileInfos)
     94    public function createImage($fileInfos): \GdImage|false
    12795    {
    12896        $sFile = $fileInfos['path'];
     
    152120    }
    153121
    154     /**
    155      * @param mixed $imageObject
    156      * @param mixed $extension
    157      * @param mixed $fileName
    158      */
    159     public function writeImage($imageObject, $extension, $fileName)
     122    public function writeImage($imageObject, $extension, $fileName): void
    160123    {
    161124        // check if we want to resample image to lower number of colours (to reduce file size)
  • jch-optimize/trunk/lib/src/Css/Sprite/Handler/Imagick.php

    r2997317 r3040365  
    2222        try {
    2323            $oImagick = new \Imagick();
    24             $aImageFormats = $oImagick->queryFormats();
     24            $imageFormats = $oImagick->queryFormats();
    2525        } catch (\ImagickException $e) {
    2626            $this->logger->error($e->getMessage());
     27
     28            return [];
    2729        }
    2830        // store supported formats for populating drop downs etc later
    29         if (\in_array('PNG', $aImageFormats)) {
     31        if (\in_array('PNG', $imageFormats)) {
    3032            $imageTypes[] = 'PNG';
    3133            $this->spriteFormats[] = 'PNG';
    3234        }
    33         if (\in_array('GIF', $aImageFormats)) {
     35        if (\in_array('GIF', $imageFormats)) {
    3436            $imageTypes[] = 'GIF';
    3537            $this->spriteFormats[] = 'GIF';
    3638        }
    37         if (\in_array('JPG', $aImageFormats) || \in_array('JPEG', $aImageFormats)) {
     39        if (\in_array('JPG', $imageFormats) || \in_array('JPEG', $imageFormats)) {
    3840            $imageTypes[] = 'JPG';
    3941        }
  • jch-optimize/trunk/lib/src/Debugger.php

    r2997317 r3040365  
    4343    }
    4444
    45     public static function debuggerErrorHandler(int $errno, string $errstr, string $errfile, int $errline): void
     45    public static function debuggerErrorHandler(int $errno, string $errstr, string $errfile = '', int $errline = 0): bool
    4646    {
    4747        /** @var LoggerInterface $logger */
     
    4949        $msg = 'Error no: '.$errno.', Message: '.$errstr.' in file: '.$errfile.' at line: '.$errline."\n";
    5050        $logger->error($msg);
    51         if (self::$dieOnError) {
    52             exit;
    53         }
     51
     52        return \true;
    5453    }
    5554
  • jch-optimize/trunk/lib/src/FileInfosUtilsTrait.php

    r2997317 r3040365  
    1313namespace JchOptimize\Core;
    1414
     15use JchOptimize\Core\Exception\PropertyNotFoundException;
     16
    1517\defined('_JCH_EXEC') or exit('Restricted access');
    1618trait FileInfosUtilsTrait
    1719{
    1820    /**
    19      * @var FileUtils
     21     * @var null|FileUtils
    2022     */
    21     private \JchOptimize\Core\FileUtils $fileUtils;
     23    private ?\JchOptimize\Core\FileUtils $fileUtils = null;
    2224
    2325    /**
     
    2628    public function prepareFileUrl(array $fileInfos, string $type): string
    2729    {
    28         return isset($fileInfos['url']) ? $this->fileUtils->prepareForDisplay($fileInfos['url'], '', \true, 40) : ('css' == $type ? 'Style' : 'Script').' Declaration';
     30        $fileUtils = $this->getFileUtils();
     31
     32        return isset($fileInfos['url']) ? $fileUtils->prepareForDisplay($fileInfos['url'], '', \true, 40) : ('css' == $type ? 'Style' : 'Script').' Declaration';
     33    }
     34
     35    private function getFileUtils(): FileUtils
     36    {
     37        if ($this->fileUtils instanceof \JchOptimize\Core\FileUtils) {
     38            return $this->fileUtils;
     39        }
     40
     41        throw new PropertyNotFoundException('FileUtils not set in '.\get_class($this));
    2942    }
    3043}
  • jch-optimize/trunk/lib/src/Helper.php

    r2997317 r3040365  
    4141    public static function isMsieLT10(): bool
    4242    {
    43         // $browser = Browser::getInstance( 'Mozilla/5.0 (Macintosh; Intel Mac OS X10_15_7) AppleWebkit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15' );
    44         /** @var Browser $browser */
    4543        $browser = \JchOptimize\Core\Browser::getInstance();
    4644
     
    6361    public static function strReplace(string $search, string $replace, string $subject): string
    6462    {
    65         return \str_replace(self::cleanPath($search), $replace, self::cleanPath($subject));
    66     }
    67 
    68     /**
    69      * @return string|string[]
    70      */
    71     public static function cleanPath(string $str)
     63        return (string) \str_replace(self::cleanPath($search), $replace, self::cleanPath($subject));
     64    }
     65
     66    public static function cleanPath(string $str): string
    7267    {
    7368        return \str_replace(['\\\\', '\\'], '/', $str);
     
    9287    }
    9388
    94     /**
    95      * Splits a string into an array using any regular delimiter or whitespace.
    96      *
    97      * @param null|array|string $string |array $string Delimited string of components
    98      *
    99      * @return string[] An array of the components
    100      */
    10189    public static function getArray(string|array|null $string): array
    10290    {
  • jch-optimize/trunk/lib/src/Html/CacheManager.php

    r3007001 r3040365  
    1515use _JchOptimizeVendor\GuzzleHttp\Psr7\UriResolver;
    1616use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    17 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
     17use _JchOptimizeVendor\Laminas\Cache\Exception\ExceptionInterface;
    1818use _JchOptimizeVendor\Laminas\Cache\Pattern\CallbackCache;
    1919use _JchOptimizeVendor\Laminas\Cache\Storage\IterableInterface;
     
    2424use _JchOptimizeVendor\Psr\Log\LoggerAwareTrait;
    2525use JchOptimize\Core\Combiner;
     26use JchOptimize\Core\Container\ContainerAwareTrait;
    2627use JchOptimize\Core\Css\Processor as CssProcessor;
    2728use JchOptimize\Core\Exception as CoreException;
     
    2930use JchOptimize\Core\FeatureHelpers\Fonts;
    3031use JchOptimize\Core\FeatureHelpers\LazyLoadExtended;
     32use JchOptimize\Core\FeatureHelpers\ResponsiveImages;
    3133use JchOptimize\Core\Helper;
    3234use JchOptimize\Core\Html\Elements\Img;
     
    100102    }
    101103
    102     /**
    103      * @throws CoreException\ExceptionInterface
    104      */
    105104    public function handleCombineJsCss(): void
    106105    {
     
    132131                        $lazyLoadExtended->cssBgImagesSelectors = \array_merge($lazyLoadExtended->cssBgImagesSelectors, $aCssCache['bgselectors']);
    133132                        foreach ($aCssCache['lcpImages'] as $lcpImage) {
    134                             $this->http2Preload->preload($lcpImage, 'image', '', 'high');
     133                            $attributes = [];
     134                            if ($lcpImage['srcset']) {
     135                                $attributes = ['imagesrcset' => $lcpImage['srcset'], 'imagesizes' => ResponsiveImages::$sizes];
     136                            }
     137                            $this->http2Preload->preload($lcpImage['src'], 'image', '', 'high', $attributes);
    135138                        }
    136139                    }
     
    195198     * @param string      $type  css or js
    196199     *
    197      * @return array|string Contents in array from cache containing combined file(s)
    198      */
    199     public function getCombinedFiles(array $links, ?string &$id, string $type)
     200     * @return null|mixed
     201     */
     202    public function getCombinedFiles(array $links, ?string &$id, string $type): mixed
    200203    {
    201204        !JCH_DEBUG ?: Profiler::start('GetCombinedFiles - '.$type);
     
    217220     * @param array $fileMatches Array matches of file to be appended to the combined file
    218221     *
    219      * @return array|bool|string
    220      */
    221     public function getAppendedFiles(array $ids, array $fileMatches, ?string &$id)
     222     * @return null|mixed
     223     *
     224     * @throws ExceptionInterface
     225     */
     226    public function getAppendedFiles(array $ids, array $fileMatches, ?string &$id): mixed
    222227    {
    223228        !JCH_DEBUG ?: Profiler::start('GetAppendedFiles');
     
    249254        $aImgAttributes = [];
    250255        foreach ($aImages[0] as $imgHtml) {
    251             // @var Img $imgObj
    252256            try {
     257                /** @var Img $imgObj */
    253258                $imgObj = \JchOptimize\Core\Html\HtmlElementBuilder::load($imgHtml);
    254259            } catch (CoreException\PregErrorException $e) {
     
    295300                if ($iWidthAttrValue && 0 == $count) {
    296301                    // Value found so we try to add the height attribute
    297                     $height = \round($aSize[1] / $aSize[0] * (int) $iWidthAttrValue);
     302                    $height = (string) \round($aSize[1] / $aSize[0] * (int) $iWidthAttrValue);
    298303                    // If add attributes not enabled put data-height instead
    299304                    $isImageAttrEnabled ? $imgObj->height($height) : $imgObj->data('height', $height);
     
    312317                // Check if a value was found for the height
    313318                if ($iHeightAttrValue && 0 == $count) {
    314                     $width = \round($aSize[0] / $aSize[1] * (int) $iHeightAttrValue);
     319                    $width = (string) \round($aSize[0] / $aSize[1] * (int) $iHeightAttrValue);
    315320                    // if add attributes not enabled put data-width instead
    316321                    $isImageAttrEnabled ? $imgObj->width($width) : $imgObj->data('width', $width);
     
    326331            if (!$existingAttributes) {
    327332                if ($isImageAttrEnabled) {
    328                     $imgObj->width($aSize[0]);
    329                     $imgObj->height($aSize[1]);
     333                    $imgObj->width((string) $aSize[0]);
     334                    $imgObj->height((string) $aSize[1]);
    330335                } else {
    331336                    $imgObj->data('width', $aSize[0]);
     
    340345
    341346    /**
    342      * @return array|bool|string
    343      *
    344347     * @throws CoreException\MissingDependencyException
    345348     */
     
    374377     * @param null|string $id       Generated id to identify cached file
    375378     *
    376      * @return array|bool|string
    377      *
    378      * @throws CoreException\RuntimeException
    379      */
    380     private function loadCache(callable $function, array $args, ?string &$id)
     379     * @return null|mixed
     380     *
     381     * @throw CoreException\RuntimeException
     382     */
     383    private function loadCache(callable $function, array $args, ?string &$id): mixed
    381384    {
    382385        try {
     
    394397            // Returns the contents of the combined file or false if failure
    395398            return $results;
    396         } catch (\Exception $e) {
     399        } catch (\Exception|ExceptionInterface $e) {
    397400            throw new CoreException\RuntimeException('Error creating cache files: '.$e->getMessage());
    398401        }
  • jch-optimize/trunk/lib/src/Html/Callbacks/AbstractCallback.php

    r2997317 r3040365  
    1515use _JchOptimizeVendor\Joomla\DI\Container;
    1616use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    17 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
     17use JchOptimize\Core\Container\ContainerAwareTrait;
    1818use JchOptimize\Core\Html\CallbackInterface;
    1919use JchOptimize\Core\Registry;
     
    2727     * @var string RegEx used to process HTML
    2828     */
    29     protected string $regex;
     29    protected string $regex = '';
    3030
    3131    /**
     
    3434    protected Registry $params;
    3535
    36     /**
    37      * Constructor.
    38      *
    39      * @param null|Container $container
    40      * @param null|Registry  $params
    41      */
    4236    public function __construct(Container $container, Registry $params)
    4337    {
  • jch-optimize/trunk/lib/src/Html/Callbacks/BuildHtmlElement.php

    r2997317 r3040365  
    88use JchOptimize\Core\Html\Elements\BaseElement;
    99use JchOptimize\Core\Html\HtmlElementBuilder;
     10use JchOptimize\Core\Html\HtmlElementInterface;
    1011use JchOptimize\Core\Html\Parser;
    1112
     
    4142    }
    4243
    43     public function getElement(): BaseElement
     44    public function getElement(): HtmlElementInterface
    4445    {
    4546        return $this->element;
    4647    }
    4748
    48     /**
    49      * @param string[] $matches
    50      */
    51     public function loadElementAttributes(array $matches): void
     49    public function loadElementAttributes(array $matches): string
    5250    {
    5351        $parts = \preg_split('#\\s*=\\s*#', $matches[0]);
     
    5553        $delimiter = $matches[1] ?? '"';
    5654        $this->element->attribute($parts[0], $value, $delimiter);
     55
     56        return '';
    5757    }
    5858
     
    8080            }
    8181            if (!empty($match[2])) {
    82                 $this->element->addChild(HtmlElementBuilder::load($match[2]));
     82                $child = HtmlElementBuilder::load($match[2]);
     83                $child->setParent($this->element->getElementName());
     84                $this->element->addChild($child);
    8385            }
    8486        }
  • jch-optimize/trunk/lib/src/Html/Callbacks/Cdn.php

    r2997317 r3040365  
    1919use JchOptimize\Core\Css\Parser as CssParser;
    2020use JchOptimize\Core\Exception\PregErrorException;
     21use JchOptimize\Core\Exception\PropertyNotFoundException;
    2122use JchOptimize\Core\Html\Elements\BaseElement;
    2223use JchOptimize\Core\Html\Elements\Style;
     
    3031{
    3132    protected string $context = 'default';
    32     protected UriInterface $baseUri;
     33    protected ?UriInterface $baseUri = null;
    3334    protected string $searchRegex = '';
    3435    protected string $localhost = '';
     
    111112    }
    112113
    113     protected function loadCdnInCssStyle($css): string
     114    protected function loadCdnInCssStyle(string $css): string
    114115    {
    115116        \preg_match_all('#url\\([\'"]?('.$this->searchRegex.CssParser::cssUrlValueToken().')([\'"]?\\))#i', $css, $matches, \PREG_SET_ORDER);
     
    134135    protected function resolvePathToBase(UriInterface $uri): UriInterface
    135136    {
    136         return UriResolver::resolve($this->baseUri, $uri);
     137        return UriResolver::resolve($this->getBaseUri(), $uri);
    137138    }
    138139
     
    156157    }
    157158
    158     protected function cdnInContentAttributes($value): string
     159    protected function cdnInContentAttributes(string $value): string
    159160    {
    160161        \preg_match_all('#'.$this->searchRegex.'#i', $value, $matches, \PREG_SET_ORDER);
     
    168169        return $value;
    169170    }
     171
     172    protected function getBaseUri(): UriInterface
     173    {
     174        if ($this->baseUri instanceof UriInterface) {
     175            return $this->baseUri;
     176        }
     177
     178        throw new PropertyNotFoundException('Base URI not set in '.\get_class($this));
     179    }
    170180}
  • jch-optimize/trunk/lib/src/Html/Callbacks/LazyLoad.php

    r3007001 r3040365  
    1818use JchOptimize\Core\Exception\PregErrorException;
    1919use JchOptimize\Core\FeatureHelpers\LazyLoadExtended;
     20use JchOptimize\Core\FeatureHelpers\ResponsiveImages;
    2021use JchOptimize\Core\FeatureHelpers\Webp;
    2122use JchOptimize\Core\Helper;
    2223use JchOptimize\Core\Html\Elements\Audio;
    23 use JchOptimize\Core\Html\Elements\BaseElement;
    2424use JchOptimize\Core\Html\Elements\Iframe;
    2525use JchOptimize\Core\Html\Elements\Img;
     
    4949    public int $height = 1;
    5050
    51     protected array $excludes;
    52 
    53     protected array $args;
     51    protected array $excludes = [];
     52
     53    protected array $args = [];
    5454
    5555    public function __construct(Container $container, Registry $params, Http2Preload $http2Preload)
     
    8686            return $element->render();
    8787        }
     88        if (\JCH_PRO && $this->params->get('pro_load_responsive_images', '0')) {
     89            $this->loadResponsiveImages($element);
     90        }
    8891        if (\JCH_PRO && $this->params->get('pro_load_webp_images', '0')) {
    8992            $this->loadWebpImages($element);
     
    150153    }
    151154
    152     private function lazyLoadElement(BaseElement $element, array $options): BaseElement
     155    private function lazyLoadElement(HtmlElementInterface $element, array $options): HtmlElementInterface
    153156    {
    154157        if ($options['lazyload']) {
     
    289292    }
    290293
     294    private function loadResponsiveImages(HtmlElementInterface $element): void
     295    {
     296        if ($element->hasChildren()) {
     297            foreach ($element->getChildren() as $child) {
     298                if ($child instanceof HtmlElementInterface) {
     299                    $this->loadResponsiveImages($child);
     300                }
     301            }
     302        }
     303        $this->getContainer()->get(ResponsiveImages::class)->convert($element);
     304    }
     305
    291306    private function lcpImageProcessed(HtmlElementInterface $element): bool
    292307    {
     
    323338            } else {
    324339                if (($src = $element->getSrc()) !== \false && Helper::findMatches($lcpImages, $src)) {
    325                     $this->http2Preload->preload($src, 'image', '', 'high');
     340                    if ('picture' == $element->getParent()) {
     341                        $element->fetchpriority('high');
     342                    } else {
     343                        $this->http2Preload->preload($src, 'image', '', 'high');
     344                    }
    326345                    if ($element->hasAttribute('loading')) {
    327346                        $element->loading('eager');
  • jch-optimize/trunk/lib/src/Html/ElementObject.php

    r2997317 r3040365  
    2727    public bool $negateAggregatedPosCriteria = \false;
    2828    public bool $bCaptureAttributes = \false;
    29 
    30     /**
    31      * @var false
    32      */
    3329    public bool $bParseContentLazily = \true;
    3430
  • jch-optimize/trunk/lib/src/Html/Elements/BaseElement.php

    r2997317 r3040365  
    2828 * @method BaseElement title(string $value)
    2929 * @method bool|string getId()
    30  * @method bool|string getClass()
     30 * @method array|bool getClass()
    3131 * @method bool|string getHidden()
    3232 * @method bool|string getStyle()
     
    3838    protected string $name = '';
    3939    protected bool $isXhtml;
     40    protected string $parent = '';
    4041
    4142    /**
     
    107108    }
    108109
    109     public function data($name, $value = ''): static
     110    public function data(string $name, UriInterface|array|string $value = ''): static
    110111    {
    111112        $this->attribute('data-'.$name, $value);
     
    114115    }
    115116
    116     /**
    117      * @return $this
    118      */
    119117    public function addChild(HtmlElementInterface|string $child): static
    120118    {
     
    136134
    137135        return $this;
     136    }
     137
     138    public function getElementName(): string
     139    {
     140        return $this->name;
    138141    }
    139142
     
    152155    }
    153156
    154     public function firstOfAttributes(array $attributes)
     157    public function firstOfAttributes(array $attributes): UriInterface|bool|array|string
    155158    {
    156159        foreach ($attributes as $name => $value) {
     
    200203    }
    201204
     205    public function setParent(string $name): static
     206    {
     207        $this->parent = $name;
     208
     209        return $this;
     210    }
     211
     212    public function getParent(): string
     213    {
     214        return $this->parent;
     215    }
     216
    202217    private function renderChildren(): string
    203218    {
  • jch-optimize/trunk/lib/src/Html/FilesManager.php

    r3007001 r3040365  
    1616use _JchOptimizeVendor\GuzzleHttp\Psr7\UriResolver;
    1717use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    18 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1918use _JchOptimizeVendor\Psr\Http\Client\ClientInterface;
    2019use _JchOptimizeVendor\Psr\Http\Message\UriInterface;
    2120use CodeAlfa\Minify\Html;
     21use JchOptimize\Core\Container\ContainerAwareTrait;
    2222use JchOptimize\Core\Exception\ExcludeException;
     23use JchOptimize\Core\Exception\PropertyNotFoundException;
    2324use JchOptimize\Core\FeatureHelpers\Fonts;
    2425use JchOptimize\Core\FileUtils;
     
    137138     */
    138139    public array $jsMarker = [];
    139     protected \JchOptimize\Core\Html\HtmlElementInterface $element;
     140    protected ?\JchOptimize\Core\Html\HtmlElementInterface $element = null;
    140141
    141142    /**
     
    147148     * @var HtmlElementInterface|string String to replace the matched link
    148149     */
    149     protected $replacement = '';
     150    protected string|\JchOptimize\Core\Html\HtmlElementInterface $replacement = '';
    150151
    151152    /**
     
    209210        $this->element = $element;
    210211        // By default, we'll return the match and save info later and what is to be removed
    211         $this->replacement = $this->element;
     212        $this->replacement = $element;
    212213
    213214        try {
     
    265266        $this->sJsExcludeType = 'ieo';
    266267        if ($addToExcludes) {
    267             $this->aExcludedJs[] = $this->element;
     268            $this->aExcludedJs[] = $this->getElement();
    268269        }
    269270
    270271        throw new ExcludeException();
     272    }
     273
     274    protected function getElement(): HtmlElementInterface
     275    {
     276        if ($this->element instanceof \JchOptimize\Core\Html\HtmlElementInterface) {
     277            return $this->element;
     278        }
     279
     280        throw new PropertyNotFoundException('HTMLElement not set in '.\get_class($this));
    271281    }
    272282
     
    278288        // Exclude invalid urls
    279289        if ('data' == $uri->getScheme()) {
    280             if ($this->element instanceof Script) {
     290            if ($this->getElement() instanceof Script) {
    281291                $this->excludeJsIEO();
    282292            } else {
     
    303313            // for different browsers and creates problems when we try to cache it.
    304314            if ('fonts.googleapis.com' == $uri->getHost() && !$this->params->get('pro_optimizeFonts_enable', '0')) {
    305                 $this->replacement = $this->element;
     315                $this->replacement = $this->getElement();
    306316            }
    307317            $this->excludeCssIEO();
     
    327337        $this->aCss[$this->iIndex_css][] = ['url' => $uri, 'media' => $media];
    328338        // Record match to be replaced
    329         $this->cssReplacements[$this->iIndex_css][] = $this->element;
     339        $this->cssReplacements[$this->iIndex_css][] = $this->getElement();
    330340    }
    331341
    332342    private function getMediaAttribute(): string
    333343    {
    334         return $this->element->attributeValue('media') ?: '';
     344        return (string) $this->getElement()->attributeValue('media') ?: '';
    335345    }
    336346
     
    381391    {
    382392        // if previous file was not excluded increment css index
    383         if (!$this->cssExcludedPeo) {
     393        if (!$this->cssExcludedPeo && !empty($this->cssReplacements[0])) {
    384394            ++$this->iIndex_css;
    385395        }
     
    393403    {
    394404        if ($this->params->get('pro_smart_combine', '0')) {
    395             $type = $this->element instanceof Script ? 'js' : 'css';
     405            $type = $this->getElement() instanceof Script ? 'js' : 'css';
    396406            $fileUri = UriResolver::resolve(SystemUri::currentUri(), $uri);
    397407            $filePath = $fileUri->getPath();
     
    436446        $this->cssExcludedIeo = \false;
    437447        $this->aCss[$this->iIndex_css][] = ['content' => Html::cleanScript($content, 'css'), 'media' => $media];
    438         $this->cssReplacements[$this->iIndex_css][] = $this->element;
     448        $this->cssReplacements[$this->iIndex_css][] = $this->getElement();
    439449    }
    440450
     
    463473            }
    464474        }
    465         if (($attributeType = $this->element->firstofAttributes($deferAttributes)) !== \false) {
     475        if (($attributeType = $this->getElement()->firstofAttributes($deferAttributes)) !== \false) {
    466476            if ($attributeType != $this->prevDeferMatches) {
    467477                ++$this->deferIndex;
    468478                $this->prevDeferMatches = $attributeType;
    469479            }
    470             $this->defers[$this->deferIndex][] = ['attributeType' => $attributeType, 'script' => $this->element, 'url' => $uri];
     480            $this->defers[$this->deferIndex][] = ['attributeType' => $attributeType, 'script' => $this->getElement(), 'url' => $uri];
    471481            $this->bLoadJsAsync = \false;
    472482            $this->excludeJsIEO(\false);
     
    480490        $this->jsExcludedIeo = \false;
    481491        $this->aJs[$this->iIndex_js][] = ['url' => $uri];
    482         $this->jsReplacements[$this->iIndex_js][] = $this->element;
     492        $this->jsReplacements[$this->iIndex_js][] = $this->getElement();
    483493    }
    484494
     
    494504        // If previous file was not excluded, update marker
    495505        if (!$this->jsExcludedPeo) {
    496             $marker = $this->element->data('jch', 'js'.$this->iIndex_js);
     506            $marker = $this->getElement()->data('jch', 'js'.$this->iIndex_js);
    497507            $this->jsMarker = \array_pad($this->jsMarker, $this->iIndex_js + 1, $marker);
    498508        }
    499509        if ($addToExcludes) {
    500             $this->aExcludedJs[] = $this->element;
     510            $this->aExcludedJs[] = $this->getElement();
    501511        }
    502512        // Record index of last excluded file
     
    535545        // different type is encountered. The defer and async attribute on inline scripts are ignored
    536546        $deferAttributes = ['type' => 'module', 'nomodule' => \true];
    537         if (($attributeType = $this->element->firstOfAttributes($deferAttributes)) !== \false) {
     547        if (($attributeType = $this->getElement()->firstOfAttributes($deferAttributes)) !== \false) {
    538548            if ($attributeType != $this->prevDeferMatches) {
    539549                ++$this->deferIndex;
    540550                $this->prevDeferMatches = $attributeType;
    541551            }
    542             $this->defers[$this->deferIndex][] = ['attributeType' => $attributeType, 'script' => $this->element, 'content' => $content];
     552            $this->defers[$this->deferIndex][] = ['attributeType' => $attributeType, 'script' => $this->getElement(), 'content' => $content];
    543553            $this->bLoadJsAsync = \false;
    544554            $this->excludeJsIEO(\false);
     
    548558        $this->jsExcludedIeo = \false;
    549559        $this->aJs[$this->iIndex_js][] = ['content' => Html::cleanScript($content, 'js')];
    550         $this->jsReplacements[$this->iIndex_js][] = $this->element;
     560        $this->jsReplacements[$this->iIndex_js][] = $this->getElement();
    551561    }
    552562
  • jch-optimize/trunk/lib/src/Html/HtmlElementBuilder.php

    r2997317 r3040365  
    4646     * @throws PregErrorException
    4747     */
    48     public static function load(string $html): BaseElement
     48    public static function load(string $html): HtmlElementInterface
    4949    {
    5050        $parser = new \JchOptimize\Core\Html\Parser();
  • jch-optimize/trunk/lib/src/Html/HtmlElementInterface.php

    r2997317 r3040365  
    1414
    1515use _JchOptimizeVendor\Psr\Http\Message\UriInterface;
     16use JchOptimize\Core\Html\Elements\BaseElement;
    1617
     18/**
     19 * @method BaseElement id(string $value)
     20 * @method BaseElement class(string $value)
     21 * @method BaseElement hidden(string $value)
     22 * @method BaseElement style(string $value)
     23 * @method BaseElement title(string $value)
     24 * @method bool|string getId()
     25 * @method array|bool  getClass()
     26 * @method bool|string getHidden()
     27 * @method bool|string getStyle()
     28 * @method bool|string getTitle()
     29 */
    1730interface HtmlElementInterface
    1831{
     
    3447
    3548    public function render(): string;
     49
     50    public function firstOfAttributes(array $attributes): UriInterface|array|string|bool;
     51
     52    public function data(string $name, UriInterface|array|string $value = ''): static;
     53
     54    public function getChildren(): array;
     55
     56    public function setParent(string $name): static;
     57
     58    public function getParent(): string;
    3659}
  • jch-optimize/trunk/lib/src/Html/HtmlManager.php

    r2997317 r3040365  
    1616use _JchOptimizeVendor\GuzzleHttp\Psr7\UriResolver;
    1717use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    18 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1918use _JchOptimizeVendor\Joomla\Filesystem\File;
    2019use _JchOptimizeVendor\Laminas\Cache\Storage\FlushableInterface;
     
    2322use _JchOptimizeVendor\Laminas\EventManager\EventManagerAwareInterface;
    2423use _JchOptimizeVendor\Laminas\EventManager\EventManagerAwareTrait;
     24use _JchOptimizeVendor\Laminas\EventManager\EventManagerInterface;
    2525use _JchOptimizeVendor\Laminas\EventManager\SharedEventManagerInterface;
    2626use _JchOptimizeVendor\Psr\Http\Message\UriInterface;
    2727use JchOptimize\Core\Cdn;
     28use JchOptimize\Core\Container\ContainerAwareTrait;
    2829use JchOptimize\Core\Exception;
    2930use JchOptimize\Core\FeatureHelpers\DynamicJs;
     
    4546
    4647    /**
     48     * @var null|EventManagerInterface
     49     */
     50    protected $events;
     51
     52    /**
    4753     * @var Processor
    4854     */
     
    5460     * @var AsyncManager
    5561     */
    56     private \JchOptimize\Core\Html\AsyncManager $asyncManager;
     62    private ?\JchOptimize\Core\Html\AsyncManager $asyncManager = null;
    5763
    5864    /**
     
    146152        $html = \str_replace($defersRemoveArray, '', $html);
    147153        $this->oProcessor->setFullHtml($html);
    148         // If we're loading javascript dynamically add the deferred javascript files to array of files to load dynamically instead
     154        // If we're loading javascript dynamically add the deferred javascript files to array
     155        // of files to load dynamically instead
    149156        if ($this->params->get('pro_reduce_unused_js_enable', '0')) {
    150157            // @see DynamicJs::prepareJsDynamicUrls()
    151158            $this->container->get(DynamicJs::class)->prepareJsDynamicUrls($defers);
    152159        } elseif (!empty($defers[0])) {
     160            // Otherwise if there are any defers we just add them to the bottom of the page
    153161            foreach ($defers as $deferGroup) {
    154162                foreach ($deferGroup as $deferArray) {
     
    323331            }
    324332        } elseif (JCH_PRO) {
    325             $this->asyncManager->loadCssAsync($cssUrls);
     333            $this->getAsyncManager()->loadCssAsync($cssUrls);
    326334        }
    327335    }
     
    350358    {
    351359        if (JCH_PRO) {
    352             $script = $this->cleanScript($this->asyncManager->printHeaderScript());
     360            $script = $this->cleanScript($this->getAsyncManager()->printHeaderScript());
    353361            if ($script) {
    354362                $this->appendChildToHead($script);
     
    424432            $css .= <<<CSS
    425433
    426 @media (max-width: 991.98px) {
     434@media (max-width: 767.98px) {
    427435    {$mobileCss}
    428436}
     
    433441            $css .= <<<CSS
    434442
    435 @media (min-width: 992px) {
     443@media (min-width: 768px) {
    436444    {$desktopCss}
    437445}
     
    485493        return $script;
    486494    }
     495
     496    protected function getAsyncManager(): AsyncManager
     497    {
     498        if ($this->asyncManager instanceof \JchOptimize\Core\Html\AsyncManager) {
     499            return $this->asyncManager;
     500        }
     501
     502        throw new Exception\PropertyNotFoundException('AsyncManager not set in '.\get_class($this));
     503    }
    487504}
  • jch-optimize/trunk/lib/src/Html/Parser.php

    r2997317 r3040365  
    1515use CodeAlfa\RegexTokenizer\Html;
    1616use JchOptimize\Core\Exception;
     17use JchOptimize\Core\Exception\PregErrorException;
    1718use JchOptimize\Core\Html\Callbacks\AbstractCallback;
    1819
     
    2122{
    2223    use Html;
    23 
    24     /**
    25      * @var true
    26      */
    2724    public bool $alsoExcludeStringsAndComments = \false;
    2825
     
    8077
    8178    /**
    82      * @param AbstractCallback $callbackObject
    83      *
    84      * @return null|array|string|string[]
    85      *
    86      * @throws Exception\PregErrorException
     79     * @throws PregErrorException
    8780     */
    88     public function processMatchesWithCallback(string $html, CallbackInterface $callbackObject)
     81    public function processMatchesWithCallback(string $html, CallbackInterface $callbackObject): string
    8982    {
    9083        $regex = $this->getHtmlSearchRegex();
     
    9285            $callbackObject->setRegex($regex);
    9386        }
    94         $sProcessedHtml = \preg_replace_callback('#'.$regex.'#six', [$callbackObject, 'processMatches'], $html);
     87        $sProcessedHtml = (string) \preg_replace_callback('#'.$regex.'#six', [$callbackObject, 'processMatches'], $html);
    9588
    9689        try {
  • jch-optimize/trunk/lib/src/Html/Processor.php

    r2997317 r3040365  
    1414
    1515use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    16 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1716use _JchOptimizeVendor\Psr\Log\LoggerAwareInterface;
    1817use _JchOptimizeVendor\Psr\Log\LoggerAwareTrait;
    1918use JchOptimize\Core\Cdn as CdnCore;
     19use JchOptimize\Core\Container\ContainerAwareTrait;
    2020use JchOptimize\Core\Css\Parser as CssParser;
    2121use JchOptimize\Core\Exception;
     
    207207    {
    208208        $bLazyLoad = $this->params->get('lazyload_enable', '0') && !$this->isAmpPage;
    209         if ($bLazyLoad || $this->params->get('pro_http2_push_enable', '0') || $this->params->get('pro_load_webp_images', '0') || $this->params->get('pro_lcp_images_enable', '0') || \JCH_DEBUG && $this->params->get('elements_above_fold_marker', '0')) {
     209        if ($bLazyLoad || $this->params->get('pro_http2_push_enable', '0') || $this->params->get('pro_load_webp_images', '0') || $this->params->get('pro_load_responsive_images', '0') || $this->params->get('pro_lcp_images_enable', '0') || \JCH_DEBUG && $this->params->get('elements_above_fold_marker', '0')) {
    210210            !\JCH_DEBUG ?: Profiler::start('LazyLoadImages');
    211211            $sHtml = $this->getBodyHtml();
     
    258258    public function processImageAttributes(): void
    259259    {
    260         if ($this->params->get('img_attributes_enable', '0') || $this->params->get('lazyload_enable', '0') && $this->params->get('lazyload_autosize', '0')) {
     260        if ($this->params->get('img_attributes_enable', '0') || $this->params->get('lazyload_enable', '0') && $this->params->get('lazyload_autosize', '0') || JCH_PRO && $this->params->get('pro_load_responsive_images', '0')) {
    261261            !\JCH_DEBUG ?: Profiler::start('ProcessImageAttributes');
    262262            $oParser = new \JchOptimize\Core\Html\Parser();
  • jch-optimize/trunk/lib/src/Http2Preload.php

    r3007001 r3040365  
    1515use _JchOptimizeVendor\GuzzleHttp\Psr7\UriResolver;
    1616use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    17 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1817use _JchOptimizeVendor\Laminas\EventManager\Event;
    1918use _JchOptimizeVendor\Psr\Http\Message\UriInterface;
     19use JchOptimize\Core\Container\ContainerAwareTrait;
    2020use JchOptimize\Core\FeatureHelpers\Http2Excludes;
    2121use JchOptimize\Core\Html\HtmlManager;
     
    6565
    6666    /**
    67      * @param UriInterface $uri Url of file
     67     * @param UriInterface $uri        Url of file
     68     * @param string[]     $attributes
    6869     *
    6970     * @return false|void
    7071     */
    71     public function add(UriInterface $uri, string $type, string $fetchPriority = 'auto')
     72    public function add(UriInterface $uri, string $type, string $fetchPriority = 'auto', array $attributes = [])
    7273    {
    7374        if (!$this->enable) {
     
    9293            return \false;
    9394        }
    94         $this->internalAdd($uri, $type, $this->extension($uri), $fetchPriority);
    95     }
    96 
    97     public function preload(UriInterface $uri, $type, $fontExt, $fetchPriority = ''): void
     95        $this->internalAdd($uri, $type, $this->extension($uri), $fetchPriority, $attributes);
     96    }
     97
     98    public function preload(UriInterface $uri, string $type, string $fontExt, string $fetchPriority = '', array $attributes = []): void
    9899    {
    99100        if ($this->validateUri($uri)) {
    100             $this->internalAdd($uri, $type, $fontExt, $fetchPriority);
    101         }
    102     }
    103 
    104     public function addAdditional(UriInterface $uri, string $type, string $fontExt, $fetchPriority = 'auto'): void
     101            $this->internalAdd($uri, $type, $fontExt, $fetchPriority, $attributes);
     102        }
     103    }
     104
     105    public function addAdditional(UriInterface $uri, string $type, string $fontExt, string $fetchPriority = 'auto', array $attributes = []): void
    105106    {
    106107        if ($this->enable) {
    107             $this->internalAdd($uri, $type, $fontExt, $fetchPriority);
     108            $this->preload($uri, $type, $fontExt, $fetchPriority, $attributes);
    108109        }
    109110    }
     
    204205    }
    205206
    206     private function internalAdd(UriInterface $uri, string $type, string $fontExt = '', string $fetchPriority = 'auto'): void
     207    /**
     208     * @param string[] $attributes
     209     */
     210    private function internalAdd(UriInterface $uri, string $type, string $fontExt = '', string $fetchPriority = 'auto', array $attributes = []): void
    207211    {
    208212        $RR_uri = $this->cdn->loadCdnResource(UriNormalizer::normalize($uri));
     
    211215            $RR_uri = UriConverter::absToNetworkPathReference($RR_uri);
    212216        }
    213         $preload = ['href' => (string) $RR_uri, 'as' => $type];
     217        $preload = \array_merge(['href' => (string) $RR_uri, 'as' => $type], $attributes);
    214218        if ('auto' != $fetchPriority) {
    215219            $preload['fetchpriority'] = $fetchPriority;
     
    279283            }
    280284        }
    281         // We need to decide how we're going to preload this file. If it's loaded by CDN or if we're using Capture cache we need
     285        // We need to decide how we're going to preload this file.
     286        // If it's loaded by CDN or if we're using Capture cache we need
    282287        // to put it in the HTML, otherwise we can send a link header, better IMO.
    283288        // Let's make the default method 'link'
    284289        $method = 'link';
    285         if ($this->cdn->isFileOnCdn($RR_uri) || UriComparator::isCrossOrigin($RR_uri) || Cache::isPageCacheEnabled($this->params, \true) && JCH_PRO && $this->params->get('pro_capture_cache_enable', '1') && !$this->params->get('pro_cache_platform', '0') || 'auto' != $fetchPriority) {
     290        if ($this->cdn->isFileOnCdn($RR_uri) || UriComparator::isCrossOrigin($RR_uri) || Cache::isPageCacheEnabled($this->params, \true) && JCH_PRO && $this->params->get('pro_capture_cache_enable', '1') && !$this->params->get('pro_cache_platform', '0') || 'auto' != $fetchPriority || !empty($attributes)) {
    286291            $method = 'html';
    287292        }
  • jch-optimize/trunk/lib/src/Interfaces/Paths.php

    r2997317 r3040365  
    3333     * Path to the directory where generated sprite images are saved.
    3434     *
    35      * @param bool $isRootRelative if true, return the root relative path with trailing slash; if false, return the absolute path without trailing slash
     35     * @param bool $isRootRelative if true, return the root relative path with trailing slash;
     36     *                             if false, return the absolute path without trailing slash
    3637     */
    3738    public static function spritePath(bool $isRootRelative = \false): string;
     
    4546
    4647    /**
    47      * The base folder for rewrites when the combined files are delivered with PHP using mod_rewrite. Generally the parent directory for the
    48      * /media/ folder with a root relative path.
     48     * The base folder for rewrites when the combined files are delivered with PHP using mod_rewrite.
     49     * Generally the parent directory for the /media/ folder with a root relative path.
    4950     */
    5051    public static function rewriteBaseFolder(): string;
     
    6162     */
    6263    public static function rootPath(): string;
     64
     65    public static function basePath(): string;
    6366
    6467    /**
     
    123126     */
    124127    public static function templateCachePath(): string;
     128
     129    public static function responsiveImagePath(bool $isRootRelative = \false): string;
    125130}
  • jch-optimize/trunk/lib/src/Laminas/ArrayPaginator.php

    r2997317 r3040365  
    66use _JchOptimizeVendor\Laminas\Paginator\Paginator;
    77
     8/**
     9 * @psalm-suppress PropertyNotSetInConstructor
     10 */
    811class ArrayPaginator extends Paginator
    912{
  • jch-optimize/trunk/lib/src/Laminas/Plugins/ClearExpiredByFactor.php

    r3007001 r3040365  
    1414
    1515use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    16 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1716use _JchOptimizeVendor\Joomla\Filesystem\File;
    1817use _JchOptimizeVendor\Laminas\Cache\Exception\ExceptionInterface;
     
    2625use _JchOptimizeVendor\Psr\Log\LoggerAwareInterface;
    2726use _JchOptimizeVendor\Psr\Log\LoggerAwareTrait;
     27use JchOptimize\Core\Container\ContainerAwareTrait;
    2828use JchOptimize\Core\PageCache\PageCache;
    2929use JchOptimize\Core\Registry;
     
    3232use JchOptimize\Platform\Paths;
    3333use JchOptimize\Platform\Profiler;
     34use Throwable;
    3435
    3536use function time;
     
    100101        $ttl = $cache->getOptions()->getTtl();
    101102        $time = \time();
    102         // Get ids of all files used on this page
    103         $fileIds = $taggableCache->getTags(\md5($pageCache->getCurrentPage()));
    104         foreach ($fileIds as $fileId) {
    105             $metaData = $taggableCache->getMetadata($fileId);
     103        $itemDeletedFlag = \false;
     104        foreach ($taggableCache->getIterator() as $item) {
     105            $metaData = $taggableCache->getMetadata($item);
    106106            if (!\is_array($metaData) || empty($metaData)) {
    107107                continue;
    108108            }
     109            $tags = $taggableCache->getTags($item);
     110            if (!\is_array($tags) || empty($tags)) {
     111                continue;
     112            }
     113            if ('pagecache' == $tags[0]) {
     114                continue;
     115            }
    109116            $mtime = (int) $metaData['mtime'];
    110             if ($time >= $mtime + $ttl) {
    111                 $pageCacheUrls = $taggableCache->getTags($fileId);
    112                 foreach ($pageCacheUrls as $pageCacheUrl) {
     117            if ($time > $mtime + $ttl) {
     118                foreach ($tags as $pageCacheUrl) {
    113119                    $pageCacheId = $pageCache->getPageCacheId(Utils::uriFor($pageCacheUrl));
    114120                    if (!$pageCache->deleteItemById($pageCacheId)) {
     
    116122                    }
    117123                }
    118                 $cache->removeItem($fileId);
    119                 $deleteTag = !$cache->hasItem($fileId);
     124                $cache->removeItem($item);
     125                $deleteTag = !$cache->hasItem($item);
     126                if ($deleteTag) {
     127                    $itemDeletedFlag = \true;
     128                }
    120129                // We need to also delete the static css/js file if that option is set
    121130                if ('2' == $params->get('htaccess', '2')) {
    122                     $files = [Paths::cachePath(\false).'/css/'.$fileId.'.css', Paths::cachePath(\false).'/js/'.$fileId.'.js'];
     131                    $files = [Paths::cachePath(\false).'/css/'.$item.'.css', Paths::cachePath(\false).'/js/'.$item.'.js'];
    123132
    124133                    try {
     
    134143                            }
    135144                        }
    136                     } catch (\Throwable $e) {
     145                    } catch (Throwable) {
    137146                        // Don't bother to delete the tags if this didn't work
    138147                        $deleteTag = \false;
     
    140149                }
    141150                if ($deleteTag) {
    142                     $taggableCache->removeItem($fileId);
     151                    $taggableCache->removeItem($item);
    143152                }
    144153            }
    145154        }
    146         if (!empty($itemsOnPages)) {
     155        if ($itemDeletedFlag) {
    147156            // Finally attempt to clean any third party page cache
    148157            Cache::cleanThirdPartyPageCache();
  • jch-optimize/trunk/lib/src/Mvc/Controller.php

    r2997317 r3040365  
    55use _JchOptimizeVendor\Joomla\Controller\AbstractController;
    66use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    7 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    87use _JchOptimizeVendor\Psr\Log\LoggerAwareInterface;
    98use _JchOptimizeVendor\Psr\Log\LoggerAwareTrait;
     9use JchOptimize\Core\Container\ContainerAwareTrait;
    1010
    1111abstract class Controller extends AbstractController implements ContainerAwareInterface, LoggerAwareInterface
  • jch-optimize/trunk/lib/src/Mvc/Model.php

    r2997317 r3040365  
    44
    55use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    6 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    76use _JchOptimizeVendor\Joomla\Model\DatabaseModelInterface;
    87use _JchOptimizeVendor\Joomla\Model\DatabaseModelTrait;
    98use _JchOptimizeVendor\Joomla\Model\StatefulModelInterface;
    109use _JchOptimizeVendor\Joomla\Model\StatefulModelTrait;
     10use JchOptimize\Core\Container\ContainerAwareTrait;
    1111
    1212class Model implements ContainerAwareInterface, DatabaseModelInterface, StatefulModelInterface
  • jch-optimize/trunk/lib/src/Optimize.php

    r2997317 r3040365  
    1515// No direct access
    1616use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    17 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1817use _JchOptimizeVendor\Psr\Log\LoggerAwareInterface;
    1918use _JchOptimizeVendor\Psr\Log\LoggerAwareTrait;
    2019use CodeAlfa\Minify\Html;
     20use JchOptimize\Core\Container\ContainerAwareTrait;
    2121use JchOptimize\Core\FeatureHelpers\ReduceDom;
    2222use JchOptimize\Core\Html\CacheManager;
     
    3636    use ContainerAwareTrait;
    3737
    38     private Registry $params;
     38    /**
     39     * @var Registry
     40     */
     41    private \JchOptimize\Core\Registry $params;
    3942
    4043    private HtmlProcessor $htmlProcessor;
     
    4447    private HtmlManager $htmlManager;
    4548
    46     private string $html;
     49    private string $html = '';
    4750
    4851    private string $jit = '1';
     
    6972        }
    7073        if (\version_compare(\PHP_VERSION, '7.3', '<')) {
    71             throw new Exception\RuntimeException('PHP Version less than 7.3, Exiting plugin...');
     74            throw new \JchOptimize\Core\Exception\RuntimeException('PHP Version less than 7.3, Exiting plugin...');
    7275        }
    7376        $pcre_version = \preg_replace('#(^\\d++\\.\\d++).++$#', '$1', \PCRE_VERSION);
    7477        if (\version_compare($pcre_version, '7.2', '<')) {
    75             throw new Exception\RuntimeException('PCRE Version less than 7.2. Exiting plugin...');
     78            throw new \JchOptimize\Core\Exception\RuntimeException('PCRE Version less than 7.2. Exiting plugin...');
    7679        }
    7780        $this->params = $params;
     
    108111            JCH_DEBUG ? Profiler::stop('Process', \true) : null;
    109112            JCH_DEBUG ? Profiler::attachProfiler($optimizedHtml, $this->htmlProcessor->isAmpPage) : null;
    110         } catch (Exception\ExceptionInterface $e) {
     113        } catch (\JchOptimize\Core\Exception\ExceptionInterface $e) {
    111114            $this->logger->error((string) $e);
    112115            $optimizedHtml = $this->html;
  • jch-optimize/trunk/lib/src/Output.php

    r2997317 r3040365  
    5757            return \false;
    5858        }
    59         if ($bSend) {
    60             $aTimeMFile = self::RFC1123DateAdd($results[0]['filemtime'], '1 year');
    61             $timeMfile = $aTimeMFile['filemtime'].' GMT';
    62             $expiryDate = $aTimeMFile['expiry'].' GMT';
    63             $modifiedSinceTime = '';
    64             $noneMatch = '';
    65             if (\function_exists('apache_request_headers')) {
    66                 $headers = \apache_request_headers();
    67                 if (isset($headers['If-Modified-Since'])) {
    68                     $modifiedSinceTime = \strtotime($headers['If-Modified-Since']);
    69                 }
    70                 if (isset($headers['If-None-Match'])) {
    71                     $noneMatch = $headers['If-None-Match'];
    72                 }
    73             }
    74             if ('' == $modifiedSinceTime && !\is_null($input->server->getString('HTTP_IF_MODIFIED_SINCE'))) {
    75                 $modifiedSinceTime = \strtotime($input->server->getString('HTTP_IF_MODIFIED_SINCE'));
    76             }
    77             if ('' == $noneMatch && !\is_null($input->server->getString('HTTP_IF_NONE_MATCH'))) {
    78                 $noneMatch = $input->server->getString('HTTP_IF_NONE_MATCH');
    79             }
    80             $etag = $results[0]['etag'];
    81             if ($modifiedSinceTime == \strtotime($timeMfile) || \trim($noneMatch) == $etag) {
    82                 // Client's cache IS current, so we just respond '304 Not Modified'.
    83                 \header('HTTP/1.1 304 Not Modified');
    84                 \header('Content-Length: 0');
    85 
    86                 return;
    87             }
    88             \header('Last-Modified: '.$timeMfile);
    89         }
    9059        $file = $results[0]['contents'];
    9160        // Return file if we're not outputting to browser
     
    9362            return $file;
    9463        }
     64        $aTimeMFile = self::RFC1123DateAdd($results[0]['filemtime'], '1 year');
     65        $timeMFile = $aTimeMFile['filemtime'].' GMT';
     66        $expiryDate = $aTimeMFile['expiry'].' GMT';
     67        $modifiedSinceTime = '';
     68        $noneMatch = '';
     69        if (\function_exists('apache_request_headers')) {
     70            $headers = \apache_request_headers();
     71            if (isset($headers['If-Modified-Since'])) {
     72                $modifiedSinceTime = \strtotime($headers['If-Modified-Since']);
     73            }
     74            if (isset($headers['If-None-Match'])) {
     75                $noneMatch = $headers['If-None-Match'];
     76            }
     77        }
     78        if ('' == $modifiedSinceTime && !\is_null($input->server->getString('HTTP_IF_MODIFIED_SINCE'))) {
     79            $modifiedSinceTime = \strtotime($input->server->getString('HTTP_IF_MODIFIED_SINCE'));
     80        }
     81        if ('' == $noneMatch && !\is_null($input->server->getString('HTTP_IF_NONE_MATCH'))) {
     82            $noneMatch = $input->server->getString('HTTP_IF_NONE_MATCH');
     83        }
     84        $etag = $results[0]['etag'];
     85        if ($modifiedSinceTime == \strtotime($timeMFile) || \trim($noneMatch) == $etag) {
     86            // Client's cache IS current, so we just respond '304 Not Modified'.
     87            \header('HTTP/1.1 304 Not Modified');
     88            \header('Content-Length: 0');
     89
     90            return;
     91        }
     92        \header('Last-Modified: '.$timeMFile);
     93
    9594        if ('css' == $vars['type']) {
    9695            \header('Content-type: text/css');
  • jch-optimize/trunk/lib/src/PageCache/PageCache.php

    r3007001 r3040365  
    1515use _JchOptimizeVendor\GuzzleHttp\Psr7\Uri;
    1616use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    17 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    1817use _JchOptimizeVendor\Joomla\Input\Input;
    1918use _JchOptimizeVendor\Laminas\Cache\Exception\ExceptionInterface;
     
    2423use _JchOptimizeVendor\Psr\Log\LoggerAwareInterface;
    2524use _JchOptimizeVendor\Psr\Log\LoggerAwareTrait;
     25use JchOptimize\Core\Container\ContainerAwareTrait;
    2626use JchOptimize\Core\Helper;
    2727use JchOptimize\Core\Laminas\Plugins\ClearExpiredByFactor;
     
    4848     * Cache id.
    4949     */
    50     protected string $cacheId;
     50    protected string $cacheId = '';
    5151
    5252    /**
     
    306306    }
    307307
    308     public function removeHtmlTag($html): ?string
     308    public function removeHtmlTag(string $html): ?string
    309309    {
    310310        $search = '#<!-- Cached by JCH Optimize on .*? GMT -->\\n#';
  • jch-optimize/trunk/lib/src/Service/CachingProvider.php

    r3007001 r3040365  
    139139    {
    140140        $params = $container->get(Registry::class);
    141         // Use whichever lifetime is greater to ensure page cache expires before
    142         $pageCacheTtl = (int) $params->get('page_cache_lifetime', '900');
    143         $globalTtl = (int) $params->get('cache_lifetime', '900');
    144         $lifetime = \max($pageCacheTtl, $globalTtl);
    145141        $cache = $this->getCacheAdapter($container, $container->get(Registry::class)->get('pro_cache_storage_adapter', 'filesystem'));
    146         $cache->getOptions()->setNamespace(Cache::getGlobalCacheNamespace())->setTtl($lifetime);
     142        $cache->getOptions()->setNamespace(Cache::getGlobalCacheNamespace())->setTtl((int) $params->get('cache_lifetime', '900'));
    147143        if ($cache instanceof PluginAwareInterface) {
    148144            if ($params->get('delete_expiry', '1')) {
  • jch-optimize/trunk/lib/src/Service/CoreProvider.php

    r2997317 r3040365  
    116116    }
    117117
     118    /**
     119     * @psalm-suppress InvalidArgument
     120     */
    118121    public function getCacheManagerService(Container $container): CacheManager
    119122    {
     
    156159    }
    157160
     161    /**
     162     * @psalm-suppress InvalidArgument
     163     */
    158164    public function getCombinerService(Container $container): Combiner
    159165    {
     
    182188    }
    183189
     190    /**
     191     * @psalm-suppress InvalidArgument
     192     */
    184193    public function getPageCacheService(Container $container): PageCache
    185194    {
     
    194203    }
    195204
     205    /**
     206     * @psalm-suppress InvalidArgument
     207     */
    196208    public function getCaptureCacheService(Container $container): CoreCaptureCache
    197209    {
  • jch-optimize/trunk/lib/src/StorageTaggingTrait.php

    r3007001 r3040365  
    1616use _JchOptimizeVendor\Psr\Http\Message\UriInterface;
    1717use JchOptimize\Core\PageCache\PageCache;
     18
     19use function md5;
    1820
    1921\defined('_JCH_EXEC') or exit('Restricted access');
     
    3638        $this->setStorageTags($id, $currentUrl);
    3739        // create an id for currentUrl and tag the cache ids saved on that page
    38         $tagPageId = \md5($currentUrl);
     40        // $tagPageId = md5($currentUrl);
    3941        // Record ids of all files used on this page
    40         $this->taggableCache->addItem($tagPageId, (string) $currentUrl);
    41         $this->setStorageTags($tagPageId, $id);
     42        // $this->taggableCache->addItem($tagPageId, (string)$currentUrl);
     43        // $this->setStorageTags($tagPageId, $id);
    4244    }
    4345
     
    4749        // If current tag not yet included, add it.
    4850        if (\is_array($tags) && !\in_array($tag, $tags)) {
    49             // Limit tags to the first 100
    50             if (\count($tags) < 100) {
    51                 $this->taggableCache->setTags($id, \array_merge($tags, [$tag]));
    52             }
     51            $this->taggableCache->setTags($id, \array_merge($tags, [$tag]));
    5352        } elseif (empty($tags)) {
    5453            $this->taggableCache->setTags($id, [$tag]);
  • jch-optimize/trunk/lib/src/Uri/UriComparator.php

    r2997317 r3040365  
    44 * JCH Optimize - Performs several front-end optimizations for fast downloads.
    55 *
    6  *  @author    Samuel Marshall <samuel@jch-optimize.net>
    7  *  @copyright Copyright (c) 2023 Samuel Marshall / JCH Optimize
    8  *  @license   GNU/GPLv3, or later. See LICENSE file
     6 * @author    Samuel Marshall <samuel@jch-optimize.net>
     7 * @copyright Copyright (c) 2023 Samuel Marshall / JCH Optimize
     8 * @license   GNU/GPLv3, or later. See LICENSE file
    99 *
    1010 *  If LICENSE file missing, see <http://www.gnu.org/licenses/>.
  • jch-optimize/trunk/lib/src/Uri/UriConverter.php

    r2997317 r3040365  
    1616use _JchOptimizeVendor\GuzzleHttp\Psr7\UriResolver;
    1717use _JchOptimizeVendor\Psr\Http\Message\UriInterface;
     18use JchOptimize\Core\Cdn;
    1819use JchOptimize\Core\SystemUri;
    1920use JchOptimize\Platform\Paths;
     
    2425    {
    2526        $resolvedUri = UriResolver::resolve(SystemUri::currentUri(), $uri);
    26         $path = \str_replace(\JchOptimize\Core\Uri\Utils::originDomains(), Paths::rootPath().'/', (string) $resolvedUri->withQuery('')->withFragment(''));
     27        $path = \str_replace(\JchOptimize\Core\Uri\Utils::originDomains(), Paths::basePath().'/', (string) $resolvedUri->withQuery('')->withFragment(''));
    2728        // convert all directory to unix style
    2829        return \strtr(\rawurldecode($path), '\\', '/');
     
    4041        return $uri->withScheme('')->withHost('')->withPort(null);
    4142    }
     43
     44    public static function filePathToUri(string|UriInterface $path, Cdn $cdn): UriInterface
     45    {
     46        $uri = \JchOptimize\Core\Uri\Utils::uriFor($path);
     47        $uri = $uri->withPath(SystemUri::basePath().\ltrim(\str_replace(Paths::basePath(), '', $uri->getPath()), '/\\'));
     48        $uri = UriResolver::resolve(SystemUri::currentUri(), $uri->withScheme(''));
     49
     50        return $cdn->loadCdnResource($uri);
     51    }
    4252}
  • jch-optimize/trunk/lib/src/Uri/Utils.php

    r2997317 r3040365  
    1717use _JchOptimizeVendor\GuzzleHttp\Psr7\Utils as GuzzleUtils;
    1818use _JchOptimizeVendor\Psr\Http\Message\UriInterface;
     19use InvalidArgumentException;
    1920use JchOptimize\ContainerFactory;
    2021use JchOptimize\Core\Cdn;
     
    4647     * received value, an '_invalidUri' string is returned,
    4748     * Use this whenever possible as Windows paths are converted to unix style so Uris can be created.
    48      *
    49      * @param string|UriInterface $uri
    5049     */
    51     public static function uriFor($uri): UriInterface
     50    public static function uriFor(UriInterface|string $uri): UriInterface
    5251    {
    5352        // convert Window directory to unix style
     
    5857        try {
    5958            return \JchOptimize\Core\Uri\UriNormalizer::normalize(GuzzleUtils::uriFor($uri));
    60         } catch (\InvalidArgumentException $e) {
     59        } catch (InvalidArgumentException) {
    6160            return new Uri('_invalidUri');
    6261        }
  • jch-optimize/trunk/lib/src/class_map.php

    r3007001 r3040365  
    2020use _JchOptimizeVendor\Joomla\DI\Container;
    2121use _JchOptimizeVendor\Joomla\DI\ContainerAwareInterface;
    22 use _JchOptimizeVendor\Joomla\DI\ContainerAwareTrait;
    2322use _JchOptimizeVendor\Joomla\DI\ServiceProviderInterface;
    2423use _JchOptimizeVendor\Joomla\Filesystem\File;
     
    5756if (!\interface_exists('\\JchOptimize\\Core\\Container\\ContainerAwareInterface', \false)) {
    5857    \class_alias(ContainerAwareInterface::class, '\\JchOptimize\\Core\\Container\\ContainerAwareInterface');
    59 }
    60 if (!\trait_exists('\\JchOptimize\\Core\\Container\\ContainerAwareTrait', \false)) {
    61     \class_alias(ContainerAwareTrait::class, '\\JchOptimize\\Core\\Container\\ContainerAwareTrait');
    6258}
    6359if (!\interface_exists('\\JchOptimize\\Core\\Container\\ServiceProviderInterface', \false)) {
  • jch-optimize/trunk/lib/vendor/composer/autoload_classmap.php

    r3007001 r3040365  
    2222    'JchOptimize\\Core\\Admin\\API\\MessageEventFactory' => $baseDir . '/src/Admin/API/MessageEventFactory.php',
    2323    'JchOptimize\\Core\\Admin\\API\\MessageEventInterface' => $baseDir . '/src/Admin/API/MessageEventInterface.php',
     24    'JchOptimize\\Core\\Admin\\API\\NullEventMessenger' => $baseDir . '/src/Admin/API/NullEventMessenger.php',
    2425    'JchOptimize\\Core\\Admin\\API\\ProcessImagesByFolders' => $baseDir . '/src/Admin/API/ProcessImagesByFolders.php',
    2526    'JchOptimize\\Core\\Admin\\API\\ProcessImagesByUrls' => $baseDir . '/src/Admin/API/ProcessImagesByUrls.php',
     
    4041    'JchOptimize\\Core\\Combiner' => $baseDir . '/src/Combiner.php',
    4142    'JchOptimize\\Core\\Container\\AbstractContainerFactory' => $baseDir . '/src/Container/AbstractContainerFactory.php',
     43    'JchOptimize\\Core\\Container\\ContainerAwareTrait' => $baseDir . '/src/Container/ContainerAwareTrait.php',
    4244    'JchOptimize\\Core\\Css\\Callbacks\\AbstractCallback' => $baseDir . '/src/Css/Callbacks/AbstractCallback.php',
    4345    'JchOptimize\\Core\\Css\\Callbacks\\CombineMediaQueries' => $baseDir . '/src/Css/Callbacks/CombineMediaQueries.php',
     
    6264    'JchOptimize\\Core\\Exception\\MissingDependencyException' => $baseDir . '/src/Exception/MissingDependencyException.php',
    6365    'JchOptimize\\Core\\Exception\\PregErrorException' => $baseDir . '/src/Exception/PregErrorException.php',
     66    'JchOptimize\\Core\\Exception\\PropertyNotFoundException' => $baseDir . '/src/Exception/PropertyNotFoundException.php',
    6467    'JchOptimize\\Core\\Exception\\RuntimeException' => $baseDir . '/src/Exception/RuntimeException.php',
    6568    'JchOptimize\\Core\\Exception\\StringableTrait' => $baseDir . '/src/Exception/StringableTrait.php',
     
    7275    'JchOptimize\\Core\\FeatureHelpers\\LazyLoadExtended' => $baseDir . '/src/FeatureHelpers/LazyLoadExtended.php',
    7376    'JchOptimize\\Core\\FeatureHelpers\\ReduceDom' => $baseDir . '/src/FeatureHelpers/ReduceDom.php',
     77    'JchOptimize\\Core\\FeatureHelpers\\ResponsiveImages' => $baseDir . '/src/FeatureHelpers/ResponsiveImages.php',
    7478    'JchOptimize\\Core\\FeatureHelpers\\Webp' => $baseDir . '/src/FeatureHelpers/Webp.php',
    7579    'JchOptimize\\Core\\FileInfosUtilsTrait' => $baseDir . '/src/FileInfosUtilsTrait.php',
  • jch-optimize/trunk/lib/vendor/composer/autoload_static.php

    r3007001 r3040365  
    285285        'JchOptimize\\Core\\Admin\\API\\MessageEventFactory' => __DIR__ . '/../..' . '/src/Admin/API/MessageEventFactory.php',
    286286        'JchOptimize\\Core\\Admin\\API\\MessageEventInterface' => __DIR__ . '/../..' . '/src/Admin/API/MessageEventInterface.php',
     287        'JchOptimize\\Core\\Admin\\API\\NullEventMessenger' => __DIR__ . '/../..' . '/src/Admin/API/NullEventMessenger.php',
    287288        'JchOptimize\\Core\\Admin\\API\\ProcessImagesByFolders' => __DIR__ . '/../..' . '/src/Admin/API/ProcessImagesByFolders.php',
    288289        'JchOptimize\\Core\\Admin\\API\\ProcessImagesByUrls' => __DIR__ . '/../..' . '/src/Admin/API/ProcessImagesByUrls.php',
     
    303304        'JchOptimize\\Core\\Combiner' => __DIR__ . '/../..' . '/src/Combiner.php',
    304305        'JchOptimize\\Core\\Container\\AbstractContainerFactory' => __DIR__ . '/../..' . '/src/Container/AbstractContainerFactory.php',
     306        'JchOptimize\\Core\\Container\\ContainerAwareTrait' => __DIR__ . '/../..' . '/src/Container/ContainerAwareTrait.php',
    305307        'JchOptimize\\Core\\Css\\Callbacks\\AbstractCallback' => __DIR__ . '/../..' . '/src/Css/Callbacks/AbstractCallback.php',
    306308        'JchOptimize\\Core\\Css\\Callbacks\\CombineMediaQueries' => __DIR__ . '/../..' . '/src/Css/Callbacks/CombineMediaQueries.php',
     
    325327        'JchOptimize\\Core\\Exception\\MissingDependencyException' => __DIR__ . '/../..' . '/src/Exception/MissingDependencyException.php',
    326328        'JchOptimize\\Core\\Exception\\PregErrorException' => __DIR__ . '/../..' . '/src/Exception/PregErrorException.php',
     329        'JchOptimize\\Core\\Exception\\PropertyNotFoundException' => __DIR__ . '/../..' . '/src/Exception/PropertyNotFoundException.php',
    327330        'JchOptimize\\Core\\Exception\\RuntimeException' => __DIR__ . '/../..' . '/src/Exception/RuntimeException.php',
    328331        'JchOptimize\\Core\\Exception\\StringableTrait' => __DIR__ . '/../..' . '/src/Exception/StringableTrait.php',
     
    335338        'JchOptimize\\Core\\FeatureHelpers\\LazyLoadExtended' => __DIR__ . '/../..' . '/src/FeatureHelpers/LazyLoadExtended.php',
    336339        'JchOptimize\\Core\\FeatureHelpers\\ReduceDom' => __DIR__ . '/../..' . '/src/FeatureHelpers/ReduceDom.php',
     340        'JchOptimize\\Core\\FeatureHelpers\\ResponsiveImages' => __DIR__ . '/../..' . '/src/FeatureHelpers/ResponsiveImages.php',
    337341        'JchOptimize\\Core\\FeatureHelpers\\Webp' => __DIR__ . '/../..' . '/src/FeatureHelpers/Webp.php',
    338342        'JchOptimize\\Core\\FileInfosUtilsTrait' => __DIR__ . '/../..' . '/src/FileInfosUtilsTrait.php',
  • jch-optimize/trunk/lib/vendor/composer/installed.php

    r3007001 r3040365  
    33namespace _JchOptimizeVendor;
    44
    5 return array('root' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'reference' => 'de0f05ea1fea90b0cae6c3abfdf52f3d1180cca3', 'name' => 'jchoptimize/lib', 'dev' => \false), 'versions' => array('codealfa/minify' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../codealfa/minify', 'aliases' => array(0 => '9999999-dev'), 'reference' => 'a11d3fc4da27e170ca8cb9f966915ff9cfdc519d', 'dev_requirement' => \false), 'codealfa/regextokenizer' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../codealfa/regextokenizer', 'aliases' => array(0 => '9999999-dev'), 'reference' => 'b660bf5d561078f40bcbf1a68eeb63428a14b17d', 'dev_requirement' => \false), 'composer/ca-bundle' => array('pretty_version' => 'dev-main', 'version' => 'dev-main', 'type' => 'library', 'install_path' => __DIR__ . '/./ca-bundle', 'aliases' => array(0 => '1.x-dev'), 'reference' => '4d0ae9807cf38e759b6f10b09195b3addd7d8685', 'dev_requirement' => \false), 'container-interop/container-interop' => array('dev_requirement' => \false, 'replaced' => array(0 => '^1.2.0')), 'guzzlehttp/guzzle' => array('pretty_version' => '7.5.x-dev', 'version' => '7.5.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/guzzle', 'aliases' => array(), 'reference' => '584d1f06b5caa07b0587f5054d551ed65460ce5d', 'dev_requirement' => \false), 'guzzlehttp/promises' => array('pretty_version' => '1.5.x-dev', 'version' => '1.5.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/promises', 'aliases' => array(), 'reference' => '67ab6e18aaa14d753cc148911d273f6e6cb6721e', 'dev_requirement' => \false), 'guzzlehttp/psr7' => array('pretty_version' => '1.9.x-dev', 'version' => '1.9.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/psr7', 'aliases' => array(), 'reference' => 'e4490cabc77465aaee90b20cfc9a770f8c04be6b', 'dev_requirement' => \false), 'illuminate/collections' => array('pretty_version' => '8.x-dev', 'version' => '8.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../illuminate/collections', 'aliases' => array(), 'reference' => '705a4e1ef93cd492c45b9b3e7911cccc990a07f4', 'dev_requirement' => \false), 'illuminate/contracts' => array('pretty_version' => '8.x-dev', 'version' => '8.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../illuminate/contracts', 'aliases' => array(), 'reference' => '5e0fd287a1b22a6b346a9f7cd484d8cf0234585d', 'dev_requirement' => \false), 'illuminate/macroable' => array('pretty_version' => '8.x-dev', 'version' => '8.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../illuminate/macroable', 'aliases' => array(), 'reference' => 'aed81891a6e046fdee72edd497f822190f61c162', 'dev_requirement' => \false), 'intervention/image' => array('pretty_version' => '2.7.2', 'version' => '2.7.2.0', 'type' => 'library', 'install_path' => __DIR__ . '/../intervention/image', 'aliases' => array(), 'reference' => '04be355f8d6734c826045d02a1079ad658322dad', 'dev_requirement' => \false), 'jchoptimize/lib' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'reference' => 'de0f05ea1fea90b0cae6c3abfdf52f3d1180cca3', 'dev_requirement' => \false), 'joomla/controller' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/controller', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => '6a5a386246f6e67ab0c3a4e71d27f0f208720b65', 'dev_requirement' => \false), 'joomla/di' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/di', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => 'b68f8de6c3a214eac22c2172f966d8965fd47f9c', 'dev_requirement' => \false), 'joomla/filesystem' => array('pretty_version' => 'dev-1.x-dev', 'version' => 'dev-1.x-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/filesystem', 'aliases' => array(), 'reference' => '9ad5d9b64960f0ea56fb71364a33622843b95c27', 'dev_requirement' => \false), 'joomla/filter' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/filter', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => '9102630f9069351c1259b6f585a704fde7029d2a', 'dev_requirement' => \false), 'joomla/input' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/input', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => '80d2b6384d60307a11b9af39bdc9a8d254949e94', 'dev_requirement' => \false), 'joomla/model' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/model', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => 'f322645993346efa5505500f59d6471cbd0d564b', 'dev_requirement' => \false), 'joomla/registry' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/registry', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => 'fde95733e7e2634d64bff71f611ee02b9ceff354', 'dev_requirement' => \false), 'joomla/renderer' => array('pretty_version' => '2.0.1', 'version' => '2.0.1.0', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/renderer', 'aliases' => array(), 'reference' => '0b514c40d3858fbbbf3bf3347832bc4fc3e776da', 'dev_requirement' => \false), 'joomla/string' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/string', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => 'c7a9330f7316a574f3ff538053fa65dc38bafbe6', 'dev_requirement' => \false), 'joomla/utilities' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/utilities', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => '2baa8af18fd2ee5a185606b91ab2e273f77e5e4b', 'dev_requirement' => \false), 'joomla/view' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/view', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => '7d5e706b29cac01d0b1ee11b871eabaa823f9063', 'dev_requirement' => \false), 'laminas/laminas-cache' => array('pretty_version' => '3.0.x-dev', 'version' => '3.0.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache', 'aliases' => array(), 'reference' => '86b47eb7b05bc4d24edafb3039494ba81405983b', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-adapter-apcu' => array('pretty_version' => '2.1.x-dev', 'version' => '2.1.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache-storage-adapter-apcu', 'aliases' => array(), 'reference' => '344aa69ff029788bd340a3bda63754d24623bd85', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-adapter-blackhole' => array('pretty_version' => '2.0.x-dev', 'version' => '2.0.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache-storage-adapter-blackhole', 'aliases' => array(), 'reference' => 'fdb6c4b9813cc7365d72c002b09dc808e34b7002', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-adapter-filesystem' => array('pretty_version' => '2.1.x-dev', 'version' => '2.1.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache-storage-adapter-filesystem', 'aliases' => array(), 'reference' => 'd9712a8292fc0a84219e4aba97b6b04b95057cb6', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-adapter-memcached' => array('pretty_version' => '2.1.x-dev', 'version' => '2.1.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache-storage-adapter-memcached', 'aliases' => array(), 'reference' => '5d6795281f388842ed96acbfc3f8659d0742282f', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-adapter-redis' => array('pretty_version' => '2.1.x-dev', 'version' => '2.1.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache-storage-adapter-redis', 'aliases' => array(), 'reference' => '289717d10a89755d3f36f799565a3fb9c7e9ab24', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0')), 'laminas/laminas-eventmanager' => array('pretty_version' => '3.11.x-dev', 'version' => '3.11.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-eventmanager', 'aliases' => array(), 'reference' => '9cfa79ce247c567f05ce4b7c975c6bdf9698c5dd', 'dev_requirement' => \false), 'laminas/laminas-json' => array('pretty_version' => '3.5.x-dev', 'version' => '3.5.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-json', 'aliases' => array(), 'reference' => '7a8a1d7bf2d05dd6c1fbd7c0868d3848cf2b57ec', 'dev_requirement' => \false), 'laminas/laminas-log' => array('pretty_version' => '2.14.x-dev', 'version' => '2.14.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-log', 'aliases' => array(), 'reference' => '39f3dcbd77fd0d84b190ff1332f5d3d28d56527e', 'dev_requirement' => \false), 'laminas/laminas-paginator' => array('pretty_version' => '2.11.x-dev', 'version' => '2.11.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-paginator', 'aliases' => array(), 'reference' => '7f00d5fdecd1b4f67c8e84e6f6d57bbabda4b7d8', 'dev_requirement' => \false), 'laminas/laminas-serializer' => array('pretty_version' => '2.12.x-dev', 'version' => '2.12.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-serializer', 'aliases' => array(), 'reference' => '2826fd71f202569c169456a4b84297da9ff630cd', 'dev_requirement' => \false), 'laminas/laminas-servicemanager' => array('pretty_version' => '3.20.x-dev', 'version' => '3.20.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-servicemanager', 'aliases' => array(), 'reference' => 'bc2c2cbe2dd90db8b9d16b0618f542692b76ab59', 'dev_requirement' => \false), 'laminas/laminas-stdlib' => array('pretty_version' => '3.16.x-dev', 'version' => '3.16.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-stdlib', 'aliases' => array(), 'reference' => 'f4f773641807c7ccee59b758bfe4ac4ba33ecb17', 'dev_requirement' => \false), 'league/flysystem' => array('pretty_version' => '2.x-dev', 'version' => '2.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../league/flysystem', 'aliases' => array(), 'reference' => '8aaffb653c5777781b0f7f69a5d937baf7ab6cdb', 'dev_requirement' => \false), 'league/glide' => array('pretty_version' => '2.3.0', 'version' => '2.3.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../league/glide', 'aliases' => array(), 'reference' => '2ff92c8f1edc80b74e2d3c5efccfc7223f74d407', 'dev_requirement' => \false), 'league/mime-type-detection' => array('pretty_version' => '1.14.0', 'version' => '1.14.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../league/mime-type-detection', 'aliases' => array(), 'reference' => 'b6a5854368533df0295c5761a0253656a2e52d9e', 'dev_requirement' => \false), 'nicmart/tree' => array('pretty_version' => '0.3.1', 'version' => '0.3.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../nicmart/tree', 'aliases' => array(), 'reference' => 'c55ba47c64a3cb7454c22e6d630729fc2aab23ff', 'dev_requirement' => \false), 'paragi/php-websocket-client' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../paragi/php-websocket-client', 'aliases' => array(0 => '9999999-dev'), 'reference' => 'a40a6bf0525a1e76950d19b41201ccccb80bf9cd', 'dev_requirement' => \false), 'psr/cache' => array('pretty_version' => '1.0.1', 'version' => '1.0.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/cache', 'aliases' => array(), 'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8', 'dev_requirement' => \false), 'psr/cache-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0')), 'psr/container' => array('pretty_version' => '1.x-dev', 'version' => '1.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/container', 'aliases' => array(), 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', 'dev_requirement' => \false), 'psr/container-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '~1.0', 1 => '^1.0')), 'psr/http-client' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-client', 'aliases' => array(0 => '1.0.x-dev'), 'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90', 'dev_requirement' => \false), 'psr/http-client-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0')), 'psr/http-message' => array('pretty_version' => '1.1', 'version' => '1.1.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-message', 'aliases' => array(), 'reference' => 'cb6ce4845ce34a8ad9e68117c10ee90a29919eba', 'dev_requirement' => \false), 'psr/http-message-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0')), 'psr/log' => array('pretty_version' => '1.1.4', 'version' => '1.1.4.0', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/log', 'aliases' => array(), 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11', 'dev_requirement' => \false), 'psr/log-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0.0')), 'psr/simple-cache' => array('pretty_version' => '1.0.1', 'version' => '1.0.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/simple-cache', 'aliases' => array(), 'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b', 'dev_requirement' => \false), 'psr/simple-cache-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0')), 'ralouphie/getallheaders' => array('pretty_version' => '3.0.3', 'version' => '3.0.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../ralouphie/getallheaders', 'aliases' => array(), 'reference' => '120b605dfeb996808c31b6477290a714d356e822', 'dev_requirement' => \false), 'slim/php-view' => array('pretty_version' => 'dev-joomla', 'version' => 'dev-joomla', 'type' => 'library', 'install_path' => __DIR__ . '/../slim/php-view', 'aliases' => array(), 'reference' => 'ab25024a44b3c65a4c2a9968ce283233b490fcb9', 'dev_requirement' => \false), 'spatie/browsershot' => array('pretty_version' => '3.60.1', 'version' => '3.60.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/browsershot', 'aliases' => array(), 'reference' => '8779b2cd10dcd9dab4abd0127429e5578da3f9ab', 'dev_requirement' => \false), 'spatie/crawler' => array('pretty_version' => 'v6.x-dev', 'version' => '6.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/crawler', 'aliases' => array(), 'reference' => '276ecb429a770474695a1278a9ad3e719fbef259', 'dev_requirement' => \false), 'spatie/image' => array('pretty_version' => '2.2.7', 'version' => '2.2.7.0', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/image', 'aliases' => array(), 'reference' => '2f802853aab017aa615224daae1588054b5ab20e', 'dev_requirement' => \false), 'spatie/image-optimizer' => array('pretty_version' => '1.7.2', 'version' => '1.7.2.0', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/image-optimizer', 'aliases' => array(), 'reference' => '62f7463483d1bd975f6f06025d89d42a29608fe1', 'dev_requirement' => \false), 'spatie/robots-txt' => array('pretty_version' => '2.0.3', 'version' => '2.0.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/robots-txt', 'aliases' => array(), 'reference' => 'dacba2ba159364987392aa1b0002e196c5923970', 'dev_requirement' => \false), 'spatie/temporary-directory' => array('pretty_version' => '2.2.0', 'version' => '2.2.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/temporary-directory', 'aliases' => array(), 'reference' => 'efc258c9f4da28f0c7661765b8393e4ccee3d19c', 'dev_requirement' => \false), 'symfony/deprecation-contracts' => array('pretty_version' => '2.5.x-dev', 'version' => '2.5.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(), 'reference' => '80d075412b557d41002320b96a096ca65aa2c98d', 'dev_requirement' => \false), 'symfony/dom-crawler' => array('pretty_version' => '5.4.x-dev', 'version' => '5.4.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/dom-crawler', 'aliases' => array(), 'reference' => '728f1fc136252a626ba5a69c02bd66a3697ff201', 'dev_requirement' => \false), 'symfony/polyfill-ctype' => array('pretty_version' => '1.x-dev', 'version' => '1.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), 'reference' => 'ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb', 'dev_requirement' => \false), 'symfony/polyfill-mbstring' => array('pretty_version' => '1.x-dev', 'version' => '1.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), 'reference' => '42292d99c55abe617799667f454222c54c60e229', 'dev_requirement' => \false), 'symfony/polyfill-php80' => array('pretty_version' => '1.x-dev', 'version' => '1.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'aliases' => array(), 'reference' => '6caa57379c4aec19c0a12a38b59b26487dcfe4b5', 'dev_requirement' => \false), 'symfony/process' => array('pretty_version' => '5.4.x-dev', 'version' => '5.4.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/process', 'aliases' => array(), 'reference' => '8fa22178dfc368911dbd513b431cd9b06f9afe7a', 'dev_requirement' => \false), 'webmozart/assert' => array('pretty_version' => '1.11.0', 'version' => '1.11.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../webmozart/assert', 'aliases' => array(), 'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991', 'dev_requirement' => \false)));
     5return array('root' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'reference' => '857797bdb745daf47b8f4e5410bcdc902b7b7341', 'name' => 'jchoptimize/lib', 'dev' => \false), 'versions' => array('codealfa/minify' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../codealfa/minify', 'aliases' => array(0 => '9999999-dev'), 'reference' => 'a11d3fc4da27e170ca8cb9f966915ff9cfdc519d', 'dev_requirement' => \false), 'codealfa/regextokenizer' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../codealfa/regextokenizer', 'aliases' => array(0 => '9999999-dev'), 'reference' => 'b660bf5d561078f40bcbf1a68eeb63428a14b17d', 'dev_requirement' => \false), 'composer/ca-bundle' => array('pretty_version' => 'dev-main', 'version' => 'dev-main', 'type' => 'library', 'install_path' => __DIR__ . '/./ca-bundle', 'aliases' => array(0 => '1.x-dev'), 'reference' => '4d0ae9807cf38e759b6f10b09195b3addd7d8685', 'dev_requirement' => \false), 'container-interop/container-interop' => array('dev_requirement' => \false, 'replaced' => array(0 => '^1.2.0')), 'guzzlehttp/guzzle' => array('pretty_version' => '7.5.x-dev', 'version' => '7.5.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/guzzle', 'aliases' => array(), 'reference' => '584d1f06b5caa07b0587f5054d551ed65460ce5d', 'dev_requirement' => \false), 'guzzlehttp/promises' => array('pretty_version' => '1.5.x-dev', 'version' => '1.5.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/promises', 'aliases' => array(), 'reference' => '67ab6e18aaa14d753cc148911d273f6e6cb6721e', 'dev_requirement' => \false), 'guzzlehttp/psr7' => array('pretty_version' => '1.9.x-dev', 'version' => '1.9.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/psr7', 'aliases' => array(), 'reference' => 'e4490cabc77465aaee90b20cfc9a770f8c04be6b', 'dev_requirement' => \false), 'illuminate/collections' => array('pretty_version' => '8.x-dev', 'version' => '8.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../illuminate/collections', 'aliases' => array(), 'reference' => '705a4e1ef93cd492c45b9b3e7911cccc990a07f4', 'dev_requirement' => \false), 'illuminate/contracts' => array('pretty_version' => '8.x-dev', 'version' => '8.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../illuminate/contracts', 'aliases' => array(), 'reference' => '5e0fd287a1b22a6b346a9f7cd484d8cf0234585d', 'dev_requirement' => \false), 'illuminate/macroable' => array('pretty_version' => '8.x-dev', 'version' => '8.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../illuminate/macroable', 'aliases' => array(), 'reference' => 'aed81891a6e046fdee72edd497f822190f61c162', 'dev_requirement' => \false), 'intervention/image' => array('pretty_version' => '2.7.2', 'version' => '2.7.2.0', 'type' => 'library', 'install_path' => __DIR__ . '/../intervention/image', 'aliases' => array(), 'reference' => '04be355f8d6734c826045d02a1079ad658322dad', 'dev_requirement' => \false), 'jchoptimize/lib' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'reference' => '857797bdb745daf47b8f4e5410bcdc902b7b7341', 'dev_requirement' => \false), 'joomla/controller' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/controller', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => '6a5a386246f6e67ab0c3a4e71d27f0f208720b65', 'dev_requirement' => \false), 'joomla/di' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/di', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => 'b68f8de6c3a214eac22c2172f966d8965fd47f9c', 'dev_requirement' => \false), 'joomla/filesystem' => array('pretty_version' => 'dev-1.x-dev', 'version' => 'dev-1.x-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/filesystem', 'aliases' => array(), 'reference' => '9ad5d9b64960f0ea56fb71364a33622843b95c27', 'dev_requirement' => \false), 'joomla/filter' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/filter', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => '9102630f9069351c1259b6f585a704fde7029d2a', 'dev_requirement' => \false), 'joomla/input' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/input', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => '80d2b6384d60307a11b9af39bdc9a8d254949e94', 'dev_requirement' => \false), 'joomla/model' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/model', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => 'f322645993346efa5505500f59d6471cbd0d564b', 'dev_requirement' => \false), 'joomla/registry' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/registry', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => 'fde95733e7e2634d64bff71f611ee02b9ceff354', 'dev_requirement' => \false), 'joomla/renderer' => array('pretty_version' => '2.0.1', 'version' => '2.0.1.0', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/renderer', 'aliases' => array(), 'reference' => '0b514c40d3858fbbbf3bf3347832bc4fc3e776da', 'dev_requirement' => \false), 'joomla/string' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/string', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => 'c7a9330f7316a574f3ff538053fa65dc38bafbe6', 'dev_requirement' => \false), 'joomla/utilities' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/utilities', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => '2baa8af18fd2ee5a185606b91ab2e273f77e5e4b', 'dev_requirement' => \false), 'joomla/view' => array('pretty_version' => 'dev-2.0-dev', 'version' => 'dev-2.0-dev', 'type' => 'joomla-package', 'install_path' => __DIR__ . '/../joomla/view', 'aliases' => array(0 => '2.0.x-dev'), 'reference' => '7d5e706b29cac01d0b1ee11b871eabaa823f9063', 'dev_requirement' => \false), 'laminas/laminas-cache' => array('pretty_version' => '3.0.x-dev', 'version' => '3.0.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache', 'aliases' => array(), 'reference' => '86b47eb7b05bc4d24edafb3039494ba81405983b', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-adapter-apcu' => array('pretty_version' => '2.1.x-dev', 'version' => '2.1.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache-storage-adapter-apcu', 'aliases' => array(), 'reference' => '344aa69ff029788bd340a3bda63754d24623bd85', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-adapter-blackhole' => array('pretty_version' => '2.0.x-dev', 'version' => '2.0.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache-storage-adapter-blackhole', 'aliases' => array(), 'reference' => 'fdb6c4b9813cc7365d72c002b09dc808e34b7002', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-adapter-filesystem' => array('pretty_version' => '2.1.x-dev', 'version' => '2.1.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache-storage-adapter-filesystem', 'aliases' => array(), 'reference' => 'd9712a8292fc0a84219e4aba97b6b04b95057cb6', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-adapter-memcached' => array('pretty_version' => '2.1.x-dev', 'version' => '2.1.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache-storage-adapter-memcached', 'aliases' => array(), 'reference' => '5d6795281f388842ed96acbfc3f8659d0742282f', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-adapter-redis' => array('pretty_version' => '2.1.x-dev', 'version' => '2.1.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-cache-storage-adapter-redis', 'aliases' => array(), 'reference' => '289717d10a89755d3f36f799565a3fb9c7e9ab24', 'dev_requirement' => \false), 'laminas/laminas-cache-storage-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0')), 'laminas/laminas-eventmanager' => array('pretty_version' => '3.11.x-dev', 'version' => '3.11.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-eventmanager', 'aliases' => array(), 'reference' => '9cfa79ce247c567f05ce4b7c975c6bdf9698c5dd', 'dev_requirement' => \false), 'laminas/laminas-json' => array('pretty_version' => '3.5.x-dev', 'version' => '3.5.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-json', 'aliases' => array(), 'reference' => '7a8a1d7bf2d05dd6c1fbd7c0868d3848cf2b57ec', 'dev_requirement' => \false), 'laminas/laminas-log' => array('pretty_version' => '2.14.x-dev', 'version' => '2.14.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-log', 'aliases' => array(), 'reference' => '39f3dcbd77fd0d84b190ff1332f5d3d28d56527e', 'dev_requirement' => \false), 'laminas/laminas-paginator' => array('pretty_version' => '2.11.x-dev', 'version' => '2.11.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-paginator', 'aliases' => array(), 'reference' => '7f00d5fdecd1b4f67c8e84e6f6d57bbabda4b7d8', 'dev_requirement' => \false), 'laminas/laminas-serializer' => array('pretty_version' => '2.12.x-dev', 'version' => '2.12.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-serializer', 'aliases' => array(), 'reference' => '2826fd71f202569c169456a4b84297da9ff630cd', 'dev_requirement' => \false), 'laminas/laminas-servicemanager' => array('pretty_version' => '3.20.x-dev', 'version' => '3.20.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-servicemanager', 'aliases' => array(), 'reference' => 'bc2c2cbe2dd90db8b9d16b0618f542692b76ab59', 'dev_requirement' => \false), 'laminas/laminas-stdlib' => array('pretty_version' => '3.16.x-dev', 'version' => '3.16.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-stdlib', 'aliases' => array(), 'reference' => 'f4f773641807c7ccee59b758bfe4ac4ba33ecb17', 'dev_requirement' => \false), 'league/flysystem' => array('pretty_version' => '2.x-dev', 'version' => '2.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../league/flysystem', 'aliases' => array(), 'reference' => '8aaffb653c5777781b0f7f69a5d937baf7ab6cdb', 'dev_requirement' => \false), 'league/glide' => array('pretty_version' => '2.3.0', 'version' => '2.3.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../league/glide', 'aliases' => array(), 'reference' => '2ff92c8f1edc80b74e2d3c5efccfc7223f74d407', 'dev_requirement' => \false), 'league/mime-type-detection' => array('pretty_version' => '1.14.0', 'version' => '1.14.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../league/mime-type-detection', 'aliases' => array(), 'reference' => 'b6a5854368533df0295c5761a0253656a2e52d9e', 'dev_requirement' => \false), 'nicmart/tree' => array('pretty_version' => '0.3.1', 'version' => '0.3.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../nicmart/tree', 'aliases' => array(), 'reference' => 'c55ba47c64a3cb7454c22e6d630729fc2aab23ff', 'dev_requirement' => \false), 'paragi/php-websocket-client' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../paragi/php-websocket-client', 'aliases' => array(0 => '9999999-dev'), 'reference' => 'a40a6bf0525a1e76950d19b41201ccccb80bf9cd', 'dev_requirement' => \false), 'psr/cache' => array('pretty_version' => '1.0.1', 'version' => '1.0.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/cache', 'aliases' => array(), 'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8', 'dev_requirement' => \false), 'psr/cache-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0')), 'psr/container' => array('pretty_version' => '1.x-dev', 'version' => '1.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/container', 'aliases' => array(), 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', 'dev_requirement' => \false), 'psr/container-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '~1.0', 1 => '^1.0')), 'psr/http-client' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-client', 'aliases' => array(0 => '1.0.x-dev'), 'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90', 'dev_requirement' => \false), 'psr/http-client-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0')), 'psr/http-message' => array('pretty_version' => '1.1', 'version' => '1.1.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/http-message', 'aliases' => array(), 'reference' => 'cb6ce4845ce34a8ad9e68117c10ee90a29919eba', 'dev_requirement' => \false), 'psr/http-message-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0')), 'psr/log' => array('pretty_version' => '1.1.4', 'version' => '1.1.4.0', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/log', 'aliases' => array(), 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11', 'dev_requirement' => \false), 'psr/log-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0.0')), 'psr/simple-cache' => array('pretty_version' => '1.0.1', 'version' => '1.0.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/simple-cache', 'aliases' => array(), 'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b', 'dev_requirement' => \false), 'psr/simple-cache-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0')), 'ralouphie/getallheaders' => array('pretty_version' => '3.0.3', 'version' => '3.0.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../ralouphie/getallheaders', 'aliases' => array(), 'reference' => '120b605dfeb996808c31b6477290a714d356e822', 'dev_requirement' => \false), 'slim/php-view' => array('pretty_version' => 'dev-joomla', 'version' => 'dev-joomla', 'type' => 'library', 'install_path' => __DIR__ . '/../slim/php-view', 'aliases' => array(), 'reference' => 'ab25024a44b3c65a4c2a9968ce283233b490fcb9', 'dev_requirement' => \false), 'spatie/browsershot' => array('pretty_version' => '3.60.1', 'version' => '3.60.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/browsershot', 'aliases' => array(), 'reference' => '8779b2cd10dcd9dab4abd0127429e5578da3f9ab', 'dev_requirement' => \false), 'spatie/crawler' => array('pretty_version' => 'v6.x-dev', 'version' => '6.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/crawler', 'aliases' => array(), 'reference' => '276ecb429a770474695a1278a9ad3e719fbef259', 'dev_requirement' => \false), 'spatie/image' => array('pretty_version' => '2.2.7', 'version' => '2.2.7.0', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/image', 'aliases' => array(), 'reference' => '2f802853aab017aa615224daae1588054b5ab20e', 'dev_requirement' => \false), 'spatie/image-optimizer' => array('pretty_version' => '1.7.2', 'version' => '1.7.2.0', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/image-optimizer', 'aliases' => array(), 'reference' => '62f7463483d1bd975f6f06025d89d42a29608fe1', 'dev_requirement' => \false), 'spatie/robots-txt' => array('pretty_version' => '2.0.3', 'version' => '2.0.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/robots-txt', 'aliases' => array(), 'reference' => 'dacba2ba159364987392aa1b0002e196c5923970', 'dev_requirement' => \false), 'spatie/temporary-directory' => array('pretty_version' => '2.2.0', 'version' => '2.2.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../spatie/temporary-directory', 'aliases' => array(), 'reference' => 'efc258c9f4da28f0c7661765b8393e4ccee3d19c', 'dev_requirement' => \false), 'symfony/deprecation-contracts' => array('pretty_version' => '2.5.x-dev', 'version' => '2.5.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(), 'reference' => '80d075412b557d41002320b96a096ca65aa2c98d', 'dev_requirement' => \false), 'symfony/dom-crawler' => array('pretty_version' => '5.4.x-dev', 'version' => '5.4.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/dom-crawler', 'aliases' => array(), 'reference' => '728f1fc136252a626ba5a69c02bd66a3697ff201', 'dev_requirement' => \false), 'symfony/polyfill-ctype' => array('pretty_version' => '1.x-dev', 'version' => '1.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), 'reference' => 'ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb', 'dev_requirement' => \false), 'symfony/polyfill-mbstring' => array('pretty_version' => '1.x-dev', 'version' => '1.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), 'reference' => '42292d99c55abe617799667f454222c54c60e229', 'dev_requirement' => \false), 'symfony/polyfill-php80' => array('pretty_version' => '1.x-dev', 'version' => '1.9999999.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'aliases' => array(), 'reference' => '6caa57379c4aec19c0a12a38b59b26487dcfe4b5', 'dev_requirement' => \false), 'symfony/process' => array('pretty_version' => '5.4.x-dev', 'version' => '5.4.9999999.9999999-dev', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/process', 'aliases' => array(), 'reference' => '8fa22178dfc368911dbd513b431cd9b06f9afe7a', 'dev_requirement' => \false), 'webmozart/assert' => array('pretty_version' => '1.11.0', 'version' => '1.11.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../webmozart/assert', 'aliases' => array(), 'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991', 'dev_requirement' => \false)));
  • jch-optimize/trunk/lib/vendor/symfony/polyfill-mbstring/bootstrap.php

    r3007001 r3040365  
    245245    }
    246246}
    247 if (!\function_exists('_JchOptimizeVendor\\mb_str_pad')) {
     247if (!\function_exists('mb_str_pad')) {
    248248    function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null) : string
    249249    {
  • jch-optimize/trunk/lib/vendor/symfony/polyfill-mbstring/bootstrap80.php

    r3007001 r3040365  
    242242    }
    243243}
    244 if (!\function_exists('_JchOptimizeVendor\\mb_str_pad')) {
     244if (!\function_exists('mb_str_pad')) {
    245245    function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null) : string
    246246    {
  • jch-optimize/trunk/media/filetree/jquery.filetree.css

    r2748708 r3040365  
    271271}
    272272
     273.jqueryFileTree LI.ext_webp {
     274    background: url(images/picture.png) left 2px no-repeat;
     275}
     276
    273277.jqueryFileTree LI.ext_wmv {
    274278    background: url(images/film.png) left top no-repeat;
  • jch-optimize/trunk/readme.txt

    r3007001 r3040365  
    33Contributors: codealfa
    44Tags: performance, pagespeed, cache, optimize, seo
    5 Tested up to: 6.4.2
    6 Stable tag: 4.1.1
     5Tested up to: 6.4.3
     6Stable tag: 4.2.0
    77License: GPLv3 or later
    88Requires at least: 5.0
     
    8080
    8181== Changelog ==
     82= 4.2.0 =
     83* Add responsive image feature to further boost LCP
     84* Add support for resizing WEBP images to create responsive images
     85* Bug Fix: Backup images were only saved when WEBP images were generated
     86* Bug Fix: Fix fatal error on servers without mbstring support
     87
    8288= 4.1.1 =
    8389* Removed support for deprecated Wincache storage.
  • jch-optimize/trunk/src/Html/Helper.php

    r2997317 r3040365  
    171171    /**
    172172     * @param   array<string|int, string>  $options
    173      * @param   string|null  $activeValue
    174      * @param   array  $conditions
     173     * @param   string|null                $activeValue
     174     * @param   array                      $conditions
    175175     *
    176176     * @return string
     
    394394
    395395    /**
    396      * @param   string  $settingName
    397      * @param   array   $activeValues
    398      * @param   array<string, string>   $options
    399      * @param   string  $class
     396     * @param   string                 $settingName
     397     * @param   array                  $activeValues
     398     * @param   array<string, string>  $options
     399     * @param   string                 $class
    400400     */
    401401    public static function checkboxes(
     
    430430        <?php
    431431    }
     432
     433    public static function textarea(string $settingName, $activeValues): void
     434    {
     435        ?>
     436        <textarea name="<?= "jch-optimize_settings[{$settingName}]"; ?>" cols="35" rows="3">
     437        <?= $activeValues ?>
     438        </textarea>
     439        <?php
     440    }
    432441}
  • jch-optimize/trunk/src/Html/Renderer/Section.php

    r2997317 r3040365  
    108108    }
    109109
     110    public static function customCssSection(): void
     111    {
     112        $title = __('Custom CSS', 'jch-optimize');
     113        $description = __(
     114            'This section is for adding CSS to correct Cumulative Layout Shift (CLS) issues caused by the page shifting around because the space wasn\'t allocated to accomodate the HTML elements rendering, such as some slideshows. The appropriate media queries will be generated for mobile and/or desktop, so you\'ll only need to add simple CSS declarations for e.g., #slideshow-container {min-height: 300px;}',
     115            'jch-optimize'
     116        );
     117
     118        echo TabContent::addSection($title, $description);
     119    }
     120
    110121    public static function optimizeCssDeliverySection(): void
    111122    {
     
    248259    {
    249260        $title = __('Preconnect Third-party Origins', 'jch-optimize');
    250         $description = __('Reduce the impact of third-party code by establising early connections with the external origins. The origin is the part of the URL containing the scheme, hostname, and port. The plugin will add preconnects to the top of the page to reduce performance impacts of thrid-party providers. CDNs and third-party origins in CSS files can be automatically detected, but you may need to manually add preconnect for scripts in the main thread.');
     261        $description = __(
     262            'Reduce the impact of third-party code by establising early connections with the external origins. The origin is the part of the URL containing the scheme, hostname, and port. The plugin will add preconnects to the top of the page to reduce performance impacts of thrid-party providers. CDNs and third-party origins in CSS files can be automatically detected, but you may need to manually add preconnect for scripts in the main thread.'
     263        );
    251264
    252265        echo TabContent::addSection($title, $description);
  • jch-optimize/trunk/src/Html/Renderer/Setting.php

    r3007001 r3040365  
    271271
    272272    /*
     273     Custom CSS section
     274     */
     275    public static function mobile_css(): void
     276    {
     277        Helper::_('textarea', __FUNCTION__, '');
     278    }
     279
     280    public static function desktop_css(): void
     281    {
     282        Helper::_('textarea', __FUNCTION__, '');
     283    }
     284
     285    /*
    273286    Optimize CSS Delivery Section
    274287    */
     
    380393        Helper::_('multiselect.pro', __FUNCTION__, [], 'js', 'script');
    381394    }
     395
     396    public static function pro_defer_criticalJs(): void
     397    {
     398        Helper::_('radio.pro', __FUNCTION__, '1');
     399    }
     400
    382401
    383402    ## Page Cache Tab
     
    716735    }
    717736
     737    public static function pro_gen_responsive_images(): void
     738    {
     739        Helper::_('radio.pro', __FUNCTION__, '1');
     740    }
     741
     742    public static function pro_load_responsive_images(): void
     743    {
     744        Helper::_('radio.pro', __FUNCTION__, '0');
     745    }
     746
    718747    public static function lossy(): void
    719748    {
  • jch-optimize/trunk/src/Html/TabSettings.php

    r2997317 r3040365  
    346346                    )
    347347                ]
     348            ],
     349            /**
     350             * Custom CSS
     351             */
     352            'customCssSection'           => [
     353                'mobile_css'  => [
     354                    __('Mobile', 'jch-optimize'),
     355                    __(
     356                        'Add simple CSS declarations to allocate space for elements rendering on mobile.',
     357                        'jch-optimize'
     358                    )
     359                ],
     360                'desktop_css' => [
     361                    __('Desktop', 'jch-optimize'),
     362                    __(
     363                        'Add CSS for preventing CLS issues on desktop devices here.',
     364                        'jch-optimize'
     365                    )
     366                ]
    348367            ]
    349368        ];
     
    478497                    __('Critical inline modules', 'jch-optimize'),
    479498                    __('You can exclude inline modules in a similar manner as outlined above.')
     499                ],
     500                'pro_defer_criticalJs'        => [
     501                    __('Defer critical js'),
     502                    __(
     503                        'The critical JavaScript will be deferred or loaded asynchronously by default to avoid render-blocking. However, if your template uses JavaScript to perform any of the initial render above the fold, you may want to disable this to ensure the critical JavaScript loads before the page starts rendering.'
     504                    )
    480505                ]
    481506            ],
     
    825850             */
    826851            'globalSection'    => [
    827                 'ignore_optimized'     => [
     852                'ignore_optimized'           => [
    828853                    __('Ignore optimized images', 'jch-optimize'),
    829854                    __(
     
    832857                    )
    833858                ],
    834                 'pro_next_gen_images'  => [
     859                'pro_next_gen_images'        => [
    835860                    __('Next-Gen images', 'jch-optimize'),
    836861                    __(
     
    843868                                sprintf( __( 'Plugin will wrap WEBP image in a %s element along with original image so browsers without WEBP support can fall back to the original image.', 'jch-optimize' ), '&lt;picture&gt;' )
    844869                        ], */
    845                 'pro_load_webp_images' => [
     870                'pro_load_webp_images'       => [
    846871                    __('Load WEBP images', 'jch-optimize'),
    847872                    __('Loads available WEBP images in place of the original ones on your web pages.', 'jch-optimize')
    848873                ],
    849                 'lossy'                => [
     874                'pro_gen_responsive_images'  => [
     875                    __('Generate responsive images', 'jch-optimize'),
     876                    __(
     877                        'While optimizing images, will also create different sized images to be used at different CSS breakpoints'
     878                    )
     879                ],
     880                'pro_load_responsive_images' => [
     881                    __('Load responsive images', 'jch-optimize'),
     882                    __(
     883                        'Use responsive images where available by adding srcset attributes on image elements and creating CSS breakpoints for background images.'
     884                    )
     885                ],
     886                'lossy'                      => [
    850887                    __('Lossy optimization', 'jch-optimize'),
    851888                    __(
     
    854891                    )
    855892                ],
    856                 'save_metadata'        => [
     893                'save_metadata'              => [
    857894                    __('Save metadata', 'jch-optimize'),
    858895                    __(
  • jch-optimize/trunk/src/Platform/Paths.php

    r3007001 r3040365  
    1616defined('_WP_EXEC') or die('Restricted access');
    1717
    18 use Exception;
    1918use JchOptimize\Core\Interfaces\Paths as PathsInterface;
    2019use JchOptimize\Core\SystemUri;
     
    5453    {
    5554        $home_path = trailingslashit(self::rootPath());
    56         $rootPath  = str_replace('/\\', DIRECTORY_SEPARATOR, $home_path);
     55        $rootPath = str_replace('/\\', DIRECTORY_SEPARATOR, $home_path);
    5756
    5857        //We can now concatenate root path to url path to get absolute path on filesystem
     
    6564    public static function rootPath(): string
    6665    {
    67         $home     = set_url_scheme((string) get_option('home'), 'http');
    68         $site_url = set_url_scheme((string) get_option('siteurl'), 'http');
    69 
    70         if (! empty($home) && 0 < strcasecmp($home, $site_url)) {
     66        $home = set_url_scheme((string)get_option('home'), 'http');
     67        $site_url = set_url_scheme((string)get_option('siteurl'), 'http');
     68
     69        if (!empty($home) && 0 < strcasecmp($home, $site_url)) {
    7170            $wp_path_rel_to_home = str_ireplace($home, '', $site_url); /* $site_url - $home */
    72             $pos                 = strripos(
     71            $pos = strripos(
    7372                str_replace('\\', '/', $_SERVER['SCRIPT_FILENAME']),
    7473                trailingslashit($wp_path_rel_to_home)
    7574            );
    76             $home_path           = substr($_SERVER['SCRIPT_FILENAME'], 0, $pos);
    77         } elseif (! empty($home) && 0 > strcasecmp($home, $site_url)) {
     75            $home_path = substr($_SERVER['SCRIPT_FILENAME'], 0, $pos);
     76        } elseif (!empty($home) && 0 > strcasecmp($home, $site_url)) {
    7877            $wp_path_rel_to_home = str_ireplace($home, '', $site_url); /* $site_url - $home */
    79             $pos                 = strripos(str_replace('\\', '/', ABSPATH), trailingslashit($wp_path_rel_to_home));
    80             $home_path           = substr(ABSPATH, 0, $pos);
     78            $pos = strripos(str_replace('\\', '/', ABSPATH), trailingslashit($wp_path_rel_to_home));
     79            $home_path = substr(ABSPATH, 0, $pos);
    8180        } else {
    8281            $home_path = ABSPATH;
     
    8685    }
    8786
     87    public static function basePath(): string
     88    {
     89        return self::rootPath();
     90    }
     91
    8892    /**
    8993     * Returns root relative path to the /assets/ folder
     
    112116        static $rewrite_base;
    113117
    114         if (! isset($rewrite_base)) {
    115             $uri          = Utils::uriFor(plugins_url());
     118        if (!isset($rewrite_base)) {
     119            $uri = Utils::uriFor(plugins_url());
    116120            $rewrite_base = trailingslashit($uri->getPath());
    117121        }
     
    145149    public static function path2Url(string $path): string
    146150    {
    147         $oUri        = Utils::uriFor(SystemUri::toString());
     151        $oUri = Utils::uriFor(SystemUri::toString());
    148152        $sBaseFolder = SystemUri::basePath();
    149153
    150154        $abs_path = str_replace(DIRECTORY_SEPARATOR, '/', self::rootPath());
    151         $path     = str_replace(DIRECTORY_SEPARATOR, '/', $path);
    152 
    153         $sUriPath = (string)$oUri->withPath($sBaseFolder .
    154                     (str_replace($abs_path . DIRECTORY_SEPARATOR, '', $path)));
     155        $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
     156
     157        $sUriPath = (string)$oUri->withPath(
     158            $sBaseFolder .
     159            (str_replace($abs_path . DIRECTORY_SEPARATOR, '', $path))
     160        );
    155161
    156162        return $sUriPath;
     
    169175    public static function nextGenImagesPath(bool $isRootRelative = false): string
    170176    {
    171         $wp_upload_dir     = wp_upload_dir(null, true, true);
     177        $wp_upload_dir = wp_upload_dir(null, true, true);
    172178        $sRelJchUploadPath = '/jch-optimize/ng';
    173179
     
    276282        return dirname(__FILE__, 3) . '/tmpl';
    277283    }
     284
     285    public static function responsiveImagePath(bool $isRootRelative = false): string
     286    {
     287        $wp_upload_dir = wp_upload_dir(null, true, true);
     288        $sRelJchUploadPath = '/jch-optimize/rs';
     289
     290        if ($isRootRelative) {
     291            $uri = Utils::uriFor($wp_upload_dir['baseurl'] . $sRelJchUploadPath);
     292
     293            return (string)$uri->withScheme('')->withHost('')->withUserInfo('');
     294        }
     295
     296        return $wp_upload_dir['basedir'] . $sRelJchUploadPath;
     297    }
    278298}
  • jch-optimize/trunk/vendor/composer/installed.php

    r3007001 r3040365  
    66        'install_path' => __DIR__ . '/../../',
    77        'aliases' => array(),
    8         'reference' => 'de0f05ea1fea90b0cae6c3abfdf52f3d1180cca3',
     8        'reference' => '857797bdb745daf47b8f4e5410bcdc902b7b7341',
    99        'name' => 'jchoptimize/wordpress-platform',
    1010        'dev' => false,
     
    1717            'install_path' => __DIR__ . '/../../',
    1818            'aliases' => array(),
    19             'reference' => 'de0f05ea1fea90b0cae6c3abfdf52f3d1180cca3',
     19            'reference' => '857797bdb745daf47b8f4e5410bcdc902b7b7341',
    2020            'dev_requirement' => false,
    2121        ),
  • jch-optimize/trunk/version.php

    r3007001 r3040365  
    1515defined('_JCH_EXEC') or die;
    1616
    17 const JCH_VERSION  = '4.1.1';
    18 const JCH_DATE     = '2023-12-07';
     17const JCH_VERSION  = '4.2.0';
     18const JCH_DATE     = '2024-02-23';
    1919const JCH_PRO      = '0';
    2020const JCH_DEVELOP  = '0';
Note: See TracChangeset for help on using the changeset viewer.