Files
Roman Pyrih c2e100a763 first commit
2023-07-24 08:30:51 +02:00

272 lines
8.2 KiB
PHP

<?php
defined('ABSPATH') || exit;
/* * * * * * * * * * * * * * * * * * * * *
*
* ██████╗ ███╗ ███╗ ██████╗ ███████╗
* ██╔═══██╗████╗ ████║██╔════╝ ██╔════╝
* ██║ ██║██╔████╔██║██║ ███╗█████╗
* ██║ ██║██║╚██╔╝██║██║ ██║██╔══╝
* ╚██████╔╝██║ ╚═╝ ██║╚██████╔╝██║
* ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝
*
* @package : OMGF
* @author : Daan van den Bergh
* @copyright: (c) 2021 Daan van den Bergh
* @url : https://daan.dev
* * * * * * * * * * * * * * * * * * * */
class OMGF_OptimizationMode_Manual
{
/** @var string */
private $plugin_text_domain = 'host-webfonts-local';
/**
* Build class.
*
* @return void
*/
public function __construct()
{
$this->run();
}
/**
* Run Manual mode.
*
* @return void
*/
private function run()
{
$url = esc_url_raw(OMGF_MANUAL_OPTIMIZE_URL);
$front_html = $this->get_front_html($url);
$error = false;
if (is_wp_error($front_html) || wp_remote_retrieve_response_code($front_html) != 200) {
$this->frontend_fetch_failed($front_html);
$error = true;
}
$api_request_urls = [];
$document = new DOMDocument();
libxml_use_internal_errors(true);
@$document->loadHtml(wp_remote_retrieve_body($front_html));
foreach ($document->getElementsByTagName('link') as $link) {
/** @var DOMElement $link */
if ($link->hasAttribute('href') && strpos($link->getAttribute('href'), '/omgf/v1/download/')) {
$api_request_urls[] = $link->getAttribute('href');
}
}
if (empty($api_request_urls)) {
$this->no_urls_found();
$error = true;
}
foreach ($api_request_urls as $url) {
if (strpos($url, 'css2') !== false) {
$url = $this->convert($url);
}
$download = $this->do_rest_request($url);
/** @var WP_REST_Response $download */
if ($download->is_error()) {
$this->download_failed($download);
$error = true;
}
}
if (!$error) {
$this->optimization_succeeded();
}
}
/**
* Converts requests to Google's Variable Fonts (CSS2) API to the 'old' (CSS) API.
*
* @param string $css2_url
*/
private function convert($css2_url)
{
$parsed_url = parse_url($css2_url);
$query = $parsed_url['query'];
parse_str($query, $params);
$raw_params = explode('&', $query);
$font_families = [];
$fonts = [];
foreach ($raw_params as $param) {
if (strpos($param, 'family') === false) {
continue;
}
parse_str($param, $parts);
$font_families[] = $parts['family'];
}
if (empty($font_families)) {
return $css2_url;
}
foreach ($font_families as $font_family) {
if (strpos($font_family, ':') !== false) {
list($family, $weights) = explode(':', $font_family);
} else {
$family = $font_family;
$weights = '';
}
/**
* @return array [ '300', '400', '500', etc. ]
*/
$weights = explode(';', substr($weights, strpos($weights, '@') + 1));
foreach ($weights as &$weight) {
$properties = explode(',', $weight);
$weight = $properties[0] == '1' ? $properties[1] . 'italic' : $properties[1];
}
$fonts[] = $family . ':' . implode(',', $weights);
}
$params['family'] = implode('|', $fonts);
return $parsed_url['scheme'] . '://' . $parsed_url['host'] . $parsed_url['path'] . '?' . http_build_query($params);
}
/**
* @param string $url
*
* @return WP_REST_Response
*/
private function do_rest_request($url)
{
$parsed_url = parse_url($url);
$request = new WP_REST_Request('GET', str_replace('/wp-json', '', $parsed_url['path']));
parse_str($parsed_url['query'], $query_params);
if (isset($query_params['_wpnonce'])) {
unset($query_params['_wpnonce']);
}
$request->set_query_params($query_params);
// TODO: Find out proper WP way to add this param to request.
$_REQUEST['_wpnonce'] = wp_create_nonce('wp_rest');
return rest_do_request($request);
}
/**
* @return void
*/
private function optimization_succeeded()
{
add_settings_error('general', 'omgf_optimization_success', __('Optimization completed successfully.'), 'success');
OMGF_Admin_Notice::set_notice(
__('If you\'re using any 3rd party optimization plugins (e.g. WP Rocket, Autoptimize, W3 Total Cache, etc.) make sure to flush their caches for OMGF\'s optimizations to take effect.', $this->plugin_text_domain),
'omgf-cache-notice',
false,
'warning'
);
}
/**
* @param $response WP_REST_Response
*/
private function download_failed($response)
{
add_settings_error('general', 'omgf_download_failed', __('OMGF encountered an error while downloading Google Fonts', $this->plugin_text_domain) . ': ' . $this->get_error_code($response) . ' - ' . $this->get_error_message($response), 'error');
}
/**
* @param $response WP_Error|array
*/
private function frontend_fetch_failed($response)
{
add_settings_error('general', 'omgf_frontend_fetch_failed', __('OMGF encountered an error while fetching this site\'s frontend HTML', $this->plugin_text_domain) . ': ' . $this->get_error_code($response) . ' - ' . $this->get_error_message($response), 'error');
}
/**
* @return void
*/
private function no_urls_found()
{
add_settings_error('general', 'omgf_no_urls_found', sprintf(__('No (additional) Google Fonts found to optimize. If you believe this is an error, please refer to the %stroubleshooting%s section of the documentation for possible solutions.', $this->plugin_text_domain), '<a href="https://docs.ffw.press/category/37-omgf-pro---troubleshooting">', '</a>'), 'info');
}
/**
* Wrapper for wp_remote_get() with preset params.
*
* @param mixed $url
* @return array|WP_Error
*/
private function get_front_html($url)
{
return wp_remote_get(
$this->no_cache_optimize_url($url),
[
'timeout' => 30
]
);
}
/**
* @param $url
*
* @return string
*/
private function no_cache_optimize_url($url)
{
return add_query_arg(['omgf_optimize' => 1, 'nocache' => substr(md5(microtime()), rand(0, 26), 5)], $url);
}
/**
* @param WP_REST_Response|WP_Error|array $response
*
* @return int|string
*/
private function get_error_code($response)
{
if ($response instanceof WP_REST_Response && $response->is_error()) {
// Convert to WP_Error if WP_REST_Response
$response = $response->as_error();
}
if (is_wp_error($response)) {
return $response->get_error_code();
}
return wp_remote_retrieve_response_code($response);
}
/**
* @param WP_REST_Response|WP_Error|array $response
*
* @return int|string
*/
private function get_error_message($response)
{
if ($response instanceof WP_REST_Response && $response->is_error()) {
// Convert to WP_Error if WP_REST_Response
$response = $response->as_error();
}
if (is_wp_error($response)) {
return $response->get_error_message();
}
return wp_remote_retrieve_response_message($response);
}
}