├── CHANGES.md ├── LICENSE ├── README.md ├── assets ├── banner-1544x500.png ├── banner-772x250.png ├── icon.svg └── screenshot-1.png ├── composer.json ├── git-updater-additions.php ├── github-updater-additions.php ├── languages └── git-updater-additions.pot ├── readme.txt ├── src └── Additions │ ├── Additions.php │ ├── Bootstrap.php │ ├── Repo_List_Table.php │ └── Settings.php └── vendor ├── autoload.php └── composer ├── ClassLoader.php ├── InstalledVersions.php ├── LICENSE ├── autoload_classmap.php ├── autoload_namespaces.php ├── autoload_psr4.php ├── autoload_real.php ├── autoload_static.php ├── installed.json ├── installed.php └── platform_check.php /CHANGES.md: -------------------------------------------------------------------------------- 1 | #### [unreleased] 2 | 3 | #### 6.1.0 / 2022-10-24 4 | * remove Freemius SDK 5 | 6 | #### 6.0.1 / 2022-08-27 7 | * update Freemius/wordpress-sdk 8 | * add placeholder text for slug and branch 9 | * add `function_exists` check for Freemius function, issue during wp-cli 10 | 11 | #### 6.0.0 / 2022-04-24 12 | * requires PHP 7.2+ 13 | 14 | #### 5.5.4 / 2022-03-10 15 | * composer update 16 | 17 | #### 5.5.3 / 2022-03-02 18 | * update Freemius/wordpress-sdk 19 | 20 | #### 5.5.2 / 2022-02-08 21 | * use `sanitize_key()` for nonces 22 | * update nonce check in `class Repo_List_Table` 23 | 24 | #### 5.5.1 / 2022-02-05 25 | * add nonce check for saving settings 26 | 27 | #### 5.5.0 / 2021-11-15 28 | * remove checkbox from list table 29 | * update screenshot 30 | * use `sanitize_title_with_dashes()` as `sanitize_file_name()` maybe have attached filter that changes output 31 | * use filter to add repository types 32 | 33 | #### 5.4.0 / 2021-08-03 34 | * add settings for `Primary Branch` and `Release Asset` 35 | * only use `esc_attr_e` for translating strings 36 | 37 | #### 5.3.0 / 2021-07-05 38 | * update Freemius for multisite 39 | * remove Freemius from the autoloader 40 | * uses new `class Fragen\Git_Updater\Shim` for PHP 5.6 compatibility, will remove when WP core changes minimum requirement 41 | 42 | #### 5.2.4 / 2021-05-21 43 | * add language pack updating 44 | 45 | #### 5.2.3 / 2021-05-18 46 | * ensure custom icon shows in update notice from Freemius 47 | 48 | #### 5.2.2 / 2021-05-17 49 | * update Freemius integration 50 | 51 | #### 5.2.0 / 2021-05-03 52 | * update branding logos 53 | 54 | #### 5.1.0 / 2021-05-03 55 | * add Freemius integration 56 | 57 | #### 5.0.0 / 2021-04-15 58 | * rebrand as Git Updater Additions 59 | * update namespace 60 | * gracefully exit if Git(GitHub) Updater not running. 61 | 62 | #### 4.1.1 / 2021-03-12 63 | * fix dropdown 64 | 65 | #### 4.1.0 / 2021-03-07 66 | * move action hook to main plugin file 67 | 68 | #### 4.0.9 / 2021-02-18 69 | * data validation for empty data on save 70 | 71 | #### 4.0.8 / 2021-02-17 72 | * data validation on saving 73 | 74 | #### 4.0.6 / 2020-04-17 75 | * can't use `sanitize_key` on an array 76 | 77 | #### 4.0.5 / 2020-04-15 78 | * more sanitize, less ignore 79 | 80 | #### 4.0.4 / 2020-04-02 81 | * sanitize, escape & ignore 82 | 83 | #### 4.0.3 / 2020-03-13 84 | * only add appropriate repo type to GitHub Updater 85 | 86 | #### 4.0.2 / 2020-02-05 87 | * ensure GitHub Updater is running 88 | 89 | #### 4.0.1 / 2020-01-31 90 | * add `uninstall.php` 91 | 92 | #### 4.0.0 / 2010-01-28 93 | * Refactored to use a Settings tab within GitHub Updater 94 | * saves data in options table 95 | 96 | #### 3.0.0 / 2010-11-19 97 | * update for new version of GitHub Updater v9.0.0 98 | 99 | #### 2.0.1 100 | * wcps linter fixes 101 | 102 | #### 2.0.0 103 | * added `class Additions` to this plugin so it's now self-contained 104 | * changed plugin requirements to mirror those of GitHub Updater 105 | 106 | #### 1.0 107 | * pseudo-initial release 108 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Andy Fragen 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Git Updater Additions 2 | * Contributors: [Andy Fragen](https://github.com/afragen), [contributors](https://github.com/afragen/git-updater-additions/graphs/contributors) 3 | * Tags: plugin, theme, github-updater, extension 4 | * Requires at least: 5.9 5 | * Requires PHP: 7.2 6 | * Stable tag: master 7 | * Donate link: https://thefragens.com/git-updater-donate 8 | * License: MIT 9 | 10 | A plugin that allows for adding installed plugins or themes hosted on GitHub, Bitbucket, GitLab, or Gitea that do not contain required headers to Git Updater. 11 | 12 | ## Description 13 | 14 | This is a plugin that will add the appropriate data via hooks in Git Updater so that repositories that are not correctly configured to use Git Updater may be added to Git Updater without modifying the repository. This only works for installed plugins/themes. 15 | 16 | This plugin adds an **Additions** tab inside the Git Updater Settings for updating settings to this plugin. 17 | 18 | ![Git Updater Additions Settings Tab](./assets/screenshot-1.png) 19 | 20 | ## Usage 21 | 22 | The `"type"` element is from the following list. 23 | 24 | * github_plugin 25 | * github_theme 26 | * bitbucket_plugin 27 | * bitbucket_theme 28 | * gitlab_plugin 29 | * gitlab_theme 30 | * gitea_plugin 31 | * gitea_theme 32 | 33 | The `"slug"` element is either the plugin slug or the theme stylesheet slug. 34 | 35 | The `"uri"` element should be self-explanatory. 36 | 37 | The `"primary_branch"` element if the repository's primary branch is not `master`. 38 | 39 | The `"release_asset"` element if the repository has a build process and is distibuted via a release asset. 40 | 41 | ### Examples 42 | 43 | ``` 44 | type: github_plugin 45 | slug: plugin-noheader/plugin-noheader.php 46 | uri: https://github.com/afragen/plugin-noheader 47 | ``` 48 | 49 | or 50 | 51 | ``` 52 | type: bitbucket_theme 53 | slug: theme-noheader 54 | uri: https://bitbucket.org/afragen/theme-noheader 55 | ``` 56 | 57 | Above are examples for a plugin or a theme. Please notice the diffence in the `slug`. 58 | 59 | ## Development 60 | PRs are welcome against the `develop` branch. 61 | -------------------------------------------------------------------------------- /assets/banner-1544x500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afragen/git-updater-additions/a7ce1e7532d1245d68adef84cf580eb81d936d40/assets/banner-1544x500.png -------------------------------------------------------------------------------- /assets/banner-772x250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afragen/git-updater-additions/a7ce1e7532d1245d68adef84cf580eb81d936d40/assets/banner-772x250.png -------------------------------------------------------------------------------- /assets/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 19 | 20 | 21 | 22 | 43 | 44 | -------------------------------------------------------------------------------- /assets/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afragen/git-updater-additions/a7ce1e7532d1245d68adef84cf580eb81d936d40/assets/screenshot-1.png -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "afragen/git-updater-additions", 3 | "description": "Add repositories to Git Updater that lack actual Git Updater headers.", 4 | "type": "wordpress-plugin", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Andy Fragen", 9 | "email": "andy@thefragens.com", 10 | "homepage": "https://thefragens.com", 11 | "role": "Developer" 12 | } 13 | ], 14 | "support": { 15 | "issues": "https://github.com/afragen/git-updater-additions/issues", 16 | "source": "https://github.com/afragen/git-updater-additions" 17 | }, 18 | "prefer-stable": true, 19 | "require": { 20 | "php": ">=7.2" 21 | }, 22 | "autoload": { 23 | "psr-4": { 24 | "Fragen\\Git_Updater\\Additions\\": "src/Additions/", 25 | "Fragen\\Git_Updater\\": "src/Git_Updater" 26 | } 27 | }, 28 | "scripts": { 29 | "post-update-cmd": [ 30 | "wp i18n make-pot . languages/git-updater-additions.pot" 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /git-updater-additions.php: -------------------------------------------------------------------------------- 1 | run(); 45 | } 46 | ); 47 | 48 | add_filter( 49 | 'gu_additions', 50 | function( $false, $repos, $type ) { 51 | $config = get_site_option( 'git_updater_additions', [] ); 52 | $additions = new Additions(); 53 | $additions->register( $config, $repos, $type ); 54 | 55 | return $additions->add_to_git_updater; 56 | }, 57 | 10, 58 | 3 59 | ); 60 | -------------------------------------------------------------------------------- /github-updater-additions.php: -------------------------------------------------------------------------------- 1 | \n" 8 | "Language-Team: LANGUAGE \n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "POT-Creation-Date: 2022-08-27T18:24:47+00:00\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "X-Generator: WP-CLI 2.6.0\n" 15 | "X-Domain: git-updater-additions\n" 16 | 17 | #. Plugin Name of the plugin 18 | msgid "Git Updater Additions" 19 | msgstr "" 20 | 21 | #. Plugin URI of the plugin 22 | msgid "https://github.com/afragen/git-updater-additions" 23 | msgstr "" 24 | 25 | #. Description of the plugin 26 | msgid "Add installed repositories lacking required headers to the Git Updater plugin." 27 | msgstr "" 28 | 29 | #. Author of the plugin 30 | msgid "Andy Fragen" 31 | msgstr "" 32 | 33 | #: src/Additions/Repo_List_Table.php:207 34 | msgid "Slug" 35 | msgstr "" 36 | 37 | #: src/Additions/Repo_List_Table.php:208 38 | msgid "URL" 39 | msgstr "" 40 | 41 | #: src/Additions/Repo_List_Table.php:209 42 | #: src/Additions/Settings.php:227 43 | msgid "Primary Branch" 44 | msgstr "" 45 | 46 | #: src/Additions/Repo_List_Table.php:210 47 | #: src/Additions/Settings.php:241 48 | msgid "Release Asset" 49 | msgstr "" 50 | 51 | #: src/Additions/Repo_List_Table.php:211 52 | msgid "Type" 53 | msgstr "" 54 | 55 | #: src/Additions/Repo_List_Table.php:257 56 | msgid "Delete" 57 | msgstr "" 58 | 59 | #: src/Additions/Repo_List_Table.php:288 60 | msgid "Items would go to edit when we write that code." 61 | msgstr "" 62 | 63 | #: src/Additions/Repo_List_Table.php:440 64 | msgid "Additions List Table" 65 | msgstr "" 66 | 67 | #: src/Additions/Settings.php:126 68 | msgid "Additions" 69 | msgstr "" 70 | 71 | #: src/Additions/Settings.php:188 72 | msgid "Repository Type" 73 | msgstr "" 74 | 75 | #: src/Additions/Settings.php:200 76 | msgid "Repository Slug" 77 | msgstr "" 78 | 79 | #: src/Additions/Settings.php:214 80 | msgid "Repository URI" 81 | msgstr "" 82 | 83 | #: src/Additions/Settings.php:234 84 | msgid "Ensure proper primary branch, default is `master`" 85 | msgstr "" 86 | 87 | #: src/Additions/Settings.php:248 88 | msgid "Check if a release asset is required." 89 | msgstr "" 90 | 91 | #: src/Additions/Settings.php:276 92 | msgid "If there are git repositories that do not natively support Git Updater you can add them here." 93 | msgstr "" 94 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | # Git Updater Additions 2 | 3 | * Contributors: afragen 4 | * Tags: plugin, theme, github-updater, extension 5 | * Requires at least: 5.9 6 | * Requires PHP: 7.2 7 | * Tested up to: trunk 8 | * Stable tag: master 9 | * Donate link: https://thefragens.com/git-updater-donate 10 | * License: MIT 11 | 12 | A plugin that allows for adding installed plugins or themes hosted on GitHub, Bitbucket, GitLab, or Gitea that do not contain required headers to Git Updater. 13 | 14 | ## Description 15 | 16 | This is a plugin that will add the appropriate data via hooks in Git Updater so that repositories that are not correctly configured to use Git Updater may be added to Git Updater without modifying the repository. This only works for installed plugins/themes. 17 | 18 | This plugin adds an **Additions** tab inside the Git Updater Settings for updating settings to this plugin. 19 | 20 | ## Usage 21 | 22 | The `"type"` element is from the following list. 23 | 24 | * github_plugin 25 | * github_theme 26 | * bitbucket_plugin 27 | * bitbucket_theme 28 | * gitlab_plugin 29 | * gitlab_theme 30 | * gitea_plugin 31 | * gitea_theme 32 | 33 | The `"slug"` element is either the plugin slug or the theme stylesheet slug. 34 | 35 | The `"uri"` element should be self-explanatory. 36 | 37 | The `"primary_branch"` element if the repository's primary branch is not `master`. 38 | 39 | The `"release_asset"` element if the repository has a build process and is distibuted via a release asset. 40 | 41 | ### Examples 42 | 43 | type: github_plugin 44 | slug: plugin-noheader/plugin-noheader.php 45 | uri: https://github.com/afragen/plugin-noheader 46 | 47 | or 48 | 49 | type: bitbucket_theme 50 | slug: theme-noheader 51 | uri: https://bitbucket.org/afragen/theme-noheader 52 | 53 | Above are examples for a plugin or a theme. Please notice the diffence in the `slug`. 54 | 55 | ## Development 56 | 57 | PRs are welcome against the `develop` branch. 58 | 59 | ## Screenshots 60 | 1. GitHub Updater Additions Settings tab 61 | -------------------------------------------------------------------------------- /src/Additions/Additions.php: -------------------------------------------------------------------------------- 1 | add_headers( $config, $repos, $type ); 54 | 55 | return true; 56 | } 57 | 58 | /** 59 | * Add Git Updater headers to plugins/themes via a filter hooks. 60 | * 61 | * @access public 62 | * @uses \Fragen\Git_Updater\Additions::add_to_git_updater() 63 | * 64 | * @param array $config The repo config. 65 | * @param array $repos The repos to pull from. 66 | * @param string $type The plugin type ('plugin' or 'theme'). 67 | * 68 | * @return void 69 | */ 70 | public function add_headers( $config, $repos, $type ) { 71 | foreach ( $config as $repo ) { 72 | $addition = []; 73 | $additions = []; 74 | 75 | $repo_type = explode( '_', $repo['type'] )[1]; 76 | $file_path = 'plugin' === $repo_type ? WP_PLUGIN_DIR . "/{$repo['slug']}" : null; 77 | $file_path = 'theme' === $repo_type ? get_theme_root() . "/{$repo['slug']}/style.css" : $file_path; 78 | 79 | if ( ! file_exists( $file_path ) || $type !== $repo_type ) { 80 | continue; 81 | } 82 | 83 | $all_headers = Singleton::get_instance( 'Base', $this )->get_headers( $repo_type ); 84 | 85 | $additions[ $repo['slug'] ]['type'] = $repo_type; 86 | $additions[ $repo['slug'] ] = get_file_data( $file_path, $all_headers ); 87 | 88 | switch ( $repo['type'] ) { 89 | case 'github_plugin': 90 | case 'github_theme': 91 | $addition[ 'GitHub' . ucwords( $repo_type ) . 'URI' ] = $repo['uri']; 92 | break; 93 | case 'bitbucket_plugin': 94 | case 'bitbucket_theme': 95 | $addition[ 'Bitbucket' . ucwords( $repo_type ) . 'URI' ] = $repo['uri']; 96 | break; 97 | case 'gitlab_plugin': 98 | case 'gitlab_theme': 99 | $addition[ 'GitLab' . ucwords( $repo_type ) . 'URI' ] = $repo['uri']; 100 | break; 101 | case 'gitea_plugin': 102 | case 'gitea_theme': 103 | $addition[ 'Gitea' . ucwords( $repo_type ) . 'URI' ] = $repo['uri']; 104 | break; 105 | } 106 | 107 | $addition['PrimaryBranch'] = ! empty( $repo['primary_branch'] ) ? $repo['primary_branch'] : 'master'; 108 | $addition['ReleaseAsset'] = isset( $repo['release_asset'] ) ? 'true' : null; 109 | 110 | $this->add_to_git_updater[ $repo['slug'] ] = array_merge( $additions[ $repo['slug'] ], $addition ); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/Additions/Bootstrap.php: -------------------------------------------------------------------------------- 1 | file = $file; 54 | $this->dir = dirname( $file ); 55 | } 56 | 57 | /** 58 | * Run the bootstrap. 59 | * 60 | * @return bool|void 61 | */ 62 | public function run() { 63 | // Bail if Git Updater not active. 64 | if ( ! class_exists( '\\Fragen\\Git_Updater\\Bootstrap' ) ) { 65 | return false; 66 | } 67 | 68 | ( new Settings() )->load_hooks(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Additions/Repo_List_Table.php: -------------------------------------------------------------------------------- 1 | md5( 'plugin-noheader/plugin-noheader.php' ), 57 | 'type' => 'github_plugin', 58 | 'slug' => 'plugin-noheader/plugin-noheader.php', 59 | 'uri' => 'https://github.com/afragen/plugin-noheader', 60 | ], 61 | [ 62 | 'ID' => md5( 'theme-noheader' ), 63 | 'type' => 'bitbucket_theme', 64 | 'slug' => 'theme-noheader', 65 | 'uri' => 'https://bitbucket.org/afragen/theme-noheader/', 66 | ], 67 | ]; 68 | // self::$examples = $examples; 69 | foreach ( (array) $options as $key => $option ) { 70 | $option['ID'] = $option['ID'] ?: null; 71 | $option['type'] = $option['type'] ?: null; 72 | $option['slug'] = $option['slug'] ?: null; 73 | $option['uri'] = $option['uri'] ?: null; 74 | $option['primary_branch'] = ! empty( $option['primary_branch'] ) ? $option['primary_branch'] : 'master'; 75 | $option['release_asset'] = isset( $option['release_asset'] ) ? '' : null; 76 | $options[ $key ] = $option; 77 | } 78 | self::$options = (array) $options; 79 | 80 | // Set parent defaults. 81 | parent::__construct( 82 | [ 83 | 'singular' => 'slug', // singular name of the listed records. 84 | 'plural' => 'slugs', // plural name of the listed records. 85 | 'ajax' => false, // does this table support ajax? 86 | ] 87 | ); 88 | } 89 | 90 | /** ************************************************************************ 91 | * Recommended. This method is called when the parent class can't find a method 92 | * specifically build for a given column. Generally, it's recommended to include 93 | * one method for each column you want to render, keeping your package class 94 | * neat and organized. For example, if the class needs to process a column 95 | * named 'title', it would first see if a method named $this->column_title() 96 | * exists - if it does, that method will be used. If it doesn't, this one will 97 | * be used. Generally, you should try to use custom column methods as much as 98 | * possible. 99 | * 100 | * Since we have defined a column_title() method later on, this method doesn't 101 | * need to concern itself with any column with a name of 'title'. Instead, it 102 | * needs to handle everything else. 103 | * 104 | * For more detailed insight into how columns are handled, take a look at 105 | * WP_List_Table::single_row_columns() 106 | * 107 | * @param array $item A singular item (one full row's worth of data). 108 | * @param array $column_name The name/slug of the column to be processed. 109 | * @return string Text or HTML to be placed inside the column 110 | **************************************************************************/ 111 | public function column_default( $item, $column_name ) { 112 | switch ( $column_name ) { 113 | case 'uri': 114 | case 'slug': 115 | case 'primary_branch': 116 | case 'release_asset': 117 | case 'type': 118 | return $item[ $column_name ]; 119 | default: 120 | // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r 121 | return print_r( $item, true ); // Show the whole array for troubleshooting purposes. 122 | } 123 | } 124 | 125 | /** ************************************************************************ 126 | * Recommended. This is a custom column method and is responsible for what 127 | * is rendered in any column with a name/slug of 'site'. Every time the class 128 | * needs to render a column, it first looks for a method named 129 | * column_{$column_title} - if it exists, that method is run. If it doesn't 130 | * exist, column_default() is called instead. 131 | * 132 | * This example also illustrates how to implement rollover actions. Actions 133 | * should be an associative array formatted as 'slug'=>'link html' - and you 134 | * will need to generate the URLs yourself. You could even ensure the links 135 | * 136 | * @see WP_List_Table::::single_row_columns() 137 | * @param array $item A singular item (one full row's worth of data). 138 | * @return string Text to be placed inside the column (site title only) 139 | **************************************************************************/ 140 | public function column_slug( $item ) { 141 | // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput 142 | $page = isset( $_REQUEST['page'] ) ? sanitize_title_with_dashes( wp_slash( $_REQUEST['page'] ) ) : null; 143 | $tab = isset( $_REQUEST['tab'] ) ? sanitize_title_with_dashes( wp_slash( $_REQUEST['tab'] ) ) : null; 144 | // phpcs:enable 145 | $location = add_query_arg( 146 | [ 147 | 'page' => $page, 148 | 'tab' => $tab, 149 | ], 150 | '' 151 | ); 152 | 153 | // Build row actions. 154 | $actions = [ 155 | // 'edit' => sprintf( 'Edit', $location, 'edit', $item['ID'] ), 156 | 'delete' => sprintf( 'Delete', wp_nonce_url( $location, 'delete_row_item', '_wpnonce_row_action_delete' ), 'delete_row_item', $item['ID'] ), 157 | ]; 158 | 159 | // Return the title contents. 160 | return sprintf( 161 | /* translators: 1: title, 2: ID, 3: row actions */ 162 | '%1$s (id:%2$s)%3$s', 163 | /*$1%s*/ 164 | $item['slug'], 165 | /*$2%s*/ 166 | $item['ID'], 167 | /*$3%s*/ 168 | $this->row_actions( $actions ) 169 | ); 170 | } 171 | 172 | /** ************************************************************************ 173 | * REQUIRED if displaying checkboxes or using bulk actions! The 'cb' column 174 | * is given special treatment when columns are processed. It ALWAYS needs to 175 | * have it's own method. 176 | * 177 | * @see WP_List_Table::::single_row_columns() 178 | * @param array $item A singular item (one full row's worth of data). 179 | * @return string Text to be placed inside the column (movie title only) 180 | **************************************************************************/ 181 | public function column_cb( $item ) { 182 | return sprintf( 183 | '', 184 | /*$1%s*/ 185 | $this->_args['singular'], // Let's simply repurpose the table's singular label ("site"). 186 | /*$2%s*/ 187 | $item['ID'] // The value of the checkbox should be the record's id. 188 | ); 189 | } 190 | 191 | /** ************************************************************************ 192 | * REQUIRED! This method dictates the table's columns and titles. This should 193 | * return an array where the key is the column slug (and class) and the value 194 | * is the column's title text. If you need a checkbox for bulk actions, refer 195 | * to the $columns array below. 196 | * 197 | * The 'cb' column is treated differently than the rest. If including a checkbox 198 | * column in your table you must create a column_cb() method. If you don't need 199 | * bulk actions or checkboxes, simply leave the 'cb' entry out of your array. 200 | * 201 | * @see WP_List_Table::::single_row_columns() 202 | * @return array An associative array containing column information: 'slugs'=>'Visible Titles' 203 | **************************************************************************/ 204 | public function get_columns() { 205 | $columns = [ 206 | // 'cb' => '', // Render a checkbox instead of text. 207 | 'slug' => esc_html__( 'Slug', 'git-updater-additions' ), 208 | 'uri' => esc_html__( 'URL', 'git-updater-additions' ), 209 | 'primary_branch' => esc_html__( 'Primary Branch', 'git-updater-additions' ), 210 | 'release_asset' => esc_html__( 'Release Asset', 'git-updater-additions' ), 211 | 'type' => esc_html__( 'Type', 'git-updater-additions' ), 212 | ]; 213 | 214 | return $columns; 215 | } 216 | 217 | /** ************************************************************************ 218 | * Optional. If you want one or more columns to be sortable (ASC/DESC toggle), 219 | * you will need to register it here. This should return an array where the 220 | * key is the column that needs to be sortable, and the value is db column to 221 | * sort by. Often, the key and value will be the same, but this is not always 222 | * the case (as the value is a column name from the database, not the list table). 223 | * 224 | * This method merely defines which columns should be sortable and makes them 225 | * clickable - it does not handle the actual sorting. You still need to detect 226 | * the ORDERBY and ORDER querystring variables within prepare_items() and sort 227 | * your data accordingly (usually by modifying your query). 228 | * 229 | * @return array An associative array containing all the columns that should be sortable: 'slugs'=>array('data_values',bool) 230 | **************************************************************************/ 231 | public function get_sortable_columns() { 232 | $sortable_columns = [ 233 | 'slug' => [ 'slug', true ], // true means it's already sorted. 234 | 'type' => [ 'type', true ], 235 | // 'api_key' => [ 'api_key', false ], 236 | ]; 237 | 238 | return $sortable_columns; 239 | } 240 | 241 | /** ************************************************************************ 242 | * Optional. If you need to include bulk actions in your list table, this is 243 | * the place to define them. Bulk actions are an associative array in the format 244 | * 'slug'=>'Visible Title' 245 | * 246 | * If this method returns an empty value, no bulk action will be rendered. If 247 | * you specify any bulk actions, the bulk actions box will be rendered with 248 | * the table automatically on display(). 249 | * 250 | * Also note that list tables are not automatically wrapped in
elements, 251 | * so you will need to create those manually in order for bulk actions to function. 252 | * 253 | * @return void|array An associative array containing all the bulk actions: 'slugs'=>'Visible Titles' 254 | **************************************************************************/ 255 | public function get_bulk_actions() { 256 | $actions = [ 257 | 'delete' => esc_html__( 'Delete', 'git-updater-additions' ), 258 | ]; 259 | 260 | // return $actions; 261 | } 262 | 263 | /** ************************************************************************ 264 | * Optional. You can handle your bulk actions anywhere or anyhow you prefer. 265 | * For this example package, we will handle it in the class to keep things 266 | * clean and organized. 267 | * 268 | * @see $this->prepare_items() 269 | **************************************************************************/ 270 | public function process_bulk_action() { 271 | // Detect when a bulk action is being triggered... 272 | if ( ! isset( $_REQUEST['_wpnonce_row_action_delete'] ) 273 | || ! \wp_verify_nonce( \sanitize_key( \wp_unslash( $_REQUEST['_wpnonce_row_action_delete'] ) ), 'delete_row_item' ) 274 | ) { 275 | return; 276 | } 277 | $slugs = isset( $_REQUEST['slug'] ) ? sanitize_key( wp_unslash( $_REQUEST['slug'] ) ) : null; 278 | $slugs = is_array( $slugs ) ? $slugs : (array) $slugs; 279 | foreach ( $slugs as $slug ) { 280 | foreach ( self::$options as $key => $option ) { 281 | if ( in_array( $slug, $option, true ) ) { 282 | unset( self::$options[ $key ] ); 283 | update_site_option( 'git_updater_additions', self::$options ); 284 | } 285 | } 286 | } 287 | if ( 'edit' === $this->current_action() ) { 288 | wp_die( esc_html__( 'Items would go to edit when we write that code.', 'git-updater-additions' ) ); 289 | } 290 | } 291 | 292 | /** ************************************************************************ 293 | * REQUIRED! This is where you prepare your data for display. This method will 294 | * usually be used to query the database, sort and filter the data, and generally 295 | * get it ready to be displayed. At a minimum, we should set $this->items and 296 | * $this->set_pagination_args(), although the following properties and methods 297 | * are frequently interacted with here... 298 | * 299 | * @global WPDB $wpdb 300 | * @uses $this->_column_headers 301 | * @uses $this->items 302 | * @uses $this->get_columns() 303 | * @uses $this->get_sortable_columns() 304 | * @uses $this->get_pagenum() 305 | * @uses $this->set_pagination_args() 306 | **************************************************************************/ 307 | public function prepare_items() { 308 | global $wpdb; // This is used only if making any database queries. 309 | 310 | /** 311 | * First, lets decide how many records per page to show. 312 | */ 313 | $per_page = 5; 314 | 315 | /** 316 | * REQUIRED. Now we need to define our column headers. This includes a complete 317 | * array of columns to be displayed (slugs & titles), a list of columns 318 | * to keep hidden, and a list of columns that are sortable. Each of these 319 | * can be defined in another method (as we've done here) before being 320 | * used to build the value for our _column_headers property. 321 | */ 322 | $columns = $this->get_columns(); 323 | $hidden = []; 324 | $sortable = $this->get_sortable_columns(); 325 | 326 | /** 327 | * REQUIRED. Finally, we build an array to be used by the class for column 328 | * headers. The $this->_column_headers property takes an array which contains 329 | * 3 other arrays. One for all columns, one for hidden columns, and one 330 | * for sortable columns. 331 | */ 332 | $this->_column_headers = [ $columns, $hidden, $sortable ]; 333 | 334 | /** 335 | * Optional. You can handle your bulk actions however you see fit. In this 336 | * case, we'll handle them within our package just to keep things clean. 337 | */ 338 | $this->process_bulk_action(); 339 | 340 | /** 341 | * Instead of querying a database, we're going to fetch the example data 342 | * property we created for use in this plugin. This makes this example 343 | * package slightly different than one you might build on your own. In 344 | * this example, we'll be using array manipulation to sort and paginate 345 | * our data. In a real-world implementation, you will probably want to 346 | * use sort and pagination data to build a custom query instead, as you'll 347 | * be able to use your precisely-queried data immediately. 348 | */ 349 | $data = array_merge( self::$examples, self::$options ); 350 | 351 | usort( $data, [ $this, 'usort_reorder' ] ); 352 | 353 | /*********************************************************************** 354 | * --------------------------------------------------------------------- 355 | * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 356 | * 357 | * In a real-world situation, this is where you would place your query. 358 | * 359 | * For information on making queries in WordPress, see this Codex entry: 360 | * http://codex.wordpress.org/Class_Reference/wpdb 361 | * 362 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 363 | * --------------------------------------------------------------------- 364 | */ 365 | 366 | /** 367 | * REQUIRED for pagination. Let's figure out what page the user is currently 368 | * looking at. We'll need this later, so you should always include it in 369 | * your own package classes. 370 | */ 371 | $current_page = $this->get_pagenum(); 372 | 373 | /** 374 | * REQUIRED for pagination. Let's check how many items are in our data array. 375 | * In real-world use, this would be the total number of items in your database, 376 | * without filtering. We'll need this later, so you should always include it 377 | * in your own package classes. 378 | */ 379 | $total_items = count( $data ); 380 | 381 | /** 382 | * The WP_List_Table class does not handle pagination for us, so we need 383 | * to ensure that the data is trimmed to only the current page. We can use 384 | * array_slice() to 385 | */ 386 | $data = array_slice( $data, ( ( $current_page - 1 ) * $per_page ), $per_page ); 387 | 388 | /** 389 | * REQUIRED. Now we can add our *sorted* data to the items property, where 390 | * it can be used by the rest of the class. 391 | */ 392 | $this->items = $data; 393 | 394 | /** 395 | * REQUIRED. We also have to register our pagination options & calculations. 396 | */ 397 | $this->set_pagination_args( 398 | [ 399 | 'total_items' => $total_items, // WE have to calculate the total number of items. 400 | 'per_page' => $per_page, // WE have to determine how many items to show on a page. 401 | 'total_pages' => ceil( $total_items / $per_page ), // WE have to calculate the total number of pages. 402 | ] 403 | ); 404 | } 405 | 406 | /** 407 | * This checks for sorting input and sorts the data in our array accordingly. 408 | * 409 | * In a real-world situation involving a database, you would probably want 410 | * to handle sorting by passing the 'orderby' and 'order' values directly 411 | * to a custom query. The returned data will be pre-sorted, and this array 412 | * sorting technique would be unnecessary. 413 | * 414 | * @param array $a Array of table row data. 415 | * @param array $b Array of table row data. 416 | * 417 | * @return int Sort order, either 1 or -1. 418 | */ 419 | public function usort_reorder( $a, $b ) { 420 | // phpcs:disable WordPress.Security.NonceVerification.Recommended 421 | $orderby = ( ! empty( $_REQUEST['orderby'] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ) : 'slug'; // If no sort, default to site. 422 | $order = ( ! empty( $_REQUEST['order'] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) : 'asc'; // If no order, default to asc. 423 | // phpcs:enable 424 | $result = strcmp( $a[ $orderby ], $b[ $orderby ] ); // Determine sort order. 425 | 426 | return ( 'asc' === $order ) ? $result : -$result; // Send final sort direction to usort. 427 | } 428 | 429 | /** 430 | * Render list table. 431 | * 432 | * Explicitly calls prepare_items() and display(). 433 | * 434 | * @return void 435 | */ 436 | public function render_list_table() { 437 | // Fetch, prepare, sort, and filter our data... 438 | $this->prepare_items(); 439 | echo '
'; 440 | echo '

' . esc_html__( 'Additions List Table', 'git-updater-additions' ) . '

'; 441 | 442 | // Forms are NOT created automatically, so you need to wrap the table in one to use features like bulk actions. 443 | echo ''; 444 | wp_nonce_field( 'process-items', '_wpnonce_list' ); 445 | 446 | // For plugins, we also need to ensure that the form posts back to our current page. 447 | // phpcs:ignore WordPress.Security.NonceVerification.Recommended 448 | $current_page = isset( $_REQUEST['page'] ) ? sanitize_title_with_dashes( wp_unslash( $_REQUEST['page'] ) ) : null; 449 | echo ''; 450 | 451 | // Now we can render the completed list table. 452 | $this->display(); 453 | echo ''; 454 | echo '
'; 455 | } 456 | } 457 | -------------------------------------------------------------------------------- /src/Additions/Settings.php: -------------------------------------------------------------------------------- 1 | load_options(); 39 | } 40 | 41 | /** 42 | * Load site options. 43 | */ 44 | private function load_options() { 45 | self::$options_additions = get_site_option( 'git_updater_additions', [] ); 46 | } 47 | 48 | /** 49 | * Load needed action/filter hooks. 50 | */ 51 | public function load_hooks() { 52 | add_action( 53 | 'gu_update_settings', 54 | function ( $post_data ) { 55 | $this->save_settings( $post_data ); 56 | } 57 | ); 58 | $this->add_settings_tabs(); 59 | 60 | add_filter( 61 | 'gu_add_admin_page', 62 | function ( $tab, $action ) { 63 | $this->add_admin_page( $tab, $action ); 64 | }, 65 | 10, 66 | 2 67 | ); 68 | } 69 | 70 | /** 71 | * Save Additions settings. 72 | * 73 | * @uses 'gu_update_settings' action hook 74 | * @uses 'gu_save_redirect' filter hook 75 | * 76 | * @param array $post_data $_POST data. 77 | */ 78 | public function save_settings( $post_data ) { 79 | if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['_wpnonce'] ) ), 'git_updater_additions-options' ) ) { 80 | return; 81 | } 82 | $options = (array) get_site_option( 'git_updater_additions', [] ); 83 | $duplicate = false; 84 | $bad_input = false; 85 | if ( isset( $post_data['option_page'] ) && 86 | 'git_updater_additions' === $post_data['option_page'] 87 | ) { 88 | $new_options = isset( $post_data['git_updater_additions'] ) 89 | ? $post_data['git_updater_additions'] 90 | : []; 91 | 92 | $new_options = $this->sanitize( $new_options ); 93 | 94 | foreach ( $options as $option ) { 95 | $is_plugin_slug = preg_match( '@/@', $new_options[0]['slug'] ); 96 | $type_plugin = \preg_match( '/plugin/', $new_options[0]['type'] ); 97 | $bad_input = $type_plugin && ! $is_plugin_slug; 98 | $bad_input = ! $bad_input ? ! $type_plugin && $is_plugin_slug : $bad_input; 99 | $bad_input = $bad_input || empty( $new_options[0]['slug'] ) || empty( $new_options[0]['uri'] ); 100 | $duplicate = in_array( $new_options[0]['ID'], $option, true ); 101 | if ( $duplicate || $bad_input ) { 102 | $_POST['action'] = false; 103 | break; 104 | } 105 | } 106 | 107 | if ( ! $duplicate && ! $bad_input ) { 108 | $options = array_merge( $options, $new_options ); 109 | $options = array_filter( $options ); 110 | update_site_option( 'git_updater_additions', $options ); 111 | } 112 | 113 | add_filter( 114 | 'gu_save_redirect', 115 | function ( $option_page ) { 116 | return array_merge( $option_page, [ 'git_updater_additions' ] ); 117 | } 118 | ); 119 | } 120 | } 121 | 122 | /** 123 | * Adds Additions tab to Settings page. 124 | */ 125 | public function add_settings_tabs() { 126 | $install_tabs = [ 'git_updater_additions' => esc_html__( 'Additions', 'git-updater-additions' ) ]; 127 | add_filter( 128 | 'gu_add_settings_tabs', 129 | function ( $tabs ) use ( $install_tabs ) { 130 | return array_merge( $tabs, $install_tabs ); 131 | }, 132 | 20, 133 | 1 134 | ); 135 | } 136 | 137 | /** 138 | * Add Settings page data via action hook. 139 | * 140 | * @uses 'gu_add_admin_page' action hook 141 | * 142 | * @param string $tab Tab name. 143 | * @param string $action Form action. 144 | */ 145 | public function add_admin_page( $tab, $action ) { 146 | $this->additions_page_init(); 147 | 148 | if ( 'git_updater_additions' === $tab ) { 149 | $action = add_query_arg( 150 | [ 151 | 'page' => 'git-updater', 152 | 'tab' => $tab, 153 | ], 154 | $action 155 | ); 156 | ( new Repo_List_Table( self::$options_additions ) )->render_list_table(); 157 | ?> 158 |
159 | 164 |
165 | 'git_updater_additions_type', 194 | 'setting' => 'type', 195 | ] 196 | ); 197 | 198 | add_settings_field( 199 | 'slug', 200 | esc_html__( 'Repository Slug', 'git-updater-additions' ), 201 | [ $this, 'callback_field' ], 202 | 'git_updater_additions', 203 | 'git_updater_additions', 204 | [ 205 | 'id' => 'git_updater_additions_slug', 206 | 'setting' => 'slug', 207 | 'title' => __( 'Ensure proper slug for plugin or theme.', 'git-updater-addtions' ), 208 | 'placeholder' => 'plugin-slug/plugin-slug.php', 209 | ] 210 | ); 211 | 212 | add_settings_field( 213 | 'uri', 214 | esc_html__( 'Repository URI', 'git-updater-additions' ), 215 | [ $this, 'callback_field' ], 216 | 'git_updater_additions', 217 | 'git_updater_additions', 218 | [ 219 | 'id' => 'git_updater_additions_uri', 220 | 'setting' => 'uri', 221 | 'title' => __( 'Ensure proper URI for plugin or theme.', 'git-updater-addtions' ), 222 | ] 223 | ); 224 | 225 | add_settings_field( 226 | 'primary_branch', 227 | esc_html__( 'Primary Branch', 'git-updater-additions' ), 228 | [ $this, 'callback_field' ], 229 | 'git_updater_additions', 230 | 'git_updater_additions', 231 | [ 232 | 'id' => 'git_updater_additions_primary_branch', 233 | 'setting' => 'primary_branch', 234 | 'title' => __( 'Ensure proper primary branch, default is `master`', 'git-updater-additions' ), 235 | 'placeholder' => 'master', 236 | ] 237 | ); 238 | 239 | add_settings_field( 240 | 'release_asset', 241 | esc_html__( 'Release Asset', 'git-updater-additions' ), 242 | [ $this, 'callback_checkbox' ], 243 | 'git_updater_additions', 244 | 'git_updater_additions', 245 | [ 246 | 'id' => 'git_updater_additions_release_asset', 247 | 'setting' => 'release_asset', 248 | 'title' => __( 'Check if a release asset is required.', 'git-updater-additions' ), 249 | ] 250 | ); 251 | } 252 | 253 | /** 254 | * Sanitize each setting field as needed. 255 | * 256 | * @param array $input Contains all settings fields as array keys. 257 | * 258 | * @return array 259 | */ 260 | public function sanitize( $input ) { 261 | $new_input = []; 262 | 263 | foreach ( (array) $input as $key => $value ) { 264 | $new_input[0][ $key ] = 'uri' === $key ? untrailingslashit( sanitize_url( trim( $value ) ) ) : sanitize_text_field( $value ); 265 | } 266 | $new_input[0]['ID'] = md5( $new_input[0]['slug'] ); 267 | 268 | return $new_input; 269 | } 270 | 271 | /** 272 | * Print the Remote Management text. 273 | */ 274 | public function print_section_additions() { 275 | echo '

'; 276 | esc_html_e( 'If there are git repositories that do not natively support Git Updater you can add them here.', 'git-updater-additions' ); 277 | echo '

'; 278 | } 279 | 280 | /** 281 | * Field callback. 282 | * 283 | * @param array $args Data passed from add_settings_field(). 284 | * 285 | * @return void 286 | */ 287 | public function callback_field( $args ) { 288 | $placeholder = isset( $args['placeholder'] ) ? $args['placeholder'] : null; 289 | ?> 290 | 297 | 310 | 326 | 337 | 341 | 7 | * Jordi Boggiano 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 39 | * @author Jordi Boggiano 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> 52 | */ 53 | private $prefixLengthsPsr4 = array(); 54 | /** 55 | * @var array[] 56 | * @psalm-var array> 57 | */ 58 | private $prefixDirsPsr4 = array(); 59 | /** 60 | * @var array[] 61 | * @psalm-var array 62 | */ 63 | private $fallbackDirsPsr4 = array(); 64 | 65 | // PSR-0 66 | /** 67 | * @var array[] 68 | * @psalm-var array> 69 | */ 70 | private $prefixesPsr0 = array(); 71 | /** 72 | * @var array[] 73 | * @psalm-var array 74 | */ 75 | private $fallbackDirsPsr0 = array(); 76 | 77 | /** @var bool */ 78 | private $useIncludePath = false; 79 | 80 | /** 81 | * @var string[] 82 | * @psalm-var array 83 | */ 84 | private $classMap = array(); 85 | 86 | /** @var bool */ 87 | private $classMapAuthoritative = false; 88 | 89 | /** 90 | * @var bool[] 91 | * @psalm-var array 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> 126 | */ 127 | public function getPrefixesPsr4() 128 | { 129 | return $this->prefixDirsPsr4; 130 | } 131 | 132 | /** 133 | * @return array[] 134 | * @psalm-return array 135 | */ 136 | public function getFallbackDirs() 137 | { 138 | return $this->fallbackDirsPsr0; 139 | } 140 | 141 | /** 142 | * @return array[] 143 | * @psalm-return array 144 | */ 145 | public function getFallbackDirsPsr4() 146 | { 147 | return $this->fallbackDirsPsr4; 148 | } 149 | 150 | /** 151 | * @return string[] Array of classname => path 152 | * @psalm-return array 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 $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 | } 573 | -------------------------------------------------------------------------------- /vendor/composer/InstalledVersions.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 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 | * @final 26 | */ 27 | class InstalledVersions 28 | { 29 | /** 30 | * @var mixed[]|null 31 | * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null 32 | */ 33 | private static $installed; 34 | 35 | /** 36 | * @var bool|null 37 | */ 38 | private static $canGetVendors; 39 | 40 | /** 41 | * @var array[] 42 | * @psalm-var array}> 43 | */ 44 | private static $installedByVendor = array(); 45 | 46 | /** 47 | * Returns a list of all package names which are present, either by being installed, replaced or provided 48 | * 49 | * @return string[] 50 | * @psalm-return list 51 | */ 52 | public static function getInstalledPackages() 53 | { 54 | $packages = array(); 55 | foreach (self::getInstalled() as $installed) { 56 | $packages[] = array_keys($installed['versions']); 57 | } 58 | 59 | if (1 === \count($packages)) { 60 | return $packages[0]; 61 | } 62 | 63 | return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); 64 | } 65 | 66 | /** 67 | * Returns a list of all package names with a specific type e.g. 'library' 68 | * 69 | * @param string $type 70 | * @return string[] 71 | * @psalm-return list 72 | */ 73 | public static function getInstalledPackagesByType($type) 74 | { 75 | $packagesByType = array(); 76 | 77 | foreach (self::getInstalled() as $installed) { 78 | foreach ($installed['versions'] as $name => $package) { 79 | if (isset($package['type']) && $package['type'] === $type) { 80 | $packagesByType[] = $name; 81 | } 82 | } 83 | } 84 | 85 | return $packagesByType; 86 | } 87 | 88 | /** 89 | * Checks whether the given package is installed 90 | * 91 | * This also returns true if the package name is provided or replaced by another package 92 | * 93 | * @param string $packageName 94 | * @param bool $includeDevRequirements 95 | * @return bool 96 | */ 97 | public static function isInstalled($packageName, $includeDevRequirements = true) 98 | { 99 | foreach (self::getInstalled() as $installed) { 100 | if (isset($installed['versions'][$packageName])) { 101 | return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); 102 | } 103 | } 104 | 105 | return false; 106 | } 107 | 108 | /** 109 | * Checks whether the given package satisfies a version constraint 110 | * 111 | * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: 112 | * 113 | * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') 114 | * 115 | * @param VersionParser $parser Install composer/semver to have access to this class and functionality 116 | * @param string $packageName 117 | * @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 118 | * @return bool 119 | */ 120 | public static function satisfies(VersionParser $parser, $packageName, $constraint) 121 | { 122 | $constraint = $parser->parseConstraints($constraint); 123 | $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); 124 | 125 | return $provided->matches($constraint); 126 | } 127 | 128 | /** 129 | * Returns a version constraint representing all the range(s) which are installed for a given package 130 | * 131 | * It is easier to use this via isInstalled() with the $constraint argument if you need to check 132 | * whether a given version of a package is installed, and not just whether it exists 133 | * 134 | * @param string $packageName 135 | * @return string Version constraint usable with composer/semver 136 | */ 137 | public static function getVersionRanges($packageName) 138 | { 139 | foreach (self::getInstalled() as $installed) { 140 | if (!isset($installed['versions'][$packageName])) { 141 | continue; 142 | } 143 | 144 | $ranges = array(); 145 | if (isset($installed['versions'][$packageName]['pretty_version'])) { 146 | $ranges[] = $installed['versions'][$packageName]['pretty_version']; 147 | } 148 | if (array_key_exists('aliases', $installed['versions'][$packageName])) { 149 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); 150 | } 151 | if (array_key_exists('replaced', $installed['versions'][$packageName])) { 152 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); 153 | } 154 | if (array_key_exists('provided', $installed['versions'][$packageName])) { 155 | $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); 156 | } 157 | 158 | return implode(' || ', $ranges); 159 | } 160 | 161 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 162 | } 163 | 164 | /** 165 | * @param string $packageName 166 | * @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 167 | */ 168 | public static function getVersion($packageName) 169 | { 170 | foreach (self::getInstalled() as $installed) { 171 | if (!isset($installed['versions'][$packageName])) { 172 | continue; 173 | } 174 | 175 | if (!isset($installed['versions'][$packageName]['version'])) { 176 | return null; 177 | } 178 | 179 | return $installed['versions'][$packageName]['version']; 180 | } 181 | 182 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 183 | } 184 | 185 | /** 186 | * @param string $packageName 187 | * @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 188 | */ 189 | public static function getPrettyVersion($packageName) 190 | { 191 | foreach (self::getInstalled() as $installed) { 192 | if (!isset($installed['versions'][$packageName])) { 193 | continue; 194 | } 195 | 196 | if (!isset($installed['versions'][$packageName]['pretty_version'])) { 197 | return null; 198 | } 199 | 200 | return $installed['versions'][$packageName]['pretty_version']; 201 | } 202 | 203 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 204 | } 205 | 206 | /** 207 | * @param string $packageName 208 | * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference 209 | */ 210 | public static function getReference($packageName) 211 | { 212 | foreach (self::getInstalled() as $installed) { 213 | if (!isset($installed['versions'][$packageName])) { 214 | continue; 215 | } 216 | 217 | if (!isset($installed['versions'][$packageName]['reference'])) { 218 | return null; 219 | } 220 | 221 | return $installed['versions'][$packageName]['reference']; 222 | } 223 | 224 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 225 | } 226 | 227 | /** 228 | * @param string $packageName 229 | * @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. 230 | */ 231 | public static function getInstallPath($packageName) 232 | { 233 | foreach (self::getInstalled() as $installed) { 234 | if (!isset($installed['versions'][$packageName])) { 235 | continue; 236 | } 237 | 238 | return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; 239 | } 240 | 241 | throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); 242 | } 243 | 244 | /** 245 | * @return array 246 | * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} 247 | */ 248 | public static function getRootPackage() 249 | { 250 | $installed = self::getInstalled(); 251 | 252 | return $installed[0]['root']; 253 | } 254 | 255 | /** 256 | * Returns the raw installed.php data for custom implementations 257 | * 258 | * @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. 259 | * @return array[] 260 | * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} 261 | */ 262 | public static function getRawData() 263 | { 264 | @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); 265 | 266 | if (null === self::$installed) { 267 | // only require the installed.php file if this file is loaded from its dumped location, 268 | // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 269 | if (substr(__DIR__, -8, 1) !== 'C') { 270 | self::$installed = include __DIR__ . '/installed.php'; 271 | } else { 272 | self::$installed = array(); 273 | } 274 | } 275 | 276 | return self::$installed; 277 | } 278 | 279 | /** 280 | * Returns the raw data of all installed.php which are currently loaded for custom implementations 281 | * 282 | * @return array[] 283 | * @psalm-return list}> 284 | */ 285 | public static function getAllRawData() 286 | { 287 | return self::getInstalled(); 288 | } 289 | 290 | /** 291 | * Lets you reload the static array from another file 292 | * 293 | * This is only useful for complex integrations in which a project needs to use 294 | * this class but then also needs to execute another project's autoloader in process, 295 | * and wants to ensure both projects have access to their version of installed.php. 296 | * 297 | * A typical case would be PHPUnit, where it would need to make sure it reads all 298 | * the data it needs from this class, then call reload() with 299 | * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure 300 | * the project in which it runs can then also use this class safely, without 301 | * interference between PHPUnit's dependencies and the project's dependencies. 302 | * 303 | * @param array[] $data A vendor/composer/installed.php data set 304 | * @return void 305 | * 306 | * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data 307 | */ 308 | public static function reload($data) 309 | { 310 | self::$installed = $data; 311 | self::$installedByVendor = array(); 312 | } 313 | 314 | /** 315 | * @return array[] 316 | * @psalm-return list}> 317 | */ 318 | private static function getInstalled() 319 | { 320 | if (null === self::$canGetVendors) { 321 | self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); 322 | } 323 | 324 | $installed = array(); 325 | 326 | if (self::$canGetVendors) { 327 | foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { 328 | if (isset(self::$installedByVendor[$vendorDir])) { 329 | $installed[] = self::$installedByVendor[$vendorDir]; 330 | } elseif (is_file($vendorDir.'/composer/installed.php')) { 331 | $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; 332 | if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { 333 | self::$installed = $installed[count($installed) - 1]; 334 | } 335 | } 336 | } 337 | } 338 | 339 | if (null === self::$installed) { 340 | // only require the installed.php file if this file is loaded from its dumped location, 341 | // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 342 | if (substr(__DIR__, -8, 1) !== 'C') { 343 | self::$installed = require __DIR__ . '/installed.php'; 344 | } else { 345 | self::$installed = array(); 346 | } 347 | } 348 | $installed[] = self::$installed; 349 | 350 | return $installed; 351 | } 352 | } 353 | -------------------------------------------------------------------------------- /vendor/composer/LICENSE: -------------------------------------------------------------------------------- 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 | 22 | -------------------------------------------------------------------------------- /vendor/composer/autoload_classmap.php: -------------------------------------------------------------------------------- 1 | $vendorDir . '/composer/InstalledVersions.php', 10 | ); 11 | -------------------------------------------------------------------------------- /vendor/composer/autoload_namespaces.php: -------------------------------------------------------------------------------- 1 | array($baseDir . '/src/Additions'), 10 | 'Fragen\\Git_Updater\\' => array($baseDir . '/src/Git_Updater'), 11 | ); 12 | -------------------------------------------------------------------------------- /vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | register(true); 35 | 36 | return $loader; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | 11 | array ( 12 | 'Fragen\\Git_Updater\\Additions\\' => 29, 13 | 'Fragen\\Git_Updater\\' => 19, 14 | ), 15 | ); 16 | 17 | public static $prefixDirsPsr4 = array ( 18 | 'Fragen\\Git_Updater\\Additions\\' => 19 | array ( 20 | 0 => __DIR__ . '/../..' . '/src/Additions', 21 | ), 22 | 'Fragen\\Git_Updater\\' => 23 | array ( 24 | 0 => __DIR__ . '/../..' . '/src/Git_Updater', 25 | ), 26 | ); 27 | 28 | public static $classMap = array ( 29 | 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 30 | ); 31 | 32 | public static function getInitializer(ClassLoader $loader) 33 | { 34 | return \Closure::bind(function () use ($loader) { 35 | $loader->prefixLengthsPsr4 = ComposerStaticInit8cc4fdeb1dc1e2ebf75c2a906ce22470::$prefixLengthsPsr4; 36 | $loader->prefixDirsPsr4 = ComposerStaticInit8cc4fdeb1dc1e2ebf75c2a906ce22470::$prefixDirsPsr4; 37 | $loader->classMap = ComposerStaticInit8cc4fdeb1dc1e2ebf75c2a906ce22470::$classMap; 38 | 39 | }, null, ClassLoader::class); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /vendor/composer/installed.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [], 3 | "dev": false, 4 | "dev-package-names": [] 5 | } 6 | -------------------------------------------------------------------------------- /vendor/composer/installed.php: -------------------------------------------------------------------------------- 1 | array( 3 | 'name' => 'afragen/git-updater-additions', 4 | 'pretty_version' => 'dev-develop', 5 | 'version' => 'dev-develop', 6 | 'reference' => 'a5205ef02202cabb6de0ceae481177caace833d8', 7 | 'type' => 'wordpress-plugin', 8 | 'install_path' => __DIR__ . '/../../', 9 | 'aliases' => array(), 10 | 'dev' => false, 11 | ), 12 | 'versions' => array( 13 | 'afragen/git-updater-additions' => array( 14 | 'pretty_version' => 'dev-develop', 15 | 'version' => 'dev-develop', 16 | 'reference' => 'a5205ef02202cabb6de0ceae481177caace833d8', 17 | 'type' => 'wordpress-plugin', 18 | 'install_path' => __DIR__ . '/../../', 19 | 'aliases' => array(), 20 | 'dev_requirement' => false, 21 | ), 22 | ), 23 | ); 24 | -------------------------------------------------------------------------------- /vendor/composer/platform_check.php: -------------------------------------------------------------------------------- 1 | = 70200)) { 8 | $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.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 | } 27 | --------------------------------------------------------------------------------