* @copyright Copyright (c) 2020 Samuel Marshall / JCH Optimize * @license GNU/GPLv3, or later. See LICENSE file * * If LICENSE file missing, see . */ namespace JchOptimize\WordPress\Platform; defined('_WP_EXEC') or die('Restricted access'); use _JchOptimizeVendor\V91\GuzzleHttp\Exception\GuzzleException; use _JchOptimizeVendor\V91\GuzzleHttp\RequestOptions; use _JchOptimizeVendor\V91\Psr\Http\Client\ClientInterface; use _JchOptimizeVendor\V91\Psr\Log\LoggerAwareInterface; use _JchOptimizeVendor\V91\Psr\Log\LoggerAwareTrait; use JchOptimize\Core\Exception; use JchOptimize\Core\Platform\HtmlInterface; use JchOptimize\Core\Platform\ProfilerInterface; use JchOptimize\Core\Platform\UtilityInterface; use JchOptimize\Core\Uri\Uri; use JchOptimize\Core\Uri\UriComparator; use JchOptimize\Core\Uri\Utils; use function __; use function array_merge; use function array_slice; use function get_nav_menu_locations; use function get_registered_nav_menus; use function home_url; use function microtime; use function parse_str; use function rtrim; use function wp_get_nav_menu_items; use function wp_get_nav_menus; class Html implements HtmlInterface, LoggerAwareInterface { use LoggerAwareTrait; public function __construct( private ClientInterface $http, private ProfilerInterface $profiler, private UtilityInterface $utility ) { } /** * @throws GuzzleException */ public function getHomePageHtml(): string { JCH_DEBUG ? $this->profiler->mark('beforeGetHtml') : null; $url = home_url() . '/?jchbackend=1'; try { $response = $this->http->get($url, ['Accept-Encoding' => 'identity;q=0']); if ($response->getStatusCode() != 200) { throw new Exception\RuntimeException( __( 'Failed fetching front end HTML with response code ' . $response->getStatusCode(), 'jch-optimize' ) ); } JCH_DEBUG ? $this->profiler->mark('afterGetHtml') : null; $body = $response->getBody(); //Set pointer to beginning of stream. $body->rewind(); return $body->getContents(); } catch (\Exception $e) { $this->logger?->error($url . ': ' . $e->getMessage()); JCH_DEBUG ? $this->profiler->mark('afterGetHtml)') : null; throw new Exception\RuntimeException( __( 'Load or refresh the front-end site first then refresh this page ' . 'to populate the multi select exclude lists.', 'jch-optimize' ) ); } } public function getMainMenuItemsHtmls($iLimit = 5, $bIncludeUrls = false): array { $aMenuUrls = $this->getMenuUrls(); $aMenuUrls = array_slice($aMenuUrls, 0, $iLimit); $aHtmls = []; //Limit the time spent on this $iTimer = microtime(true); foreach ($aMenuUrls as $menuUrl) { try { if ($bIncludeUrls) { $aHtmls[] = [ 'url' => $menuUrl, 'html' => $this->getHtml($menuUrl) ]; } else { $aHtmls[] = $this->getHtml($menuUrl); } } catch (Exception\ExceptionInterface $e) { $this->logger?->error((string)$e); } if (microtime(true) > $iTimer + 10.0) { break; } } return $aHtmls; } protected function getMenuUrls(): array { $homeUrl = rtrim(home_url(), '/\\'); //Start array of oMenu urls with home page $aMenuUrls = [$homeUrl]; $aMenus = wp_get_nav_menus(); //If nothing just work with the home url if (! $aMenus) { return $aMenuUrls; } $locations = get_registered_nav_menus(); $aMenuLocations = get_nav_menu_locations(); //Iterate through menus to find primary foreach ($aMenus as $oMenu) { if ($oMenu->term_id == $aMenuLocations['menu-primary']) { break; } } $aMenuItems = wp_get_nav_menu_items($oMenu); foreach ($aMenuItems as $oMenuItem) { if (rtrim($oMenuItem->url, '/\\') == $homeUrl) { continue; } if (! $cleanUrl = $this->cleanUrl($oMenuItem->url)) { continue; } if (!UriComparator::isCrossOrigin(Utils::uriFor($cleanUrl))) { $aMenuUrls[] = $cleanUrl; } } return $aMenuUrls; } private function cleanUrl(string $oMenuItem): string { $oUri = Utils::uriFor($oMenuItem); return (string)$oUri; } /** * @throws Exception\RuntimeException * @throws GuzzleException */ protected function getHtml(string $url): string { $oUri = Utils::uriFor($url); $sQuery = $oUri->getQuery(); parse_str($sQuery, $aQuery); $aNewQuery = array_merge($aQuery, array('jchbackend' => '1')); $oUri = Uri::withQueryValues($oUri, $aNewQuery); $options = [ RequestOptions::HEADERS => [ 'Accept-Enconding' => 'identity;q=0' ] ]; $response = $this->http->get($oUri, $options); if ($response->getStatusCode() != 200) { throw new Exception\RuntimeException( 'Failed fetching HTML: ' . $url . ' - Response code: ' . $response->getStatusCode() ); } $body = $response->getBody(); $body->rewind(); return $body->getContents(); } }