Coming Soon, Under Construction & Maintenance Page - Version 2.0.2

Version Description

  • Implement local webfonts
  • Minor bug fixes
Download this release

Release Info

Developer wpconcern
Plugin Icon 128x128 Coming Soon, Under Construction & Maintenance Page
Version 2.0.2
Comparing to
See all releases

Code changes from version 2.0.1 to 2.0.2

admin/includes/class-ot-settings.php CHANGED
@@ -295,11 +295,11 @@ if ( ! class_exists( 'OT_Settings' ) ) {
295
  if ( $show_buttons )
296
  echo '<button class="option-tree-ui-button button button-primary right">' . $page['button_text'] . '</button>';
297
  echo '<a target="_blank" href="'. get_site_url().'/?get_preview=true"><div class="option-tree-ui-button button right">Live Preview</div></a>';
298
- $options = get_option('nifty_options');
299
- if (empty($options['hide_notice']['rate'])) {
300
- $dismiss_url = add_query_arg(array('action' => 'nifty_dismiss_notice', 'notice' => 'rate', 'redirect' => urlencode($_SERVER['REQUEST_URI'])), admin_url('admin.php'));
301
- echo '<div id="rate-plugin">Please help us out by rating Nifty. It only takes a second &amp; it helps to keep the plugin going! <b>Thank you!</b><p><a target="_blank" href="https://wordpress.org/support/plugin/nifty-coming-soon-and-under-construction-page/reviews/#new-post" class="button button-primary">I want to help! Let\'s rate the plugin!</a> &nbsp;&nbsp; <a href="' . $dismiss_url . '">I\'ve already rated Nifty</a></p></div>';
302
- }
303
 
304
  echo '</div>';
305
 
295
  if ( $show_buttons )
296
  echo '<button class="option-tree-ui-button button button-primary right">' . $page['button_text'] . '</button>';
297
  echo '<a target="_blank" href="'. get_site_url().'/?get_preview=true"><div class="option-tree-ui-button button right">Live Preview</div></a>';
298
+ // $options = get_option('nifty_options');
299
+ // if (empty($options['hide_notice']['rate'])) {
300
+ // $dismiss_url = add_query_arg(array('action' => 'nifty_dismiss_notice', 'notice' => 'rate', 'redirect' => urlencode($_SERVER['REQUEST_URI'])), admin_url('admin.php'));
301
+ // echo '<div id="rate-plugin">Please help us out by rating Nifty. It only takes a second &amp; it helps to keep the plugin going! <b>Thank you!</b><p><a target="_blank" href="https://wordpress.org/support/plugin/nifty-coming-soon-and-under-construction-page/reviews/#new-post" class="button button-primary">I want to help! Let\'s rate the plugin!</a> &nbsp;&nbsp; <a href="' . $dismiss_url . '">I\'ve already rated Nifty</a></p></div>';
302
+ // }
303
 
304
  echo '</div>';
305
 
admin/includes/ot-settings-api.php CHANGED
@@ -302,11 +302,11 @@ if ( ! class_exists( 'OT_Settings' ) ) {
302
  if ( $show_buttons )
303
  echo '<button class="option-tree-ui-button button button-primary right">' . $page['button_text'] . '</button>';
304
  echo '<a target="_blank" href="'. get_site_url().'/?get_preview=true"><div class="option-tree-ui-button button right">Live Preview</div></a>';
305
- $options = get_option('nifty_options');
306
- if (empty($options['hide_notice']['rate'])) {
307
- $dismiss_url = add_query_arg(array('action' => 'nifty_dismiss_notice', 'notice' => 'rate', 'redirect' => urlencode($_SERVER['REQUEST_URI'])), admin_url('admin.php'));
308
- echo '<div id="rate-plugin">Please help us out by rating Nifty. It only takes a second &amp; it helps to keep the plugin going! <b>Thank you!</b><p><a target="_blank" href="https://wordpress.org/support/plugin/nifty-coming-soon-and-under-construction-page/reviews/#new-post" class="button button-primary">I want to help! Let\'s rate the plugin!</a> &nbsp;&nbsp; <a href="' . $dismiss_url . '">I\'ve already rated Nifty</a></p></div>';
309
- }
310
 
311
  echo '</div>';
312
 
302
  if ( $show_buttons )
303
  echo '<button class="option-tree-ui-button button button-primary right">' . $page['button_text'] . '</button>';
304
  echo '<a target="_blank" href="'. get_site_url().'/?get_preview=true"><div class="option-tree-ui-button button right">Live Preview</div></a>';
305
+ // $options = get_option('nifty_options');
306
+ // if (empty($options['hide_notice']['rate'])) {
307
+ // $dismiss_url = add_query_arg(array('action' => 'nifty_dismiss_notice', 'notice' => 'rate', 'redirect' => urlencode($_SERVER['REQUEST_URI'])), admin_url('admin.php'));
308
+ // echo '<div id="rate-plugin">Please help us out by rating Nifty. It only takes a second &amp; it helps to keep the plugin going! <b>Thank you!</b><p><a target="_blank" href="https://wordpress.org/support/plugin/nifty-coming-soon-and-under-construction-page/reviews/#new-post" class="button button-primary">I want to help! Let\'s rate the plugin!</a> &nbsp;&nbsp; <a href="' . $dismiss_url . '">I\'ve already rated Nifty</a></p></div>';
309
+ // }
310
 
311
  echo '</div>';
312
 
admin/main-options.php CHANGED
@@ -986,6 +986,7 @@ function admin_action_dismiss_notice() {
986
  <li><a href="https://wpconcern.com/plugins/woocommerce-product-tabs/" target="_blank">WooCommerce Product Tabs</a></li>
987
  <li><a href="https://wpconcern.com/plugins/post-grid-elementor-addon/" target="_blank">Post Grid Elementor Addon</a></li>
988
  <li><a href="https://wpconcern.com/plugins/advanced-google-recaptcha/" target="_blank">Advanced Google reCAPTCHA</a></li>
 
989
  </ul>',
990
  'std' => '',
991
  'type' => 'textblock',
986
  <li><a href="https://wpconcern.com/plugins/woocommerce-product-tabs/" target="_blank">WooCommerce Product Tabs</a></li>
987
  <li><a href="https://wpconcern.com/plugins/post-grid-elementor-addon/" target="_blank">Post Grid Elementor Addon</a></li>
988
  <li><a href="https://wpconcern.com/plugins/advanced-google-recaptcha/" target="_blank">Advanced Google reCAPTCHA</a></li>
989
+ <li><a href="https://wordpress.org/plugins/admin-customizer/" target="_blank">Admin Customizer</a></li>
990
  </ul>',
991
  'std' => '',
992
  'type' => 'textblock',
admin/ot-loader.php CHANGED
@@ -20,7 +20,7 @@ if ( class_exists( 'OT_Loader' ) && defined( 'OT_PLUGIN_MODE' ) && true === OT_P
20
  * Forces Plugin Mode when OptionTree is already loaded and displays an admin notice.
21
  */
22
  function ot_conflict_notice() {
23
- echo '<div class="error"><p>' . esc_html__( 'OptionTree is installed as a plugin and also embedded in your current theme. Please deactivate the plugin to load the theme dependent version of OptionTree, and remove this warning.', 'option-tree' ) . '</p></div>';
24
  }
25
 
26
  add_action( 'admin_notices', 'ot_conflict_notice' );
@@ -719,7 +719,7 @@ if ( ! class_exists( 'OT_Loader' ) && defined( 'ABSPATH' ) ) {
719
 
720
  // Once is enough.
721
  remove_filter( 'gettext', array( $this, 'ot_change_image_button' ) );
722
- return apply_filters( 'ot_upload_text', esc_html__( 'Send to OptionTree', 'option-tree' ) );
723
 
724
  }
725
 
20
  * Forces Plugin Mode when OptionTree is already loaded and displays an admin notice.
21
  */
22
  function ot_conflict_notice() {
23
+ echo '<div class="error"><p>' . esc_html__( 'OptionTree is installed as a plugin and also embedded in your current theme. Please deactivate the plugin to load the theme dependent version of OptionTree, and remove this warning.', 'nifty-coming-soon-and-under-construction-page' ) . '</p></div>';
24
  }
25
 
26
  add_action( 'admin_notices', 'ot_conflict_notice' );
719
 
720
  // Once is enough.
721
  remove_filter( 'gettext', array( $this, 'ot_change_image_button' ) );
722
+ return apply_filters( 'ot_upload_text', esc_html__( 'Send to OptionTree', 'nifty-coming-soon-and-under-construction-page' ) );
723
 
724
  }
725
 
languages/nifty-coming-soon-and-under-construction-page.pot ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2022 WP Concern
2
+ # This file is distributed under the GPLv3.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: Nifty Coming Soon & Maintenance page 2.0.2\n"
6
+ "Report-Msgid-Bugs-To: "
7
+ "https://wordpress.org/support/plugin/nifty-coming-soon-and-under-"
8
+ "construction-page\n"
9
+ "POT-Creation-Date: 2022-07-01 11:07:05+00:00\n"
10
+ "MIME-Version: 1.0\n"
11
+ "Content-Type: text/plain; charset=utf-8\n"
12
+ "Content-Transfer-Encoding: 8bit\n"
13
+ "PO-Revision-Date: 2022-MO-DA HO:MI+ZONE\n"
14
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
15
+ "Language-Team: LANGUAGE <LL@li.org>\n"
16
+ "X-Generator: node-wp-i18n 1.2.6\n"
17
+
18
+ #: admin/ot-loader.php:23
19
+ msgid ""
20
+ "OptionTree is installed as a plugin and also embedded in your current "
21
+ "theme. Please deactivate the plugin to load the theme dependent version of "
22
+ "OptionTree, and remove this warning."
23
+ msgstr ""
24
+
25
+ #: admin/ot-loader.php:722
26
+ msgid "Send to OptionTree"
27
+ msgstr ""
28
+
29
+ #: nifty-coming-soon.php:55
30
+ msgid "Nifty Coming Soon is Enabled"
31
+ msgstr ""
32
+
33
+ #: nifty-coming-soon.php:291
34
+ msgid "Settings"
35
+ msgstr ""
36
+
37
+ #: nifty-coming-soon.php:328
38
+ msgid "Coming Soon & Maintenance Mode Page"
39
+ msgstr ""
40
+
41
+ #. Plugin Name of the plugin/theme
42
+ msgid "Nifty Coming Soon & Maintenance page"
43
+ msgstr ""
44
+
45
+ #. Plugin URI of the plugin/theme
46
+ msgid "https://wpconcern.com/plugins/nifty-coming-soon-and-under-construction-page/"
47
+ msgstr ""
48
+
49
+ #. Description of the plugin/theme
50
+ msgid ""
51
+ "Easy to set up Coming Soon, Maintenance and Under Construction page. It "
52
+ "features Responsive design, Countdown timer, Animations, Live Preview, "
53
+ "Background Slider, Subscription form and more."
54
+ msgstr ""
55
+
56
+ #. Author of the plugin/theme
57
+ msgid "WP Concern"
58
+ msgstr ""
59
+
60
+ #. Author URI of the plugin/theme
61
+ msgid "https://wpconcern.com/"
62
+ msgstr ""
nifty-coming-soon.php CHANGED
@@ -1,15 +1,14 @@
1
  <?php
2
  /*
3
  Plugin Name: Nifty Coming Soon & Maintenance page
4
- Plugin URI: https://wpconcern.com/nifty-coming-soon-and-under-construction-page/
5
  Description: Easy to set up Coming Soon, Maintenance and Under Construction page. It features Responsive design, Countdown timer, Animations, Live Preview, Background Slider, Subscription form and more.
6
- Version: 2.0.1
7
  Author: WP Concern
8
  Author URI: https://wpconcern.com/
 
9
  License: GPLv3
10
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
11
- Tested up to: 6.0
12
- Requires PHP: 5.6
13
 
14
  Copyright 2015 - 2021 WebFactory Ltd (email: support@webfactoryltd.com)
15
 
@@ -30,6 +29,18 @@ Requires PHP: 5.6
30
 
31
  defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
32
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  // Display status of the coming soon page in the admin bar
34
  add_action('admin_bar_menu', 'nifty_cs_custom_menu', 1000);
35
 
@@ -41,7 +52,7 @@ function nifty_cs_custom_menu()
41
 
42
  $argsParent=array(
43
  'id' => 'niftycs_custom_menu',
44
- 'title' => 'Nifty Coming Soon is Enabled',
45
  'href' => admin_url('?page=niftycs-options#section_general_settings'),
46
  'meta' => array( 'class' => 'red-hot-button' ),
47
 
@@ -276,23 +287,50 @@ if ( isset($_POST['email']) && filter_var($_POST['email'], FILTER_VALIDATE_EMAIL
276
 
277
 
278
  // add settings link to plugins page
279
- function nifty_plugin_action_links($links)
280
- {
281
- $settings_link = '<a href="' . admin_url('admin.php?page=niftycs-options') . '" title="Nifty Coming Soon & Maintenance page">Settings</a>';
282
  array_unshift($links, $settings_link);
283
 
284
  return $links;
285
- } // nifty_plugin_action_links
286
 
287
  add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'nifty_plugin_action_links');
288
 
289
  // remove options on deactivate
290
  function nifty_deactivate() {
291
- delete_option('nifty_options');
292
  }
293
 
294
  register_deactivation_hook(__FILE__, 'nifty_deactivate');
295
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  // Calling plugins option panel
297
  require_once 'admin/main-options.php';
298
  require_once 'admin/ot-loader.php';
1
  <?php
2
  /*
3
  Plugin Name: Nifty Coming Soon & Maintenance page
4
+ Plugin URI: https://wpconcern.com/plugins/nifty-coming-soon-and-under-construction-page/
5
  Description: Easy to set up Coming Soon, Maintenance and Under Construction page. It features Responsive design, Countdown timer, Animations, Live Preview, Background Slider, Subscription form and more.
6
+ Version: 2.0.2
7
  Author: WP Concern
8
  Author URI: https://wpconcern.com/
9
+ Text Domain: nifty-coming-soon-and-under-construction-page
10
  License: GPLv3
11
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
 
 
12
 
13
  Copyright 2015 - 2021 WebFactory Ltd (email: support@webfactoryltd.com)
14
 
29
 
30
  defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
31
 
32
+ define( 'NCSUCP_VERSION', '2.0.2' );
33
+ define( 'NCSUCP_SLUG', 'nifty-coming-soon-and-under-construction-page' );
34
+ define( 'NCSUCP_BASE_NAME', basename( dirname( __FILE__ ) ) );
35
+ define( 'NCSUCP_BASE_FILEPATH', __FILE__ );
36
+ define( 'NCSUCP_BASE_FILENAME', plugin_basename( __FILE__ ) );
37
+ define( 'NCSUCP_DIR', rtrim( plugin_dir_path( __FILE__ ), '/' ) );
38
+ define( 'NCSUCP_URL', rtrim( plugin_dir_url( __FILE__ ), '/' ) );
39
+
40
+ // Init autoload.
41
+ require_once NCSUCP_DIR . '/vendor/autoload.php';
42
+ require_once NCSUCP_DIR . '/vendor/wptt/webfont-loader/wptt-webfont-loader.php';
43
+
44
  // Display status of the coming soon page in the admin bar
45
  add_action('admin_bar_menu', 'nifty_cs_custom_menu', 1000);
46
 
52
 
53
  $argsParent=array(
54
  'id' => 'niftycs_custom_menu',
55
+ 'title' => esc_html__( 'Nifty Coming Soon is Enabled', 'nifty-coming-soon-and-under-construction-page' ),
56
  'href' => admin_url('?page=niftycs-options#section_general_settings'),
57
  'meta' => array( 'class' => 'red-hot-button' ),
58
 
287
 
288
 
289
  // add settings link to plugins page
290
+ function nifty_plugin_action_links($links) {
291
+ $settings_link = '<a href="' . esc_url( admin_url( 'admin.php?page=niftycs-options' ) ) . '">' . esc_html__( 'Settings', 'nifty-coming-soon-and-under-construction-page' ) . '</a>';
292
+
293
  array_unshift($links, $settings_link);
294
 
295
  return $links;
296
+ }
297
 
298
  add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'nifty_plugin_action_links');
299
 
300
  // remove options on deactivate
301
  function nifty_deactivate() {
302
+ // delete_option('nifty_options');
303
  }
304
 
305
  register_deactivation_hook(__FILE__, 'nifty_deactivate');
306
 
307
+ /**
308
+ * Load plugin textdomain.
309
+ *
310
+ * @since 2.0.2
311
+ */
312
+ function nifty_cs_load_textdomain() {
313
+ load_plugin_textdomain( 'nifty-coming-soon-and-under-construction-page' );
314
+ }
315
+
316
+ add_action( 'plugins_loaded', 'nifty_cs_load_textdomain' );
317
+
318
+ /**
319
+ * Add admin notice.
320
+ *
321
+ * @since 2.0.2
322
+ */
323
+ function nifty_cs_admin_notice() {
324
+ // Setup notice.
325
+ \Nilambar\AdminNotice\Notice::init(
326
+ array(
327
+ 'slug' => NCSUCP_SLUG,
328
+ 'name' => esc_html__( 'Coming Soon & Maintenance Mode Page', 'nifty-coming-soon-and-under-construction-page' ),
329
+ )
330
+ );
331
+ }
332
+ add_action( 'admin_init', 'nifty_cs_admin_notice' );
333
+
334
  // Calling plugins option panel
335
  require_once 'admin/main-options.php';
336
  require_once 'admin/ot-loader.php';
readme.txt CHANGED
@@ -1,11 +1,14 @@
1
  === Coming Soon & Maintenance Mode Page ===
 
2
  Contributors: wpconcern, maneshtimilsina, rabmalin
 
3
  Tags: coming soon, coming soon page, launch page, maintenance mode, maintenance page, coming soon mode, under construction, maintenance mode page, landing page, offline page, subscribe form, maintenance, maintenance mode with countdown timer, maintenance mode with timer, coming soon plugin, wp coming soon, wordpress under construction, under construction page, wp maintenance, wordpress coming soon page, simple maintenance mode, custom coming soon, custom maintenance mode
4
  Tested up to: 6.0
5
  License: GPLv3
6
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
7
- Stable tag: 2.0.1
8
  Requires PHP: 5.6
 
9
 
10
  Nifty Coming Soon & Maintenance Page creates awesome Coming Soon & Maintenance Pages with premium features for free.
11
 
@@ -76,6 +79,10 @@ As from the update of 1.0.9, the plugin offers the way to Live Preview you're Co
76
 
77
  == Changelog ==
78
 
 
 
 
 
79
  = 2.0.1 =
80
  * WP compatibility check
81
  * Minor bug fixes
1
  === Coming Soon & Maintenance Mode Page ===
2
+
3
  Contributors: wpconcern, maneshtimilsina, rabmalin
4
+ Donate link: https://wpconcern.com/plugins/nifty-coming-soon-and-under-construction-page/
5
  Tags: coming soon, coming soon page, launch page, maintenance mode, maintenance page, coming soon mode, under construction, maintenance mode page, landing page, offline page, subscribe form, maintenance, maintenance mode with countdown timer, maintenance mode with timer, coming soon plugin, wp coming soon, wordpress under construction, under construction page, wp maintenance, wordpress coming soon page, simple maintenance mode, custom coming soon, custom maintenance mode
6
  Tested up to: 6.0
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
+ Stable tag: 2.0.2
10
  Requires PHP: 5.6
11
+ Requires at least: 4.9
12
 
13
  Nifty Coming Soon & Maintenance Page creates awesome Coming Soon & Maintenance Pages with premium features for free.
14
 
79
 
80
  == Changelog ==
81
 
82
+ = 2.0.2 =
83
+ * Implement local webfonts
84
+ * Minor bug fixes
85
+
86
  = 2.0.1 =
87
  * WP compatibility check
88
  * Minor bug fixes
template/index.php CHANGED
@@ -42,13 +42,20 @@ $nifty_timer = ot_get_option('display_count_down_timer');
42
  $button_color = ot_get_option('sign_up_button_color');
43
  $button_color_hover = ot_get_option('sign_up_button_color_hover');
44
 
 
45
 
46
- echo "<link href='https://fonts.googleapis.com/css?family=" . $sitetitle_font . "&subset=latin,latin-ext' rel='stylesheet' type='text/css'>";
47
- echo "<link href='https://fonts.googleapis.com/css?family=" . $heading_font . "&subset=latin,latin-ext' rel='stylesheet' type='text/css'>";
48
- echo "<link href='https://fonts.googleapis.com/css?family=" . $paragraph_font . "&subset=latin,latin-ext' rel='stylesheet' type='text/css'>";
49
- if ('off' != $nifty_timer) {
50
- echo "<link href='https://fonts.googleapis.com/css?family=" . $counter_font . "&subset=latin,latin-ext' rel='stylesheet' type='text/css'>";
 
 
 
 
 
51
  }
 
52
  echo "<style>";
53
  echo "body {background:" . $background_color . " !important;}";
54
  echo '#days, #hours, #minutes, #seconds { color: ' . (ot_get_option('countdown_font_color') ? ot_get_option('countdown_font_color') : '#ffffff') . '; }';
@@ -537,4 +544,4 @@ $nifty_timer = ot_get_option('display_count_down_timer');
537
 
538
  </body>
539
 
540
- </html>
42
  $button_color = ot_get_option('sign_up_button_color');
43
  $button_color_hover = ot_get_option('sign_up_button_color_hover');
44
 
45
+ $all_fonts = array( $sitetitle_font, $heading_font, $paragraph_font );
46
 
47
+ if ( 'off' != $nifty_timer ) {
48
+ $all_fonts[] = $counter_font;
49
+ }
50
+
51
+ $required_fonts = array_unique( $all_fonts );
52
+
53
+ if ( ! empty( $required_fonts ) ) {
54
+ foreach ( $required_fonts as $font ) {
55
+ echo "<link href='". wptt_get_webfont_url( "https://fonts.googleapis.com/css2?family={$font}&display=swap&subset=latin,latin-ext" ) . "' rel='stylesheet' type='text/css'>";
56
+ }
57
  }
58
+
59
  echo "<style>";
60
  echo "body {background:" . $background_color . " !important;}";
61
  echo '#days, #hours, #minutes, #seconds { color: ' . (ot_get_option('countdown_font_color') ? ot_get_option('countdown_font_color') : '#ffffff') . '; }';
544
 
545
  </body>
546
 
547
+ </html>
uninstall.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Uninstall
4
+ *
5
+ * @package NCSUCP
6
+ */
7
+
8
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
9
+ exit;
10
+ }
11
+
12
+ // Remove plugin options.
13
+ delete_option( 'nifty_options' );
vendor/autoload.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload.php @generated by Composer
4
+
5
+ require_once __DIR__ . '/composer/autoload_real.php';
6
+
7
+ return ComposerAutoloaderInit39e2ad4da7c7acaed459aa3b0c41d20e::getLoader();
vendor/composer/ClassLoader.php ADDED
@@ -0,0 +1,572 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Composer.
5
+ *
6
+ * (c) Nils Adermann <naderman@naderman.de>
7
+ * Jordi Boggiano <j.boggiano@seld.be>
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ namespace Composer\Autoload;
14
+
15
+ /**
16
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
17
+ *
18
+ * $loader = new \Composer\Autoload\ClassLoader();
19
+ *
20
+ * // register classes with namespaces
21
+ * $loader->add('Symfony\Component', __DIR__.'/component');
22
+ * $loader->add('Symfony', __DIR__.'/framework');
23
+ *
24
+ * // activate the autoloader
25
+ * $loader->register();
26
+ *
27
+ * // to enable searching the include path (eg. for PEAR packages)
28
+ * $loader->setUseIncludePath(true);
29
+ *
30
+ * In this example, if you try to use a class in the Symfony\Component
31
+ * namespace or one of its children (Symfony\Component\Console for instance),
32
+ * the autoloader will first look for the class under the component/
33
+ * directory, and it will then fallback to the framework/ directory if not
34
+ * found before giving up.
35
+ *
36
+ * This class is loosely based on the Symfony UniversalClassLoader.
37
+ *
38
+ * @author Fabien Potencier <fabien@symfony.com>
39
+ * @author Jordi Boggiano <j.boggiano@seld.be>
40
+ * @see https://www.php-fig.org/psr/psr-0/
41
+ * @see https://www.php-fig.org/psr/psr-4/
42
+ */
43
+ class ClassLoader
44
+ {
45
+ /** @var ?string */
46
+ private $vendorDir;
47
+
48
+ // PSR-4
49
+ /**
50
+ * @var array[]
51
+ * @psalm-var array<string, array<string, int>>
52
+ */
53
+ private $prefixLengthsPsr4 = array();
54
+ /**
55
+ * @var array[]
56
+ * @psalm-var array<string, array<int, string>>
57
+ */
58
+ private $prefixDirsPsr4 = array();
59
+ /**
60
+ * @var array[]
61
+ * @psalm-var array<string, string>
62
+ */
63
+ private $fallbackDirsPsr4 = array();
64
+
65
+ // PSR-0
66
+ /**
67
+ * @var array[]
68
+ * @psalm-var array<string, array<string, string[]>>
69
+ */
70
+ private $prefixesPsr0 = array();
71
+ /**
72
+ * @var array[]
73
+ * @psalm-var array<string, string>
74
+ */
75
+ private $fallbackDirsPsr0 = array();
76
+
77
+ /** @var bool */
78
+ private $useIncludePath = false;
79
+
80
+ /**
81
+ * @var string[]
82
+ * @psalm-var array<string, string>
83
+ */
84
+ private $classMap = array();
85
+
86
+ /** @var bool */
87
+ private $classMapAuthoritative = false;
88
+
89
+ /**
90
+ * @var bool[]
91
+ * @psalm-var array<string, bool>
92
+ */
93
+ private $missingClasses = array();
94
+
95
+ /** @var ?string */
96
+ private $apcuPrefix;
97
+
98
+ /**
99
+ * @var self[]
100
+ */
101
+ private static $registeredLoaders = array();
102
+
103
+ /**
104
+ * @param ?string $vendorDir
105
+ */
106
+ public function __construct($vendorDir = null)
107
+ {
108
+ $this->vendorDir = $vendorDir;
109
+ }
110
+
111
+ /**
112
+ * @return string[]
113
+ */
114
+ public function getPrefixes()
115
+ {
116
+ if (!empty($this->prefixesPsr0)) {
117
+ return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
118
+ }
119
+
120
+ return array();
121
+ }
122
+
123
+ /**
124
+ * @return array[]
125
+ * @psalm-return array<string, array<int, string>>
126
+ */
127
+ public function getPrefixesPsr4()
128
+ {
129
+ return $this->prefixDirsPsr4;
130
+ }
131
+
132
+ /**
133
+ * @return array[]
134
+ * @psalm-return array<string, string>
135
+ */
136
+ public function getFallbackDirs()
137
+ {
138
+ return $this->fallbackDirsPsr0;
139
+ }
140
+
141
+ /**
142
+ * @return array[]
143
+ * @psalm-return array<string, string>
144
+ */
145
+ public function getFallbackDirsPsr4()
146
+ {
147
+ return $this->fallbackDirsPsr4;
148
+ }
149
+
150
+ /**
151
+ * @return string[] Array of classname => path
152
+ * @psalm-var array<string, string>
153
+ */
154
+ public function getClassMap()
155
+ {
156
+ return $this->classMap;
157
+ }
158
+
159
+ /**
160
+ * @param string[] $classMap Class to filename map
161
+ * @psalm-param array<string, string> $classMap
162
+ *
163
+ * @return void
164
+ */
165
+ public function addClassMap(array $classMap)
166
+ {
167
+ if ($this->classMap) {
168
+ $this->classMap = array_merge($this->classMap, $classMap);
169
+ } else {
170
+ $this->classMap = $classMap;
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Registers a set of PSR-0 directories for a given prefix, either
176
+ * appending or prepending to the ones previously set for this prefix.
177
+ *
178
+ * @param string $prefix The prefix
179
+ * @param string[]|string $paths The PSR-0 root directories
180
+ * @param bool $prepend Whether to prepend the directories
181
+ *
182
+ * @return void
183
+ */
184
+ public function add($prefix, $paths, $prepend = false)
185
+ {
186
+ if (!$prefix) {
187
+ if ($prepend) {
188
+ $this->fallbackDirsPsr0 = array_merge(
189
+ (array) $paths,
190
+ $this->fallbackDirsPsr0
191
+ );
192
+ } else {
193
+ $this->fallbackDirsPsr0 = array_merge(
194
+ $this->fallbackDirsPsr0,
195
+ (array) $paths
196
+ );
197
+ }
198
+
199
+ return;
200
+ }
201
+
202
+ $first = $prefix[0];
203
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
204
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
205
+
206
+ return;
207
+ }
208
+ if ($prepend) {
209
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
210
+ (array) $paths,
211
+ $this->prefixesPsr0[$first][$prefix]
212
+ );
213
+ } else {
214
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
215
+ $this->prefixesPsr0[$first][$prefix],
216
+ (array) $paths
217
+ );
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Registers a set of PSR-4 directories for a given namespace, either
223
+ * appending or prepending to the ones previously set for this namespace.
224
+ *
225
+ * @param string $prefix The prefix/namespace, with trailing '\\'
226
+ * @param string[]|string $paths The PSR-4 base directories
227
+ * @param bool $prepend Whether to prepend the directories
228
+ *
229
+ * @throws \InvalidArgumentException
230
+ *
231
+ * @return void
232
+ */
233
+ public function addPsr4($prefix, $paths, $prepend = false)
234
+ {
235
+ if (!$prefix) {
236
+ // Register directories for the root namespace.
237
+ if ($prepend) {
238
+ $this->fallbackDirsPsr4 = array_merge(
239
+ (array) $paths,
240
+ $this->fallbackDirsPsr4
241
+ );
242
+ } else {
243
+ $this->fallbackDirsPsr4 = array_merge(
244
+ $this->fallbackDirsPsr4,
245
+ (array) $paths
246
+ );
247
+ }
248
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
249
+ // Register directories for a new namespace.
250
+ $length = strlen($prefix);
251
+ if ('\\' !== $prefix[$length - 1]) {
252
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
253
+ }
254
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
255
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
256
+ } elseif ($prepend) {
257
+ // Prepend directories for an already registered namespace.
258
+ $this->prefixDirsPsr4[$prefix] = array_merge(
259
+ (array) $paths,
260
+ $this->prefixDirsPsr4[$prefix]
261
+ );
262
+ } else {
263
+ // Append directories for an already registered namespace.
264
+ $this->prefixDirsPsr4[$prefix] = array_merge(
265
+ $this->prefixDirsPsr4[$prefix],
266
+ (array) $paths
267
+ );
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Registers a set of PSR-0 directories for a given prefix,
273
+ * replacing any others previously set for this prefix.
274
+ *
275
+ * @param string $prefix The prefix
276
+ * @param string[]|string $paths The PSR-0 base directories
277
+ *
278
+ * @return void
279
+ */
280
+ public function set($prefix, $paths)
281
+ {
282
+ if (!$prefix) {
283
+ $this->fallbackDirsPsr0 = (array) $paths;
284
+ } else {
285
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Registers a set of PSR-4 directories for a given namespace,
291
+ * replacing any others previously set for this namespace.
292
+ *
293
+ * @param string $prefix The prefix/namespace, with trailing '\\'
294
+ * @param string[]|string $paths The PSR-4 base directories
295
+ *
296
+ * @throws \InvalidArgumentException
297
+ *
298
+ * @return void
299
+ */
300
+ public function setPsr4($prefix, $paths)
301
+ {
302
+ if (!$prefix) {
303
+ $this->fallbackDirsPsr4 = (array) $paths;
304
+ } else {
305
+ $length = strlen($prefix);
306
+ if ('\\' !== $prefix[$length - 1]) {
307
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
308
+ }
309
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
310
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
311
+ }
312
+ }
313
+
314
+ /**
315
+ * Turns on searching the include path for class files.
316
+ *
317
+ * @param bool $useIncludePath
318
+ *
319
+ * @return void
320
+ */
321
+ public function setUseIncludePath($useIncludePath)
322
+ {
323
+ $this->useIncludePath = $useIncludePath;
324
+ }
325
+
326
+ /**
327
+ * Can be used to check if the autoloader uses the include path to check
328
+ * for classes.
329
+ *
330
+ * @return bool
331
+ */
332
+ public function getUseIncludePath()
333
+ {
334
+ return $this->useIncludePath;
335
+ }
336
+
337
+ /**
338
+ * Turns off searching the prefix and fallback directories for classes
339
+ * that have not been registered with the class map.
340
+ *
341
+ * @param bool $classMapAuthoritative
342
+ *
343
+ * @return void
344
+ */
345
+ public function setClassMapAuthoritative($classMapAuthoritative)
346
+ {
347
+ $this->classMapAuthoritative = $classMapAuthoritative;
348
+ }
349
+
350
+ /**
351
+ * Should class lookup fail if not found in the current class map?
352
+ *
353
+ * @return bool
354
+ */
355
+ public function isClassMapAuthoritative()
356
+ {
357
+ return $this->classMapAuthoritative;
358
+ }
359
+
360
+ /**
361
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
362
+ *
363
+ * @param string|null $apcuPrefix
364
+ *
365
+ * @return void
366
+ */
367
+ public function setApcuPrefix($apcuPrefix)
368
+ {
369
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
370
+ }
371
+
372
+ /**
373
+ * The APCu prefix in use, or null if APCu caching is not enabled.
374
+ *
375
+ * @return string|null
376
+ */
377
+ public function getApcuPrefix()
378
+ {
379
+ return $this->apcuPrefix;
380
+ }
381
+
382
+ /**
383
+ * Registers this instance as an autoloader.
384
+ *
385
+ * @param bool $prepend Whether to prepend the autoloader or not
386
+ *
387
+ * @return void
388
+ */
389
+ public function register($prepend = false)
390
+ {
391
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
392
+
393
+ if (null === $this->vendorDir) {
394
+ return;
395
+ }
396
+
397
+ if ($prepend) {
398
+ self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
399
+ } else {
400
+ unset(self::$registeredLoaders[$this->vendorDir]);
401
+ self::$registeredLoaders[$this->vendorDir] = $this;
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Unregisters this instance as an autoloader.
407
+ *
408
+ * @return void
409
+ */
410
+ public function unregister()
411
+ {
412
+ spl_autoload_unregister(array($this, 'loadClass'));
413
+
414
+ if (null !== $this->vendorDir) {
415
+ unset(self::$registeredLoaders[$this->vendorDir]);
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Loads the given class or interface.
421
+ *
422
+ * @param string $class The name of the class
423
+ * @return true|null True if loaded, null otherwise
424
+ */
425
+ public function loadClass($class)
426
+ {
427
+ if ($file = $this->findFile($class)) {
428
+ includeFile($file);
429
+
430
+ return true;
431
+ }
432
+
433
+ return null;
434
+ }
435
+
436
+ /**
437
+ * Finds the path to the file where the class is defined.
438
+ *
439
+ * @param string $class The name of the class
440
+ *
441
+ * @return string|false The path if found, false otherwise
442
+ */
443
+ public function findFile($class)
444
+ {
445
+ // class map lookup
446
+ if (isset($this->classMap[$class])) {
447
+ return $this->classMap[$class];
448
+ }
449
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
450
+ return false;
451
+ }
452
+ if (null !== $this->apcuPrefix) {
453
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
454
+ if ($hit) {
455
+ return $file;
456
+ }
457
+ }
458
+
459
+ $file = $this->findFileWithExtension($class, '.php');
460
+
461
+ // Search for Hack files if we are running on HHVM
462
+ if (false === $file && defined('HHVM_VERSION')) {
463
+ $file = $this->findFileWithExtension($class, '.hh');
464
+ }
465
+
466
+ if (null !== $this->apcuPrefix) {
467
+ apcu_add($this->apcuPrefix.$class, $file);
468
+ }
469
+
470
+ if (false === $file) {
471
+ // Remember that this class does not exist.
472
+ $this->missingClasses[$class] = true;
473
+ }
474
+
475
+ return $file;
476
+ }
477
+
478
+ /**
479
+ * Returns the currently registered loaders indexed by their corresponding vendor directories.
480
+ *
481
+ * @return self[]
482
+ */
483
+ public static function getRegisteredLoaders()
484
+ {
485
+ return self::$registeredLoaders;
486
+ }
487
+
488
+ /**
489
+ * @param string $class
490
+ * @param string $ext
491
+ * @return string|false
492
+ */
493
+ private function findFileWithExtension($class, $ext)
494
+ {
495
+ // PSR-4 lookup
496
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
497
+
498
+ $first = $class[0];
499
+ if (isset($this->prefixLengthsPsr4[$first])) {
500
+ $subPath = $class;
501
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
502
+ $subPath = substr($subPath, 0, $lastPos);
503
+ $search = $subPath . '\\';
504
+ if (isset($this->prefixDirsPsr4[$search])) {
505
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
506
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
507
+ if (file_exists($file = $dir . $pathEnd)) {
508
+ return $file;
509
+ }
510
+ }
511
+ }
512
+ }
513
+ }
514
+
515
+ // PSR-4 fallback dirs
516
+ foreach ($this->fallbackDirsPsr4 as $dir) {
517
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
518
+ return $file;
519
+ }
520
+ }
521
+
522
+ // PSR-0 lookup
523
+ if (false !== $pos = strrpos($class, '\\')) {
524
+ // namespaced class name
525
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
526
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
527
+ } else {
528
+ // PEAR-like class name
529
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
530
+ }
531
+
532
+ if (isset($this->prefixesPsr0[$first])) {
533
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
534
+ if (0 === strpos($class, $prefix)) {
535
+ foreach ($dirs as $dir) {
536
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
537
+ return $file;
538
+ }
539
+ }
540
+ }
541
+ }
542
+ }
543
+
544
+ // PSR-0 fallback dirs
545
+ foreach ($this->fallbackDirsPsr0 as $dir) {
546
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
547
+ return $file;
548
+ }
549
+ }
550
+
551
+ // PSR-0 include paths.
552
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
553
+ return $file;
554
+ }
555
+
556
+ return false;
557
+ }
558
+ }
559
+
560
+ /**
561
+ * Scope isolated include.
562
+ *
563
+ * Prevents access to $this/self from included files.
564
+ *
565
+ * @param string $file
566
+ * @return void
567
+ * @private
568
+ */
569
+ function includeFile($file)
570
+ {
571
+ include $file;
572
+ }
vendor/composer/InstalledVersions.php ADDED
@@ -0,0 +1,350 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Composer.
5
+ *
6
+ * (c) Nils Adermann <naderman@naderman.de>
7
+ * Jordi Boggiano <j.boggiano@seld.be>
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ namespace Composer;
14
+
15
+ use Composer\Autoload\ClassLoader;
16
+ use Composer\Semver\VersionParser;
17
+
18
+ /**
19
+ * This class is copied in every Composer installed project and available to all
20
+ *
21
+ * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
22
+ *
23
+ * To require its presence, you can require `composer-runtime-api ^2.0`
24
+ */
25
+ class InstalledVersions
26
+ {
27
+ /**
28
+ * @var mixed[]|null
29
+ * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
30
+ */
31
+ private static $installed;
32
+
33
+ /**
34
+ * @var bool|null
35
+ */
36
+ private static $canGetVendors;
37
+
38
+ /**
39
+ * @var array[]
40
+ * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
41
+ */
42
+ private static $installedByVendor = array();
43
+
44
+ /**
45
+ * Returns a list of all package names which are present, either by being installed, replaced or provided
46
+ *
47
+ * @return string[]
48
+ * @psalm-return list<string>
49
+ */
50
+ public static function getInstalledPackages()
51
+ {
52
+ $packages = array();
53
+ foreach (self::getInstalled() as $installed) {
54
+ $packages[] = array_keys($installed['versions']);
55
+ }
56
+
57
+ if (1 === \count($packages)) {
58
+ return $packages[0];
59
+ }
60
+
61
+ return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
62
+ }
63
+
64
+ /**
65
+ * Returns a list of all package names with a specific type e.g. 'library'
66
+ *
67
+ * @param string $type
68
+ * @return string[]
69
+ * @psalm-return list<string>
70
+ */
71
+ public static function getInstalledPackagesByType($type)
72
+ {
73
+ $packagesByType = array();
74
+
75
+ foreach (self::getInstalled() as $installed) {
76
+ foreach ($installed['versions'] as $name => $package) {
77
+ if (isset($package['type']) && $package['type'] === $type) {
78
+ $packagesByType[] = $name;
79
+ }
80
+ }
81
+ }
82
+
83
+ return $packagesByType;
84
+ }
85
+
86
+ /**
87
+ * Checks whether the given package is installed
88
+ *
89
+ * This also returns true if the package name is provided or replaced by another package
90
+ *
91
+ * @param string $packageName
92
+ * @param bool $includeDevRequirements
93
+ * @return bool
94
+ */
95
+ public static function isInstalled($packageName, $includeDevRequirements = true)
96
+ {
97
+ foreach (self::getInstalled() as $installed) {
98
+ if (isset($installed['versions'][$packageName])) {
99
+ return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
100
+ }
101
+ }
102
+
103
+ return false;
104
+ }
105
+
106
+ /**
107
+ * Checks whether the given package satisfies a version constraint
108
+ *
109
+ * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
110
+ *
111
+ * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
112
+ *
113
+ * @param VersionParser $parser Install composer/semver to have access to this class and functionality
114
+ * @param string $packageName
115
+ * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
116
+ * @return bool
117
+ */
118
+ public static function satisfies(VersionParser $parser, $packageName, $constraint)
119
+ {
120
+ $constraint = $parser->parseConstraints($constraint);
121
+ $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
122
+
123
+ return $provided->matches($constraint);
124
+ }
125
+
126
+ /**
127
+ * Returns a version constraint representing all the range(s) which are installed for a given package
128
+ *
129
+ * It is easier to use this via isInstalled() with the $constraint argument if you need to check
130
+ * whether a given version of a package is installed, and not just whether it exists
131
+ *
132
+ * @param string $packageName
133
+ * @return string Version constraint usable with composer/semver
134
+ */
135
+ public static function getVersionRanges($packageName)
136
+ {
137
+ foreach (self::getInstalled() as $installed) {
138
+ if (!isset($installed['versions'][$packageName])) {
139
+ continue;
140
+ }
141
+
142
+ $ranges = array();
143
+ if (isset($installed['versions'][$packageName]['pretty_version'])) {
144
+ $ranges[] = $installed['versions'][$packageName]['pretty_version'];
145
+ }
146
+ if (array_key_exists('aliases', $installed['versions'][$packageName])) {
147
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
148
+ }
149
+ if (array_key_exists('replaced', $installed['versions'][$packageName])) {
150
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
151
+ }
152
+ if (array_key_exists('provided', $installed['versions'][$packageName])) {
153
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
154
+ }
155
+
156
+ return implode(' || ', $ranges);
157
+ }
158
+
159
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
160
+ }
161
+
162
+ /**
163
+ * @param string $packageName
164
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
165
+ */
166
+ public static function getVersion($packageName)
167
+ {
168
+ foreach (self::getInstalled() as $installed) {
169
+ if (!isset($installed['versions'][$packageName])) {
170
+ continue;
171
+ }
172
+
173
+ if (!isset($installed['versions'][$packageName]['version'])) {
174
+ return null;
175
+ }
176
+
177
+ return $installed['versions'][$packageName]['version'];
178
+ }
179
+
180
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
181
+ }
182
+
183
+ /**
184
+ * @param string $packageName
185
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
186
+ */
187
+ public static function getPrettyVersion($packageName)
188
+ {
189
+ foreach (self::getInstalled() as $installed) {
190
+ if (!isset($installed['versions'][$packageName])) {
191
+ continue;
192
+ }
193
+
194
+ if (!isset($installed['versions'][$packageName]['pretty_version'])) {
195
+ return null;
196
+ }
197
+
198
+ return $installed['versions'][$packageName]['pretty_version'];
199
+ }
200
+
201
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
202
+ }
203
+
204
+ /**
205
+ * @param string $packageName
206
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
207
+ */
208
+ public static function getReference($packageName)
209
+ {
210
+ foreach (self::getInstalled() as $installed) {
211
+ if (!isset($installed['versions'][$packageName])) {
212
+ continue;
213
+ }
214
+
215
+ if (!isset($installed['versions'][$packageName]['reference'])) {
216
+ return null;
217
+ }
218
+
219
+ return $installed['versions'][$packageName]['reference'];
220
+ }
221
+
222
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
223
+ }
224
+
225
+ /**
226
+ * @param string $packageName
227
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
228
+ */
229
+ public static function getInstallPath($packageName)
230
+ {
231
+ foreach (self::getInstalled() as $installed) {
232
+ if (!isset($installed['versions'][$packageName])) {
233
+ continue;
234
+ }
235
+
236
+ return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
237
+ }
238
+
239
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
240
+ }
241
+
242
+ /**
243
+ * @return array
244
+ * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
245
+ */
246
+ public static function getRootPackage()
247
+ {
248
+ $installed = self::getInstalled();
249
+
250
+ return $installed[0]['root'];
251
+ }
252
+
253
+ /**
254
+ * Returns the raw installed.php data for custom implementations
255
+ *
256
+ * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
257
+ * @return array[]
258
+ * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
259
+ */
260
+ public static function getRawData()
261
+ {
262
+ @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
263
+
264
+ if (null === self::$installed) {
265
+ // only require the installed.php file if this file is loaded from its dumped location,
266
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
267
+ if (substr(__DIR__, -8, 1) !== 'C') {
268
+ self::$installed = include __DIR__ . '/installed.php';
269
+ } else {
270
+ self::$installed = array();
271
+ }
272
+ }
273
+
274
+ return self::$installed;
275
+ }
276
+
277
+ /**
278
+ * Returns the raw data of all installed.php which are currently loaded for custom implementations
279
+ *
280
+ * @return array[]
281
+ * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
282
+ */
283
+ public static function getAllRawData()
284
+ {
285
+ return self::getInstalled();
286
+ }
287
+
288
+ /**
289
+ * Lets you reload the static array from another file
290
+ *
291
+ * This is only useful for complex integrations in which a project needs to use
292
+ * this class but then also needs to execute another project's autoloader in process,
293
+ * and wants to ensure both projects have access to their version of installed.php.
294
+ *
295
+ * A typical case would be PHPUnit, where it would need to make sure it reads all
296
+ * the data it needs from this class, then call reload() with
297
+ * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
298
+ * the project in which it runs can then also use this class safely, without
299
+ * interference between PHPUnit's dependencies and the project's dependencies.
300
+ *
301
+ * @param array[] $data A vendor/composer/installed.php data set
302
+ * @return void
303
+ *
304
+ * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
305
+ */
306
+ public static function reload($data)
307
+ {
308
+ self::$installed = $data;
309
+ self::$installedByVendor = array();
310
+ }
311
+
312
+ /**
313
+ * @return array[]
314
+ * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
315
+ */
316
+ private static function getInstalled()
317
+ {
318
+ if (null === self::$canGetVendors) {
319
+ self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
320
+ }
321
+
322
+ $installed = array();
323
+
324
+ if (self::$canGetVendors) {
325
+ foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
326
+ if (isset(self::$installedByVendor[$vendorDir])) {
327
+ $installed[] = self::$installedByVendor[$vendorDir];
328
+ } elseif (is_file($vendorDir.'/composer/installed.php')) {
329
+ $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
330
+ if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
331
+ self::$installed = $installed[count($installed) - 1];
332
+ }
333
+ }
334
+ }
335
+ }
336
+
337
+ if (null === self::$installed) {
338
+ // only require the installed.php file if this file is loaded from its dumped location,
339
+ // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
340
+ if (substr(__DIR__, -8, 1) !== 'C') {
341
+ self::$installed = require __DIR__ . '/installed.php';
342
+ } else {
343
+ self::$installed = array();
344
+ }
345
+ }
346
+ $installed[] = self::$installed;
347
+
348
+ return $installed;
349
+ }
350
+ }
vendor/composer/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Copyright (c) Nils Adermann, Jordi Boggiano
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished
9
+ to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
vendor/composer/autoload_classmap.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_classmap.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
10
+ );
vendor/composer/autoload_namespaces.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_namespaces.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ );
vendor/composer/autoload_psr4.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_psr4.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'Nilambar\\AdminNotice\\' => array($vendorDir . '/ernilambar/wp-admin-notice/src'),
10
+ );
vendor/composer/autoload_real.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_real.php @generated by Composer
4
+
5
+ class ComposerAutoloaderInit39e2ad4da7c7acaed459aa3b0c41d20e
6
+ {
7
+ private static $loader;
8
+
9
+ public static function loadClassLoader($class)
10
+ {
11
+ if ('Composer\Autoload\ClassLoader' === $class) {
12
+ require __DIR__ . '/ClassLoader.php';
13
+ }
14
+ }
15
+
16
+ /**
17
+ * @return \Composer\Autoload\ClassLoader
18
+ */
19
+ public static function getLoader()
20
+ {
21
+ if (null !== self::$loader) {
22
+ return self::$loader;
23
+ }
24
+
25
+ require __DIR__ . '/platform_check.php';
26
+
27
+ spl_autoload_register(array('ComposerAutoloaderInit39e2ad4da7c7acaed459aa3b0c41d20e', 'loadClassLoader'), true, true);
28
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
29
+ spl_autoload_unregister(array('ComposerAutoloaderInit39e2ad4da7c7acaed459aa3b0c41d20e', 'loadClassLoader'));
30
+
31
+ $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
32
+ if ($useStaticLoader) {
33
+ require __DIR__ . '/autoload_static.php';
34
+
35
+ call_user_func(\Composer\Autoload\ComposerStaticInit39e2ad4da7c7acaed459aa3b0c41d20e::getInitializer($loader));
36
+ } else {
37
+ $map = require __DIR__ . '/autoload_namespaces.php';
38
+ foreach ($map as $namespace => $path) {
39
+ $loader->set($namespace, $path);
40
+ }
41
+
42
+ $map = require __DIR__ . '/autoload_psr4.php';
43
+ foreach ($map as $namespace => $path) {
44
+ $loader->setPsr4($namespace, $path);
45
+ }
46
+
47
+ $classMap = require __DIR__ . '/autoload_classmap.php';
48
+ if ($classMap) {
49
+ $loader->addClassMap($classMap);
50
+ }
51
+ }
52
+
53
+ $loader->register(true);
54
+
55
+ return $loader;
56
+ }
57
+ }
vendor/composer/autoload_static.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_static.php @generated by Composer
4
+
5
+ namespace Composer\Autoload;
6
+
7
+ class ComposerStaticInit39e2ad4da7c7acaed459aa3b0c41d20e
8
+ {
9
+ public static $prefixLengthsPsr4 = array (
10
+ 'N' =>
11
+ array (
12
+ 'Nilambar\\AdminNotice\\' => 21,
13
+ ),
14
+ );
15
+
16
+ public static $prefixDirsPsr4 = array (
17
+ 'Nilambar\\AdminNotice\\' =>
18
+ array (
19
+ 0 => __DIR__ . '/..' . '/ernilambar/wp-admin-notice/src',
20
+ ),
21
+ );
22
+
23
+ public static $classMap = array (
24
+ 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
25
+ );
26
+
27
+ public static function getInitializer(ClassLoader $loader)
28
+ {
29
+ return \Closure::bind(function () use ($loader) {
30
+ $loader->prefixLengthsPsr4 = ComposerStaticInit39e2ad4da7c7acaed459aa3b0c41d20e::$prefixLengthsPsr4;
31
+ $loader->prefixDirsPsr4 = ComposerStaticInit39e2ad4da7c7acaed459aa3b0c41d20e::$prefixDirsPsr4;
32
+ $loader->classMap = ComposerStaticInit39e2ad4da7c7acaed459aa3b0c41d20e::$classMap;
33
+
34
+ }, null, ClassLoader::class);
35
+ }
36
+ }
vendor/composer/installed.json ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "packages": [
3
+ {
4
+ "name": "ernilambar/wp-admin-notice",
5
+ "version": "1.0.0",
6
+ "version_normalized": "1.0.0.0",
7
+ "source": {
8
+ "type": "git",
9
+ "url": "https://github.com/ernilambar/wp-admin-notice.git",
10
+ "reference": "1fd14ff6d79994750d25b4f529284a6942e117eb"
11
+ },
12
+ "dist": {
13
+ "type": "zip",
14
+ "url": "https://api.github.com/repos/ernilambar/wp-admin-notice/zipball/1fd14ff6d79994750d25b4f529284a6942e117eb",
15
+ "reference": "1fd14ff6d79994750d25b4f529284a6942e117eb",
16
+ "shasum": ""
17
+ },
18
+ "require": {
19
+ "php": ">=5.6"
20
+ },
21
+ "time": "2022-06-27T07:08:52+00:00",
22
+ "type": "library",
23
+ "installation-source": "dist",
24
+ "autoload": {
25
+ "psr-4": {
26
+ "Nilambar\\AdminNotice\\": "src"
27
+ }
28
+ },
29
+ "notification-url": "https://packagist.org/downloads/",
30
+ "license": [
31
+ "MIT"
32
+ ],
33
+ "authors": [
34
+ {
35
+ "name": "Nilambar Sharma",
36
+ "email": "nilambar@outlook.com",
37
+ "homepage": "https://www.nilambar.net/"
38
+ }
39
+ ],
40
+ "description": "WordPress Helper for showing admin notice",
41
+ "homepage": "https://github.com/ernilambar/wp-admin-notice",
42
+ "keywords": [
43
+ "admin",
44
+ "notice",
45
+ "wordpress"
46
+ ],
47
+ "support": {
48
+ "issues": "https://github.com/ernilambar/wp-admin-notice/issues/",
49
+ "source": "https://github.com/ernilambar/wp-admin-notice/tree/1.0.0"
50
+ },
51
+ "install-path": "../ernilambar/wp-admin-notice"
52
+ },
53
+ {
54
+ "name": "wptt/webfont-loader",
55
+ "version": "v1.1.2",
56
+ "version_normalized": "1.1.2.0",
57
+ "source": {
58
+ "type": "git",
59
+ "url": "https://github.com/WPTT/webfont-loader.git",
60
+ "reference": "780e564bf0554c419ef447c2b5b768b497ecee40"
61
+ },
62
+ "dist": {
63
+ "type": "zip",
64
+ "url": "https://api.github.com/repos/WPTT/webfont-loader/zipball/780e564bf0554c419ef447c2b5b768b497ecee40",
65
+ "reference": "780e564bf0554c419ef447c2b5b768b497ecee40",
66
+ "shasum": ""
67
+ },
68
+ "require": {
69
+ "php": ">=5.6"
70
+ },
71
+ "require-dev": {
72
+ "composer/installers": "~1.0",
73
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
74
+ "php-parallel-lint/php-parallel-lint": "^1.2",
75
+ "wptrt/wpthemereview": "^0.2.1"
76
+ },
77
+ "time": "2022-06-17T10:41:00+00:00",
78
+ "type": "package",
79
+ "installation-source": "dist",
80
+ "notification-url": "https://packagist.org/downloads/",
81
+ "license": [
82
+ "MIT"
83
+ ],
84
+ "authors": [
85
+ {
86
+ "name": "Contributors",
87
+ "homepage": "https://github.com/WPTT/font-loader/graphs/contributors"
88
+ }
89
+ ],
90
+ "description": "Locally host webfonts.",
91
+ "homepage": "https://github.com/WPTT/font-loader",
92
+ "keywords": [
93
+ "wordpress"
94
+ ],
95
+ "support": {
96
+ "issues": "https://github.com/WPTT/font-loader/issues",
97
+ "source": "https://github.com/WPTT/font-loader"
98
+ },
99
+ "install-path": "../wptt/webfont-loader"
100
+ }
101
+ ],
102
+ "dev": true,
103
+ "dev-package-names": []
104
+ }
vendor/composer/installed.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php return array(
2
+ 'root' => array(
3
+ 'pretty_version' => 'dev-main',
4
+ 'version' => 'dev-main',
5
+ 'type' => 'library',
6
+ 'install_path' => __DIR__ . '/../../',
7
+ 'aliases' => array(),
8
+ 'reference' => 'af67a24fcc2ba01d680d5895284d7e2d40d4f4f3',
9
+ 'name' => '__root__',
10
+ 'dev' => true,
11
+ ),
12
+ 'versions' => array(
13
+ '__root__' => array(
14
+ 'pretty_version' => 'dev-main',
15
+ 'version' => 'dev-main',
16
+ 'type' => 'library',
17
+ 'install_path' => __DIR__ . '/../../',
18
+ 'aliases' => array(),
19
+ 'reference' => 'af67a24fcc2ba01d680d5895284d7e2d40d4f4f3',
20
+ 'dev_requirement' => false,
21
+ ),
22
+ 'ernilambar/wp-admin-notice' => array(
23
+ 'pretty_version' => '1.0.0',
24
+ 'version' => '1.0.0.0',
25
+ 'type' => 'library',
26
+ 'install_path' => __DIR__ . '/../ernilambar/wp-admin-notice',
27
+ 'aliases' => array(),
28
+ 'reference' => '1fd14ff6d79994750d25b4f529284a6942e117eb',
29
+ 'dev_requirement' => false,
30
+ ),
31
+ 'wptt/webfont-loader' => array(
32
+ 'pretty_version' => 'v1.1.2',
33
+ 'version' => '1.1.2.0',
34
+ 'type' => 'package',
35
+ 'install_path' => __DIR__ . '/../wptt/webfont-loader',
36
+ 'aliases' => array(),
37
+ 'reference' => '780e564bf0554c419ef447c2b5b768b497ecee40',
38
+ 'dev_requirement' => false,
39
+ ),
40
+ ),
41
+ );
vendor/composer/platform_check.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // platform_check.php @generated by Composer
4
+
5
+ $issues = array();
6
+
7
+ if (!(PHP_VERSION_ID >= 50600)) {
8
+ $issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.0". You are running ' . PHP_VERSION . '.';
9
+ }
10
+
11
+ if ($issues) {
12
+ if (!headers_sent()) {
13
+ header('HTTP/1.1 500 Internal Server Error');
14
+ }
15
+ if (!ini_get('display_errors')) {
16
+ if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
17
+ fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
18
+ } elseif (!headers_sent()) {
19
+ echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
20
+ }
21
+ }
22
+ trigger_error(
23
+ 'Composer detected issues in your platform: ' . implode(' ', $issues),
24
+ E_USER_ERROR
25
+ );
26
+ }
vendor/ernilambar/wp-admin-notice/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Nilambar Sharma
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
vendor/ernilambar/wp-admin-notice/README.md ADDED
@@ -0,0 +1,2 @@
 
 
1
+ # WP- Admin Notice
2
+ WordPress Helper for showing admin notice
vendor/ernilambar/wp-admin-notice/composer.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "ernilambar/wp-admin-notice",
3
+ "description": "WordPress Helper for showing admin notice",
4
+ "license": "MIT",
5
+ "type": "library",
6
+ "authors": [
7
+ {
8
+ "name": "Nilambar Sharma",
9
+ "email": "nilambar@outlook.com",
10
+ "homepage": "https://www.nilambar.net/"
11
+ }
12
+ ],
13
+ "keywords": ["wordpress", "admin", "notice"],
14
+ "homepage" : "https://github.com/ernilambar/wp-admin-notice",
15
+ "support": {
16
+ "issues": "https://github.com/ernilambar/wp-admin-notice/issues/"
17
+ },
18
+ "require": {
19
+ "php": ">=5.6"
20
+ },
21
+ "autoload": {
22
+ "psr-4": {
23
+ "Nilambar\\AdminNotice\\": "src"
24
+ }
25
+ },
26
+ "minimum-stability": "dev"
27
+ }
vendor/ernilambar/wp-admin-notice/src/Notice.php ADDED
@@ -0,0 +1,462 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WordPress Helper for showing admin notice
4
+ *
5
+ * @author Nilambar Sharma <nilambar@outlook.com>
6
+ * @copyright 2022 Nilambar Sharma
7
+ * @package WPAdminNotice
8
+ */
9
+
10
+ namespace Nilambar\AdminNotice;
11
+
12
+ defined( 'WPINC' ) || die;
13
+
14
+ /**
15
+ * Class Notice.
16
+ */
17
+ class Notice {
18
+
19
+ /**
20
+ * Prefix.
21
+ *
22
+ * @var string $prefix
23
+ *
24
+ * @since 1.0.0
25
+ */
26
+ private $prefix = '';
27
+
28
+ /**
29
+ * Name.
30
+ *
31
+ * @var string $name
32
+ *
33
+ * @since 1.0.0
34
+ */
35
+ private $name = '';
36
+
37
+ /**
38
+ * Type.
39
+ *
40
+ * @var string $type
41
+ *
42
+ * @since 1.0.0
43
+ */
44
+ private $type = '';
45
+
46
+ /**
47
+ * Slug.
48
+ *
49
+ * @var string $slug
50
+ *
51
+ * @since 1.0.0
52
+ */
53
+ private $slug = '';
54
+
55
+ /**
56
+ * Number of days to show the notice after.
57
+ *
58
+ * @var int $days
59
+ *
60
+ * @since 1.0.0
61
+ */
62
+ private $days = 7;
63
+
64
+ /**
65
+ * WP admin page screens to show notice.
66
+ *
67
+ * @var array $screens
68
+ *
69
+ * @since 1.0.0
70
+ */
71
+ private $screens = array();
72
+
73
+ /**
74
+ * Notice classes.
75
+ *
76
+ * @var array $classes
77
+ *
78
+ * @since 1.0.0
79
+ */
80
+ private $classes = array( 'notice', 'notice-info' );
81
+
82
+ /**
83
+ * Actions link texts.
84
+ *
85
+ * @var array $action_labels
86
+ *
87
+ * @since 1.0.0
88
+ */
89
+ private $action_labels = array();
90
+
91
+ /**
92
+ * Message.
93
+ *
94
+ * @var string $message
95
+ *
96
+ * @since 1.0.0
97
+ */
98
+ private $message = '';
99
+
100
+ /**
101
+ * Minimum capability for the user to see and dismiss notice.
102
+ *
103
+ * @var string $capability
104
+ *
105
+ * @since 1.0.0
106
+ */
107
+ private $capability = 'manage_options';
108
+
109
+ /**
110
+ * Constructor.
111
+ *
112
+ * @param array $args Arguments.
113
+ *
114
+ * @since 1.0.0
115
+ *
116
+ * @return void
117
+ */
118
+ private function __construct( $args ) {
119
+ if ( is_admin() ) {
120
+ $this->configure( $args );
121
+ $this->hooks();
122
+ $this->process_actions();
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Create and get new Notice instance.
128
+ *
129
+ * @param array $args Arguments array.
130
+ *
131
+ * @since 1.0.0
132
+ *
133
+ * @return Notice
134
+ */
135
+ public static function init( $args ) {
136
+ static $notices = array();
137
+
138
+ $slug = ( isset( $args['slug'] ) && ! empty( $args['slug'] ) ) ? $args['slug'] : '';
139
+
140
+ if ( '' === $slug ) {
141
+ return;
142
+ }
143
+
144
+ if ( ! isset( $notices[ $slug ] ) || ! $notices[ $slug ] instanceof Notice ) {
145
+ $notices[ $slug ] = new self( $args );
146
+ }
147
+
148
+ return $notices[ $slug ];
149
+ }
150
+
151
+ public function hooks() {
152
+ add_action('admin_notices', array( $this, 'hook_notice' ) );
153
+ }
154
+
155
+ public function hook_notice() {
156
+ $this->render();
157
+ }
158
+
159
+ /**
160
+ * Return review URL.
161
+ *
162
+ * @since 1.0.0
163
+ *
164
+ * @return string Review URL.
165
+ */
166
+ public function get_review_url() {
167
+ $url = '';
168
+
169
+ switch ( $this->type ) {
170
+ case 'plugin':
171
+ $url = 'https://wordpress.org/support/plugin/' . $this->slug . '/reviews/#new-post';
172
+ break;
173
+
174
+ case 'theme':
175
+ $url = 'https://wordpress.org/support/theme/' . $this->slug . '/reviews/#new-post';
176
+ break;
177
+
178
+ default:
179
+ break;
180
+ }
181
+
182
+ return $url;
183
+ }
184
+
185
+ /**
186
+ * Render links.
187
+ *
188
+ * @since 1.0.0
189
+ */
190
+ public function render_links() {
191
+ // Review link.
192
+ if ( ! empty( $this->action_labels['review'] ) ) {
193
+ echo '<p><a href="' . esc_url( $this->get_review_url() ) . '" target="_blank">' . esc_html( $this->action_labels['review'] ) . '</a></p>';
194
+ }
195
+
196
+ // Later link.
197
+ if ( ! empty( $this->action_labels['later'] ) ) {
198
+ echo '<p><a href="' . esc_url( add_query_arg( $this->key( 'action' ), 'later' ) ) . '">' . esc_html( $this->action_labels['later'] ) . '</a></p>';
199
+ }
200
+
201
+ // Dismiss link.
202
+ if ( ! empty( $this->action_labels['dismiss'] ) ) {
203
+ echo '<p><a href="' . esc_url( add_query_arg( $this->key( 'action' ), 'dismiss' ) ) . '">' . esc_html( $this->action_labels['dismiss'] ) . '</a></p>';
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Render the notice.
209
+ *
210
+ * @since 1.0.0
211
+ */
212
+ public function render() {
213
+ // Bail if not valid.
214
+ if ( ! $this->can_show() && ! empty( $this->message ) ) {
215
+ return;
216
+ }
217
+ ?>
218
+
219
+ <div id="wp-admin-notice-<?php echo esc_attr( $this->slug ); ?>" class="<?php echo esc_attr( $this->get_classes() ); ?>">
220
+ <p><?php echo $this->message; ?></p>
221
+
222
+ <?php $this->render_links(); ?>
223
+ </div>
224
+ <?php
225
+ }
226
+
227
+ /**
228
+ * Check if it's time to show the notice.
229
+ *
230
+ * @since 1.0.0
231
+ *
232
+ * @return bool
233
+ */
234
+ protected function is_time() {
235
+ // Get the notice time.
236
+ $time = get_site_option( $this->key( 'time' ) );
237
+
238
+ // If not set, set now and bail.
239
+ if ( empty( $time ) ) {
240
+ $time = time() + ( $this->days * DAY_IN_SECONDS );
241
+
242
+ // Set to future.
243
+ update_site_option( $this->key( 'time' ), $time );
244
+
245
+ return false;
246
+ }
247
+
248
+ // Check if time passed or reached.
249
+ return (int) $time <= time();
250
+ }
251
+
252
+ /**
253
+ * Check if the notice is already dismissed.
254
+ *
255
+ * @since 1.0.0
256
+ *
257
+ * @return bool
258
+ */
259
+ protected function is_dismissed() {
260
+ // Get current user.
261
+ $current_user = wp_get_current_user();
262
+
263
+ // Check if current item is dismissed.
264
+ return (bool) get_user_meta(
265
+ $current_user->ID,
266
+ $this->key( 'dismissed' ),
267
+ true
268
+ );
269
+ }
270
+
271
+ /**
272
+ * Check if current user has the capability.
273
+ *
274
+ * @since 1.0.0
275
+ *
276
+ * @return bool
277
+ */
278
+ protected function is_capable() {
279
+ return current_user_can( $this->capability );
280
+ }
281
+
282
+ /**
283
+ * Check if the current screen is allowed.
284
+ *
285
+ * @since 1.0.0
286
+ *
287
+ * @return bool
288
+ */
289
+ protected function in_screen() {
290
+ // If not screen ID is set, show everywhere.
291
+ if ( empty( $this->screens ) ) {
292
+ return true;
293
+ }
294
+
295
+ if ( ! function_exists( 'get_current_screen' ) ) {
296
+ return true;
297
+ }
298
+
299
+ // Get current screen.
300
+ $screen = get_current_screen();
301
+
302
+ // Check if current screen id is allowed.
303
+ return ! empty( $screen->id ) && in_array( $screen->id, $this->screens, true );
304
+ }
305
+
306
+ /**
307
+ * Get the class names for notice div.
308
+ *
309
+ * @since 1.0.0
310
+ *
311
+ * @return string
312
+ */
313
+ protected function get_classes() {
314
+ // Required classes.
315
+ $classes = array( 'notice', 'notice-info' );
316
+
317
+ // Add extra classes.
318
+ if ( ! empty( $this->classes ) && is_array( $this->classes ) ) {
319
+ $classes = array_merge( $classes, $this->classes );
320
+ $classes = array_unique( $classes );
321
+ }
322
+
323
+ return implode( ' ', $classes );
324
+ }
325
+
326
+ /**
327
+ * Get the default notice message.
328
+ *
329
+ * @since 1.0.0
330
+ *
331
+ * @return string
332
+ */
333
+ protected function get_message() {
334
+ $message = sprintf(
335
+ // translators: %1$s Name, %2$s days.
336
+ esc_html__( 'Hello! Seems like you have been using %1$s for more than %2$d days – that’s awesome! Could you please do us a BIG favor and give it a 5-star rating on WordPress? This would boost our motivation and help us spread the word.', 'wp-admin-notice' ),
337
+ '<strong>' . esc_html( $this->name ) . '</strong>',
338
+ (int) $this->days
339
+ );
340
+
341
+ return $message;
342
+ }
343
+
344
+ /**
345
+ * Check if we can show the notice.
346
+ */
347
+ protected function can_show() {
348
+ // return true;
349
+ return (
350
+ $this->in_screen() &&
351
+ $this->is_capable() &&
352
+ $this->is_time() &&
353
+ ! $this->is_dismissed()
354
+ );
355
+ }
356
+
357
+ /**
358
+ * Process the notice actions.
359
+ *
360
+ * If current user is capable process actions.
361
+ * > Later: Extend the time to show the notice.
362
+ * > Dismiss: Hide the notice to current user.
363
+ *
364
+ * @since 1.0.0
365
+ *
366
+ * @return void
367
+ */
368
+ protected function process_actions() {
369
+ // Only if required.
370
+ if ( ! $this->in_screen() || ! $this->is_capable() ) {
371
+ return;
372
+ }
373
+
374
+ $action_list = array( 'later', 'dismiss' );
375
+
376
+ $action = '';
377
+
378
+ if ( isset( $_REQUEST[ $this->key( 'action' ) ] ) && ! empty( $_REQUEST[ $this->key( 'action' ) ] ) && in_array( $_REQUEST[ $this->key( 'action' ) ], $action_list, true ) ) {
379
+ $action = $_REQUEST[ $this->key( 'action' ) ];
380
+ }
381
+
382
+ switch ( $action ) {
383
+ case 'later':
384
+ // Show after 7 days.
385
+ $time = time() + ( $this->days * DAY_IN_SECONDS + 7 * DAY_IN_SECONDS );
386
+ update_site_option( $this->key( 'time' ), $time );
387
+ break;
388
+ case 'dismiss':
389
+ // Do not show again to this user.
390
+ update_user_meta( get_current_user_id(), $this->key( 'dismissed' ), true );
391
+ break;
392
+ }
393
+ }
394
+
395
+ /**
396
+ * Configure notice.
397
+ *
398
+ * @param array $args Arguments.
399
+ *
400
+ * @since 1.0.0
401
+ *
402
+ * @return void
403
+ */
404
+ private function configure( $args ) {
405
+ $slug = ( isset( $args['slug'] ) && ! empty( $args['slug'] ) ) ? $args['slug'] : '';
406
+
407
+ if ( empty( $slug ) ) {
408
+ return;
409
+ }
410
+
411
+ // Default arguments.
412
+ $args = wp_parse_args(
413
+ $args,
414
+ array(
415
+ 'days' => 7,
416
+ 'name' => ucwords( str_replace( '-', ' ', $slug ) ),
417
+ 'capability' => 'manage_options',
418
+ 'type' => 'plugin',
419
+ 'screens' => array(),
420
+ 'classes' => array(),
421
+ 'action_labels' => array(),
422
+ )
423
+ );
424
+
425
+ // Action button/link labels.
426
+ $this->action_labels = wp_parse_args(
427
+ (array) $args['action_labels'],
428
+ array(
429
+ 'review' => esc_html__( 'Ok, you deserve it', 'wp-admin-notice' ),
430
+ 'later' => esc_html__( 'Nope, maybe later', 'wp-admin-notice' ),
431
+ 'dismiss' => esc_html__( 'I already did', 'wp-admin-notice' ),
432
+ )
433
+ );
434
+
435
+ if ( ! in_array( $args['type'], array( 'plugin', 'theme' ), true ) ) {
436
+ $args['type'] = 'plugin';
437
+ }
438
+
439
+ $this->slug = (string) $slug;
440
+ $this->name = (string) $args['name'];
441
+ $this->type = (string) $args['type'];
442
+ $this->capability = (string) $args['capability'];
443
+ $this->days = (int) $args['days'];
444
+ $this->screens = (array) $args['screens'];
445
+ $this->classes = (array) $args['classes'];
446
+ $this->prefix = str_replace( '-', '_', $this->slug );
447
+ $this->message = empty( $args['message'] ) ? $this->get_message() : (string) $args['message'];
448
+ }
449
+
450
+ /**
451
+ * Create prefixed key.
452
+ *
453
+ * @param string $key Key.
454
+ *
455
+ * @since 1.0.0
456
+ *
457
+ * @return string
458
+ */
459
+ private function key( $key ) {
460
+ return $this->prefix . '_wpan_' . $key;
461
+ }
462
+ }
vendor/wptt/webfont-loader/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2020 WPTT
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
vendor/wptt/webfont-loader/README.md ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Webfonts Loader
2
+
3
+ Downloads webfonts (like for example Google-Fonts), and hosts them locally on a WordPress site.
4
+
5
+ This improves performance (fewer requests to multiple top-level domains) and increases privacy. Since fonts get hosted locally on the site, there are no pings to a 3rd-party server to get the webfonts and therefore no tracking.
6
+
7
+ ## Usage
8
+
9
+ A WordPress theme will typically enqueue assets using the [`wp_enqueue_style`](https://developer.wordpress.org/reference/functions/wp_enqueue_style/) function:
10
+
11
+ ```php
12
+ function my_theme_enqueue_assets() {
13
+ // Load the theme stylesheet.
14
+ wp_enqueue_style(
15
+ 'my-theme',
16
+ get_stylesheet_directory_uri() . '/style.css',
17
+ array(),
18
+ '1.0'
19
+ );
20
+ // Load the webfont.
21
+ wp_enqueue_style(
22
+ 'literata',
23
+ 'https://fonts.googleapis.com/css2?family=Literata&display=swap',
24
+ array(),
25
+ '1.0'
26
+ );
27
+ }
28
+ add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_assets' );
29
+ ```
30
+
31
+ To locally host the webfonts, you will first need to download the [`wptt-webfont-loader.php`](https://raw.githubusercontent.com/WPTT/font-loader/master/wptt-webfont-loader.php) file from this repository and copy it in your theme. Once you do that, the above code can be converted to this:
32
+ ```php
33
+ function my_theme_enqueue_assets() {
34
+ // Include the file.
35
+ require_once get_theme_file_path( 'inc/wptt-webfont-loader.php' );
36
+ // Load the theme stylesheet.
37
+ wp_enqueue_style(
38
+ 'my-theme',
39
+ get_stylesheet_directory_uri() . '/style.css',
40
+ array(),
41
+ '1.0'
42
+ );
43
+ // Load the webfont.
44
+ wp_enqueue_style(
45
+ 'literata',
46
+ wptt_get_webfont_url( 'https://fonts.googleapis.com/css2?family=Literata&display=swap' ),
47
+ array(),
48
+ '1.0'
49
+ );
50
+ }
51
+ add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_assets' );
52
+ ```
53
+
54
+ ## Available functions
55
+
56
+ ### `wptt_get_webfont_styles`
57
+ ```
58
+ $remote_url = 'https://fonts.googleapis.com/css2?family=Literata&display=swap';
59
+ $contents = wptt_get_webfont_styles( $remote_url );
60
+ ```
61
+ Returns the stylesheet contents, using locally hosted webfonts.
62
+
63
+ ### `wptt_get_webfont_url`
64
+ ```
65
+ $remote_url = 'https://fonts.googleapis.com/css2?family=Literata&display=swap';
66
+ $contents = wptt_get_webfont_url( $remote_url );
67
+ ```
68
+ Returns a stylesheet URL, locally-hosted.
69
+
70
+ ## Build url for multiple fonts
71
+ ```php
72
+ $font_families = array(
73
+ 'Quicksand:wght@300;400;500;600;700',
74
+ 'Work+Sans:wght@300;400;500;600;700'
75
+ );
76
+
77
+ $fonts_url = add_query_arg( array(
78
+ 'family' => implode( '&family=', $font_families ),
79
+ 'display' => 'swap',
80
+ ), 'https://fonts.googleapis.com/css2' );
81
+
82
+ $contents = wptt_get_webfont_url( esc_url_raw( $fonts_url ) );
83
+ ```
84
+
85
+ ## Supporting IE
86
+ The `wptt_get_webfont_url` will - by default - download `.woff2` files. However, if you need to support IE you will need to use `.woff` files instead. To do that, you can pass `woff` as the 2nd argument in the `wptt_get_webfont_url` function:
87
+ ```php
88
+ wptt_get_webfont_url( 'https://fonts.googleapis.com/css2?family=Literata&display=swap', 'woff' );
89
+ ```
90
+
91
+ ## Storing In A Custom Directory
92
+ If you have the need to store font files in a custom directory you can pass a custom path and URL using filters. Be sure you add these filters **BEFORE** the file containing the `WPTT_WebFont_Loader` class is called.
93
+
94
+ ```php
95
+ /**
96
+ * Change the base path.
97
+ * This is by default WP_CONTENT_DIR.
98
+ *
99
+ * NOTE: Do not include trailing slash.
100
+ */
101
+ add_filter( 'wptt_get_local_fonts_base_path', function( $path ) {
102
+ return WP_CONTENT_DIR;
103
+ } );
104
+
105
+ /**
106
+ * Change the base URL.
107
+ * This is by default the content_url().
108
+ *
109
+ * NOTE: Do not include trailing slash.
110
+ */
111
+ add_filter( 'wptt_get_local_fonts_base_url', function( $url ) {
112
+ return content_url();
113
+ } );
114
+
115
+ /**
116
+ * Change the subfolder name.
117
+ * This is by default "fonts".
118
+ *
119
+ * Return empty string or false to not use a subfolder.
120
+ */
121
+ add_filter( 'wptt_get_local_fonts_subfolder_name', function( $subfolder_name ) {
122
+ return 'fonts';
123
+ } );
124
+ ```
vendor/wptt/webfont-loader/wptt-webfont-loader.php ADDED
@@ -0,0 +1,697 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Download webfonts locally.
4
+ *
5
+ * @package wptt/font-loader
6
+ * @license https://opensource.org/licenses/MIT
7
+ */
8
+
9
+ if ( ! class_exists( 'WPTT_WebFont_Loader' ) ) {
10
+ /**
11
+ * Download webfonts locally.
12
+ */
13
+ class WPTT_WebFont_Loader {
14
+
15
+ /**
16
+ * The font-format.
17
+ *
18
+ * Use "woff" or "woff2".
19
+ * This will change the user-agent user to make the request.
20
+ *
21
+ * @access protected
22
+ * @since 1.0.0
23
+ * @var string
24
+ */
25
+ protected $font_format = 'woff2';
26
+
27
+ /**
28
+ * The remote URL.
29
+ *
30
+ * @access protected
31
+ * @since 1.1.0
32
+ * @var string
33
+ */
34
+ protected $remote_url;
35
+
36
+ /**
37
+ * Base path.
38
+ *
39
+ * @access protected
40
+ * @since 1.1.0
41
+ * @var string
42
+ */
43
+ protected $base_path;
44
+
45
+ /**
46
+ * Base URL.
47
+ *
48
+ * @access protected
49
+ * @since 1.1.0
50
+ * @var string
51
+ */
52
+ protected $base_url;
53
+
54
+ /**
55
+ * Subfolder name.
56
+ *
57
+ * @access protected
58
+ * @since 1.1.0
59
+ * @var string
60
+ */
61
+ protected $subfolder_name;
62
+
63
+ /**
64
+ * The fonts folder.
65
+ *
66
+ * @access protected
67
+ * @since 1.1.0
68
+ * @var string
69
+ */
70
+ protected $fonts_folder;
71
+
72
+ /**
73
+ * The local stylesheet's path.
74
+ *
75
+ * @access protected
76
+ * @since 1.1.0
77
+ * @var string
78
+ */
79
+ protected $local_stylesheet_path;
80
+
81
+ /**
82
+ * The local stylesheet's URL.
83
+ *
84
+ * @access protected
85
+ * @since 1.1.0
86
+ * @var string
87
+ */
88
+ protected $local_stylesheet_url;
89
+
90
+ /**
91
+ * The remote CSS.
92
+ *
93
+ * @access protected
94
+ * @since 1.1.0
95
+ * @var string
96
+ */
97
+ protected $remote_styles;
98
+
99
+ /**
100
+ * The final CSS.
101
+ *
102
+ * @access protected
103
+ * @since 1.1.0
104
+ * @var string
105
+ */
106
+ protected $css;
107
+
108
+ /**
109
+ * Cleanup routine frequency.
110
+ */
111
+ const CLEANUP_FREQUENCY = 'monthly';
112
+
113
+ /**
114
+ * Constructor.
115
+ *
116
+ * Get a new instance of the object for a new URL.
117
+ *
118
+ * @access public
119
+ * @since 1.1.0
120
+ * @param string $url The remote URL.
121
+ */
122
+ public function __construct( $url = '' ) {
123
+ $this->remote_url = $url;
124
+
125
+ // Add a cleanup routine.
126
+ $this->schedule_cleanup();
127
+ add_action( 'delete_fonts_folder', array( $this, 'delete_fonts_folder' ) );
128
+ }
129
+
130
+ /**
131
+ * Get the local URL which contains the styles.
132
+ *
133
+ * Fallback to the remote URL if we were unable to write the file locally.
134
+ *
135
+ * @access public
136
+ * @since 1.1.0
137
+ * @return string
138
+ */
139
+ public function get_url() {
140
+
141
+ // Check if the local stylesheet exists.
142
+ if ( $this->local_file_exists() ) {
143
+
144
+ // Attempt to update the stylesheet. Return the local URL on success.
145
+ if ( $this->write_stylesheet() ) {
146
+ return $this->get_local_stylesheet_url();
147
+ }
148
+ }
149
+
150
+ // If the local file exists, return its URL, with a fallback to the remote URL.
151
+ return file_exists( $this->get_local_stylesheet_path() )
152
+ ? $this->get_local_stylesheet_url()
153
+ : $this->remote_url;
154
+ }
155
+
156
+ /**
157
+ * Get the local stylesheet URL.
158
+ *
159
+ * @access public
160
+ * @since 1.1.0
161
+ * @return string
162
+ */
163
+ public function get_local_stylesheet_url() {
164
+ if ( ! $this->local_stylesheet_url ) {
165
+ $this->local_stylesheet_url = str_replace(
166
+ $this->get_base_path(),
167
+ $this->get_base_url(),
168
+ $this->get_local_stylesheet_path()
169
+ );
170
+ }
171
+ return $this->local_stylesheet_url;
172
+ }
173
+
174
+ /**
175
+ * Get styles with fonts downloaded locally.
176
+ *
177
+ * @access public
178
+ * @since 1.0.0
179
+ * @return string
180
+ */
181
+ public function get_styles() {
182
+
183
+ // If we already have the local file, return its contents.
184
+ $local_stylesheet_contents = $this->get_local_stylesheet_contents();
185
+ if ( $local_stylesheet_contents ) {
186
+ return $local_stylesheet_contents;
187
+ }
188
+
189
+ // Get the remote URL contents.
190
+ $this->remote_styles = $this->get_remote_url_contents();
191
+
192
+ // Get an array of locally-hosted files.
193
+ $files = $this->get_local_files_from_css();
194
+
195
+ // Convert paths to URLs.
196
+ foreach ( $files as $remote => $local ) {
197
+ $files[ $remote ] = str_replace(
198
+ $this->get_base_path(),
199
+ $this->get_base_url(),
200
+ $local
201
+ );
202
+ }
203
+
204
+ $this->css = str_replace(
205
+ array_keys( $files ),
206
+ array_values( $files ),
207
+ $this->remote_styles
208
+ );
209
+
210
+ $this->write_stylesheet();
211
+
212
+ return $this->css;
213
+ }
214
+
215
+ /**
216
+ * Get local stylesheet contents.
217
+ *
218
+ * @access public
219
+ * @since 1.1.0
220
+ * @return string|false Returns the remote URL contents.
221
+ */
222
+ public function get_local_stylesheet_contents() {
223
+ $local_path = $this->get_local_stylesheet_path();
224
+
225
+ // Check if the local stylesheet exists.
226
+ if ( $this->local_file_exists() ) {
227
+
228
+ // Attempt to update the stylesheet. Return false on fail.
229
+ if ( ! $this->write_stylesheet() ) {
230
+ return false;
231
+ }
232
+ }
233
+
234
+ ob_start();
235
+ include $local_path;
236
+ return ob_get_clean();
237
+ }
238
+
239
+ /**
240
+ * Get remote file contents.
241
+ *
242
+ * @access public
243
+ * @since 1.0.0
244
+ * @return string Returns the remote URL contents.
245
+ */
246
+ public function get_remote_url_contents() {
247
+
248
+ /**
249
+ * The user-agent we want to use.
250
+ *
251
+ * The default user-agent is the only one compatible with woff (not woff2)
252
+ * which also supports unicode ranges.
253
+ */
254
+ $user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8';
255
+
256
+ // Switch to a user-agent supporting woff2 if we don't need to support IE.
257
+ if ( 'woff2' === $this->font_format ) {
258
+ $user_agent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0';
259
+ }
260
+
261
+ // Get the response.
262
+ $response = wp_remote_get( $this->remote_url, array( 'user-agent' => $user_agent ) );
263
+
264
+ // Early exit if there was an error.
265
+ if ( is_wp_error( $response ) ) {
266
+ return '';
267
+ }
268
+
269
+ // Get the CSS from our response.
270
+ $contents = wp_remote_retrieve_body( $response );
271
+
272
+ return $contents;
273
+ }
274
+
275
+ /**
276
+ * Download files mentioned in our CSS locally.
277
+ *
278
+ * @access public
279
+ * @since 1.0.0
280
+ * @return array Returns an array of remote URLs and their local counterparts.
281
+ */
282
+ public function get_local_files_from_css() {
283
+ $font_files = $this->get_remote_files_from_css();
284
+ $stored = get_site_option( 'downloaded_font_files', array() );
285
+ $change = false; // If in the end this is true, we need to update the cache option.
286
+
287
+ if ( ! defined( 'FS_CHMOD_DIR' ) ) {
288
+ define( 'FS_CHMOD_DIR', ( 0755 & ~ umask() ) );
289
+ }
290
+
291
+ // If the fonts folder don't exist, create it.
292
+ if ( ! file_exists( $this->get_fonts_folder() ) ) {
293
+ $this->get_filesystem()->mkdir( $this->get_fonts_folder(), FS_CHMOD_DIR );
294
+ }
295
+
296
+ foreach ( $font_files as $font_family => $files ) {
297
+
298
+ // The folder path for this font-family.
299
+ $folder_path = $this->get_fonts_folder() . '/' . $font_family;
300
+
301
+ // If the folder doesn't exist, create it.
302
+ if ( ! file_exists( $folder_path ) ) {
303
+ $this->get_filesystem()->mkdir( $folder_path, FS_CHMOD_DIR );
304
+ }
305
+
306
+ foreach ( $files as $url ) {
307
+
308
+ // Get the filename.
309
+ $filename = basename( wp_parse_url( $url, PHP_URL_PATH ) );
310
+ $font_path = $folder_path . '/' . $filename;
311
+
312
+ // Check if the file already exists.
313
+ if ( file_exists( $font_path ) ) {
314
+
315
+ // Skip if already cached.
316
+ if ( isset( $stored[ $url ] ) ) {
317
+ continue;
318
+ }
319
+
320
+ // Add file to the cache and change the $changed var to indicate we need to update the option.
321
+ $stored[ $url ] = $font_path;
322
+ $change = true;
323
+
324
+ // Since the file exists we don't need to proceed with downloading it.
325
+ continue;
326
+ }
327
+
328
+ /**
329
+ * If we got this far, we need to download the file.
330
+ */
331
+
332
+ // require file.php if the download_url function doesn't exist.
333
+ if ( ! function_exists( 'download_url' ) ) {
334
+ require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' );
335
+ }
336
+
337
+ // Download file to temporary location.
338
+ $tmp_path = download_url( $url );
339
+
340
+ // Make sure there were no errors.
341
+ if ( is_wp_error( $tmp_path ) ) {
342
+ continue;
343
+ }
344
+
345
+ // Move temp file to final destination.
346
+ $success = $this->get_filesystem()->move( $tmp_path, $font_path, true );
347
+ if ( $success ) {
348
+ $stored[ $url ] = $font_path;
349
+ $change = true;
350
+ }
351
+ }
352
+ }
353
+
354
+ // If there were changes, update the option.
355
+ if ( $change ) {
356
+
357
+ // Cleanup the option and then save it.
358
+ foreach ( $stored as $url => $path ) {
359
+ if ( ! file_exists( $path ) ) {
360
+ unset( $stored[ $url ] );
361
+ }
362
+ }
363
+ update_site_option( 'downloaded_font_files', $stored );
364
+ }
365
+
366
+ return $stored;
367
+ }
368
+
369
+ /**
370
+ * Get font files from the CSS.
371
+ *
372
+ * @access public
373
+ * @since 1.0.0
374
+ * @return array Returns an array of font-families and the font-files used.
375
+ */
376
+ public function get_remote_files_from_css() {
377
+
378
+ $font_faces = explode( '@font-face', $this->remote_styles );
379
+
380
+ $result = array();
381
+
382
+ // Loop all our font-face declarations.
383
+ foreach ( $font_faces as $font_face ) {
384
+
385
+ // Make sure we only process styles inside this declaration.
386
+ $style = explode( '}', $font_face )[0];
387
+
388
+ // Sanity check.
389
+ if ( false === strpos( $style, 'font-family' ) ) {
390
+ continue;
391
+ }
392
+
393
+ // Get an array of our font-families.
394
+ preg_match_all( '/font-family.*?\;/', $style, $matched_font_families );
395
+
396
+ // Get an array of our font-files.
397
+ preg_match_all( '/url\(.*?\)/i', $style, $matched_font_files );
398
+
399
+ // Get the font-family name.
400
+ $font_family = 'unknown';
401
+ if ( isset( $matched_font_families[0] ) && isset( $matched_font_families[0][0] ) ) {
402
+ $font_family = rtrim( ltrim( $matched_font_families[0][0], 'font-family:' ), ';' );
403
+ $font_family = trim( str_replace( array( "'", ';' ), '', $font_family ) );
404
+ $font_family = sanitize_key( strtolower( str_replace( ' ', '-', $font_family ) ) );
405
+ }
406
+
407
+ // Make sure the font-family is set in our array.
408
+ if ( ! isset( $result[ $font_family ] ) ) {
409
+ $result[ $font_family ] = array();
410
+ }
411
+
412
+ // Get files for this font-family and add them to the array.
413
+ foreach ( $matched_font_files as $match ) {
414
+
415
+ // Sanity check.
416
+ if ( ! isset( $match[0] ) ) {
417
+ continue;
418
+ }
419
+
420
+ // Add the file URL.
421
+ $font_family_url = rtrim( ltrim( $match[0], 'url(' ), ')' );
422
+
423
+ // Make sure to convert relative URLs to absolute.
424
+ $font_family_url = $this->get_absolute_path( $font_family_url );
425
+
426
+ $result[ $font_family ][] = $font_family_url;
427
+ }
428
+
429
+ // Make sure we have unique items.
430
+ // We're using array_flip here instead of array_unique for improved performance.
431
+ $result[ $font_family ] = array_flip( array_flip( $result[ $font_family ] ) );
432
+ }
433
+ return $result;
434
+ }
435
+
436
+ /**
437
+ * Write the CSS to the filesystem.
438
+ *
439
+ * @access protected
440
+ * @since 1.1.0
441
+ * @return string|false Returns the absolute path of the file on success, or false on fail.
442
+ */
443
+ protected function write_stylesheet() {
444
+ $file_path = $this->get_local_stylesheet_path();
445
+ $filesystem = $this->get_filesystem();
446
+
447
+ if ( ! defined( 'FS_CHMOD_DIR' ) ) {
448
+ define( 'FS_CHMOD_DIR', ( 0755 & ~ umask() ) );
449
+ }
450
+
451
+ // If the folder doesn't exist, create it.
452
+ if ( ! file_exists( $this->get_fonts_folder() ) ) {
453
+ $this->get_filesystem()->mkdir( $this->get_fonts_folder(), FS_CHMOD_DIR );
454
+ }
455
+
456
+ // If the file doesn't exist, create it. Return false if it can not be created.
457
+ if ( ! $filesystem->exists( $file_path ) && ! $filesystem->touch( $file_path ) ) {
458
+ return false;
459
+ }
460
+
461
+ // If we got this far, we need to write the file.
462
+ // Get the CSS.
463
+ if ( ! $this->css ) {
464
+ $this->get_styles();
465
+ }
466
+
467
+ // Put the contents in the file. Return false if that fails.
468
+ if ( ! $filesystem->put_contents( $file_path, $this->css ) ) {
469
+ return false;
470
+ }
471
+
472
+ return $file_path;
473
+ }
474
+
475
+ /**
476
+ * Get the stylesheet path.
477
+ *
478
+ * @access public
479
+ * @since 1.1.0
480
+ * @return string
481
+ */
482
+ public function get_local_stylesheet_path() {
483
+ if ( ! $this->local_stylesheet_path ) {
484
+ $this->local_stylesheet_path = $this->get_fonts_folder() . '/' . $this->get_local_stylesheet_filename() . '.css';
485
+ }
486
+ return $this->local_stylesheet_path;
487
+ }
488
+
489
+ /**
490
+ * Get the local stylesheet filename.
491
+ *
492
+ * This is a hash, generated from the site-URL, the wp-content path and the URL.
493
+ * This way we can avoid issues with sites changing their URL, or the wp-content path etc.
494
+ *
495
+ * @access public
496
+ * @since 1.1.0
497
+ * @return string
498
+ */
499
+ public function get_local_stylesheet_filename() {
500
+ return md5( $this->get_base_url() . $this->get_base_path() . $this->remote_url . $this->font_format );
501
+ }
502
+
503
+ /**
504
+ * Set the font-format to be used.
505
+ *
506
+ * @access public
507
+ * @since 1.0.0
508
+ * @param string $format The format to be used. Use "woff" or "woff2".
509
+ * @return void
510
+ */
511
+ public function set_font_format( $format = 'woff2' ) {
512
+ $this->font_format = $format;
513
+ }
514
+
515
+ /**
516
+ * Check if the local stylesheet exists.
517
+ *
518
+ * @access public
519
+ * @since 1.1.0
520
+ * @return bool
521
+ */
522
+ public function local_file_exists() {
523
+ return ( ! file_exists( $this->get_local_stylesheet_path() ) );
524
+ }
525
+
526
+ /**
527
+ * Get the base path.
528
+ *
529
+ * @access public
530
+ * @since 1.1.0
531
+ * @return string
532
+ */
533
+ public function get_base_path() {
534
+ if ( ! $this->base_path ) {
535
+ $this->base_path = apply_filters( 'wptt_get_local_fonts_base_path', $this->get_filesystem()->wp_content_dir() );
536
+ }
537
+ return $this->base_path;
538
+ }
539
+
540
+ /**
541
+ * Get the base URL.
542
+ *
543
+ * @access public
544
+ * @since 1.1.0
545
+ * @return string
546
+ */
547
+ public function get_base_url() {
548
+ if ( ! $this->base_url ) {
549
+ $this->base_url = apply_filters( 'wptt_get_local_fonts_base_url', content_url() );
550
+ }
551
+ return $this->base_url;
552
+ }
553
+
554
+ /**
555
+ * Get the subfolder name.
556
+ *
557
+ * @access public
558
+ * @since 1.1.0
559
+ * @return string
560
+ */
561
+ public function get_subfolder_name() {
562
+ if ( ! $this->subfolder_name ) {
563
+ $this->subfolder_name = apply_filters( 'wptt_get_local_fonts_subfolder_name', 'fonts' );
564
+ }
565
+ return $this->subfolder_name;
566
+ }
567
+
568
+ /**
569
+ * Get the folder for fonts.
570
+ *
571
+ * @access public
572
+ * @return string
573
+ */
574
+ public function get_fonts_folder() {
575
+ if ( ! $this->fonts_folder ) {
576
+ $this->fonts_folder = $this->get_base_path();
577
+ if ( $this->get_subfolder_name() ) {
578
+ $this->fonts_folder .= '/' . $this->get_subfolder_name();
579
+ }
580
+ }
581
+ return $this->fonts_folder;
582
+ }
583
+
584
+ /**
585
+ * Schedule a cleanup.
586
+ *
587
+ * Deletes the fonts files on a regular basis.
588
+ * This way font files will get updated regularly,
589
+ * and we avoid edge cases where unused files remain in the server.
590
+ *
591
+ * @access public
592
+ * @since 1.1.0
593
+ * @return void
594
+ */
595
+ public function schedule_cleanup() {
596
+ if ( ! is_multisite() || ( is_multisite() && is_main_site() ) ) {
597
+ if ( ! wp_next_scheduled( 'delete_fonts_folder' ) && ! wp_installing() ) {
598
+ wp_schedule_event( time(), self::CLEANUP_FREQUENCY, 'delete_fonts_folder' );
599
+ }
600
+ }
601
+ }
602
+
603
+ /**
604
+ * Delete the fonts folder.
605
+ *
606
+ * This runs as part of a cleanup routine.
607
+ *
608
+ * @access public
609
+ * @since 1.1.0
610
+ * @return bool
611
+ */
612
+ public function delete_fonts_folder() {
613
+ return $this->get_filesystem()->delete( $this->get_fonts_folder(), true );
614
+ }
615
+
616
+ /**
617
+ * Get the filesystem.
618
+ *
619
+ * @access protected
620
+ * @since 1.0.0
621
+ * @return \WP_Filesystem_Base
622
+ */
623
+ protected function get_filesystem() {
624
+ global $wp_filesystem;
625
+
626
+ // If the filesystem has not been instantiated yet, do it here.
627
+ if ( ! $wp_filesystem ) {
628
+ if ( ! function_exists( 'WP_Filesystem' ) ) {
629
+ require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' );
630
+ }
631
+ WP_Filesystem();
632
+ }
633
+ return $wp_filesystem;
634
+ }
635
+
636
+ /**
637
+ * Get an absolute URL from a relative URL.
638
+ *
639
+ * @access protected
640
+ *
641
+ * @param string $url The URL.
642
+ *
643
+ * @return string
644
+ */
645
+ protected function get_absolute_path( $url ) {
646
+
647
+ // If dealing with a root-relative URL.
648
+ if ( 0 === stripos( $url, '/' ) ) {
649
+ $parsed_url = parse_url( $this->remote_url );
650
+ return $parsed_url['scheme'] . '://' . $parsed_url['hostname'] . $url;
651
+ }
652
+
653
+ return $url;
654
+ }
655
+ }
656
+ }
657
+
658
+ if ( ! function_exists( 'wptt_get_webfont_styles' ) ) {
659
+ /**
660
+ * Get styles for a webfont.
661
+ *
662
+ * This will get the CSS from the remote API,
663
+ * download any fonts it contains,
664
+ * replace references to remote URLs with locally-downloaded assets,
665
+ * and finally return the resulting CSS.
666
+ *
667
+ * @since 1.0.0
668
+ *
669
+ * @param string $url The URL of the remote webfont.
670
+ * @param string $format The font-format. If you need to support IE, change this to "woff".
671
+ *
672
+ * @return string Returns the CSS.
673
+ */
674
+ function wptt_get_webfont_styles( $url, $format = 'woff2' ) {
675
+ $font = new WPTT_WebFont_Loader( $url );
676
+ $font->set_font_format( $format );
677
+ return $font->get_styles();
678
+ }
679
+ }
680
+
681
+ if ( ! function_exists( 'wptt_get_webfont_url' ) ) {
682
+ /**
683
+ * Get a stylesheet URL for a webfont.
684
+ *
685
+ * @since 1.1.0
686
+ *
687
+ * @param string $url The URL of the remote webfont.
688
+ * @param string $format The font-format. If you need to support IE, change this to "woff".
689
+ *
690
+ * @return string Returns the CSS.
691
+ */
692
+ function wptt_get_webfont_url( $url, $format = 'woff2' ) {
693
+ $font = new WPTT_WebFont_Loader( $url );
694
+ $font->set_font_format( $format );
695
+ return $font->get_url();
696
+ }
697
+ }