├── .editorconfig
├── .github
├── CODEOWNERS
└── workflows
│ ├── close-stale-issues.yml
│ ├── dependency-review.yml
│ └── wordpress-version-checker.yml
├── .gitignore
├── .travis.yml
├── .wordpress-org
├── banner-1544x500.jpg
├── banner-1544x500.png
├── banner-772x250.png
├── icon-128x128.png
├── icon-256x256.jpg
├── icon-256x256.png
└── icon.svg
├── 10up-sitemaps.php
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── CREDITS.md
├── LICENSE.md
├── README.md
├── bin
└── install-wp-tests.sh
├── composer.json
├── composer.lock
├── includes
├── classes
│ ├── Command.php
│ └── Sitemap.php
├── core.php
├── templates
│ ├── sitemap-page.php
│ └── sitemap-root.php
└── utils.php
├── phpcs.xml
├── phpunit.xml.dist
├── readme.txt
└── tests
├── TestSitemap.php
└── bootstrap.php
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | insert_final_newline = true
7 | trim_trailing_whitespace = true
8 | indent_style = tab
9 |
10 | [{*.json,*.yml,.babelrc,.bowerrc,.browserslistrc,.postcssrc}]
11 | indent_style = space
12 | indent_size = 2
13 |
14 | [*.txt,wp-config-sample.php]
15 | end_of_line = crlf
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # These owners will be the default owners for everything in the repo. Unless a later match takes precedence, @tlovett1, as primary maintainer will be requested for review when someone opens a Pull Request.
2 | * @tlovett1 @10up/open-source-practice
3 |
4 | # GitHub and WordPress.org specifics
5 | /.github/ @jeffpaul
6 | /.wordpress-org/ @jeffpaul
7 | CODE_OF_CONDUCT.md @jeffpaul
8 | LICENSE.md @jeffpaul
9 |
--------------------------------------------------------------------------------
/.github/workflows/close-stale-issues.yml:
--------------------------------------------------------------------------------
1 | name: 'Close stale issues'
2 |
3 | # **What it does**: Closes issues where the original author doesn't respond to a request for information.
4 | # **Why we have it**: To remove the need for maintainers to remember to check back on issues periodically to see if contributors have responded.
5 |
6 | on:
7 | schedule:
8 | # Schedule for every day at 1:30am UTC
9 | - cron: '30 1 * * *'
10 |
11 | permissions:
12 | issues: write
13 |
14 | jobs:
15 | stale:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/stale@v9
19 | with:
20 | days-before-stale: 7
21 | days-before-close: 7
22 | stale-issue-message: >
23 | It has been 7 days since more information was requested from you in this issue and we have not heard back. This issue is now marked as stale and will be closed in 7 days, but if you have more information to add then please comment and the issue will stay open.
24 | close-issue-message: >
25 | This issue has been automatically closed because there has been no response
26 | to our request for more information. With only the
27 | information that is currently in the issue, we don't have enough information
28 | to take action. Please reach out if you have or find the answers we need so
29 | that we can investigate further. See [this blog post on bug reports and the
30 | importance of repro steps](https://www.lee-dohm.com/2015/01/04/writing-good-bug-reports/)
31 | for more information about the kind of information that may be helpful.
32 | stale-issue-label: 'stale'
33 | close-issue-reason: 'not_planned'
34 | any-of-labels: 'needs:feedback'
35 | remove-stale-when-updated: true
36 |
37 |
--------------------------------------------------------------------------------
/.github/workflows/dependency-review.yml:
--------------------------------------------------------------------------------
1 | # Dependency Review Action
2 | #
3 | # This Action will scan dependency manifest files that change as part of a Pull Reqest, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging.
4 | #
5 | # Source repository: https://github.com/actions/dependency-review-action
6 | # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
7 | name: 'Dependency Review'
8 | on: [pull_request]
9 |
10 | permissions:
11 | contents: read
12 |
13 | jobs:
14 | dependency-review:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - name: 'Checkout Repository'
18 | uses: actions/checkout@v3
19 | - name: Dependency Review
20 | uses: actions/dependency-review-action@v3
21 | with:
22 | license-check: true
23 | vulnerability-check: false
24 | config-file: 10up/.github/.github/dependency-review-config.yml@trunk
25 |
--------------------------------------------------------------------------------
/.github/workflows/wordpress-version-checker.yml:
--------------------------------------------------------------------------------
1 | name: "WordPress version checker"
2 | on:
3 | push:
4 | branches:
5 | - develop
6 | - trunk
7 | pull_request:
8 | branches:
9 | - develop
10 | schedule:
11 | - cron: '0 0 * * 1'
12 |
13 | permissions:
14 | issues: write
15 |
16 | jobs:
17 | wordpress-version-checker:
18 | runs-on: ubuntu-latest
19 | steps:
20 | - name: WordPress version checker
21 | uses: skaut/wordpress-version-checker@master
22 | with:
23 | repo-token: ${{ secrets.GITHUB_TOKEN }}
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | node_modules
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 | php:
3 | - 7.2
4 | notifications:
5 | email: false
6 | services:
7 | - mysql
8 | env:
9 | global:
10 | - WP_VERSION=latest WP_MULTISITE=1"
11 | before_script:
12 | - composer install
13 | - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION
14 | script:
15 | - composer run-script lint
16 | - composer run-script test
17 |
--------------------------------------------------------------------------------
/.wordpress-org/banner-1544x500.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/10up/10up-sitemaps/9cb41fefa2d74d8e6cff1b210fc696489acc49db/.wordpress-org/banner-1544x500.jpg
--------------------------------------------------------------------------------
/.wordpress-org/banner-1544x500.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/10up/10up-sitemaps/9cb41fefa2d74d8e6cff1b210fc696489acc49db/.wordpress-org/banner-1544x500.png
--------------------------------------------------------------------------------
/.wordpress-org/banner-772x250.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/10up/10up-sitemaps/9cb41fefa2d74d8e6cff1b210fc696489acc49db/.wordpress-org/banner-772x250.png
--------------------------------------------------------------------------------
/.wordpress-org/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/10up/10up-sitemaps/9cb41fefa2d74d8e6cff1b210fc696489acc49db/.wordpress-org/icon-128x128.png
--------------------------------------------------------------------------------
/.wordpress-org/icon-256x256.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/10up/10up-sitemaps/9cb41fefa2d74d8e6cff1b210fc696489acc49db/.wordpress-org/icon-256x256.jpg
--------------------------------------------------------------------------------
/.wordpress-org/icon-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/10up/10up-sitemaps/9cb41fefa2d74d8e6cff1b210fc696489acc49db/.wordpress-org/icon-256x256.png
--------------------------------------------------------------------------------
/.wordpress-org/icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/10up-sitemaps.php:
--------------------------------------------------------------------------------
1 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 10up Sitemaps
2 |
3 | 
4 |
5 | [](#support-level) [](https://github.com/10up/10up-sitemaps/releases/latest)  [](https://github.com/10up/10up-sitemaps/blob/develop/LICENSE.md) [](https://github.com/10up/10up-sitemaps/actions/workflows/dependency-review.yml)
6 |
7 | > Simple sitemaps plugin that performs at scale.
8 |
9 | ## Overview
10 |
11 | This is a simple sitemap plugin meant to run at scale. Sitemaps are only updated via WP-CLI. Output is saved in an option for fast reading/displaying on the front end.
12 |
13 | ## Usage
14 |
15 | 1. Install the plugin.
16 | 2. Run the WP-CLI command: `wp tenup-sitemaps generate`
17 | 3. Add WP-CLI command to cron job. For multisite, add a command for each site in the network.
18 |
19 | You can pass `--range` to the `generate` command to only index content within a certain age range. `wp tenup-sitemaps generate --range=12` would only index content created/updated within the last 12 months.
20 |
21 | The plugin indexes all public posts, post type archives, and public taxonomy term archives. For posts, images are parsed and included. Translated content needs to be manually filtered in via `tenup_sitemaps_term_translations`.
22 |
23 | ## Support Level
24 |
25 | **Stable:** 10up is not planning to develop any new features for this, but will still respond to bug reports and security concerns. We welcome PRs, but any that include new features should be small and easy to integrate and should not include breaking changes. We otherwise intend to keep this tested up to the most recent version of WordPress.
26 |
27 | ## Changelog
28 |
29 | A complete listing of all notable changes to 10up Sitemaps is documented in [CHANGELOG.md](https://github.com/10up/10up-sitemaps/blob/develop/CHANGELOG.md).
30 |
31 | ## Contributing
32 |
33 | Please read [CODE_OF_CONDUCT.md](https://github.com/10up/10up-sitemaps/blob/develop/CODE_OF_CONDUCT.md) for details on our code of conduct, [CONTRIBUTING.md](https://github.com/10up/10up-sitemaps/blob/develop/CONTRIBUTING.md) for details on the process for submitting pull requests to us, and [CREDITS.md](https://github.com/10up/10up-sitemaps/blob/develop/CREDITS.md) for a listing of maintainers of, contributors to, and libraries used by 10up Sitemaps.
34 |
35 | ## Like what you see?
36 |
37 |
38 |
--------------------------------------------------------------------------------
/bin/install-wp-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if [ $# -lt 3 ]; then
4 | echo "usage: $0 [db-host] [wp-version] [skip-database-creation]"
5 | exit 1
6 | fi
7 |
8 | DB_NAME=$1
9 | DB_USER=$2
10 | DB_PASS=$3
11 | DB_HOST=${4-localhost}
12 | WP_VERSION=${5-latest}
13 | CREATE_DB_IF_EXISTS=${6-false}
14 |
15 | TMPDIR=${TMPDIR-/tmp}
16 | TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//")
17 | WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib}
18 | WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress/}
19 |
20 | download() {
21 | if [ `which curl` ]; then
22 | curl -s "$1" > "$2";
23 | elif [ `which wget` ]; then
24 | wget -nv -O "$2" "$1"
25 | fi
26 | }
27 |
28 | if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then
29 | WP_BRANCH=${WP_VERSION%\-*}
30 | WP_TESTS_TAG="branches/$WP_BRANCH"
31 |
32 | elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
33 | WP_TESTS_TAG="branches/$WP_VERSION"
34 | elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
35 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
36 | # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
37 | WP_TESTS_TAG="tags/${WP_VERSION%??}"
38 | else
39 | WP_TESTS_TAG="tags/$WP_VERSION"
40 | fi
41 | elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
42 | WP_TESTS_TAG="trunk"
43 | else
44 | # http serves a single offer, whereas https serves multiple. we only want one
45 | download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
46 | grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
47 | LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
48 | if [[ -z "$LATEST_VERSION" ]]; then
49 | echo "Latest WordPress version could not be found"
50 | exit 1
51 | fi
52 | WP_TESTS_TAG="tags/$LATEST_VERSION"
53 | fi
54 | set -ex
55 |
56 | install_wp() {
57 |
58 | if [ -d $WP_CORE_DIR ]; then
59 | return;
60 | fi
61 |
62 | mkdir -p $WP_CORE_DIR
63 |
64 | if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
65 | mkdir -p $TMPDIR/wordpress-nightly
66 | download https://wordpress.org/nightly-builds/wordpress-latest.zip $TMPDIR/wordpress-nightly/wordpress-nightly.zip
67 | unzip -q $TMPDIR/wordpress-nightly/wordpress-nightly.zip -d $TMPDIR/wordpress-nightly/
68 | mv $TMPDIR/wordpress-nightly/wordpress/* $WP_CORE_DIR
69 | else
70 | if [ $WP_VERSION == 'latest' ]; then
71 | local ARCHIVE_NAME='latest'
72 | elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then
73 | # https serves multiple offers, whereas http serves single.
74 | download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json
75 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
76 | # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
77 | LATEST_VERSION=${WP_VERSION%??}
78 | else
79 | # otherwise, scan the releases and get the most up to date minor version of the major release
80 | local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'`
81 | LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1)
82 | fi
83 | if [[ -z "$LATEST_VERSION" ]]; then
84 | local ARCHIVE_NAME="wordpress-$WP_VERSION"
85 | else
86 | local ARCHIVE_NAME="wordpress-$LATEST_VERSION"
87 | fi
88 | else
89 | local ARCHIVE_NAME="wordpress-$WP_VERSION"
90 | fi
91 | download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz
92 | tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR
93 | fi
94 |
95 | download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
96 | }
97 |
98 | install_test_suite() {
99 | # portable in-place argument for both GNU sed and Mac OSX sed
100 | if [[ $(uname -s) == 'Darwin' ]]; then
101 | local ioption='-i.bak'
102 | else
103 | local ioption='-i'
104 | fi
105 |
106 | # set up testing suite if it doesn't yet exist
107 | if [ ! -d $WP_TESTS_DIR ]; then
108 | # set up testing suite
109 | mkdir -p $WP_TESTS_DIR
110 | svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
111 | svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data
112 | fi
113 |
114 | if [ ! -f wp-tests-config.php ]; then
115 | download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
116 | # remove all forward slashes in the end
117 | WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::")
118 | sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
119 | sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
120 | sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
121 | sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
122 | sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
123 | fi
124 |
125 | }
126 |
127 | install_db() {
128 |
129 | # parse DB_HOST for port or socket references
130 | local PARTS=(${DB_HOST//\:/ })
131 | local DB_HOSTNAME=${PARTS[0]};
132 | local DB_SOCK_OR_PORT=${PARTS[1]};
133 | local EXTRA=""
134 |
135 | if ! [ -z $DB_HOSTNAME ] ; then
136 | if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
137 | EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
138 | elif ! [ -z $DB_SOCK_OR_PORT ] ; then
139 | EXTRA=" --socket=$DB_SOCK_OR_PORT"
140 | elif ! [ -z $DB_HOSTNAME ] ; then
141 | EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
142 | fi
143 | fi
144 |
145 | if [ ${CREATE_DB_IF_EXISTS} = "true" ]; then
146 | mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA || echo "Database already exists."
147 | else
148 | mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
149 | fi
150 | }
151 |
152 | install_wp
153 | install_test_suite
154 | install_db
155 |
156 | echo "Done!"
157 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "10up/tenup-sitemaps",
3 | "description": "10up Sitemaps",
4 | "type": "wordpress-plugin",
5 | "license": "GPL-2.0-or-later",
6 | "authors": [
7 | {
8 | "name": "Taylor Lovett",
9 | "email": "taylor.lovett@10up.com"
10 | }
11 | ],
12 | "require": {
13 | "php": ">=7.0"
14 | },
15 | "autoload": {
16 | "psr-4": {
17 | "TenupSitemaps\\": "includes/classes/"
18 | }
19 | },
20 | "require-dev": {
21 | "10up/phpcs-composer": "dev-master",
22 | "phpunit/phpunit": "^7"
23 | },
24 | "scripts": {
25 | "lint": "phpcs .",
26 | "lint-fix": "phpcbf .",
27 | "test": "phpunit",
28 | "setup-local-tests": "bash bin/install-wp-tests.sh tsm_wp_test root password mysql latest true"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "a6b77d6e4beb787c4896f2e1a831b4af",
8 | "packages": [],
9 | "packages-dev": [
10 | {
11 | "name": "10up/phpcs-composer",
12 | "version": "dev-master",
13 | "source": {
14 | "type": "git",
15 | "url": "https://github.com/10up/phpcs-composer.git",
16 | "reference": "00940fa9732fb0069d7b4624f10bb46fdf7e1a28"
17 | },
18 | "dist": {
19 | "type": "zip",
20 | "url": "https://api.github.com/repos/10up/phpcs-composer/zipball/00940fa9732fb0069d7b4624f10bb46fdf7e1a28",
21 | "reference": "00940fa9732fb0069d7b4624f10bb46fdf7e1a28",
22 | "shasum": ""
23 | },
24 | "require": {
25 | "dealerdirect/phpcodesniffer-composer-installer": "*",
26 | "phpcompatibility/phpcompatibility-wp": "^2",
27 | "squizlabs/php_codesniffer": "^3.4.0",
28 | "wp-coding-standards/wpcs": "*"
29 | },
30 | "type": "phpcodesniffer-standard",
31 | "notification-url": "https://packagist.org/downloads/",
32 | "license": [
33 | "MIT"
34 | ],
35 | "authors": [
36 | {
37 | "name": "Ephraim Gregor",
38 | "email": "ephraim.gregor@10up.com"
39 | }
40 | ],
41 | "time": "2019-03-04T14:40:41+00:00"
42 | },
43 | {
44 | "name": "dealerdirect/phpcodesniffer-composer-installer",
45 | "version": "v0.5.0",
46 | "source": {
47 | "type": "git",
48 | "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
49 | "reference": "e749410375ff6fb7a040a68878c656c2e610b132"
50 | },
51 | "dist": {
52 | "type": "zip",
53 | "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e749410375ff6fb7a040a68878c656c2e610b132",
54 | "reference": "e749410375ff6fb7a040a68878c656c2e610b132",
55 | "shasum": ""
56 | },
57 | "require": {
58 | "composer-plugin-api": "^1.0",
59 | "php": "^5.3|^7",
60 | "squizlabs/php_codesniffer": "^2|^3"
61 | },
62 | "require-dev": {
63 | "composer/composer": "*",
64 | "phpcompatibility/php-compatibility": "^9.0",
65 | "sensiolabs/security-checker": "^4.1.0"
66 | },
67 | "type": "composer-plugin",
68 | "extra": {
69 | "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
70 | },
71 | "autoload": {
72 | "psr-4": {
73 | "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
74 | }
75 | },
76 | "notification-url": "https://packagist.org/downloads/",
77 | "license": [
78 | "MIT"
79 | ],
80 | "authors": [
81 | {
82 | "name": "Franck Nijhof",
83 | "email": "franck.nijhof@dealerdirect.com",
84 | "homepage": "http://www.frenck.nl",
85 | "role": "Developer / IT Manager"
86 | }
87 | ],
88 | "description": "PHP_CodeSniffer Standards Composer Installer Plugin",
89 | "homepage": "http://www.dealerdirect.com",
90 | "keywords": [
91 | "PHPCodeSniffer",
92 | "PHP_CodeSniffer",
93 | "code quality",
94 | "codesniffer",
95 | "composer",
96 | "installer",
97 | "phpcs",
98 | "plugin",
99 | "qa",
100 | "quality",
101 | "standard",
102 | "standards",
103 | "style guide",
104 | "stylecheck",
105 | "tests"
106 | ],
107 | "time": "2018-10-26T13:21:45+00:00"
108 | },
109 | {
110 | "name": "doctrine/instantiator",
111 | "version": "1.2.0",
112 | "source": {
113 | "type": "git",
114 | "url": "https://github.com/doctrine/instantiator.git",
115 | "reference": "a2c590166b2133a4633738648b6b064edae0814a"
116 | },
117 | "dist": {
118 | "type": "zip",
119 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a",
120 | "reference": "a2c590166b2133a4633738648b6b064edae0814a",
121 | "shasum": ""
122 | },
123 | "require": {
124 | "php": "^7.1"
125 | },
126 | "require-dev": {
127 | "doctrine/coding-standard": "^6.0",
128 | "ext-pdo": "*",
129 | "ext-phar": "*",
130 | "phpbench/phpbench": "^0.13",
131 | "phpstan/phpstan-phpunit": "^0.11",
132 | "phpstan/phpstan-shim": "^0.11",
133 | "phpunit/phpunit": "^7.0"
134 | },
135 | "type": "library",
136 | "extra": {
137 | "branch-alias": {
138 | "dev-master": "1.2.x-dev"
139 | }
140 | },
141 | "autoload": {
142 | "psr-4": {
143 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
144 | }
145 | },
146 | "notification-url": "https://packagist.org/downloads/",
147 | "license": [
148 | "MIT"
149 | ],
150 | "authors": [
151 | {
152 | "name": "Marco Pivetta",
153 | "email": "ocramius@gmail.com",
154 | "homepage": "http://ocramius.github.com/"
155 | }
156 | ],
157 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
158 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
159 | "keywords": [
160 | "constructor",
161 | "instantiate"
162 | ],
163 | "time": "2019-03-17T17:37:11+00:00"
164 | },
165 | {
166 | "name": "myclabs/deep-copy",
167 | "version": "1.9.3",
168 | "source": {
169 | "type": "git",
170 | "url": "https://github.com/myclabs/DeepCopy.git",
171 | "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea"
172 | },
173 | "dist": {
174 | "type": "zip",
175 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea",
176 | "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea",
177 | "shasum": ""
178 | },
179 | "require": {
180 | "php": "^7.1"
181 | },
182 | "replace": {
183 | "myclabs/deep-copy": "self.version"
184 | },
185 | "require-dev": {
186 | "doctrine/collections": "^1.0",
187 | "doctrine/common": "^2.6",
188 | "phpunit/phpunit": "^7.1"
189 | },
190 | "type": "library",
191 | "autoload": {
192 | "psr-4": {
193 | "DeepCopy\\": "src/DeepCopy/"
194 | },
195 | "files": [
196 | "src/DeepCopy/deep_copy.php"
197 | ]
198 | },
199 | "notification-url": "https://packagist.org/downloads/",
200 | "license": [
201 | "MIT"
202 | ],
203 | "description": "Create deep copies (clones) of your objects",
204 | "keywords": [
205 | "clone",
206 | "copy",
207 | "duplicate",
208 | "object",
209 | "object graph"
210 | ],
211 | "time": "2019-08-09T12:45:53+00:00"
212 | },
213 | {
214 | "name": "phar-io/manifest",
215 | "version": "1.0.3",
216 | "source": {
217 | "type": "git",
218 | "url": "https://github.com/phar-io/manifest.git",
219 | "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4"
220 | },
221 | "dist": {
222 | "type": "zip",
223 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
224 | "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4",
225 | "shasum": ""
226 | },
227 | "require": {
228 | "ext-dom": "*",
229 | "ext-phar": "*",
230 | "phar-io/version": "^2.0",
231 | "php": "^5.6 || ^7.0"
232 | },
233 | "type": "library",
234 | "extra": {
235 | "branch-alias": {
236 | "dev-master": "1.0.x-dev"
237 | }
238 | },
239 | "autoload": {
240 | "classmap": [
241 | "src/"
242 | ]
243 | },
244 | "notification-url": "https://packagist.org/downloads/",
245 | "license": [
246 | "BSD-3-Clause"
247 | ],
248 | "authors": [
249 | {
250 | "name": "Arne Blankerts",
251 | "role": "Developer",
252 | "email": "arne@blankerts.de"
253 | },
254 | {
255 | "name": "Sebastian Heuer",
256 | "role": "Developer",
257 | "email": "sebastian@phpeople.de"
258 | },
259 | {
260 | "name": "Sebastian Bergmann",
261 | "role": "Developer",
262 | "email": "sebastian@phpunit.de"
263 | }
264 | ],
265 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
266 | "time": "2018-07-08T19:23:20+00:00"
267 | },
268 | {
269 | "name": "phar-io/version",
270 | "version": "2.0.1",
271 | "source": {
272 | "type": "git",
273 | "url": "https://github.com/phar-io/version.git",
274 | "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6"
275 | },
276 | "dist": {
277 | "type": "zip",
278 | "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6",
279 | "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6",
280 | "shasum": ""
281 | },
282 | "require": {
283 | "php": "^5.6 || ^7.0"
284 | },
285 | "type": "library",
286 | "autoload": {
287 | "classmap": [
288 | "src/"
289 | ]
290 | },
291 | "notification-url": "https://packagist.org/downloads/",
292 | "license": [
293 | "BSD-3-Clause"
294 | ],
295 | "authors": [
296 | {
297 | "name": "Arne Blankerts",
298 | "role": "Developer",
299 | "email": "arne@blankerts.de"
300 | },
301 | {
302 | "name": "Sebastian Heuer",
303 | "role": "Developer",
304 | "email": "sebastian@phpeople.de"
305 | },
306 | {
307 | "name": "Sebastian Bergmann",
308 | "role": "Developer",
309 | "email": "sebastian@phpunit.de"
310 | }
311 | ],
312 | "description": "Library for handling version information and constraints",
313 | "time": "2018-07-08T19:19:57+00:00"
314 | },
315 | {
316 | "name": "phpcompatibility/php-compatibility",
317 | "version": "9.2.0",
318 | "source": {
319 | "type": "git",
320 | "url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
321 | "reference": "3db1bf1e28123fd574a4ae2e9a84072826d51b5e"
322 | },
323 | "dist": {
324 | "type": "zip",
325 | "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/3db1bf1e28123fd574a4ae2e9a84072826d51b5e",
326 | "reference": "3db1bf1e28123fd574a4ae2e9a84072826d51b5e",
327 | "shasum": ""
328 | },
329 | "require": {
330 | "php": ">=5.3",
331 | "squizlabs/php_codesniffer": "^2.3 || ^3.0.2"
332 | },
333 | "conflict": {
334 | "squizlabs/php_codesniffer": "2.6.2"
335 | },
336 | "require-dev": {
337 | "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0"
338 | },
339 | "suggest": {
340 | "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.",
341 | "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
342 | },
343 | "type": "phpcodesniffer-standard",
344 | "notification-url": "https://packagist.org/downloads/",
345 | "license": [
346 | "LGPL-3.0-or-later"
347 | ],
348 | "authors": [
349 | {
350 | "name": "Contributors",
351 | "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors"
352 | },
353 | {
354 | "name": "Wim Godden",
355 | "role": "lead",
356 | "homepage": "https://github.com/wimg"
357 | },
358 | {
359 | "name": "Juliette Reinders Folmer",
360 | "role": "lead",
361 | "homepage": "https://github.com/jrfnl"
362 | }
363 | ],
364 | "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.",
365 | "homepage": "http://techblog.wimgodden.be/tag/codesniffer/",
366 | "keywords": [
367 | "compatibility",
368 | "phpcs",
369 | "standards"
370 | ],
371 | "time": "2019-06-27T19:58:56+00:00"
372 | },
373 | {
374 | "name": "phpcompatibility/phpcompatibility-paragonie",
375 | "version": "1.0.1",
376 | "source": {
377 | "type": "git",
378 | "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git",
379 | "reference": "9160de79fcd683b5c99e9c4133728d91529753ea"
380 | },
381 | "dist": {
382 | "type": "zip",
383 | "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/9160de79fcd683b5c99e9c4133728d91529753ea",
384 | "reference": "9160de79fcd683b5c99e9c4133728d91529753ea",
385 | "shasum": ""
386 | },
387 | "require": {
388 | "phpcompatibility/php-compatibility": "^9.0"
389 | },
390 | "require-dev": {
391 | "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4"
392 | },
393 | "suggest": {
394 | "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
395 | "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
396 | },
397 | "type": "phpcodesniffer-standard",
398 | "notification-url": "https://packagist.org/downloads/",
399 | "license": [
400 | "LGPL-3.0-or-later"
401 | ],
402 | "authors": [
403 | {
404 | "name": "Wim Godden",
405 | "role": "lead"
406 | },
407 | {
408 | "name": "Juliette Reinders Folmer",
409 | "role": "lead"
410 | }
411 | ],
412 | "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.",
413 | "homepage": "http://phpcompatibility.com/",
414 | "keywords": [
415 | "compatibility",
416 | "paragonie",
417 | "phpcs",
418 | "polyfill",
419 | "standards"
420 | ],
421 | "time": "2018-12-16T19:10:44+00:00"
422 | },
423 | {
424 | "name": "phpcompatibility/phpcompatibility-wp",
425 | "version": "2.0.0",
426 | "source": {
427 | "type": "git",
428 | "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git",
429 | "reference": "cb303f0067cd5b366a41d4fb0e254fb40ff02efd"
430 | },
431 | "dist": {
432 | "type": "zip",
433 | "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/cb303f0067cd5b366a41d4fb0e254fb40ff02efd",
434 | "reference": "cb303f0067cd5b366a41d4fb0e254fb40ff02efd",
435 | "shasum": ""
436 | },
437 | "require": {
438 | "phpcompatibility/php-compatibility": "^9.0",
439 | "phpcompatibility/phpcompatibility-paragonie": "^1.0"
440 | },
441 | "require-dev": {
442 | "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3"
443 | },
444 | "suggest": {
445 | "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
446 | "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
447 | },
448 | "type": "phpcodesniffer-standard",
449 | "notification-url": "https://packagist.org/downloads/",
450 | "license": [
451 | "LGPL-3.0-or-later"
452 | ],
453 | "authors": [
454 | {
455 | "name": "Wim Godden",
456 | "role": "lead"
457 | },
458 | {
459 | "name": "Juliette Reinders Folmer",
460 | "role": "lead"
461 | }
462 | ],
463 | "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.",
464 | "homepage": "http://phpcompatibility.com/",
465 | "keywords": [
466 | "compatibility",
467 | "phpcs",
468 | "standards",
469 | "wordpress"
470 | ],
471 | "time": "2018-10-07T18:31:37+00:00"
472 | },
473 | {
474 | "name": "phpdocumentor/reflection-common",
475 | "version": "1.0.1",
476 | "source": {
477 | "type": "git",
478 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
479 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
480 | },
481 | "dist": {
482 | "type": "zip",
483 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
484 | "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
485 | "shasum": ""
486 | },
487 | "require": {
488 | "php": ">=5.5"
489 | },
490 | "require-dev": {
491 | "phpunit/phpunit": "^4.6"
492 | },
493 | "type": "library",
494 | "extra": {
495 | "branch-alias": {
496 | "dev-master": "1.0.x-dev"
497 | }
498 | },
499 | "autoload": {
500 | "psr-4": {
501 | "phpDocumentor\\Reflection\\": [
502 | "src"
503 | ]
504 | }
505 | },
506 | "notification-url": "https://packagist.org/downloads/",
507 | "license": [
508 | "MIT"
509 | ],
510 | "authors": [
511 | {
512 | "name": "Jaap van Otterdijk",
513 | "email": "opensource@ijaap.nl"
514 | }
515 | ],
516 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
517 | "homepage": "http://www.phpdoc.org",
518 | "keywords": [
519 | "FQSEN",
520 | "phpDocumentor",
521 | "phpdoc",
522 | "reflection",
523 | "static analysis"
524 | ],
525 | "time": "2017-09-11T18:02:19+00:00"
526 | },
527 | {
528 | "name": "phpdocumentor/reflection-docblock",
529 | "version": "4.3.1",
530 | "source": {
531 | "type": "git",
532 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
533 | "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c"
534 | },
535 | "dist": {
536 | "type": "zip",
537 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c",
538 | "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c",
539 | "shasum": ""
540 | },
541 | "require": {
542 | "php": "^7.0",
543 | "phpdocumentor/reflection-common": "^1.0.0",
544 | "phpdocumentor/type-resolver": "^0.4.0",
545 | "webmozart/assert": "^1.0"
546 | },
547 | "require-dev": {
548 | "doctrine/instantiator": "~1.0.5",
549 | "mockery/mockery": "^1.0",
550 | "phpunit/phpunit": "^6.4"
551 | },
552 | "type": "library",
553 | "extra": {
554 | "branch-alias": {
555 | "dev-master": "4.x-dev"
556 | }
557 | },
558 | "autoload": {
559 | "psr-4": {
560 | "phpDocumentor\\Reflection\\": [
561 | "src/"
562 | ]
563 | }
564 | },
565 | "notification-url": "https://packagist.org/downloads/",
566 | "license": [
567 | "MIT"
568 | ],
569 | "authors": [
570 | {
571 | "name": "Mike van Riel",
572 | "email": "me@mikevanriel.com"
573 | }
574 | ],
575 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
576 | "time": "2019-04-30T17:48:53+00:00"
577 | },
578 | {
579 | "name": "phpdocumentor/type-resolver",
580 | "version": "0.4.0",
581 | "source": {
582 | "type": "git",
583 | "url": "https://github.com/phpDocumentor/TypeResolver.git",
584 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
585 | },
586 | "dist": {
587 | "type": "zip",
588 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
589 | "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
590 | "shasum": ""
591 | },
592 | "require": {
593 | "php": "^5.5 || ^7.0",
594 | "phpdocumentor/reflection-common": "^1.0"
595 | },
596 | "require-dev": {
597 | "mockery/mockery": "^0.9.4",
598 | "phpunit/phpunit": "^5.2||^4.8.24"
599 | },
600 | "type": "library",
601 | "extra": {
602 | "branch-alias": {
603 | "dev-master": "1.0.x-dev"
604 | }
605 | },
606 | "autoload": {
607 | "psr-4": {
608 | "phpDocumentor\\Reflection\\": [
609 | "src/"
610 | ]
611 | }
612 | },
613 | "notification-url": "https://packagist.org/downloads/",
614 | "license": [
615 | "MIT"
616 | ],
617 | "authors": [
618 | {
619 | "name": "Mike van Riel",
620 | "email": "me@mikevanriel.com"
621 | }
622 | ],
623 | "time": "2017-07-14T14:27:02+00:00"
624 | },
625 | {
626 | "name": "phpspec/prophecy",
627 | "version": "1.8.1",
628 | "source": {
629 | "type": "git",
630 | "url": "https://github.com/phpspec/prophecy.git",
631 | "reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76"
632 | },
633 | "dist": {
634 | "type": "zip",
635 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/1927e75f4ed19131ec9bcc3b002e07fb1173ee76",
636 | "reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76",
637 | "shasum": ""
638 | },
639 | "require": {
640 | "doctrine/instantiator": "^1.0.2",
641 | "php": "^5.3|^7.0",
642 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
643 | "sebastian/comparator": "^1.1|^2.0|^3.0",
644 | "sebastian/recursion-context": "^1.0|^2.0|^3.0"
645 | },
646 | "require-dev": {
647 | "phpspec/phpspec": "^2.5|^3.2",
648 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
649 | },
650 | "type": "library",
651 | "extra": {
652 | "branch-alias": {
653 | "dev-master": "1.8.x-dev"
654 | }
655 | },
656 | "autoload": {
657 | "psr-4": {
658 | "Prophecy\\": "src/Prophecy"
659 | }
660 | },
661 | "notification-url": "https://packagist.org/downloads/",
662 | "license": [
663 | "MIT"
664 | ],
665 | "authors": [
666 | {
667 | "name": "Konstantin Kudryashov",
668 | "email": "ever.zet@gmail.com",
669 | "homepage": "http://everzet.com"
670 | },
671 | {
672 | "name": "Marcello Duarte",
673 | "email": "marcello.duarte@gmail.com"
674 | }
675 | ],
676 | "description": "Highly opinionated mocking framework for PHP 5.3+",
677 | "homepage": "https://github.com/phpspec/prophecy",
678 | "keywords": [
679 | "Double",
680 | "Dummy",
681 | "fake",
682 | "mock",
683 | "spy",
684 | "stub"
685 | ],
686 | "time": "2019-06-13T12:50:23+00:00"
687 | },
688 | {
689 | "name": "phpunit/php-code-coverage",
690 | "version": "6.1.4",
691 | "source": {
692 | "type": "git",
693 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
694 | "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d"
695 | },
696 | "dist": {
697 | "type": "zip",
698 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d",
699 | "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d",
700 | "shasum": ""
701 | },
702 | "require": {
703 | "ext-dom": "*",
704 | "ext-xmlwriter": "*",
705 | "php": "^7.1",
706 | "phpunit/php-file-iterator": "^2.0",
707 | "phpunit/php-text-template": "^1.2.1",
708 | "phpunit/php-token-stream": "^3.0",
709 | "sebastian/code-unit-reverse-lookup": "^1.0.1",
710 | "sebastian/environment": "^3.1 || ^4.0",
711 | "sebastian/version": "^2.0.1",
712 | "theseer/tokenizer": "^1.1"
713 | },
714 | "require-dev": {
715 | "phpunit/phpunit": "^7.0"
716 | },
717 | "suggest": {
718 | "ext-xdebug": "^2.6.0"
719 | },
720 | "type": "library",
721 | "extra": {
722 | "branch-alias": {
723 | "dev-master": "6.1-dev"
724 | }
725 | },
726 | "autoload": {
727 | "classmap": [
728 | "src/"
729 | ]
730 | },
731 | "notification-url": "https://packagist.org/downloads/",
732 | "license": [
733 | "BSD-3-Clause"
734 | ],
735 | "authors": [
736 | {
737 | "name": "Sebastian Bergmann",
738 | "role": "lead",
739 | "email": "sebastian@phpunit.de"
740 | }
741 | ],
742 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
743 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
744 | "keywords": [
745 | "coverage",
746 | "testing",
747 | "xunit"
748 | ],
749 | "time": "2018-10-31T16:06:48+00:00"
750 | },
751 | {
752 | "name": "phpunit/php-file-iterator",
753 | "version": "2.0.2",
754 | "source": {
755 | "type": "git",
756 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
757 | "reference": "050bedf145a257b1ff02746c31894800e5122946"
758 | },
759 | "dist": {
760 | "type": "zip",
761 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946",
762 | "reference": "050bedf145a257b1ff02746c31894800e5122946",
763 | "shasum": ""
764 | },
765 | "require": {
766 | "php": "^7.1"
767 | },
768 | "require-dev": {
769 | "phpunit/phpunit": "^7.1"
770 | },
771 | "type": "library",
772 | "extra": {
773 | "branch-alias": {
774 | "dev-master": "2.0.x-dev"
775 | }
776 | },
777 | "autoload": {
778 | "classmap": [
779 | "src/"
780 | ]
781 | },
782 | "notification-url": "https://packagist.org/downloads/",
783 | "license": [
784 | "BSD-3-Clause"
785 | ],
786 | "authors": [
787 | {
788 | "name": "Sebastian Bergmann",
789 | "role": "lead",
790 | "email": "sebastian@phpunit.de"
791 | }
792 | ],
793 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
794 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
795 | "keywords": [
796 | "filesystem",
797 | "iterator"
798 | ],
799 | "time": "2018-09-13T20:33:42+00:00"
800 | },
801 | {
802 | "name": "phpunit/php-text-template",
803 | "version": "1.2.1",
804 | "source": {
805 | "type": "git",
806 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
807 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
808 | },
809 | "dist": {
810 | "type": "zip",
811 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
812 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
813 | "shasum": ""
814 | },
815 | "require": {
816 | "php": ">=5.3.3"
817 | },
818 | "type": "library",
819 | "autoload": {
820 | "classmap": [
821 | "src/"
822 | ]
823 | },
824 | "notification-url": "https://packagist.org/downloads/",
825 | "license": [
826 | "BSD-3-Clause"
827 | ],
828 | "authors": [
829 | {
830 | "name": "Sebastian Bergmann",
831 | "role": "lead",
832 | "email": "sebastian@phpunit.de"
833 | }
834 | ],
835 | "description": "Simple template engine.",
836 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
837 | "keywords": [
838 | "template"
839 | ],
840 | "time": "2015-06-21T13:50:34+00:00"
841 | },
842 | {
843 | "name": "phpunit/php-timer",
844 | "version": "2.1.2",
845 | "source": {
846 | "type": "git",
847 | "url": "https://github.com/sebastianbergmann/php-timer.git",
848 | "reference": "1038454804406b0b5f5f520358e78c1c2f71501e"
849 | },
850 | "dist": {
851 | "type": "zip",
852 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e",
853 | "reference": "1038454804406b0b5f5f520358e78c1c2f71501e",
854 | "shasum": ""
855 | },
856 | "require": {
857 | "php": "^7.1"
858 | },
859 | "require-dev": {
860 | "phpunit/phpunit": "^7.0"
861 | },
862 | "type": "library",
863 | "extra": {
864 | "branch-alias": {
865 | "dev-master": "2.1-dev"
866 | }
867 | },
868 | "autoload": {
869 | "classmap": [
870 | "src/"
871 | ]
872 | },
873 | "notification-url": "https://packagist.org/downloads/",
874 | "license": [
875 | "BSD-3-Clause"
876 | ],
877 | "authors": [
878 | {
879 | "name": "Sebastian Bergmann",
880 | "role": "lead",
881 | "email": "sebastian@phpunit.de"
882 | }
883 | ],
884 | "description": "Utility class for timing",
885 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
886 | "keywords": [
887 | "timer"
888 | ],
889 | "time": "2019-06-07T04:22:29+00:00"
890 | },
891 | {
892 | "name": "phpunit/php-token-stream",
893 | "version": "3.1.0",
894 | "source": {
895 | "type": "git",
896 | "url": "https://github.com/sebastianbergmann/php-token-stream.git",
897 | "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a"
898 | },
899 | "dist": {
900 | "type": "zip",
901 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e899757bb3df5ff6e95089132f32cd59aac2220a",
902 | "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a",
903 | "shasum": ""
904 | },
905 | "require": {
906 | "ext-tokenizer": "*",
907 | "php": "^7.1"
908 | },
909 | "require-dev": {
910 | "phpunit/phpunit": "^7.0"
911 | },
912 | "type": "library",
913 | "extra": {
914 | "branch-alias": {
915 | "dev-master": "3.1-dev"
916 | }
917 | },
918 | "autoload": {
919 | "classmap": [
920 | "src/"
921 | ]
922 | },
923 | "notification-url": "https://packagist.org/downloads/",
924 | "license": [
925 | "BSD-3-Clause"
926 | ],
927 | "authors": [
928 | {
929 | "name": "Sebastian Bergmann",
930 | "email": "sebastian@phpunit.de"
931 | }
932 | ],
933 | "description": "Wrapper around PHP's tokenizer extension.",
934 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
935 | "keywords": [
936 | "tokenizer"
937 | ],
938 | "time": "2019-07-25T05:29:42+00:00"
939 | },
940 | {
941 | "name": "phpunit/phpunit",
942 | "version": "7.5.15",
943 | "source": {
944 | "type": "git",
945 | "url": "https://github.com/sebastianbergmann/phpunit.git",
946 | "reference": "d79c053d972856b8b941bb233e39dc521a5093f0"
947 | },
948 | "dist": {
949 | "type": "zip",
950 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d79c053d972856b8b941bb233e39dc521a5093f0",
951 | "reference": "d79c053d972856b8b941bb233e39dc521a5093f0",
952 | "shasum": ""
953 | },
954 | "require": {
955 | "doctrine/instantiator": "^1.1",
956 | "ext-dom": "*",
957 | "ext-json": "*",
958 | "ext-libxml": "*",
959 | "ext-mbstring": "*",
960 | "ext-xml": "*",
961 | "myclabs/deep-copy": "^1.7",
962 | "phar-io/manifest": "^1.0.2",
963 | "phar-io/version": "^2.0",
964 | "php": "^7.1",
965 | "phpspec/prophecy": "^1.7",
966 | "phpunit/php-code-coverage": "^6.0.7",
967 | "phpunit/php-file-iterator": "^2.0.1",
968 | "phpunit/php-text-template": "^1.2.1",
969 | "phpunit/php-timer": "^2.1",
970 | "sebastian/comparator": "^3.0",
971 | "sebastian/diff": "^3.0",
972 | "sebastian/environment": "^4.0",
973 | "sebastian/exporter": "^3.1",
974 | "sebastian/global-state": "^2.0",
975 | "sebastian/object-enumerator": "^3.0.3",
976 | "sebastian/resource-operations": "^2.0",
977 | "sebastian/version": "^2.0.1"
978 | },
979 | "conflict": {
980 | "phpunit/phpunit-mock-objects": "*"
981 | },
982 | "require-dev": {
983 | "ext-pdo": "*"
984 | },
985 | "suggest": {
986 | "ext-soap": "*",
987 | "ext-xdebug": "*",
988 | "phpunit/php-invoker": "^2.0"
989 | },
990 | "bin": [
991 | "phpunit"
992 | ],
993 | "type": "library",
994 | "extra": {
995 | "branch-alias": {
996 | "dev-master": "7.5-dev"
997 | }
998 | },
999 | "autoload": {
1000 | "classmap": [
1001 | "src/"
1002 | ]
1003 | },
1004 | "notification-url": "https://packagist.org/downloads/",
1005 | "license": [
1006 | "BSD-3-Clause"
1007 | ],
1008 | "authors": [
1009 | {
1010 | "name": "Sebastian Bergmann",
1011 | "role": "lead",
1012 | "email": "sebastian@phpunit.de"
1013 | }
1014 | ],
1015 | "description": "The PHP Unit Testing framework.",
1016 | "homepage": "https://phpunit.de/",
1017 | "keywords": [
1018 | "phpunit",
1019 | "testing",
1020 | "xunit"
1021 | ],
1022 | "time": "2019-08-21T07:05:16+00:00"
1023 | },
1024 | {
1025 | "name": "sebastian/code-unit-reverse-lookup",
1026 | "version": "1.0.1",
1027 | "source": {
1028 | "type": "git",
1029 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
1030 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
1031 | },
1032 | "dist": {
1033 | "type": "zip",
1034 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
1035 | "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
1036 | "shasum": ""
1037 | },
1038 | "require": {
1039 | "php": "^5.6 || ^7.0"
1040 | },
1041 | "require-dev": {
1042 | "phpunit/phpunit": "^5.7 || ^6.0"
1043 | },
1044 | "type": "library",
1045 | "extra": {
1046 | "branch-alias": {
1047 | "dev-master": "1.0.x-dev"
1048 | }
1049 | },
1050 | "autoload": {
1051 | "classmap": [
1052 | "src/"
1053 | ]
1054 | },
1055 | "notification-url": "https://packagist.org/downloads/",
1056 | "license": [
1057 | "BSD-3-Clause"
1058 | ],
1059 | "authors": [
1060 | {
1061 | "name": "Sebastian Bergmann",
1062 | "email": "sebastian@phpunit.de"
1063 | }
1064 | ],
1065 | "description": "Looks up which function or method a line of code belongs to",
1066 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
1067 | "time": "2017-03-04T06:30:41+00:00"
1068 | },
1069 | {
1070 | "name": "sebastian/comparator",
1071 | "version": "3.0.2",
1072 | "source": {
1073 | "type": "git",
1074 | "url": "https://github.com/sebastianbergmann/comparator.git",
1075 | "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da"
1076 | },
1077 | "dist": {
1078 | "type": "zip",
1079 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
1080 | "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da",
1081 | "shasum": ""
1082 | },
1083 | "require": {
1084 | "php": "^7.1",
1085 | "sebastian/diff": "^3.0",
1086 | "sebastian/exporter": "^3.1"
1087 | },
1088 | "require-dev": {
1089 | "phpunit/phpunit": "^7.1"
1090 | },
1091 | "type": "library",
1092 | "extra": {
1093 | "branch-alias": {
1094 | "dev-master": "3.0-dev"
1095 | }
1096 | },
1097 | "autoload": {
1098 | "classmap": [
1099 | "src/"
1100 | ]
1101 | },
1102 | "notification-url": "https://packagist.org/downloads/",
1103 | "license": [
1104 | "BSD-3-Clause"
1105 | ],
1106 | "authors": [
1107 | {
1108 | "name": "Jeff Welch",
1109 | "email": "whatthejeff@gmail.com"
1110 | },
1111 | {
1112 | "name": "Volker Dusch",
1113 | "email": "github@wallbash.com"
1114 | },
1115 | {
1116 | "name": "Bernhard Schussek",
1117 | "email": "bschussek@2bepublished.at"
1118 | },
1119 | {
1120 | "name": "Sebastian Bergmann",
1121 | "email": "sebastian@phpunit.de"
1122 | }
1123 | ],
1124 | "description": "Provides the functionality to compare PHP values for equality",
1125 | "homepage": "https://github.com/sebastianbergmann/comparator",
1126 | "keywords": [
1127 | "comparator",
1128 | "compare",
1129 | "equality"
1130 | ],
1131 | "time": "2018-07-12T15:12:46+00:00"
1132 | },
1133 | {
1134 | "name": "sebastian/diff",
1135 | "version": "3.0.2",
1136 | "source": {
1137 | "type": "git",
1138 | "url": "https://github.com/sebastianbergmann/diff.git",
1139 | "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29"
1140 | },
1141 | "dist": {
1142 | "type": "zip",
1143 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29",
1144 | "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29",
1145 | "shasum": ""
1146 | },
1147 | "require": {
1148 | "php": "^7.1"
1149 | },
1150 | "require-dev": {
1151 | "phpunit/phpunit": "^7.5 || ^8.0",
1152 | "symfony/process": "^2 || ^3.3 || ^4"
1153 | },
1154 | "type": "library",
1155 | "extra": {
1156 | "branch-alias": {
1157 | "dev-master": "3.0-dev"
1158 | }
1159 | },
1160 | "autoload": {
1161 | "classmap": [
1162 | "src/"
1163 | ]
1164 | },
1165 | "notification-url": "https://packagist.org/downloads/",
1166 | "license": [
1167 | "BSD-3-Clause"
1168 | ],
1169 | "authors": [
1170 | {
1171 | "name": "Kore Nordmann",
1172 | "email": "mail@kore-nordmann.de"
1173 | },
1174 | {
1175 | "name": "Sebastian Bergmann",
1176 | "email": "sebastian@phpunit.de"
1177 | }
1178 | ],
1179 | "description": "Diff implementation",
1180 | "homepage": "https://github.com/sebastianbergmann/diff",
1181 | "keywords": [
1182 | "diff",
1183 | "udiff",
1184 | "unidiff",
1185 | "unified diff"
1186 | ],
1187 | "time": "2019-02-04T06:01:07+00:00"
1188 | },
1189 | {
1190 | "name": "sebastian/environment",
1191 | "version": "4.2.2",
1192 | "source": {
1193 | "type": "git",
1194 | "url": "https://github.com/sebastianbergmann/environment.git",
1195 | "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404"
1196 | },
1197 | "dist": {
1198 | "type": "zip",
1199 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/f2a2c8e1c97c11ace607a7a667d73d47c19fe404",
1200 | "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404",
1201 | "shasum": ""
1202 | },
1203 | "require": {
1204 | "php": "^7.1"
1205 | },
1206 | "require-dev": {
1207 | "phpunit/phpunit": "^7.5"
1208 | },
1209 | "suggest": {
1210 | "ext-posix": "*"
1211 | },
1212 | "type": "library",
1213 | "extra": {
1214 | "branch-alias": {
1215 | "dev-master": "4.2-dev"
1216 | }
1217 | },
1218 | "autoload": {
1219 | "classmap": [
1220 | "src/"
1221 | ]
1222 | },
1223 | "notification-url": "https://packagist.org/downloads/",
1224 | "license": [
1225 | "BSD-3-Clause"
1226 | ],
1227 | "authors": [
1228 | {
1229 | "name": "Sebastian Bergmann",
1230 | "email": "sebastian@phpunit.de"
1231 | }
1232 | ],
1233 | "description": "Provides functionality to handle HHVM/PHP environments",
1234 | "homepage": "http://www.github.com/sebastianbergmann/environment",
1235 | "keywords": [
1236 | "Xdebug",
1237 | "environment",
1238 | "hhvm"
1239 | ],
1240 | "time": "2019-05-05T09:05:15+00:00"
1241 | },
1242 | {
1243 | "name": "sebastian/exporter",
1244 | "version": "3.1.1",
1245 | "source": {
1246 | "type": "git",
1247 | "url": "https://github.com/sebastianbergmann/exporter.git",
1248 | "reference": "06a9a5947f47b3029d76118eb5c22802e5869687"
1249 | },
1250 | "dist": {
1251 | "type": "zip",
1252 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/06a9a5947f47b3029d76118eb5c22802e5869687",
1253 | "reference": "06a9a5947f47b3029d76118eb5c22802e5869687",
1254 | "shasum": ""
1255 | },
1256 | "require": {
1257 | "php": "^7.0",
1258 | "sebastian/recursion-context": "^3.0"
1259 | },
1260 | "require-dev": {
1261 | "ext-mbstring": "*",
1262 | "phpunit/phpunit": "^6.0"
1263 | },
1264 | "type": "library",
1265 | "extra": {
1266 | "branch-alias": {
1267 | "dev-master": "3.1.x-dev"
1268 | }
1269 | },
1270 | "autoload": {
1271 | "classmap": [
1272 | "src/"
1273 | ]
1274 | },
1275 | "notification-url": "https://packagist.org/downloads/",
1276 | "license": [
1277 | "BSD-3-Clause"
1278 | ],
1279 | "authors": [
1280 | {
1281 | "name": "Sebastian Bergmann",
1282 | "email": "sebastian@phpunit.de"
1283 | },
1284 | {
1285 | "name": "Jeff Welch",
1286 | "email": "whatthejeff@gmail.com"
1287 | },
1288 | {
1289 | "name": "Volker Dusch",
1290 | "email": "github@wallbash.com"
1291 | },
1292 | {
1293 | "name": "Adam Harvey",
1294 | "email": "aharvey@php.net"
1295 | },
1296 | {
1297 | "name": "Bernhard Schussek",
1298 | "email": "bschussek@gmail.com"
1299 | }
1300 | ],
1301 | "description": "Provides the functionality to export PHP variables for visualization",
1302 | "homepage": "http://www.github.com/sebastianbergmann/exporter",
1303 | "keywords": [
1304 | "export",
1305 | "exporter"
1306 | ],
1307 | "time": "2019-08-11T12:43:14+00:00"
1308 | },
1309 | {
1310 | "name": "sebastian/global-state",
1311 | "version": "2.0.0",
1312 | "source": {
1313 | "type": "git",
1314 | "url": "https://github.com/sebastianbergmann/global-state.git",
1315 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
1316 | },
1317 | "dist": {
1318 | "type": "zip",
1319 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
1320 | "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
1321 | "shasum": ""
1322 | },
1323 | "require": {
1324 | "php": "^7.0"
1325 | },
1326 | "require-dev": {
1327 | "phpunit/phpunit": "^6.0"
1328 | },
1329 | "suggest": {
1330 | "ext-uopz": "*"
1331 | },
1332 | "type": "library",
1333 | "extra": {
1334 | "branch-alias": {
1335 | "dev-master": "2.0-dev"
1336 | }
1337 | },
1338 | "autoload": {
1339 | "classmap": [
1340 | "src/"
1341 | ]
1342 | },
1343 | "notification-url": "https://packagist.org/downloads/",
1344 | "license": [
1345 | "BSD-3-Clause"
1346 | ],
1347 | "authors": [
1348 | {
1349 | "name": "Sebastian Bergmann",
1350 | "email": "sebastian@phpunit.de"
1351 | }
1352 | ],
1353 | "description": "Snapshotting of global state",
1354 | "homepage": "http://www.github.com/sebastianbergmann/global-state",
1355 | "keywords": [
1356 | "global state"
1357 | ],
1358 | "time": "2017-04-27T15:39:26+00:00"
1359 | },
1360 | {
1361 | "name": "sebastian/object-enumerator",
1362 | "version": "3.0.3",
1363 | "source": {
1364 | "type": "git",
1365 | "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1366 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
1367 | },
1368 | "dist": {
1369 | "type": "zip",
1370 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5",
1371 | "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
1372 | "shasum": ""
1373 | },
1374 | "require": {
1375 | "php": "^7.0",
1376 | "sebastian/object-reflector": "^1.1.1",
1377 | "sebastian/recursion-context": "^3.0"
1378 | },
1379 | "require-dev": {
1380 | "phpunit/phpunit": "^6.0"
1381 | },
1382 | "type": "library",
1383 | "extra": {
1384 | "branch-alias": {
1385 | "dev-master": "3.0.x-dev"
1386 | }
1387 | },
1388 | "autoload": {
1389 | "classmap": [
1390 | "src/"
1391 | ]
1392 | },
1393 | "notification-url": "https://packagist.org/downloads/",
1394 | "license": [
1395 | "BSD-3-Clause"
1396 | ],
1397 | "authors": [
1398 | {
1399 | "name": "Sebastian Bergmann",
1400 | "email": "sebastian@phpunit.de"
1401 | }
1402 | ],
1403 | "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1404 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1405 | "time": "2017-08-03T12:35:26+00:00"
1406 | },
1407 | {
1408 | "name": "sebastian/object-reflector",
1409 | "version": "1.1.1",
1410 | "source": {
1411 | "type": "git",
1412 | "url": "https://github.com/sebastianbergmann/object-reflector.git",
1413 | "reference": "773f97c67f28de00d397be301821b06708fca0be"
1414 | },
1415 | "dist": {
1416 | "type": "zip",
1417 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be",
1418 | "reference": "773f97c67f28de00d397be301821b06708fca0be",
1419 | "shasum": ""
1420 | },
1421 | "require": {
1422 | "php": "^7.0"
1423 | },
1424 | "require-dev": {
1425 | "phpunit/phpunit": "^6.0"
1426 | },
1427 | "type": "library",
1428 | "extra": {
1429 | "branch-alias": {
1430 | "dev-master": "1.1-dev"
1431 | }
1432 | },
1433 | "autoload": {
1434 | "classmap": [
1435 | "src/"
1436 | ]
1437 | },
1438 | "notification-url": "https://packagist.org/downloads/",
1439 | "license": [
1440 | "BSD-3-Clause"
1441 | ],
1442 | "authors": [
1443 | {
1444 | "name": "Sebastian Bergmann",
1445 | "email": "sebastian@phpunit.de"
1446 | }
1447 | ],
1448 | "description": "Allows reflection of object attributes, including inherited and non-public ones",
1449 | "homepage": "https://github.com/sebastianbergmann/object-reflector/",
1450 | "time": "2017-03-29T09:07:27+00:00"
1451 | },
1452 | {
1453 | "name": "sebastian/recursion-context",
1454 | "version": "3.0.0",
1455 | "source": {
1456 | "type": "git",
1457 | "url": "https://github.com/sebastianbergmann/recursion-context.git",
1458 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8"
1459 | },
1460 | "dist": {
1461 | "type": "zip",
1462 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
1463 | "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
1464 | "shasum": ""
1465 | },
1466 | "require": {
1467 | "php": "^7.0"
1468 | },
1469 | "require-dev": {
1470 | "phpunit/phpunit": "^6.0"
1471 | },
1472 | "type": "library",
1473 | "extra": {
1474 | "branch-alias": {
1475 | "dev-master": "3.0.x-dev"
1476 | }
1477 | },
1478 | "autoload": {
1479 | "classmap": [
1480 | "src/"
1481 | ]
1482 | },
1483 | "notification-url": "https://packagist.org/downloads/",
1484 | "license": [
1485 | "BSD-3-Clause"
1486 | ],
1487 | "authors": [
1488 | {
1489 | "name": "Jeff Welch",
1490 | "email": "whatthejeff@gmail.com"
1491 | },
1492 | {
1493 | "name": "Sebastian Bergmann",
1494 | "email": "sebastian@phpunit.de"
1495 | },
1496 | {
1497 | "name": "Adam Harvey",
1498 | "email": "aharvey@php.net"
1499 | }
1500 | ],
1501 | "description": "Provides functionality to recursively process PHP variables",
1502 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
1503 | "time": "2017-03-03T06:23:57+00:00"
1504 | },
1505 | {
1506 | "name": "sebastian/resource-operations",
1507 | "version": "2.0.1",
1508 | "source": {
1509 | "type": "git",
1510 | "url": "https://github.com/sebastianbergmann/resource-operations.git",
1511 | "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9"
1512 | },
1513 | "dist": {
1514 | "type": "zip",
1515 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
1516 | "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9",
1517 | "shasum": ""
1518 | },
1519 | "require": {
1520 | "php": "^7.1"
1521 | },
1522 | "type": "library",
1523 | "extra": {
1524 | "branch-alias": {
1525 | "dev-master": "2.0-dev"
1526 | }
1527 | },
1528 | "autoload": {
1529 | "classmap": [
1530 | "src/"
1531 | ]
1532 | },
1533 | "notification-url": "https://packagist.org/downloads/",
1534 | "license": [
1535 | "BSD-3-Clause"
1536 | ],
1537 | "authors": [
1538 | {
1539 | "name": "Sebastian Bergmann",
1540 | "email": "sebastian@phpunit.de"
1541 | }
1542 | ],
1543 | "description": "Provides a list of PHP built-in functions that operate on resources",
1544 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
1545 | "time": "2018-10-04T04:07:39+00:00"
1546 | },
1547 | {
1548 | "name": "sebastian/version",
1549 | "version": "2.0.1",
1550 | "source": {
1551 | "type": "git",
1552 | "url": "https://github.com/sebastianbergmann/version.git",
1553 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
1554 | },
1555 | "dist": {
1556 | "type": "zip",
1557 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
1558 | "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
1559 | "shasum": ""
1560 | },
1561 | "require": {
1562 | "php": ">=5.6"
1563 | },
1564 | "type": "library",
1565 | "extra": {
1566 | "branch-alias": {
1567 | "dev-master": "2.0.x-dev"
1568 | }
1569 | },
1570 | "autoload": {
1571 | "classmap": [
1572 | "src/"
1573 | ]
1574 | },
1575 | "notification-url": "https://packagist.org/downloads/",
1576 | "license": [
1577 | "BSD-3-Clause"
1578 | ],
1579 | "authors": [
1580 | {
1581 | "name": "Sebastian Bergmann",
1582 | "role": "lead",
1583 | "email": "sebastian@phpunit.de"
1584 | }
1585 | ],
1586 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1587 | "homepage": "https://github.com/sebastianbergmann/version",
1588 | "time": "2016-10-03T07:35:21+00:00"
1589 | },
1590 | {
1591 | "name": "squizlabs/php_codesniffer",
1592 | "version": "3.4.2",
1593 | "source": {
1594 | "type": "git",
1595 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
1596 | "reference": "b8a7362af1cc1aadb5bd36c3defc4dda2cf5f0a8"
1597 | },
1598 | "dist": {
1599 | "type": "zip",
1600 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/b8a7362af1cc1aadb5bd36c3defc4dda2cf5f0a8",
1601 | "reference": "b8a7362af1cc1aadb5bd36c3defc4dda2cf5f0a8",
1602 | "shasum": ""
1603 | },
1604 | "require": {
1605 | "ext-simplexml": "*",
1606 | "ext-tokenizer": "*",
1607 | "ext-xmlwriter": "*",
1608 | "php": ">=5.4.0"
1609 | },
1610 | "require-dev": {
1611 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
1612 | },
1613 | "bin": [
1614 | "bin/phpcs",
1615 | "bin/phpcbf"
1616 | ],
1617 | "type": "library",
1618 | "extra": {
1619 | "branch-alias": {
1620 | "dev-master": "3.x-dev"
1621 | }
1622 | },
1623 | "notification-url": "https://packagist.org/downloads/",
1624 | "license": [
1625 | "BSD-3-Clause"
1626 | ],
1627 | "authors": [
1628 | {
1629 | "name": "Greg Sherwood",
1630 | "role": "lead"
1631 | }
1632 | ],
1633 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
1634 | "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
1635 | "keywords": [
1636 | "phpcs",
1637 | "standards"
1638 | ],
1639 | "time": "2019-04-10T23:49:02+00:00"
1640 | },
1641 | {
1642 | "name": "symfony/polyfill-ctype",
1643 | "version": "v1.12.0",
1644 | "source": {
1645 | "type": "git",
1646 | "url": "https://github.com/symfony/polyfill-ctype.git",
1647 | "reference": "550ebaac289296ce228a706d0867afc34687e3f4"
1648 | },
1649 | "dist": {
1650 | "type": "zip",
1651 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4",
1652 | "reference": "550ebaac289296ce228a706d0867afc34687e3f4",
1653 | "shasum": ""
1654 | },
1655 | "require": {
1656 | "php": ">=5.3.3"
1657 | },
1658 | "suggest": {
1659 | "ext-ctype": "For best performance"
1660 | },
1661 | "type": "library",
1662 | "extra": {
1663 | "branch-alias": {
1664 | "dev-master": "1.12-dev"
1665 | }
1666 | },
1667 | "autoload": {
1668 | "psr-4": {
1669 | "Symfony\\Polyfill\\Ctype\\": ""
1670 | },
1671 | "files": [
1672 | "bootstrap.php"
1673 | ]
1674 | },
1675 | "notification-url": "https://packagist.org/downloads/",
1676 | "license": [
1677 | "MIT"
1678 | ],
1679 | "authors": [
1680 | {
1681 | "name": "Gert de Pagter",
1682 | "email": "BackEndTea@gmail.com"
1683 | },
1684 | {
1685 | "name": "Symfony Community",
1686 | "homepage": "https://symfony.com/contributors"
1687 | }
1688 | ],
1689 | "description": "Symfony polyfill for ctype functions",
1690 | "homepage": "https://symfony.com",
1691 | "keywords": [
1692 | "compatibility",
1693 | "ctype",
1694 | "polyfill",
1695 | "portable"
1696 | ],
1697 | "time": "2019-08-06T08:03:45+00:00"
1698 | },
1699 | {
1700 | "name": "theseer/tokenizer",
1701 | "version": "1.1.3",
1702 | "source": {
1703 | "type": "git",
1704 | "url": "https://github.com/theseer/tokenizer.git",
1705 | "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9"
1706 | },
1707 | "dist": {
1708 | "type": "zip",
1709 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
1710 | "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9",
1711 | "shasum": ""
1712 | },
1713 | "require": {
1714 | "ext-dom": "*",
1715 | "ext-tokenizer": "*",
1716 | "ext-xmlwriter": "*",
1717 | "php": "^7.0"
1718 | },
1719 | "type": "library",
1720 | "autoload": {
1721 | "classmap": [
1722 | "src/"
1723 | ]
1724 | },
1725 | "notification-url": "https://packagist.org/downloads/",
1726 | "license": [
1727 | "BSD-3-Clause"
1728 | ],
1729 | "authors": [
1730 | {
1731 | "name": "Arne Blankerts",
1732 | "role": "Developer",
1733 | "email": "arne@blankerts.de"
1734 | }
1735 | ],
1736 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
1737 | "time": "2019-06-13T22:48:21+00:00"
1738 | },
1739 | {
1740 | "name": "webmozart/assert",
1741 | "version": "1.4.0",
1742 | "source": {
1743 | "type": "git",
1744 | "url": "https://github.com/webmozart/assert.git",
1745 | "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9"
1746 | },
1747 | "dist": {
1748 | "type": "zip",
1749 | "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9",
1750 | "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9",
1751 | "shasum": ""
1752 | },
1753 | "require": {
1754 | "php": "^5.3.3 || ^7.0",
1755 | "symfony/polyfill-ctype": "^1.8"
1756 | },
1757 | "require-dev": {
1758 | "phpunit/phpunit": "^4.6",
1759 | "sebastian/version": "^1.0.1"
1760 | },
1761 | "type": "library",
1762 | "extra": {
1763 | "branch-alias": {
1764 | "dev-master": "1.3-dev"
1765 | }
1766 | },
1767 | "autoload": {
1768 | "psr-4": {
1769 | "Webmozart\\Assert\\": "src/"
1770 | }
1771 | },
1772 | "notification-url": "https://packagist.org/downloads/",
1773 | "license": [
1774 | "MIT"
1775 | ],
1776 | "authors": [
1777 | {
1778 | "name": "Bernhard Schussek",
1779 | "email": "bschussek@gmail.com"
1780 | }
1781 | ],
1782 | "description": "Assertions to validate method input/output with nice error messages.",
1783 | "keywords": [
1784 | "assert",
1785 | "check",
1786 | "validate"
1787 | ],
1788 | "time": "2018-12-25T11:19:39+00:00"
1789 | },
1790 | {
1791 | "name": "wp-coding-standards/wpcs",
1792 | "version": "2.1.1",
1793 | "source": {
1794 | "type": "git",
1795 | "url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
1796 | "reference": "bd9c33152115e6741e3510ff7189605b35167908"
1797 | },
1798 | "dist": {
1799 | "type": "zip",
1800 | "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/bd9c33152115e6741e3510ff7189605b35167908",
1801 | "reference": "bd9c33152115e6741e3510ff7189605b35167908",
1802 | "shasum": ""
1803 | },
1804 | "require": {
1805 | "php": ">=5.4",
1806 | "squizlabs/php_codesniffer": "^3.3.1"
1807 | },
1808 | "require-dev": {
1809 | "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
1810 | "phpcompatibility/php-compatibility": "^9.0",
1811 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
1812 | },
1813 | "suggest": {
1814 | "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
1815 | },
1816 | "type": "phpcodesniffer-standard",
1817 | "notification-url": "https://packagist.org/downloads/",
1818 | "license": [
1819 | "MIT"
1820 | ],
1821 | "authors": [
1822 | {
1823 | "name": "Contributors",
1824 | "homepage": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/graphs/contributors"
1825 | }
1826 | ],
1827 | "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
1828 | "keywords": [
1829 | "phpcs",
1830 | "standards",
1831 | "wordpress"
1832 | ],
1833 | "time": "2019-05-21T02:50:00+00:00"
1834 | }
1835 | ],
1836 | "aliases": [],
1837 | "minimum-stability": "stable",
1838 | "stability-flags": {
1839 | "10up/phpcs-composer": 20
1840 | },
1841 | "prefer-stable": false,
1842 | "prefer-lowest": false,
1843 | "platform": {
1844 | "php": ">=7.0"
1845 | },
1846 | "platform-dev": []
1847 | }
1848 |
--------------------------------------------------------------------------------
/includes/classes/Command.php:
--------------------------------------------------------------------------------
1 | [ '\WP_CLI', 'success' ],
45 | 'debug' => [ '\WP_CLI', 'debug' ],
46 | 'warning' => [ '\WP_CLI', 'warning' ],
47 | 'notice' => [ '\WP_CLI', 'line' ],
48 | ];
49 |
50 | $urls_per_page = apply_filters( 'tenup_sitemaps_urls_per_page', 200 );
51 |
52 | if ( ! array_key_exists( 'range', $assoc_args ) ) {
53 | $assoc_args['range'] = 'all';
54 | }
55 |
56 | $sitemap = new Sitemap( $assoc_args['range'], $urls_per_page, [], $logger );
57 |
58 | $sitemap->build();
59 | $sitemap->write();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/includes/classes/Sitemap.php:
--------------------------------------------------------------------------------
1 | ...,
40 | * 'debug' => ...,
41 | * 'notice' => ...,
42 | * 'warning' => ...
43 | * ]
44 | *
45 | * @var array
46 | * @since 1.2
47 | */
48 | private $logger;
49 |
50 | /**
51 | * URLs to include in each sitemap page
52 | *
53 | * @var int
54 | * @since 1.2
55 | */
56 | private $urls_per_page;
57 |
58 | /**
59 | * URLs to process in each DB cycle
60 | *
61 | * @var int
62 | * @since 1.2
63 | */
64 | private $process_page_size = 500;
65 |
66 | /**
67 | * Create a new empty sitemap
68 | *
69 | * @param string $range Range of content
70 | * @param integer $urls_per_page URLs per sitemap page
71 | * @param array $urls Preexisting URLs to use
72 | * @param array $logger Logged to use
73 | * @since 1.2
74 | */
75 | public function __construct( $range = 'all', $urls_per_page = 200, $urls = [], $logger = null ) {
76 | if ( ! empty( $range ) && 'all' !== $range ) {
77 | $this->range = date( 'Y-m-d H:i:s', strtotime( '-' . (int) $range . ' month' ) );
78 | } else {
79 | $this->range = '0000-00-00 00:00:00';
80 | }
81 |
82 | $this->urls = $urls;
83 | $this->logger = $logger;
84 | $this->urls_per_page = $urls_per_page;
85 | }
86 |
87 | /**
88 | * Log a message
89 | *
90 | * @param string $message Message to log
91 | * @param string $type Type of message
92 | * @since 1.2
93 | */
94 | public function log( $message, $type = 'notice' ) {
95 | if ( ! empty( $this->logger ) && ! empty( $this->logger[ $type ] ) ) {
96 | call_user_func( $this->logger[ $type ], $message );
97 | }
98 | }
99 |
100 | /**
101 | * Build entire sitemap
102 | *
103 | * @since 1.2
104 | */
105 | public function build() {
106 | $this->build_homepage();
107 |
108 | if ( apply_filters( 'tenup_sitemaps_index_post_types', true ) ) {
109 | $this->build_post_types();
110 | }
111 |
112 | if ( apply_filters( 'tenup_sitemaps_index_terms', true ) ) {
113 | $this->build_terms();
114 | }
115 |
116 | if ( apply_filters( 'tenup_sitemaps_index_authors', false ) ) {
117 | $this->build_authors();
118 | }
119 | }
120 |
121 | /**
122 | * Add post types to URLs
123 | *
124 | * @since 1.2
125 | */
126 | public function build_post_types() {
127 | global $wpdb;
128 |
129 | $args = [
130 | 'public' => true,
131 | ];
132 |
133 | $post_types = get_post_types( $args );
134 |
135 | if ( ! empty( $post_types['attachment'] ) ) {
136 | unset( $post_types['attachment'] );
137 | }
138 |
139 | $post_types = apply_filters( 'tenup_sitemaps_post_types', $post_types );
140 |
141 | foreach ( $post_types as $post_type ) {
142 | $offset = 0;
143 |
144 | $post_type_archive_url = [
145 | 'url' => get_post_type_archive_link( $post_type ),
146 | 'modified' => time(),
147 | ];
148 |
149 | $post_type_archive_url = apply_filters( 'tenup_sitemaps_index_post_type_archive', $post_type_archive_url, $post_type );
150 |
151 | if ( ! empty( $post_type_archive_url ) ) {
152 | $urls[] = $post_type_archive_url;
153 | }
154 |
155 | while ( true ) {
156 | $this->log( 'Processing post type `' . $post_type . '` from offset ' . $offset, 'debug' );
157 |
158 | // phpcs:disable
159 | $results = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_title, post_date_gmt, post_content FROM {$wpdb->prefix}posts WHERE post_status = 'publish' AND post_type = '%s' AND post_date_gmt >= '%s' ORDER BY post_date_gmt DESC LIMIT %d, %d", $post_type, $this->range, (int) $offset, (int) $this->process_page_size ), ARRAY_A );
160 | // phpcs:enable
161 |
162 | if ( empty( $results ) ) {
163 | break;
164 | }
165 |
166 | foreach ( $results as $result ) {
167 | $permalink = get_permalink( $result['ID'] );
168 |
169 | $url = [
170 | 'ID' => (int) $result['ID'],
171 | 'url' => $permalink,
172 | 'modified' => strtotime( $result['post_date_gmt'] ),
173 | ];
174 |
175 | if ( apply_filters( 'tenup_sitemaps_index_images', true, $result['ID'] ) ) {
176 | $images = [];
177 |
178 | $thumbnail_id = get_post_thumbnail_id( $result['ID'] );
179 |
180 | if ( $thumbnail_id ) {
181 | $images[] = Utils\prepare_sitemap_image( $thumbnail_id );
182 | }
183 |
184 | $images = array_merge( $images, Utils\parse_html_images( $result['post_content'] ) );
185 |
186 | $gallery_images = Utils\parse_galleries( $result['post_content'], $result['ID'] );
187 |
188 | foreach ( $gallery_images as $image_id ) {
189 | $images[] = Utils\prepare_sitemap_image( $image_id );
190 | }
191 |
192 | if ( ! empty( $images ) ) {
193 | // Make sure unique
194 | $image_urls = [];
195 |
196 | foreach ( $images as $key => $image ) {
197 | if ( empty( $image['url'] ) || ! empty( $image_urls[ $image['url'] ] ) ) {
198 | unset( $images[ $key ] );
199 | }
200 |
201 | $image_urls[ $image['url'] ] = true;
202 | }
203 |
204 | $url['images'] = array_values( $images );
205 | }
206 | }
207 |
208 | /**
209 | * Should return an array like so:
210 | *
211 | * [
212 | * 'sp' => 'spanish link',
213 | * 'fr' => 'french link,'
214 | * ]
215 | */
216 | $translations = apply_filters( 'tenup_sitemaps_post_translations', [], $result['ID'], $post_type );
217 |
218 | if ( ! empty( $translations ) ) {
219 | $url['translations'] = $translations;
220 | }
221 |
222 | $url = apply_filters( 'tenup_sitemaps_index_post', $url, $result['ID'], $post_type );
223 |
224 | if ( ! empty( $url ) && ! empty( $url['url'] ) ) {
225 | $this->urls[] = $url;
226 |
227 | $this->log(
228 | sprintf(
229 | '%s (%d) added to page %d.',
230 | $permalink,
231 | count( $this->urls ),
232 | ceil( count( $this->urls ) / $this->urls_per_page )
233 | ),
234 | 'notice'
235 | );
236 | } else {
237 | $this->log(
238 | sprintf(
239 | 'Could not add %s.',
240 | $permalink
241 | ),
242 | 'warning'
243 | );
244 | }
245 |
246 | $this->stop_the_insanity();
247 | }
248 |
249 | $offset += $this->process_page_size;
250 | }
251 | }
252 | }
253 |
254 | /**
255 | * Add terms to URLs
256 | *
257 | * @since 1.2
258 | */
259 | public function build_terms() {
260 | global $wpdb;
261 |
262 | $args = [
263 | 'public' => true,
264 | ];
265 |
266 | $taxonomies = get_taxonomies( $args );
267 |
268 | $taxonomies = apply_filters( 'tenup_sitemaps_taxonomies', $taxonomies );
269 |
270 | foreach ( $taxonomies as $taxonomy ) {
271 | $offset = 0;
272 |
273 | while ( true ) {
274 | $this->log( 'Processing taxonomy `' . $taxonomy . '` from offset ' . $offset, 'debug' );
275 |
276 | // phpcs:disable
277 | $results = $wpdb->get_results( $wpdb->prepare( "SELECT term_taxonomy.term_id as term_id, name, slug FROM {$wpdb->prefix}term_taxonomy as term_taxonomy, {$wpdb->prefix}terms as terms WHERE term_taxonomy.term_id = terms.term_id AND term_taxonomy.taxonomy = '%s' AND term_taxonomy.count > 0 ORDER BY term_taxonomy.term_id DESC LIMIT %d, %d", $taxonomy, (int) $offset, (int) $this->process_page_size ), ARRAY_A );
278 | // phpcs:enable
279 |
280 | if ( empty( $results ) ) {
281 | break;
282 | }
283 |
284 | foreach ( $results as $result ) {
285 | $permalink = get_term_link( (int) $result['term_id'] );
286 |
287 | $url = [
288 | 'ID' => (int) $result['term_id'],
289 | 'url' => $permalink,
290 | 'modified' => time(),
291 | ];
292 |
293 | /**
294 | * Should return an array like so:
295 | *
296 | * [
297 | * 'sp' => 'spanish link',
298 | * 'fr' => 'french link,'
299 | * ]
300 | */
301 | $translations = apply_filters( 'tenup_sitemaps_term_translations', [], $result['term_id'], $taxonomy );
302 |
303 | if ( ! empty( $translations ) ) {
304 | $url['translations'] = $translations;
305 | }
306 |
307 | $url = apply_filters( 'tenup_sitemaps_index_term', $url, $result['term_id'], $taxonomy );
308 |
309 | if ( ! empty( $url ) && ! empty( $url['url'] ) ) {
310 | $this->urls[] = $url;
311 |
312 | $this->log(
313 | sprintf(
314 | '%s (%d) added to page %d.',
315 | $permalink,
316 | count( $this->urls ),
317 | ceil( count( $this->urls ) / $this->urls_per_page )
318 | ),
319 | 'notice'
320 | );
321 | } else {
322 | $this->log(
323 | sprintf(
324 | 'Could not add %s.',
325 | $permalink
326 | ),
327 | 'warning'
328 | );
329 | }
330 |
331 | $this->stop_the_insanity();
332 | }
333 |
334 | $offset += $this->process_page_size;
335 | }
336 | }
337 | }
338 |
339 | /**
340 | * Add authors to urls
341 | *
342 | * @since 1.2
343 | */
344 | public function build_authors() {
345 | global $wpdb;
346 |
347 | $offset = 0;
348 |
349 | $roles = [
350 | 'administrator',
351 | 'editor',
352 | 'author',
353 | ];
354 |
355 | $roles = apply_filters( 'tenup_sitemaps_user_roles', $roles );
356 |
357 | if ( empty( $roles ) ) {
358 | return;
359 | }
360 |
361 | $roles_like = '';
362 |
363 | foreach ( $roles as $role ) {
364 | if ( ! empty( $roles_like ) ) {
365 | $roles_like .= ' OR ';
366 | }
367 |
368 | $roles_like .= "usermeta.meta_value LIKE '%%\"" . esc_sql( $role ) . "\"%%'";
369 | }
370 |
371 | $roles_like = '(' . $roles_like . ')';
372 |
373 | $capability_col = $wpdb->prefix . 'capabilities';
374 |
375 | if ( is_multisite() && 1 < (int) get_current_blog_id() ) {
376 | $capability_col = $wpdb->prefix . get_current_blog_id() . '_capabilities';
377 | }
378 |
379 | while ( true ) {
380 | // phpcs:disable
381 | $results = $wpdb->get_results( sprintf( "SELECT * FROM {$wpdb->prefix}users as users, {$wpdb->prefix}usermeta as usermeta WHERE users.ID = usermeta.user_id AND usermeta.meta_key = '{$capability_col}' AND {$roles_like} ORDER BY user_login ASC LIMIT %d, %d", (int) $offset, (int) $this->process_page_size ), ARRAY_A );
382 | // phpcs:enable
383 |
384 | if ( empty( $results ) ) {
385 | break;
386 | }
387 |
388 | foreach ( $results as $result ) {
389 | $permalink = get_author_posts_url( (int) $result['term_id'] );
390 |
391 | $url = [
392 | 'ID' => (int) $result['ID'],
393 | 'url' => $permalink,
394 | 'modified' => time(),
395 | ];
396 |
397 | $url = apply_filters( 'tenup_sitemaps_index_author', $url, $result['ID'] );
398 |
399 | if ( ! empty( $url ) && ! empty( $url['url'] ) ) {
400 | $this->urls[] = $url;
401 |
402 | $this->log(
403 | sprintf(
404 | '%s (%d) added to page %d.',
405 | $permalink,
406 | count( $this->urls ),
407 | ceil( count( $this->urls ) / $this->urls_per_page )
408 | ),
409 | 'notice'
410 | );
411 | } else {
412 | $this->log(
413 | sprintf(
414 | 'Could not add %s.',
415 | $permalink
416 | ),
417 | 'warning'
418 | );
419 | }
420 |
421 | $this->stop_the_insanity();
422 | }
423 |
424 | $offset += $this->process_page_size;
425 | }
426 | }
427 |
428 | /**
429 | * Add homepage url
430 | *
431 | * @since 1.2
432 | */
433 | public function build_homepage() {
434 | $homepage_url = [
435 | 'url' => home_url(),
436 | 'modified' => time(),
437 | ];
438 |
439 | $homepage_url = apply_filters( 'tenup_sitemaps_index_homepage', $homepage_url );
440 |
441 | if ( ! empty( $homepage_url ) ) {
442 | $this->urls[] = $homepage_url;
443 | }
444 | }
445 |
446 | /**
447 | * Write sitemap to options
448 | *
449 | * @since 1.2
450 | */
451 | public function write() {
452 | $total_pages = ceil( count( $this->urls ) / $this->urls_per_page );
453 |
454 | update_option( 'tenup_sitemaps_total_pages', (int) $total_pages, false );
455 |
456 | for ( $i = 1; $i <= $total_pages; $i++ ) {
457 | $data = array_slice( $this->urls, ( ( $i - 1 ) * $this->urls_per_page ), $this->urls_per_page );
458 |
459 | // phpcs:disable
460 | $this->log( 'Saving sitemap page ' . $i . '. Total option size is ~' . round( strlen( serialize( $data ) ) / 1024 ) . ' kilobytes.', 'debug' );
461 | // phpcs:enable
462 |
463 | update_option( 'tenup_sitemaps_page_' . $i, $data, false );
464 | }
465 |
466 | $this->log( 'Sitemap generated. ' . count( $this->urls ) . ' urls included. ' . $total_pages . ' pages created.', 'success' );
467 | }
468 |
469 | /**
470 | * Get urls
471 | *
472 | * @since 1.2
473 | * @return array
474 | */
475 | public function get_urls() {
476 | return $this->urls;
477 | }
478 |
479 | /**
480 | * Get urls per page
481 | *
482 | * @since 1.2
483 | * @return int
484 | */
485 | public function get_urls_per_page() {
486 | return $this->urls_per_page;
487 | }
488 |
489 | /**
490 | * Get range
491 | *
492 | * @since 1.2
493 | * @return string
494 | */
495 | public function get_range() {
496 | return $this->range;
497 | }
498 |
499 | /**
500 | * Get logger
501 | *
502 | * @since 1.2
503 | * @return array
504 | */
505 | public function get_logger() {
506 | return $this->logger;
507 | }
508 |
509 |
510 | /**
511 | * Clear all of the caches for memory management
512 | *
513 | * @since 1.2
514 | */
515 | private function stop_the_insanity() {
516 | global $wpdb, $wp_object_cache;
517 |
518 | $one_hundred_mb = 104857600;
519 | if ( memory_get_usage() <= $one_hundred_mb ) {
520 | return;
521 | }
522 |
523 | $wpdb->queries = array();
524 |
525 | if ( is_object( $wp_object_cache ) ) {
526 | $wp_object_cache->group_ops = array();
527 | $wp_object_cache->stats = array();
528 | $wp_object_cache->memcache_debug = array();
529 | $wp_object_cache->cache = array();
530 |
531 | if ( method_exists( $wp_object_cache, '__remoteset' ) ) {
532 | $wp_object_cache->__remoteset(); // important
533 | }
534 | }
535 |
536 | gc_collect_cycles();
537 | }
538 | }
539 |
--------------------------------------------------------------------------------
/includes/core.php:
--------------------------------------------------------------------------------
1 | set_404();
35 | status_header( 404 );
36 | }
37 | }
38 |
39 | /**
40 | * Render sitemap
41 | *
42 | * @param string $template Template file to use
43 | * @return string
44 | */
45 | function load_sitemap_template( $template ) {
46 |
47 | if ( 'true' === get_query_var( 'sitemap' ) ) {
48 | if ( ! Utils\sitemap_setup() ) {
49 | return $template;
50 | }
51 |
52 | if ( ! empty( get_query_var( 'sitemap-page' ) ) ) {
53 | $template = __DIR__ . '/templates/sitemap-page.php';
54 | } else {
55 | $template = __DIR__ . '/templates/sitemap-root.php';
56 | }
57 | }
58 |
59 | return $template;
60 | }
61 |
62 | /**
63 | * Add rewrite rules/tags
64 | */
65 | function create_rewrites() {
66 | add_rewrite_tag( '%sitemap%', 'true' );
67 |
68 | add_rewrite_tag( '%sitemap-page%', '[0-9]+' );
69 | add_rewrite_rule( '^sitemap.xml$', 'index.php?sitemap=true', 'top' );
70 | add_rewrite_rule( '^sitemap-page-([0-9]+).xml$', 'index.php?sitemap=true&sitemap-page=$matches[1]', 'top' );
71 | add_action( 'redirect_canonical', __NAMESPACE__ . '\disable_canonical_redirects_for_sitemap_xml', 10, 2 );
72 | }
73 |
74 | /**
75 | * Disable Main Query when rendering sitemaps
76 | *
77 | * @param array|null $posts array of post data or null
78 | * @param \WP_Query $query The WP_Query instance.
79 | * @return array
80 | */
81 | function disable_main_query_for_sitemap_xml( $posts, $query ) {
82 |
83 | if ( $query->is_main_query() && ! empty( $query->query_vars['sitemap'] ) ) {
84 | if ( Utils\sitemap_setup() ) {
85 | $posts = [];
86 | }
87 | }
88 |
89 | return $posts;
90 | }
91 |
92 | /**
93 | * Disable canonical redirects for the sitemap files
94 | *
95 | * @param string $redirect_url URL to redirect to
96 | * @param string $requested_url Originally requested url
97 | * @return string URL to redirect
98 | */
99 | function disable_canonical_redirects_for_sitemap_xml( $redirect_url, $requested_url ) {
100 | if ( preg_match( '/sitemap(\-page\-[0-9]+)?\.xml/i', $requested_url ) ) {
101 | return $requested_url;
102 | }
103 |
104 | return $redirect_url;
105 | }
106 |
107 | /**
108 | * Add the sitemap URL to robots.txt
109 | *
110 | * @param string $output Robots.txt output.
111 | * @return string
112 | */
113 | function add_sitemap_robots_txt( $output ) {
114 | $url = site_url( '/sitemap.xml' );
115 | $output .= "\nSitemap: {$url}\n";
116 | return $output;
117 | }
118 |
--------------------------------------------------------------------------------
/includes/templates/sitemap-page.php:
--------------------------------------------------------------------------------
1 | ';
11 |
12 | $sitemap_page = get_query_var( 'sitemap-page' );
13 |
14 | $links = apply_filters( 'tenup_sitemaps_page_links', get_option( 'tenup_sitemaps_page_' . $sitemap_page ), $sitemap_page );
15 |
16 | if ( empty( $links ) ) {
17 | $links = [];
18 | }
19 | ?>
20 |
21 |
22 |
23 |
28 |
29 |
30 |
31 |
32 |
33 | $translated_url ) : ?>
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/includes/templates/sitemap-root.php:
--------------------------------------------------------------------------------
1 | ';
11 |
12 | $total_pages = get_option( 'tenup_sitemaps_total_pages', 0 );
13 | ?>
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/includes/utils.php:
--------------------------------------------------------------------------------
1 | $id,
56 | 'url' => $src,
57 | 'alt' => prepare_valid_xml( $alt ),
58 | 'title' => prepare_valid_xml( $title ),
59 | ];
60 | }
61 |
62 | /**
63 | * Get attached image URL with filters applied. Adapted from core for speed.
64 | *
65 | * @param int $post_id ID of the post.
66 | * @return string
67 | */
68 | function get_image_url( $post_id ) {
69 | static $uploads;
70 |
71 | if ( empty( $uploads ) ) {
72 | $uploads = wp_upload_dir();
73 | }
74 |
75 | if ( false !== $uploads['error'] ) {
76 | return '';
77 | }
78 |
79 | $file = get_post_meta( $post_id, '_wp_attached_file', true );
80 |
81 | if ( empty( $file ) ) {
82 | return '';
83 | }
84 |
85 | // Check that the upload base exists in the file location.
86 | if ( 0 === strpos( $file, $uploads['basedir'] ) ) {
87 | $src = str_replace( $uploads['basedir'], $uploads['baseurl'], $file );
88 | } elseif ( false !== strpos( $file, 'wp-content/uploads' ) ) {
89 | $src = $uploads['baseurl'] . substr( $file, ( strpos( $file, 'wp-content/uploads' ) + 18 ) );
90 | } else {
91 | // It's a newly uploaded file, therefore $file is relative to the baseurl.
92 | $src = $uploads['baseurl'] . '/' . $file;
93 | }
94 |
95 | return apply_filters( 'wp_get_attachment_url', $src, $post_id );
96 | }
97 |
98 | /**
99 | * Parse `
` tags in content.
100 | *
101 | * @param string $content Content string to parse.
102 | *
103 | * @return array
104 | */
105 | function parse_html_images( $content ) {
106 | $images = [];
107 |
108 | if ( empty( $content ) ) {
109 | return $images;
110 | }
111 |
112 | // Prevent DOMDocument from bubbling warnings about invalid HTML.
113 | libxml_use_internal_errors( true );
114 |
115 | $post_dom = new \DOMDocument();
116 | $post_dom->loadHTML( '' . $content );
117 |
118 | // Clear the errors, so they don't get kept in memory.
119 | libxml_clear_errors();
120 |
121 | foreach ( $post_dom->getElementsByTagName( 'img' ) as $img ) {
122 | $src = $img->getAttribute( 'src' );
123 |
124 | if ( empty( $src ) ) {
125 | continue;
126 | }
127 |
128 | $class = $img->getAttribute( 'class' );
129 |
130 | if (
131 | ! empty( $class )
132 | && false === strpos( $class, 'size-full' )
133 | && preg_match( '|wp-image-(?P\d+)|', $class, $matches )
134 | && get_post_status( $matches['id'] )
135 | ) {
136 | $images[] = prepare_sitemap_image( $matches['id'] );
137 | continue;
138 | }
139 |
140 | $src = get_absolute_url( $src );
141 |
142 | if ( false === strpos( $src, str_replace( 'www.', '', wp_parse_url( home_url(), PHP_URL_HOST ) ) ) ) {
143 | continue;
144 | }
145 |
146 | $images[] = array(
147 | 'url' => $src,
148 | 'title' => $img->getAttribute( 'title' ),
149 | 'alt' => $img->getAttribute( 'alt' ),
150 | );
151 | }
152 |
153 | return $images;
154 | }
155 |
156 | /**
157 | * Retrieves galleries from the passed content.
158 | *
159 | * Forked from core to skip executing shortcodes for performance.
160 | *
161 | * @param string $content Content to parse for shortcodes.
162 | * @return array A list of arrays, each containing gallery data.
163 | */
164 | function get_content_galleries( $content ) {
165 | if ( ! has_shortcode( $content, 'gallery' ) ) {
166 | return array();
167 | }
168 |
169 | $galleries = array();
170 |
171 | if ( ! preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER ) ) {
172 | return $galleries;
173 | }
174 |
175 | foreach ( $matches as $shortcode ) {
176 | if ( 'gallery' === $shortcode[2] ) {
177 | $attributes = shortcode_parse_atts( $shortcode[3] );
178 |
179 | if ( '' === $attributes ) {
180 | $attributes = array();
181 | }
182 |
183 | $galleries[] = $attributes;
184 | }
185 | }
186 |
187 | return $galleries;
188 | }
189 |
190 | /**
191 | * Parse gallery shortcodes in a given content.
192 | *
193 | * @param string $content Content string.
194 | * @param int $post_id ID of post being parsed.
195 | *
196 | * @return array Set of attachment objects.
197 | */
198 | function parse_galleries( $content, $post_id ) {
199 | $attachments = array();
200 | $galleries = get_content_galleries( $content );
201 |
202 | foreach ( $galleries as $gallery ) {
203 | $id = $post_id;
204 |
205 | if ( ! empty( $gallery['id'] ) ) {
206 | $id = intval( $gallery['id'] );
207 | }
208 |
209 | // Forked from core gallery_shortcode() to have exact same logic.
210 | if ( ! empty( $gallery['ids'] ) ) {
211 | $gallery['include'] = $gallery['ids'];
212 | }
213 |
214 | $gallery_attachments = get_gallery_attachments( $id, $gallery );
215 |
216 | $attachments = array_merge( $attachments, $gallery_attachments );
217 | }
218 |
219 | return array_unique( $attachments );
220 | }
221 |
222 | /**
223 |
224 |
225 | /**
226 | * Returns the attachments for a gallery.
227 | *
228 | * @param int $id The post ID.
229 | * @param array $gallery The gallery config.
230 | *
231 | * @return array The selected attachments.
232 | */
233 | function get_gallery_attachments( $id, $gallery ) {
234 | // When there are attachments to include.
235 | if ( ! empty( $gallery['include'] ) ) {
236 | return wp_parse_id_list( $gallery['include'] );
237 | }
238 |
239 | return get_gallery_attachments_for_parent( $id, $gallery );
240 | }
241 |
242 | /**
243 | * Returns the attachments for the given ID.
244 | *
245 | * @param int $id The post ID.
246 | * @param array $gallery The gallery config.
247 | *
248 | * @return array The selected attachments.
249 | */
250 | function get_gallery_attachments_for_parent( $id, $gallery ) {
251 | $query = array(
252 | 'post_parent' => $id,
253 | );
254 |
255 | // When there are posts that should be excluded from result set.
256 | if ( ! empty( $gallery['exclude'] ) ) {
257 | $query['post__not_in'] = wp_parse_id_list( $gallery['exclude'] );
258 | }
259 |
260 | return get_attachments( $query );
261 | }
262 |
263 | /**
264 | * Returns the attachments.
265 | *
266 | * @param array $args Array with query args.
267 | *
268 | * @return array The found attachments.
269 | */
270 | function get_attachments( $args ) {
271 | $default_args = array(
272 | 'post_status' => 'inherit',
273 | 'post_type' => 'attachment',
274 | 'post_mime_type' => 'image',
275 | 'orderby' => 'date',
276 | 'order' => 'DESC',
277 | 'ignore_sticky_posts' => true,
278 | 'no_found_rows' => true,
279 | 'fields' => 'ids',
280 | 'cache_results' => false,
281 | 'update_post_meta_cache' => false,
282 | 'update_post_term_cache' => false,
283 | );
284 |
285 | $args = wp_parse_args( $args, $default_args );
286 |
287 | $get_attachments = new \WP_Query( $args );
288 |
289 | return $get_attachments->posts;
290 | }
291 |
292 | /**
293 | * Check if a url is relative
294 | *
295 | * @param string $url Url to check
296 | * @return boolean
297 | */
298 | function is_url_relative( $url ) {
299 | return ( strpos( $url, 'http' ) !== 0 && strpos( $url, '//' ) !== 0 );
300 | }
301 |
302 | /**
303 | * Make absolute URL for domain or protocol-relative one.
304 | *
305 | * @param string $src URL to process.
306 | *
307 | * @return string
308 | */
309 | function get_absolute_url( $src ) {
310 | if ( empty( $src ) || ! is_string( $src ) ) {
311 | return $src;
312 | }
313 |
314 | if ( is_url_relative( $src ) === true ) {
315 | if ( '/' !== $src[0] ) {
316 | return $src;
317 | }
318 | // The URL is relative, we'll have to make it absolute.
319 | return home_url() . $src;
320 | }
321 |
322 | if ( 0 !== strpos( $src, 'http' ) ) {
323 | // Protocol relative URL, we add the scheme as the standard requires a protocol.
324 | return wp_parse_url( home_url(), PHP_URL_SCHEME ) . ':' . $src;
325 | }
326 |
327 | return $src;
328 | }
329 |
--------------------------------------------------------------------------------
/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 10up PHPCS extended.
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | ./tests/
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === 10up Sitemaps ===
2 | Contributors: 10up, tlovett1, jeffpaul
3 | Tags: sitemap, wp-cli, cli
4 | Tested up to: 6.7
5 | Stable tag: 1.0.4
6 | License: GPL-2.0-or-later
7 | License URI: https://spdx.org/licenses/GPL-2.0-or-later.html
8 |
9 | Simple sitemaps plugin that performs at scale.
10 |
11 | == Description ==
12 |
13 | This is a simple sitemap plugin meant to run at scale. Sitemaps are only updated via WP-CLI. Output is saved in an option for fast reading/displaying on the front end.
14 |
15 | == Setup/Usage ==
16 |
17 | 1. Install the plugin.
18 | 2. Run the WP-CLI command: `wp tenup-sitemaps generate`
19 | 3. Add WP-CLI command to cron job. For multisite, add a command for each site in the network.
20 |
21 | You can pass `--range` to the `generate` command to only index content within a certain age range. `wp tenup-sitemaps generate --range=12` would only index content created/updated within the last 12 months.
22 |
23 | The plugin indexes all public posts, post type archives, and public taxonomy term archives. For posts, images are parsed and included. Translated content needs to be manually filtered in via `tenup_sitemaps_term_translations`.
24 |
25 | == Changelog ==
26 |
27 | = 1.0.4 - 2023-09-07 =
28 | * **Fixed:** Prefix sitemap index in `robots.txt` with line feed.
29 |
30 | = 1.0.3 - 2019-08-12 =
31 | * **Fixed:** No empty urls in sitemap.
32 |
33 | = 1.0.2 - 2019-08-05 =
34 | * **Added:** WordPress Plugin type.
35 |
36 | = 1.0.1 - 2019-08-05 =
37 | * **Changed:** Package name.
38 | * **Fixed:** Log url properly.
39 |
40 | = 1.0.0 - 2019-08-01 =
41 | * **Added:** Homepage and post type archive.
42 | * **Added:** Progress estimator.
43 | * **Added:** `stop_the_insanity()` calls.
44 | * **Added:** `robots_txt` filter to include the `sitemap.xml` file.
45 | * **Added:** Page link filter.
46 | * **Removed:** `changefrew` and `priority` from template.
47 |
48 | = 0.1.0 - 2019-06-26 =
49 | * **Added:** Initial plugin release! 🎉
50 | * **Added:** Sitemaps are only updated via WP-CLI.
51 | * **Added:** Output is saved in an option for fast reading/displaying on the front end.
52 |
--------------------------------------------------------------------------------
/tests/TestSitemap.php:
--------------------------------------------------------------------------------
1 | set_permalink_structure('/%postname%/');
22 |
23 | update_option( "rewrite_rules", true );
24 |
25 | $wp_rewrite->flush_rules( true );
26 | }
27 |
28 | /**
29 | * Test setting up the sitemap class
30 | *
31 | * @since 1.2
32 | */
33 | public function testConstruct() {
34 | $logger = [
35 | 'success' => 'success',
36 | 'debug' => 'debug',
37 | 'warning' => 'warning',
38 | 'notice' => 'line',
39 | ];
40 |
41 | $sitemap = new Sitemap( 6, 50, [ 'test' ], $logger );
42 |
43 | $this->assertEquals( date( 'Y-m-d', strtotime( '-6 month' ) ), date( 'Y-m-d', strtotime( $sitemap->get_range() ) ) );
44 | $this->assertEquals( 50, $sitemap->get_urls_per_page() );
45 | $this->assertEquals( [ 'test' ], $sitemap->get_urls() );
46 | $this->assertEquals( $logger, $sitemap->get_logger() );
47 | }
48 |
49 | /**
50 | * Test logger
51 | *
52 | * @since 1.2
53 | */
54 | public function testLog() {
55 | $func = function() {
56 | $this->assertTrue( true );
57 | };
58 |
59 | $logger = [
60 | 'success' => $func,
61 | ];
62 |
63 | $sitemap = new Sitemap( 6, 50, [ 'test' ], $logger );
64 |
65 | $sitemap->log( 'test', 'success' );
66 | }
67 |
68 | /**
69 | * Test building post types
70 | *
71 | * @since 1.2
72 | */
73 | public function testBuildPostTypes() {
74 | $args = array(
75 | 'post_status' => 'publish',
76 | 'post_type' => 'post',
77 | 'post_title' => 'Test Post One',
78 | );
79 |
80 | wp_insert_post( $args );
81 |
82 | $args = array(
83 | 'post_status' => 'publish',
84 | 'post_type' => 'post',
85 | 'post_title' => 'Test Post Two',
86 | );
87 |
88 | $post_id = wp_insert_post( $args );
89 |
90 | $args = array(
91 | 'post_status' => 'publish',
92 | 'post_type' => 'post',
93 | 'post_title' => 'Test Post Three',
94 | );
95 |
96 | wp_insert_post( $args );
97 |
98 | $args = array(
99 | 'post_status' => 'publish',
100 | 'post_type' => 'tsm_test',
101 | 'post_title' => 'Test Custom One',
102 | );
103 |
104 | wp_insert_post( $args );
105 |
106 | $args = array(
107 | 'post_status' => 'publish',
108 | 'post_type' => 'tsm_test_private',
109 | 'post_title' => 'Test Custom Two',
110 | );
111 |
112 | wp_insert_post( $args );
113 |
114 | $sitemap = new Sitemap();
115 | $sitemap->build_post_types();
116 |
117 | $urls = $sitemap->get_urls();
118 | $links = wp_list_pluck( $urls, 'url' );
119 | $ids = wp_list_pluck( $urls, 'ID' );
120 |
121 | $this->assertEquals( 4, count( $urls ) );
122 | $this->assertTrue( in_array( (int) $post_id, $ids, true ) );
123 | $this->assertTrue( in_array( home_url() . '/test-post-two/', $links, true ) );
124 | }
125 |
126 | /**
127 | * Test building terms
128 | *
129 | * @since 1.2
130 | */
131 | public function testBuildTerms() {
132 | $term1 = wp_insert_term( 'Cat 1', 'category' );
133 | $term2 = wp_insert_term( 'Tag 1', 'post_tag' );
134 |
135 | $args = array(
136 | 'post_status' => 'publish',
137 | 'post_type' => 'post',
138 | 'post_title' => 'Test Post One',
139 | 'post_category' => [ $term1['term_id'] ],
140 | );
141 |
142 | wp_insert_post( $args );
143 |
144 | $args = array(
145 | 'post_status' => 'publish',
146 | 'post_type' => 'post',
147 | 'post_title' => 'Test Post Two',
148 | 'post_category' => [ $term1['term_id'] ],
149 | );
150 |
151 | $post_id = wp_insert_post( $args );
152 |
153 | wp_set_post_terms( $post_id, [ $term2['term_id'] ], 'post_tag' );
154 |
155 | $sitemap = new Sitemap();
156 | $sitemap->build_terms();
157 |
158 | $urls = $sitemap->get_urls();
159 | $links = wp_list_pluck( $urls, 'url' );
160 |
161 | $this->assertTrue( in_array( get_term_link( $term1['term_id'] ), $links, true ) );
162 | $this->assertTrue( in_array( get_term_link( $term2['term_id'] ), $links, true ) );
163 | }
164 |
165 | /**
166 | * Test sitemaps writing
167 | *
168 | * @since 1.2
169 | */
170 | public function testSitemapWrite() {
171 | $urls = [];
172 |
173 | for ( $i = 1; $i <= 52; $i++ ) {
174 | $urls[] = [
175 | 'ID' => $i,
176 | 'url' => 'url' . $i,
177 | ];
178 | }
179 |
180 | $sitemap = new Sitemap( 'all', 10, $urls );
181 | $sitemap->write();
182 |
183 | $num_pages = get_option( 'tenup_sitemaps_total_pages' );
184 |
185 | $this->assertEquals( 6, $num_pages );
186 |
187 | for ( $i = 1; $i <= $num_pages; $i++ ) {
188 | $page = get_option( 'tenup_sitemaps_page_' . $i );
189 |
190 | $this->assertTrue( ! empty( $page ) );
191 | }
192 |
193 | $page2 = get_option( 'tenup_sitemaps_page_2' );
194 |
195 | $this->assertEquals( 11, $page2[0]['ID'] );
196 | }
197 |
198 | /**
199 | * Test building homepage
200 | *
201 | * @since 1.2
202 | */
203 | public function testBuildHomepage() {
204 | $sitemap = new Sitemap();
205 | $sitemap->build_homepage();
206 |
207 | $urls = $sitemap->get_urls();
208 |
209 | $this->assertEquals( 1, count( $urls ) );
210 | $this->assertEquals( home_url(), $urls[0]['url'] );
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | [],
47 | ];
48 | }
49 |
50 | tests_add_filter( 'translations_api', __NAMESPACE__ . '\skip_translations_api' );
51 |
52 | /**
53 | * Register post types for testing
54 | *
55 | * @since 1.2
56 | */
57 | function register_post_types() {
58 | $args = array(
59 | 'public' => true,
60 | 'taxonomies' => array( 'post_tag', 'category' ),
61 | );
62 |
63 | register_post_type( 'tsm_test', $args );
64 |
65 | $args = array(
66 | 'taxonomies' => array( 'post_tag', 'category' ),
67 | 'public' => false,
68 | );
69 |
70 | register_post_type( 'tsm_test_private', $args );
71 | }
72 |
73 | require_once $_tests_dir . '/includes/bootstrap.php';
74 |
--------------------------------------------------------------------------------