Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add prefetch/prerender with the Quicklink plugin #406

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions classes/autoptimizeConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,7 @@ public static function get_ao_extra_default_options()
'autoptimize_extra_text_field_3' => '',
'autoptimize_extra_text_field_7' => '',
'autoptimize_extra_checkbox_field_8' => '0',
'autoptimize_extra_checkbox_field_9' => '1',
);

return $defaults;
Expand Down
11 changes: 11 additions & 0 deletions classes/autoptimizeExtra.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public function __construct( $options = array() )
}

$this->options = $options;

// Potentially load quicklink.
if ( ! empty( $options['autoptimize_extra_checkbox_field_9'] ) ) {
require_once dirname( __FILE__ ) . '/external/php/quicklink/quicklink.php';
}
}

/**
Expand Down Expand Up @@ -565,6 +570,12 @@ public function options_page()
<input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="4" <?php checked( 4, $gfonts, true ); ?> ><?php echo __( 'Combine and load fonts asynchronously with <a href="https://github.com/typekit/webfontloader#readme" target="_blank">webfont.js</a>', 'autoptimize' ) . ' ' . __( '(deprecated)', 'autoptimize' ); ?><br/>
</td>
</tr>
<tr>
<th scope="row"><?php _e( 'Prefetch links', 'autoptimize' ); ?></th>
<td>
<label><input type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_9]' <?php if ( ! empty( $options['autoptimize_extra_checkbox_field_9'] ) && '1' === $options['autoptimize_extra_checkbox_field_9'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Detects links in the viewport, waits until the browser is idle and prefetches the URLs for these links.', 'autoptimize' ); ?></label>
</td>
</tr>
<tr>
<th scope="row"><?php _e( 'Remove emojis', 'autoptimize' ); ?></th>
<td>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php
/**
* The plugin compatibility for the WooCommerce plugin
*
* @package quicklink
*/

/**
* The function that extends the default quicklink options for WooCommerce
*
* @param array $options The default Quicklink options.
*
* @return array The extended Quicklink options
*/
function quicklink_woocommerce_compatibility( $options ) {
// Check if the WooCommerce exists.
global $woocommerce;
$has_woocommerce = (
isset( $woocommerce )
&&
class_exists( 'WooCommerce' )
&&
$woocommerce instanceof WooCommerce
);
if ( ! $has_woocommerce ) {
return $options;
}

// Do not preload the 'my account' page, as it is usually ressource heavy.
$myaccount_page_id = get_option( 'woocommerce_myaccount_page_id' );
if ( $myaccount_page_id ) {
$wc_ignores[] = '^' . preg_quote( get_permalink( $myaccount_page_id ), '/' );
}

// Do not preload the cart, as it is usally ressource heavy.
$wc_ignores[] = '^' . preg_quote( wc_get_cart_url(), '/' );

// Do not preload the checkout url for the same reason as above.
$wc_ignores[] = '^' . preg_quote( wc_get_checkout_url(), '/' );

// Remove possible empty strings and duplicates from the array.
$wc_ignores = array_unique( array_filter( $wc_ignores ) );

$options['ignores'] = array_merge( $options['ignores'], $wc_ignores );

return $options;
}
add_filter( 'quicklink_options', 'quicklink_woocommerce_compatibility' );
133 changes: 133 additions & 0 deletions classes/external/php/quicklink/quicklink.bundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/******/ (function() { // webpackBootstrap
/******/ "use strict";
/******/ // The require scope
/******/ var __webpack_require__ = {};
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ !function() {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = function(exports, definition) {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ }();
/******/
/******/ /* webpack/runtime/global */
/******/ !function() {
/******/ __webpack_require__.g = (function() {
/******/ if (typeof globalThis === 'object') return globalThis;
/******/ try {
/******/ return this || new Function('return this')();
/******/ } catch (e) {
/******/ if (typeof window === 'object') return window;
/******/ }
/******/ })();
/******/ }();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ !function() {
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
/******/ }();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ !function() {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ }();
/******/
/************************************************************************/
var __webpack_exports__ = {};

// NAMESPACE OBJECT: ./node_modules/quicklink/dist/quicklink.mjs
var quicklink_namespaceObject = {};
__webpack_require__.r(quicklink_namespaceObject);
__webpack_require__.d(quicklink_namespaceObject, {
"listen": function() { return u; },
"prefetch": function() { return s; },
"prerender": function() { return f; }
});

;// CONCATENATED MODULE: ./node_modules/quicklink/dist/quicklink.mjs
function e(e){return new Promise(function(n,r,t){(t=new XMLHttpRequest).open("GET",e,t.withCredentials=!0),t.onload=function(){200===t.status?n():r()},t.send()})}var n,r=(n=document.createElement("link")).relList&&n.relList.supports&&n.relList.supports("prefetch")?function(e){return new Promise(function(n,r,t){(t=document.createElement("link")).rel="prefetch",t.href=e,t.onload=n,t.onerror=r,document.head.appendChild(t)})}:e,t=window.requestIdleCallback||function(e){var n=Date.now();return setTimeout(function(){e({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-n))}})},1)},o=new Set,i=new Set,c=!1;function a(e){if(e){if(e.saveData)return new Error("Save-Data is enabled");if(/2g/.test(e.effectiveType))return new Error("network conditions are poor")}return!0}function u(e){if(e||(e={}),window.IntersectionObserver){var n=function(e){e=e||1;var n=[],r=0;function t(){r<e&&n.length>0&&(n.shift()(),r++)}return[function(e){n.push(e)>1||t()},function(){r--,t()}]}(e.throttle||1/0),r=n[0],a=n[1],u=e.limit||1/0,l=e.origins||[location.hostname],d=e.ignores||[],h=e.delay||0,p=[],m=e.timeoutFn||t,w="function"==typeof e.hrefFn&&e.hrefFn,g=e.prerender||!1;c=e.prerenderAndPrefetch||!1;var v=new IntersectionObserver(function(n){n.forEach(function(n){if(n.isIntersecting)p.push((n=n.target).href),function(e,n){n?setTimeout(e,n):e()}(function(){-1!==p.indexOf(n.href)&&(v.unobserve(n),(c||g)&&i.size<1?f(w?w(n):n.href).catch(function(n){if(!e.onError)throw n;e.onError(n)}):o.size<u&&!g&&r(function(){s(w?w(n):n.href,e.priority).then(a).catch(function(n){a(),e.onError&&e.onError(n)})}))},h);else{var t=p.indexOf((n=n.target).href);t>-1&&p.splice(t)}})},{threshold:e.threshold||0});return m(function(){(e.el||document).querySelectorAll("a").forEach(function(e){l.length&&!l.includes(e.hostname)||function e(n,r){return Array.isArray(r)?r.some(function(r){return e(n,r)}):(r.test||r).call(r,n.href,n)}(e,d)||v.observe(e)})},{timeout:e.timeout||2e3}),function(){o.clear(),v.disconnect()}}}function s(n,t,u){var s=a(navigator.connection);return s instanceof Error?Promise.reject(new Error("Cannot prefetch, "+s.message)):(i.size>0&&!c&&console.warn("[Warning] You are using both prefetching and prerendering on the same document"),Promise.all([].concat(n).map(function(n){if(!o.has(n))return o.add(n),(t?function(n){return window.fetch?fetch(n,{credentials:"include"}):e(n)}:r)(new URL(n,location.href).toString())})))}function f(e,n){var r=a(navigator.connection);if(r instanceof Error)return Promise.reject(new Error("Cannot prerender, "+r.message));if(!HTMLScriptElement.supports("speculationrules"))return s(e),Promise.reject(new Error("This browser does not support the speculation rules API. Falling back to prefetch."));if(document.querySelector('script[type="speculationrules"]'))return Promise.reject(new Error("Speculation Rules is already defined and cannot be altered."));for(var t=0,u=[].concat(e);t<u.length;t+=1){var f=u[t];if(window.location.origin!==new URL(f,window.location.href).origin)return Promise.reject(new Error("Only same origin URLs are allowed: "+f));i.add(f)}o.size>0&&!c&&console.warn("[Warning] You are using both prefetching and prerendering on the same document");var l=function(e){var n=document.createElement("script");n.type="speculationrules",n.text='{"prerender":[{"source": "list","urls": ["'+Array.from(e).join('","')+'"]}]}';try{document.head.appendChild(n)}catch(e){return e}return!0}(i);return!0===l?Promise.resolve():Promise.reject(l)}

;// CONCATENATED MODULE: ./build/js/quicklink.js


// Move quicklink to the global scope
window.quicklink = quicklink_namespaceObject;
__webpack_require__.g.addEventListener('load', () => {
const exportedOptions = window.quicklinkOptions || {};
const listenerOptions = {};

// el: Convert selector into element reference.
if ('string' === typeof exportedOptions.el && exportedOptions.el) {
listenerOptions.el = document.querySelector(exportedOptions.el);
}

// timeout: Verify we actually get an int for milliseconds.
if ('number' === typeof exportedOptions.timeout) {
listenerOptions.timeout = exportedOptions.timeout;
}

// limit: Verify we actually get an int.
if ('number' === typeof exportedOptions.limit && exportedOptions.limit > 0) {
listenerOptions.limit = exportedOptions.limit;
}

// throttle: Verify we actually get an int.
if ('number' === typeof exportedOptions.throttle && exportedOptions.throttle > 0) {
listenerOptions.throttle = exportedOptions.throttle;
}

// timeoutFn: Obtain function reference as opposed to function string, if it is not the default.
if ('string' === typeof exportedOptions.timeoutFn && 'requestIdleCallback' !== exportedOptions.timeoutFn && typeof 'function' === window[exportedOptions.timeoutFn]) {
const timeoutFn = window[exportedOptions.timeoutFn];
listenerOptions.timeoutFn = function () {
return timeoutFn.apply(window, arguments);
};
}

// onError: Obtain function reference as opposed to function string, if it is not the default.
if ('string' === typeof exportedOptions.onError && typeof 'function' === window[exportedOptions.onError]) {
const onError = window[exportedOptions.onError];
listenerOptions.onError = function () {
return onError.apply(window, arguments);
};
}

// priority: Obtain priority.
if ('boolean' === typeof exportedOptions.priority) {
listenerOptions.priority = exportedOptions.priority;
}

// origins: Verify we don't get an empty array, as that would turn off quicklink.
if (Array.isArray(exportedOptions.origins) && 0 < exportedOptions.origins.length) {
listenerOptions.origins = exportedOptions.origins;
}

// ignores: Convert strings to regular expressions.
if (Array.isArray(exportedOptions.ignores) && 0 < exportedOptions.ignores.length) {
listenerOptions.ignores = exportedOptions.ignores.map(ignore => {
return new RegExp(ignore);
});
}
u(listenerOptions);

/**
* The option to prefetch urls from the options is deprecated as of version 0.8.0.
*/
if (Array.isArray(exportedOptions.urls) && 0 < exportedOptions.urls.length) {
s(exportedOptions.urls);
}
});
/******/ })()
;
1 change: 1 addition & 0 deletions classes/external/php/quicklink/quicklink.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading