installing composer post type helper

This commit is contained in:
Antoine M 2025-01-30 10:36:27 +01:00
parent 3616f8c5b3
commit a72bdc6252
88 changed files with 11294 additions and 0 deletions

339
vendor/johnbillion/args/LICENSE vendored Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{{description}}
Copyright (C) {{year}} {{fullname}}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

248
vendor/johnbillion/args/README.md vendored Normal file
View File

@ -0,0 +1,248 @@
[![](https://img.shields.io/github/actions/workflow/status/johnbillion/args/tests.yml?branch=trunk&style=flat-square)](https://github.com/johnbillion/args/actions)
# Args
Many functions and methods in WordPress accept arguments as an associative array which your IDE or code editor cannot autocomplete like it does for individual function parameters.
```php
$query = new WP_Query( [
'post_type' => 'post',
'category' => 'does this accept an ID or a slug?',
'number_of_...errr'
] );
```
This library provides well-documented classes which represent many of the associative array parameters used throughout WordPress. Using them at the point where you populate the arguments means you get autocompletion and intellisense in your code editor, and strict typing thanks to typed properties in PHP 7.4. Comprehensive types and constraints for [PHPStan](https://phpstan.org/) are also included.
![](.github/assets/screenshot.png)
## Current Status
Last updated for WordPress 6.5.
## Requirements
* PHP 7.4 or PHP 8+
## Installation
```shell
composer require johnbillion/args
```
## Usage
Usage with a class constructor:
```php
$args = new \Args\WP_Query;
$args->tag = 'amazing';
$args->posts_per_page = 100;
$query = new \WP_Query( $args->toArray() );
```
Usage with a procedural function parameter:
```php
$args = new \Args\register_post_type;
$args->show_in_rest = true;
$args->taxonomies = [ 'genre', 'audience' ];
$story = register_post_type( 'story', $args->toArray() );
```
## Meta Queries, Tax Queries, and Date Queries
The query classes in WordPress support variously `meta_query`, `tax_query`, and `date_query` arguments. These are fully supported and you can construct them in a structured and strongly typed way.
Creating a `meta_query` argument:
```php
$args = new \Args\WP_Query;
// Create a clause
$clause = new \Args\MetaQuery\Clause;
$clause->key = 'my_meta_key';
$clause->value = 'my_meta_value';
// Add the clause
$args->meta_query->clauses[] = $clause;
$query = new \WP_Query( $args->toArray() );
```
Creating a `tax_query` argument:
```php
$args = new \Args\WP_Query;
// Create a clause
$clause = new \Args\TaxQuery\Clause;
$clause->taxonomy = 'post_tag';
$clause->terms = [ 'amazing' ];
// Add the clause
$args->tax_query->clauses[] = $clause;
$query = new \WP_Query( $args->toArray() );
```
Creating a `date_query` argument:
```php
$args = new \Args\WP_Query;
// Create a clause
$clause = new \Args\DateQuery\Clause;
$clause->year = 2000;
$clause->compare = '>=';
// Add the clause
$args->date_query->clauses[] = $clause;
$query = new \WP_Query( $args->toArray() );
```
Alternatively you can construct a complete query object by calling the `fromArray()` static method with the same nested array syntax that WordPress core uses:
```php
$args = new \Args\WP_Query;
// Set the meta query from an array
$array = [
[
'key' => 'my_meta_key',
'value' => 'my_meta_value',
]
];
$args->meta_query = $args->meta_query::fromArray( $array );
$query = new \WP_Query( $args->toArray() );
```
## What's Provided
### Posts
* `\Args\WP_Query`
* `\Args\register_post_type`
* `\Args\wp_insert_post`
* `\Args\wp_update_post`
* `\Args\get_posts`
* `\Args\register_post_meta`
* `\Args\register_post_status`
### Taxonomies and Terms
* `\Args\WP_Term_Query`
* `\Args\register_taxonomy`
* `\Args\wp_insert_term`
* `\Args\wp_update_term`
* `\Args\get_terms`
* `\Args\get_categories`
* `\Args\get_tags`
* `\Args\register_term_meta`
* `\Args\wp_count_terms`
* `\Args\wp_get_object_terms`
* `\Args\wp_dropdown_categories`
### Users
* `\Args\WP_User_Query`
* `\Args\wp_insert_user`
* `\Args\wp_update_user`
* `\Args\get_users`
### Comments
* `\Args\WP_Comment_Query`
* `\Args\get_comments`
### HTTP API
* `\Args\wp_remote_get`
* `\Args\wp_remote_post`
* `\Args\wp_remote_head`
* `\Args\wp_remote_request`
* `\Args\wp_safe_remote_get`
* `\Args\wp_safe_remote_post`
* `\Args\wp_safe_remote_head`
* `\Args\wp_safe_remote_request`
### Blocks
* `\Args\WP_Block_Type`
* `\Args\register_block_type`
### Customizer
* `\Args\WP_Customize_Control`
* `\Args\WP_Customize_Manager`
* `\Args\WP_Customize_Panel`
* `\Args\WP_Customize_Section`
* `\Args\WP_Customize_Setting`
### Everything Else
* `\Args\paginate_links`
* `\Args\register_meta`
* `\Args\register_rest_field`
* `\Args\wp_get_nav_menus`
* `\Args\wp_nav_menu`
* `\Args\wp_die`
* `\Args\wp_dropdown_languages`
* `\Args\wp_generate_tag_cloud`
## Type Checking
Typed class properties are implemented in this library where possible. If you pass a value of the wrong type to an argument that is typed, you'll get a fatal error as long as you're using strict types:
```php
<?php
declare( strict_types=1 );
```
No more mysterious bugs due to incorrect types.
Note that several parameters in WordPress accept multiple types, for example the `$ignore_sticky_posts` argument for `\WP_Query` can be a boolean or an integer. In some of these cases I've opted to type the parameter with the most appropriate type even though it can technically accept other types.
## Static Analysis
PHPStan-specific `@phpstan-var` tags are used for properties that have a fixed set of values or other constraints. This allows for even greater type and value checking via static analysis with PHPStan.
Ensure you're using PHPStan 1.0 or higher to make the best use of these constraints.
## Contributing
Check out [CONTRIBUTING.md](CONTRIBUTING.md) for information about generating your own Args definitions or contributing to the Args library.
## But Why?
I have a name for these array-type parameters for passing arguments. I call them *Stockholm Parameters*. We've gotten so used to using them that we forget what a terrible design pattern it is. This library exists to work around the immediate issue without rearchitecting the whole of WordPress.
## Sponsors
The time that I spend maintaining this library and others is in part sponsored by:
[![Automattic](.github/assets/gh/automattic.png)](https://automattic.com)
Plus all my kind sponsors on GitHub:
[![Sponsors](.github/assets/gh/everyone.png)](https://github.com/sponsors/johnbillion)
[Click here to find out about supporting this library and my other WordPress development tools and plugins](https://github.com/sponsors/johnbillion).
## License: GPLv2
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

126
vendor/johnbillion/args/composer.json vendored Normal file
View File

@ -0,0 +1,126 @@
{
"name": "johnbillion/args",
"description": "I don't want to get into an argument about this.",
"type": "library",
"license": "GPL-2.0-or-later",
"authors": [
{
"name": "John Blackbourn",
"homepage": "https://johnblackbourn.com/"
}
],
"config": {
"preferred-install": "dist",
"sort-packages": true,
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true,
"roots/wordpress-core-installer": true
}
},
"require": {
"php": ">=7.4"
},
"autoload": {
"psr-4": {
"Args\\": "src/"
}
},
"scripts": {
"generate": [
"@php bin/generate.php"
],
"test:shapes": [
"@php bin/shapes.php"
],
"test:shape": [
"@php bin/shape.php"
],
"test:phpcs": [
"phpcs -p --basepath='./' ."
],
"test:phpunit": [
"phpunit --testdox"
],
"test:phpstan": [
"phpstan analyze"
],
"test": [
"@test:shapes",
"@test:phpcs",
"@test:phpunit",
"@test:phpstan"
]
},
"extra": {
"args-shapes": [
"--function=\"\\get_categories()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/category.php",
"--function=\"\\get_comments()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/comment.php",
"--function=\"\\get_posts()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/post.php",
"--function=\"\\get_tags()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/category.php",
"--function=\"\\get_terms()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php",
"--function=\"\\get_users()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/user.php",
"--function=\"\\paginate_links()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/general-template.php",
"--function=\"\\register_block_type()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/blocks.php",
"--function=\"\\register_meta()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/meta.php",
"--function=\"\\register_post_meta()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/post.php",
"--function=\"\\register_post_status()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/post.php",
"--function=\"\\register_post_type()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/post.php",
"--function=\"\\register_rest_field()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/rest-api.php",
"--function=\"\\register_taxonomy()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php",
"--function=\"\\register_term_meta()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php",
"--function=\"\\wp_count_terms()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php",
"--function=\"\\wp_die()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/functions.php",
"--function=\"\\wp_dropdown_categories()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/category-template.php",
"--function=\"\\wp_dropdown_languages()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/l10n.php",
"--function=\"\\wp_generate_tag_cloud()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/category-template.php",
"--function=\"\\wp_get_nav_menus()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/nav-menu.php",
"--function=\"\\wp_get_object_terms()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php",
"--function=\"\\wp_insert_post()\" --param=postarr --file=vendor/wordpress/wordpress/wp-includes/post.php",
"--function=\"\\wp_insert_term()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php",
"--function=\"\\wp_insert_user()\" --param=userdata --file=vendor/wordpress/wordpress/wp-includes/user.php",
"--function=\"\\wp_nav_menu()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/nav-menu-template.php",
"--function=\"\\wp_remote_get()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php",
"--function=\"\\wp_remote_head()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php",
"--function=\"\\wp_remote_post()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php",
"--function=\"\\wp_remote_request()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php",
"--function=\"\\wp_safe_remote_get()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php",
"--function=\"\\wp_safe_remote_head()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php",
"--function=\"\\wp_safe_remote_post()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php",
"--function=\"\\wp_safe_remote_request()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php",
"--function=\"\\wp_update_post()\" --param=postarr --file=vendor/wordpress/wordpress/wp-includes/post.php",
"--function=\"\\wp_update_term()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php",
"--function=\"\\wp_update_user()\" --param=userdata --file=vendor/wordpress/wordpress/wp-includes/user.php",
"--method=\"\\WP_Block_Type::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-block-type.php",
"--method=\"\\WP_Comment_Query::__construct()\" --param=query --file=vendor/wordpress/wordpress/wp-includes/class-wp-comment-query.php",
"--method=\"\\WP_Customize_Control::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-customize-control.php",
"--method=\"\\WP_Customize_Manager::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-customize-manager.php",
"--method=\"\\WP_Customize_Panel::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-customize-panel.php",
"--method=\"\\WP_Customize_Section::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-customize-section.php",
"--method=\"\\WP_Customize_Setting::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-customize-setting.php",
"--method=\"\\WP_Http::request()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-http.php",
"--method=\"\\WP_Query::parse_query()\" --param=query --file=vendor/wordpress/wordpress/wp-includes/class-wp-query.php",
"--method=\"\\WP_Term_Query::__construct()\" --param=query --file=vendor/wordpress/wordpress/wp-includes/class-wp-term-query.php",
"--method=\"\\WP_User_Query::prepare_query()\" --param=query --file=vendor/wordpress/wordpress/wp-includes/class-wp-user-query.php"
],
"wordpress-install-dir": "vendor/wordpress/wordpress"
},
"require-dev": {
"ergebnis/json-printer": "^3.2",
"ergebnis/phpstan-rules": "^1.0",
"humanmade/coding-standards": "^1.1",
"johnbillion/falsey-assertequals-detector": "^3",
"phpdocumentor/reflection": "~4.0 || ~5.0",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpstan/phpstan-strict-rules": "^1.1",
"phpunit/phpunit": "^9.0",
"roots/wordpress-core-installer": "^1.0.0",
"roots/wordpress-full": "~6.5.0"
},
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/johnbillion"
}
]
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Args\Arrayable;
/**
* Arguments object that can be converted to an array.
*/
interface Arrayable {
/**
* @return ?array<string|int,mixed>
*/
public function toArray() :? array;
}

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Args\Arrayable;
/**
* An arguments object which provides a vanilla `fromArray()` method.
*/
trait ProvidesFromArray {
/**
* @param array<string, mixed> $args
* @return static
*/
final public static function fromArray( array $args ) : self {
$class = new static();
foreach ( $args as $key => $value ) {
$class->$key = $value;
}
return $class;
}
}

View File

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace Args\Arrayable;
/**
* An arguments object which provides a vanilla `toArray()` method.
*/
trait ProvidesToArray {
/** @var array<string, string> */
protected array $map = [];
/**
* @return array<string, string>
*/
final public function getMap() : array {
return $this->map;
}
/**
* @return array<string,mixed>
*/
final public function toArray() : array {
$vars = get_object_vars( $this );
foreach ( $this->getMap() as $from => $to ) {
if ( array_key_exists( $from, $vars ) ) {
$vars[ $to ] = $vars[ $from ];
unset( $vars[ $from ] );
}
}
unset( $vars['map'] );
foreach ( $vars as $key => $var ) {
if ( ! $var instanceof Arrayable ) {
continue;
}
$vars[ $key ] = $var->toArray();
}
$vars = array_filter( $vars, fn( $value ) : bool => $value !== null );
ksort( $vars );
return $vars;
}
}

View File

@ -0,0 +1,179 @@
<?php
declare(strict_types=1);
namespace Args\DateQuery;
use Args\Arrayable\Arrayable;
/**
* Arguments for a clause within a date query, for example those within a `$date_query` argument.
*/
final class Clause implements Arrayable, Values {
use \Args\Arrayable\ProvidesFromArray;
use \Args\Arrayable\ProvidesToArray;
/**
* Date to retrieve posts before. Accepts `strtotime()`-compatible string, or array of 'year', 'month', 'day' values.
*
* @var string|array<string, string>
* @phpstan-var string|array{
* year: numeric-string,
* month?: numeric-string,
* day?: numeric-string,
* }
*/
public $before;
/**
* Date to retrieve posts after. Accepts `strtotime()`-compatible string, or array of 'year', 'month', 'day' values.
*
* @var string|array<string, string>
* @phpstan-var string|array{
* year: numeric-string,
* month?: numeric-string,
* day?: numeric-string,
* }
*/
public $after;
/**
* Used to add a clause comparing a column other than
* the column specified in the top-level `$column` parameter.
* See WP_Date_Query::validate_column() and
* the {@see 'date_query_valid_columns'} filter for the list
* of accepted values.
*
* Default is the value of top-level `$column`.
*/
public string $column;
/**
* The comparison operator. Accepts '=', '!=', '>', '>=',
* '<', '<=', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'. 'IN',
* 'NOT IN', 'BETWEEN', and 'NOT BETWEEN'. Comparisons support
* arrays in some time-related parameters.
*
* Default '='.
*
* @phpstan-var Values::DATE_QUERY_COMPARE_*
*/
public string $compare;
/**
* Include results from dates specified in 'before' or 'after'.
*
* Default false.
*/
public bool $inclusive;
/**
* The four-digit year number. Accepts any four-digit year
* or an array of years if `$compare` supports it.
*
* Default empty.
*
* @var int|int[]
*/
public $year;
/**
* The two-digit month number. Accepts numbers 1-12 or an
* array of valid numbers if `$compare` supports it.
*
* Default empty.
*
* @var int|int[]
* @phpstan-var int<1,12>|array<int, int<1,12>>
*/
public $month;
/**
* The week number of the year. Accepts numbers 0-53 or an
* array of valid numbers if `$compare` supports it.
*
* Default empty.
*
* @var int|int[]
* @phpstan-var int<0,53>|array<int, int<0,53>>
*/
public $week;
/**
* The day number of the year. Accepts numbers 1-366 or an
* array of valid numbers if `$compare` supports it.
*
* Default empty.
*
* @var int|int[]
* @phpstan-var int<1,366>|array<int, int<1,366>>
*/
public $dayofyear;
/**
* The day of the month. Accepts numbers 1-31 or an array
* of valid numbers if `$compare` supports it.
*
* Default empty.
*
* @var int|int[]
* @phpstan-var int<1,31>|array<int, int<1,31>>
*/
public $day;
/**
* The day number of the week. Accepts numbers 1-7 (1 is
* Sunday) or an array of valid numbers if `$compare` supports it.
*
* Default empty.
*
* @var int|int[]
* @phpstan-var int<1,7>|array<int, int<1,7>>
*/
public $dayofweek;
/**
* The day number of the week (ISO). Accepts numbers 1-7
* (1 is Monday) or an array of valid numbers if `$compare` supports it.
*
* Default empty.
*
* @var int|int[]
* @phpstan-var int<1,7>|array<int, int<1,7>>
*/
public $dayofweek_iso;
/**
* The hour of the day. Accepts numbers 0-23 or an array
* of valid numbers if `$compare` supports it.
*
* Default empty.
*
* @var int|int[]
* @phpstan-var int<1,23>|array<int, int<1,23>>
*/
public $hour;
/**
* The minute of the hour. Accepts numbers 0-59 or an array
* of valid numbers if `$compare` supports it.
*
* Default empty.
*
* @var int|int[]
* @phpstan-var int<0,59>|array<int, int<0,59>>
*/
public $minute;
/**
* The second of the minute. Accepts numbers 0-59 or an
* array of valid numbers if `$compare` supports it.
*
* Default empty.
*
* @var int|int[]
* @phpstan-var int<0,59>|array<int, int<0,59>>
*/
public $second;
}

View File

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace Args\DateQuery;
/**
* Arguments for any query class that supports date queries.
*/
trait ProvidesArgs {
/**
* A `Query` object representing the `WP_Date_Query` constructor argument.
*/
public Query $date_query;
public function setDateQuery( Query $date_query ) : void {
$this->date_query = $date_query;
}
}

View File

@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
namespace Args\DateQuery;
use Args\Arrayable\Arrayable;
/**
* Structure for a `date_query` argument.
*/
final class Query implements Arrayable, Values {
/**
* The column to query against.
*
* If undefined, inherits the value of the `$default_column` parameter. See WP_Date_Query::validate_column() and the 'date_query_valid_columns' filter for the list of accepted values.
*
* Default 'post_date'.
*/
public string $column;
/**
* The comparison operator.
*
* Accepts '=', '!=', '>', '>=', '<', '<=', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'.
*
* Default '='.
*
* @phpstan-var Values::DATE_QUERY_COMPARE_*
*/
public string $compare;
/**
* The MySQL keyword used to join the clauses of the query. Accepts 'AND' or 'OR'.
*
* Default 'AND'.
*
* @phpstan-var Values::DATE_QUERY_RELATION_*
*/
public string $relation;
/**
* @var array<int, Clause>
*/
public array $clauses;
/**
* @param mixed[] $clauses
* @return static
*/
final public static function fromArray( array $clauses ) : self {
$class = new static();
foreach ( $clauses as $key => $value ) {
if ( 'column' === $key ) {
$class->column = $value;
} elseif ( 'compare' === $key ) {
$class->compare = $value;
} elseif ( 'relation' === $key ) {
$class->relation = $value;
} else {
$class->addClause( Clause::fromArray( $value ) );
}
}
return $class;
}
final public function addClause( Clause $clause ) : void {
$this->clauses[] = $clause;
}
/**
* @return ?array<string|int,mixed>
*/
final public function toArray() :? array {
if ( ! isset( $this->clauses ) || count( $this->clauses ) === 0 ) {
return null;
}
$vars = [];
if ( isset( $this->column ) ) {
$vars['column'] = $this->column;
}
if ( isset( $this->compare ) ) {
$vars['compare'] = $this->compare;
}
if ( isset( $this->relation ) ) {
$vars['relation'] = $this->relation;
}
foreach ( $this->clauses as $key => $value ) {
$vars[ $key ] = $value->toArray();
}
return $vars;
}
}

View File

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace Args\DateQuery;
/**
* Argument values for any query class that supports date queries.
*/
interface Values {
public const DATE_QUERY_RELATION_AND = 'AND';
public const DATE_QUERY_RELATION_OR = 'OR';
public const DATE_QUERY_COMPARE_EQUALS = '=';
public const DATE_QUERY_COMPARE_NOT_EQUALS = '!=';
public const DATE_QUERY_COMPARE_GREATER_THAN = '>';
public const DATE_QUERY_COMPARE_GREATER_THAN_OR_EQUALS = '>=';
public const DATE_QUERY_COMPARE_LESS_THAN = '<';
public const DATE_QUERY_COMPARE_LESS_THAN_OR_EQUALS = '<=';
public const DATE_QUERY_COMPARE_IN = 'IN';
public const DATE_QUERY_COMPARE_NOT_IN = 'NOT IN';
public const DATE_QUERY_COMPARE_BETWEEN = 'BETWEEN';
public const DATE_QUERY_COMPARE_NOT_BETWEEN = 'NOT BETWEEN';
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Args\DateQuery;
/**
* Methods for any query class that supports date queries.
*/
interface WithArgs {
public function setDateQuery( Query $tax_query ) : void;
}

View File

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace Args\MetaQuery;
use Args\Arrayable\Arrayable;
/**
* Arguments for a clause within a meta query, for example those within a `$meta_query` argument.
*/
final class Clause implements Arrayable, Values {
use \Args\Arrayable\ProvidesFromArray;
use \Args\Arrayable\ProvidesToArray;
/**
* Meta key or keys to filter by.
*
* @var string|array<int,string>
*/
public $key;
/**
* Meta value or values to filter by.
*
* @var string|array<int,string>
*/
public $value;
/**
* MySQL operator used for comparing the meta value.
*
* Default is 'IN' when `value` is an array, '=' otherwise.
*
* @phpstan-var Values::META_COMPARE_VALUE_*
*/
public string $compare;
/**
* MySQL operator used for comparing the meta key.
*
* Default is 'IN' when `key` is an array, '=' otherwise.
*
* @phpstan-var Values::META_COMPARE_KEY_*
*/
public string $compare_key;
/**
* MySQL data type that the `meta_value` column will be CAST to for comparisons.
*
* @phpstan-var Values::META_TYPE_VALUE_*
*/
public string $type;
/**
* MySQL data type that the `meta_key` column will be CAST to for comparisons.
*
* @phpstan-var Values::META_TYPE_KEY_*
*/
public string $type_key;
}

View File

@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace Args\MetaQuery;
/**
* Arguments for any query class that supports meta queries.
*/
trait ProvidesArgs {
/**
* Meta key or keys to filter by.
*
* @var string|array<int,string>
*/
public $meta_key;
/**
* Meta value or values to filter by.
*
* @var string|array<int,string>
*/
public $meta_value;
/**
* MySQL operator used for comparing the meta value.
*
* Default is 'IN' when `meta_value` is an array, '=' otherwise.
*
* @phpstan-var Values::META_COMPARE_VALUE_*
*/
public string $meta_compare;
/**
* MySQL operator used for comparing the meta key.
*
* Default is 'IN' when `meta_key` is an array, '=' otherwise.
*
* @phpstan-var Values::META_COMPARE_KEY_*
*/
public string $meta_compare_key;
/**
* MySQL data type that the `meta_value` column will be CAST to for comparisons.
*
* @phpstan-var Values::META_TYPE_VALUE_*
*/
public string $meta_type;
/**
* MySQL data type that the `meta_key` column will be CAST to for comparisons.
*
* @phpstan-var Values::META_TYPE_KEY_*
*/
public string $meta_type_key;
/**
* A `Query` object representing the `WP_Meta_Query` constructor argument.
*/
public Query $meta_query;
public function setMetaQuery( Query $meta_query ) : void {
$this->meta_query = $meta_query;
}
}

View File

@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
namespace Args\MetaQuery;
use Args\Arrayable\Arrayable;
/**
* Structure for a `meta_query` argument.
*/
final class Query implements Arrayable, Values {
/**
* The MySQL keyword used to join the clauses of the query. Accepts 'AND' or 'OR'.
*
* Default 'AND'.
*
* @phpstan-var Values::META_QUERY_RELATION_*
*/
public string $relation;
/**
* @var array<int|string, Clause>
*/
public array $clauses;
/**
* @param mixed[] $clauses
* @return static
*/
final public static function fromArray( array $clauses ) : self {
$class = new static();
foreach ( $clauses as $key => $value ) {
if ( 'relation' === $key ) {
$class->relation = $value;
} elseif ( is_string( $key ) ) {
$class->addClause( Clause::fromArray( $value ), $key );
} else {
$class->addClause( Clause::fromArray( $value ) );
}
}
return $class;
}
final public function addClause( Clause $clause, string $key = null ) : void {
if ( null !== $key ) {
$this->clauses[ $key ] = $clause;
} else {
$this->clauses[] = $clause;
}
}
/**
* @return ?array<string|int,mixed>
*/
final public function toArray() :? array {
if ( ! isset( $this->clauses ) || count( $this->clauses ) === 0 ) {
return null;
}
$vars = [];
if ( isset( $this->relation ) ) {
$vars['relation'] = $this->relation;
}
foreach ( $this->clauses as $key => $value ) {
$vars[ $key ] = $value->toArray();
}
return $vars;
}
}

View File

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace Args\MetaQuery;
/**
* Argument values for any query class that supports meta queries.
*/
interface Values {
public const META_COMPARE_KEY_EQUALS = '=';
public const META_COMPARE_KEY_NOT_EQUALS = '!=';
public const META_COMPARE_KEY_LIKE = 'LIKE';
public const META_COMPARE_KEY_NOT_LIKE = 'NOT LIKE';
public const META_COMPARE_KEY_IN = 'IN';
public const META_COMPARE_KEY_NOT_IN = 'NOT IN';
public const META_COMPARE_KEY_REGEXP = 'REGEXP';
public const META_COMPARE_KEY_NOT_REGEXP = 'NOT REGEXP';
public const META_COMPARE_KEY_RLIKE = 'RLIKE';
public const META_COMPARE_KEY_EXISTS = 'EXISTS';
public const META_COMPARE_KEY_NOT_EXISTS = 'NOT EXISTS';
public const META_COMPARE_VALUE_EQUALS = '=';
public const META_COMPARE_VALUE_NOT_EQUALS = '!=';
public const META_COMPARE_VALUE_GREATER_THAN = '>';
public const META_COMPARE_VALUE_GREATER_THAN_OR_EQUALS = '>=';
public const META_COMPARE_VALUE_LESS_THAN = '<';
public const META_COMPARE_VALUE_LESS_THAN_OR_EQUALS = '<=';
public const META_COMPARE_VALUE_LIKE = 'LIKE';
public const META_COMPARE_VALUE_NOT_LIKE = 'NOT LIKE';
public const META_COMPARE_VALUE_IN = 'IN';
public const META_COMPARE_VALUE_NOT_IN = 'NOT IN';
public const META_COMPARE_VALUE_BETWEEN = 'BETWEEN';
public const META_COMPARE_VALUE_NOT_BETWEEN = 'NOT BETWEEN';
public const META_COMPARE_VALUE_REGEXP = 'REGEXP';
public const META_COMPARE_VALUE_NOT_REGEXP = 'NOT REGEXP';
public const META_COMPARE_VALUE_RLIKE = 'RLIKE';
public const META_COMPARE_VALUE_EXISTS = 'EXISTS';
public const META_COMPARE_VALUE_NOT_EXISTS = 'NOT EXISTS';
public const META_TYPE_KEY_NONE = '';
public const META_TYPE_KEY_BINARY = 'BINARY';
public const META_TYPE_VALUE_NUMERIC = 'NUMERIC';
public const META_TYPE_VALUE_BINARY = 'BINARY';
public const META_TYPE_VALUE_CHAR = 'CHAR';
public const META_TYPE_VALUE_DATE = 'DATE';
public const META_TYPE_VALUE_DATETIME = 'DATETIME';
public const META_TYPE_VALUE_DECIMAL = 'DECIMAL';
public const META_TYPE_VALUE_SIGNED = 'SIGNED';
public const META_TYPE_VALUE_TIME = 'TIME';
public const META_TYPE_VALUE_UNSIGNED = 'UNSIGNED';
public const META_QUERY_RELATION_AND = 'AND';
public const META_QUERY_RELATION_OR = 'OR';
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Args\MetaQuery;
/**
* Methods for any query class that supports meta queries.
*/
interface WithArgs {
public function setMetaQuery( Query $meta_query ) : void;
}

View File

@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace Args\Shared;
use Args\Arrayable\Arrayable;
/**
* @implements \ArrayAccess<string, mixed>
* @implements \IteratorAggregate<string, mixed>
*/
abstract class Base implements \ArrayAccess, \Countable, \IteratorAggregate, Arrayable {
public const ORDER_ASC = 'ASC';
public const ORDER_DESC = 'DESC';
use \Args\Arrayable\ProvidesFromArray;
use \Args\Arrayable\ProvidesToArray;
final public function __construct() {
if ( $this instanceof \Args\DateQuery\WithArgs ) {
$this->setDateQuery( new \Args\DateQuery\Query );
}
if ( $this instanceof \Args\MetaQuery\WithArgs ) {
$this->setMetaQuery( new \Args\MetaQuery\Query );
}
if ( $this instanceof \Args\TaxQuery\WithArgs ) {
$this->setTaxQuery( new \Args\TaxQuery\Query );
}
}
/**
* @param mixed $offset
*/
#[\ReturnTypeWillChange]
final public function offsetExists( $offset ) : bool {
if ( ! is_string( $offset ) ) {
return false;
}
return array_key_exists( $offset, get_object_vars( $this ) );
}
/**
* @param mixed $offset
* @return mixed
*/
#[\ReturnTypeWillChange]
final public function offsetGet( $offset ) {
if ( ! is_string( $offset ) ) {
return null;
}
if ( ! array_key_exists( $offset, get_object_vars( $this ) ) ) {
return null;
}
return $this->$offset;
}
/**
* @param mixed $offset
* @param mixed $value
*/
#[\ReturnTypeWillChange]
final public function offsetSet( $offset, $value ) : void {
$this->$offset = $value;
}
/**
* @param mixed $offset
*/
#[\ReturnTypeWillChange]
final public function offsetUnset( $offset ) : void {
unset( $this->$offset );
}
final public function count() : int {
return count( $this->toArray() );
}
final public function getIterator() : \Traversable {
return new \ArrayIterator( $this->toArray() );
}
}

View File

@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace Args\TaxQuery;
use Args\Arrayable\Arrayable;
/**
* Arguments for a clause within a taxonomy query, for example those within a `$tax_query` argument.
*/
final class Clause implements Arrayable, Values {
use \Args\Arrayable\ProvidesFromArray;
use \Args\Arrayable\ProvidesToArray;
/**
* Taxonomy being queried. Optional when field=term_taxonomy_id.
*/
public string $taxonomy;
/**
* Term or terms to filter by.
*
* @var string|int|array<int,string>|array<int,int>
*/
public $terms;
/**
* Field to match `$terms` against. Accepts:
*
* - 'term_id'
* - 'slug'
* - 'name'
* - 'term_taxonomy_id'
*
* Default: 'term_id'.
*
* @phpstan-var 'term_id'|'slug'|'name'|'term_taxonomy_id'
*/
public string $field;
/**
* MySQL operator to be used with $terms in the WHERE clause.
*
* Accepts:
*
* - 'AND'
* - 'IN'
* - 'NOT IN'
* - 'EXISTS'
* - 'NOT EXISTS'
*
* Default: 'IN'.
*
* @phpstan-var Values::TAX_QUERY_OPERATOR_*
*/
public string $operator;
/**
* Whether to include child terms. Requires a `$taxonomy`.
*
* Default: true.
*/
public bool $children;
}

View File

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace Args\TaxQuery;
/**
* Arguments for any query class that supports taxonomy queries.
*/
trait ProvidesArgs {
/**
* A `Query` object representing the `WP_Tax_Query` constructor argument.
*/
public Query $tax_query;
public function setTaxQuery( Query $tax_query ) : void {
$this->tax_query = $tax_query;
}
}

View File

@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace Args\TaxQuery;
use Args\Arrayable\Arrayable;
/**
* Structure for a `tax_query` argument.
*/
final class Query implements Arrayable, Values {
/**
* The MySQL keyword used to join the clauses of the query. Accepts 'AND' or 'OR'.
*
* Default 'AND'.
*
* @phpstan-var Values::TAX_QUERY_RELATION_*
*/
public string $relation;
/**
* @var array<int, Clause>
*/
public array $clauses;
/**
* @param mixed[] $clauses
* @return static
*/
final public static function fromArray( array $clauses ) : self {
$class = new static();
foreach ( $clauses as $key => $value ) {
if ( 'relation' === $key ) {
$class->relation = $value;
} else {
$class->addClause( Clause::fromArray( $value ) );
}
}
return $class;
}
final public function addClause( Clause $clause ) : void {
$this->clauses[] = $clause;
}
/**
* @return ?array<string|int,mixed>
*/
final public function toArray() :? array {
if ( ! isset( $this->clauses ) || count( $this->clauses ) === 0 ) {
return null;
}
$vars = [];
if ( isset( $this->relation ) ) {
$vars['relation'] = $this->relation;
}
foreach ( $this->clauses as $key => $value ) {
$vars[ $key ] = $value->toArray();
}
return $vars;
}
}

View File

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace Args\TaxQuery;
/**
* Argument values for any query class that supports taxonomy queries.
*/
interface Values {
public const TAX_QUERY_RELATION_AND = 'AND';
public const TAX_QUERY_RELATION_OR = 'OR';
public const TAX_QUERY_OPERATOR_AND = 'AND';
public const TAX_QUERY_OPERATOR_IN = 'IN';
public const TAX_QUERY_OPERATOR_NOT_IN = 'NOT IN';
public const TAX_QUERY_OPERATOR_EXISTS = 'EXISTS';
public const TAX_QUERY_OPERATOR_NOT_EXISTS = 'NOT EXISTS';
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Args\TaxQuery;
/**
* Methods for any query class that supports taxonomy queries.
*/
interface WithArgs {
public function setTaxQuery( Query $tax_query ) : void;
}

View File

@ -0,0 +1,240 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `WP_Block_Type` class in WordPress.
*
* @link https://developer.wordpress.org/reference/classes/WP_Block_Type/
*/
class WP_Block_Type extends Shared\Base {
/**
* Block API version.
*/
public int $api_version;
/**
* Human-readable block type label.
*/
public string $title;
/**
* Block type category classification, used in search interfaces to arrange block types by category.
*/
public string $category;
/**
* Setting parent lets a block require that it is only available when nested within the specified blocks.
*
* @var array<int, string>
*/
public array $parent;
/**
* Setting ancestor makes a block available only inside the specified block types at any position of the ancestor's block subtree.
*
* @var array<int, string>
*/
public array $ancestor;
/**
* Block type icon.
*/
public string $icon;
/**
* A detailed block type description.
*/
public string $description;
/**
* Additional keywords to produce block type as result in search interfaces.
*
* @var array<int, string>
*/
public array $keywords;
/**
* The translation textdomain.
*/
public string $textdomain;
/**
* Alternative block styles.
*
* @link https://developer.wordpress.org/block-editor/reference-guides/block-api/block-styles/
*
* @var array<int, array<string, mixed>>
* @phpstan-var array<int, array{
* name: string,
* label: string,
* inline_style?: string,
* style_handle?: string,
* is_default?: bool,
* }>
*/
public array $styles;
/**
* Supported features.
*
* @link https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/
*
* @var array<string,mixed>
*/
public array $supports;
/**
* Structured data for the block preview.
*
* @var array<string, array<string, mixed>>
*/
public array $example;
/**
* Block type render callback.
*
* @var callable
* @phpstan-var callable( array<string, mixed>, string, \WP_Block= ): string
*/
public $render_callback;
/**
* Block type attributes property schemas.
*
* @var array<string, array<string, mixed>>
*/
public array $attributes;
/**
* Context values inherited by blocks of this type.
*
* @var array<int, string>
*/
public array $uses_context;
/**
* Context provided by blocks of this type.
*
* @var array<string, string>
*/
public array $provides_context;
/**
* Block hooks.
*
* @var array<string, string>
* @phpstan-var array<string, 'before'|'after'|'first_child'|'last_child'>
*/
public array $block_hooks;
/**
* Limits which block types can be inserted as children of this block type
*
* @var array<int, string>
* @phpstan-var list<string>
*/
public array $allowed_blocks;
/**
* Block type variations callback.
*
* @var callable
* @phpstan-var callable(): list<array<string, mixed>>
*/
public $variation_callback;
/**
* Block type front end only style handles.
*
* @var array<int, string>
* @phpstan-var list<string>
*/
public array $view_style_handles;
/**
* Block type editor script handle.
*
* @deprecated WordPress 6.1.0
*/
public string $editor_script;
/**
* Block type editor only script handles.
*
* @var array<int, string>
*/
public array $editor_script_handles;
/**
* Block type front end script handle.
*
* @deprecated WordPress 6.1.0
*/
public string $script;
/**
* Block type front end and editor script handles.
*
* @var array<int, string>
*/
public array $script_handles;
/**
* Custom CSS selectors for theme.json style generation.
*
* @var array<string, mixed>
*/
public array $selectors;
/**
* Block type editor style handle.
*
* @deprecated WordPress 6.1.0
*/
public string $editor_style;
/**
* Block type editor only style handles.
*
* @var array<int, string>
*/
public array $editor_style_handles;
/**
* Block type front end style handle.
*
* @deprecated WordPress 6.1.0
*/
public string $style;
/**
* Block type front end and editor style handles.
*
* @var array<int, string>
*/
public array $style_handles;
/**
* Block type front end only script handle.
*
* @deprecated WordPress 6.1.0
*/
public string $view_script;
/**
* Block type front end only script handles.
*
* @var array<int, string>
*/
public array $view_script_handles;
/**
* Block variations.
*
* @var array<int, array<string, mixed>>
*/
public array $variations;
}

View File

@ -0,0 +1,385 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `WP_Comment_Query::__construct()` method in WordPress.
*
* @link https://developer.wordpress.org/reference/classes/wp_comment_query/__construct/
*/
class WP_Comment_Query extends Shared\Base implements DateQuery\WithArgs, MetaQuery\WithArgs {
public const FIELD_IDS = 'ids';
public const FIELD_ALL = '';
public const HIERARCHICAL_FALSE = false;
public const HIERARCHICAL_THREADED = 'threaded';
public const HIERARCHICAL_FLAT = 'flat';
use DateQuery\ProvidesArgs;
use MetaQuery\ProvidesArgs;
/**
* Comment author email address.
*
* Default empty.
*/
public string $author_email;
/**
* Comment author URL.
*
* Default empty.
*/
public string $author_url;
/**
* Array of author IDs to include comments for.
*
* Default empty.
*
* @var array<int,int>
*/
public array $author__in;
/**
* Array of author IDs to exclude comments for.
*
* Default empty.
*
* @var array<int,int>
*/
public array $author__not_in;
/**
* Array of comment IDs to include.
*
* Default empty.
*
* @var array<int,int>
*/
public array $comment__in;
/**
* Array of comment IDs to exclude.
*
* Default empty.
*
* @var array<int,int>
*/
public array $comment__not_in;
/**
* Whether to return a comment count (true) or array of comment objects (false).
*
* Default false.
*/
public bool $count;
/**
* Comment fields to return. Accepts 'ids' for comment IDs only or empty for all fields.
*
* Default empty.
*
* @phpstan-var self::FIELD_*
*/
public string $fields;
/**
* Array of IDs or email addresses of users whose unapproved comments will be returned by the query regardless of `$status`.
*
* Default empty.
*
* @var array<int,(int|string)>
*/
public array $include_unapproved;
/**
* Karma score to retrieve matching comments for.
*
* Default empty.
*/
public int $karma;
/**
* Maximum number of comments to retrieve.
*
* Default empty (no limit).
*/
public int $number;
/**
* When used with `$number`, defines the page of results to return. When used with `$offset`, `$offset` takes precedence.
*
* Default 1.
*/
public int $paged;
/**
* Number of comments to offset the query. Used to build `LIMIT` clause.
*
* Default 0.
*/
public int $offset;
/**
* Whether to disable the `SQL_CALC_FOUND_ROWS` query.
*
* Default: true.
*/
public bool $no_found_rows;
/**
* Field(s) to order comments by. To use 'meta_value' or 'meta_value_num', `$meta_key` must also be defined. To sort by a specific `$meta_query` clause, use that clause's array key. Accepts:
*
* - 'comment_agent'
* - 'comment_approved'
* - 'comment_author'
* - 'comment_author_email'
* - 'comment_author_IP'
* - 'comment_author_url'
* - 'comment_content'
* - 'comment_date'
* - 'comment_date_gmt'
* - 'comment_ID'
* - 'comment_karma'
* - 'comment_parent'
* - 'comment_post_ID'
* - 'comment_type'
* - 'user_id'
* - 'comment__in'
* - 'meta_value'
* - 'meta_value_num'
* - the value of `$meta_key`
* - the array keys of `$meta_query`
* - an empty array or 'none' to disable `ORDER BY` clause.
*
* Default: 'comment_date_gmt'.
*
* @var string|array<int,string>
*/
public $orderby;
/**
* How to order retrieved comments. Accepts 'ASC', 'DESC'.
*
* Default: 'DESC'.
*
* @phpstan-var Shared\Base::ORDER_*
*/
public string $order;
/**
* Parent ID of comment to retrieve children of.
*
* Default empty.
*/
public int $parent;
/**
* Array of parent IDs of comments to retrieve children for.
*
* Default empty.
*
* @var array<int,int>
*/
public array $parent__in;
/**
* Array of parent IDs of comments *not* to retrieve children for.
*
* Default empty.
*
* @var array<int,int>
*/
public array $parent__not_in;
/**
* Array of author IDs to retrieve comments for.
*
* Default empty.
*
* @var array<int,int>
*/
public array $post_author__in;
/**
* Array of author IDs *not* to retrieve comments for.
*
* Default empty.
*
* @var array<int,int>
*/
public array $post_author__not_in;
/**
* Limit results to those affiliated with a given post ID.
*
* Default 0.
*/
public int $post_id;
/**
* Array of post IDs to include affiliated comments for.
*
* Default empty.
*
* @var array<int,int>
*/
public array $post__in;
/**
* Array of post IDs to exclude affiliated comments for.
*
* Default empty.
*
* @var array<int,int>
*/
public array $post__not_in;
/**
* Post author ID to limit results by.
*
* Default empty.
*/
public int $post_author;
/**
* Post status or array of post statuses to retrieve affiliated comments for. Pass 'any' to match any value.
*
* Default empty.
*
* @var string|array<int,string>
*/
public $post_status;
/**
* Post type or array of post types to retrieve affiliated comments for. Pass 'any' to match any value.
*
* Default empty.
*
* @var string|array<int,string>
*/
public $post_type;
/**
* Post name to retrieve affiliated comments for.
*
* Default empty.
*/
public string $post_name;
/**
* Post parent ID to retrieve affiliated comments for.
*
* Default empty.
*/
public int $post_parent;
/**
* Search term(s) to retrieve matching comments for.
*
* Default empty.
*/
public string $search;
/**
* Comment statuses to limit results by. Accepts an array or space/comma-separated list of:
*
* - 'hold' (`comment_status=0`)
* - 'approve' (`comment_status=1`)
* - 'all'
* - a custom comment status
*
* Default 'all'.
*
* @var string|array<int,string>
*/
public $status;
/**
* Include comments of a given type, or array of types. Accepts:
*
* - 'comment'
* - 'pings' (includes 'pingback' and 'trackback')
* - any custom type string
*
* Default empty.
*
* @var string|array<int,string>
*/
public $type;
/**
* Include comments from a given array of comment types.
*
* Default empty.
*
* @var array<int,string>
*/
public array $type__in;
/**
* Exclude comments from a given array of comment types.
*
* Default empty.
*
* @var array<int,string>
*/
public array $type__not_in;
/**
* Include comments for a specific user ID.
*
* Default empty.
*/
public int $user_id;
/**
* Whether to include comment descendants in the results.
*
* - 'threaded' returns a tree, with each comment's children stored in a `children` property on the `WP_Comment` object.
* - 'flat' returns a flat array of found comments plus their children.
* - Boolean `false` leaves out descendants.
*
* The parameter is ignored (forced to `false`) when `$fields` is 'ids' or 'counts'.
*
* Default: false.
*
* @var false|string
* @phpstan-var self::HIERARCHICAL_*
*/
public $hierarchical;
/**
* Unique cache key to be produced when this query is stored in an object cache.
*
* Default is 'core'.
*/
public string $cache_domain;
/**
* Whether to prime the metadata cache for found comments.
*
* Default true.
*/
public bool $update_comment_meta_cache;
/**
* Whether to prime the cache for comment posts.
*
* Default false.
*/
public bool $update_comment_post_cache;
/**
* Currently unused.
*/
protected int $ID;
/**
* Currently unused.
*/
protected int $post_ID;
}

View File

@ -0,0 +1,130 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `WP_Customize_Control::__construct()` method in WordPress.
*
* @link https://developer.wordpress.org/reference/classes/wp_customize_control/__construct/
* @link https://developer.wordpress.org/themes/customize-api/customizer-objects/
*/
class WP_Customize_Control extends Shared\Base {
/**
* Order in which this instance was created in relation to other instances.
*/
public int $instance_number;
/**
* Customizer bootstrap instance.
*/
public \WP_Customize_Manager $manager;
/**
* Control ID.
*/
public string $id;
/**
* All settings tied to the control.
*
* If undefined, `$id` will be used.
*
* @var array<string, mixed>
*/
public array $settings;
/**
* The primary setting for the control (if there is one).
*
* Default 'default'.
*/
public string $setting;
/**
* Capability required to use this control.
*
* Normally this is empty and the capability is derived from `$settings`.
*/
public string $capability;
/**
* Order priority to load the control.
*
* Default 10.
*/
public int $priority;
/**
* Section the control belongs to.
*
* Default empty.
*/
public string $section;
/**
* Label for the control.
*
* Default empty.
*/
public string $label;
/**
* Description for the control.
*
* Default empty.
*/
public string $description;
/**
* List of choices for 'radio' or 'select' type controls, where values are the keys, and labels are the values.
*
* Default empty array.
*
* @var array<string, string>
*/
public array $choices;
/**
* List of custom input attributes for control output, where attribute names are the keys and values are the values.
*
* Not used for 'checkbox', 'radio', 'select', 'textarea', or 'dropdown-pages' control types.
*
* Default empty array.
*
* @var array<string, string>
*/
public array $input_attrs;
/**
* Show UI for adding new content, currently only used for the dropdown-pages control.
*
* Default false.
*/
public bool $allow_addition;
/**
* Deprecated. Use `WP_Customize_Control::json()` instead.
*
* @var array<string, mixed>
*/
protected array $json;
/**
* Control type.
*
* Core controls include 'text', 'checkbox', 'textarea', 'radio', 'select', and 'dropdown-pages'. Additional input types such as 'email', 'url', 'number', 'hidden', and 'date' are supported implicitly.
*
* Default 'text'.
*/
public string $type;
/**
* Active callback.
*
* @var callable
* @phpstan-var callable(\WP_Customize_Control): bool
*/
public $active_callback;
}

View File

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `WP_Customize_Manager::__construct()` method in WordPress.
*
* @link https://developer.wordpress.org/reference/classes/wp_customize_manager/__construct/
* @link https://developer.wordpress.org/themes/customize-api/customizer-objects/
*/
class WP_Customize_Manager extends Shared\Base {
/**
* Changeset UUID, the `post_name` for the customize_changeset post containing the customized state.
*
* Defaults to `null` resulting in a UUID to be immediately generated. If `false` is provided, then then the changeset UUID will be determined during `after_setup_theme`: when the `customize_changeset_branching` filter returns false, then the default UUID will be that of the most recent `customize_changeset` post that has a status other than 'auto-draft', 'publish', or 'trash'. Otherwise, if changeset branching is enabled, then a random UUID will be used.
*
* @var null|string|false
*/
public $changeset_uuid;
/**
* Theme to be previewed (for theme switch).
*
* Defaults to customize_theme or theme query params.
*/
public string $theme;
/**
* Messenger channel.
*
* Defaults to customize_messenger_channel query param.
*/
public string $messenger_channel;
/**
* If settings should be previewed.
*
* Defaults to true.
*/
public bool $settings_previewed;
/**
* If changeset branching is allowed; otherwise, changesets are linear.
*
* Defaults to true.
*/
public bool $branching;
/**
* If data from a changeset's autosaved revision should be loaded if it exists.
*
* Defaults to false.
*/
public bool $autosaved;
}

View File

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `WP_Customize_Panel::__construct()` method in WordPress.
*
* @link https://developer.wordpress.org/reference/classes/wp_customize_panel/__construct/
* @link https://developer.wordpress.org/themes/customize-api/customizer-objects/
*/
class WP_Customize_Panel extends Shared\Base {
/**
* Priority of the panel, defining the display order of panels and sections. Default 160.
*/
public int $priority;
/**
* Capability required for the panel. Default `edit_theme_options`.
*/
public string $capability;
/**
* Theme features required to support the panel.
*
* @var string|array<int, mixed>
* @phpstan-var string|array{
* 0: string,
* }
*/
public $theme_supports;
/**
* Title of the panel to show in UI.
*/
public string $title;
/**
* Description to show in the UI.
*/
public string $description;
/**
* Type of the panel.
*/
public string $type;
/**
* Active callback.
*
* @phpstan-var callable(\WP_Customize_Panel): bool
*/
public $active_callback;
}

View File

@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `WP_Customize_Section::__construct()` method in WordPress.
*
* @link https://developer.wordpress.org/reference/classes/wp_customize_section/__construct/
* @link https://developer.wordpress.org/themes/customize-api/customizer-objects/
*/
class WP_Customize_Section extends Shared\Base {
/**
* Priority of the section, defining the display order of panels and sections.
*
* Default 160.
*/
public int $priority;
/**
* The panel this section belongs to (if any).
*
* Default empty.
*/
public string $panel;
/**
* Capability required for the section.
*
* Default 'edit_theme_options'
*/
public string $capability;
/**
* Theme features required to support the section.
*
* @var string|array<int, mixed>
* @phpstan-var string|array{
* 0: string,
* }
*/
public $theme_supports;
/**
* Title of the section to show in UI.
*/
public string $title;
/**
* Description to show in the UI.
*/
public string $description;
/**
* Type of the section.
*/
public string $type;
/**
* Active callback.
*
* @phpstan-var callable(\WP_Customize_Section): bool
*/
public $active_callback;
/**
* Hide the description behind a help icon, instead of inline above the first control.
*
* Default false.
*/
public bool $description_hidden;
}

View File

@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `WP_Customize_Setting::__construct()` method in WordPress.
*
* @link https://developer.wordpress.org/reference/classes/wp_customize_setting/__construct/
* @link https://developer.wordpress.org/themes/customize-api/customizer-objects/
*/
class WP_Customize_Setting extends Shared\Base {
public const TRANSPORT_REFRESH = 'refresh';
public const TRANSPORT_POSTMESSAGE = 'postMessage';
/**
* Type of the setting.
*
* Default 'theme_mod'.
*/
public string $type;
/**
* Capability required for the setting.
*
* Default 'edit_theme_options'
*/
public string $capability;
/**
* Theme features required to support the setting.
*
* @var string|array<int, mixed>
* @phpstan-var string|array{
* 0: string,
* }
*/
public $theme_supports;
/**
* Default value for the setting.
*
* Default is empty string.
*/
public string $default;
/**
* Options for rendering the live preview of changes in Customizer.
*
* Using 'refresh' makes the change visible by reloading the whole preview. Using 'postMessage' allows a custom JavaScript to handle live changes.
*
* Default is 'refresh'.
*
* @phpstan-var self::TRANSPORT_*
*/
public string $transport;
/**
* Server-side validation callback for the setting's value.
*
* @var callable
* @phpstan-var callable(\WP_Error, mixed, \WP_Customize_Setting): \WP_Error
*/
public $validate_callback;
/**
* Callback to filter a Customize setting value in un-slashed form.
*
* @var callable
* @phpstan-var callable(mixed, \WP_Customize_Setting): mixed
*/
public $sanitize_callback;
/**
* Callback to convert a Customize PHP setting value to a value that is JSON serializable.
*
* @var callable
* @phpstan-var callable(mixed, \WP_Customize_Setting): mixed
*/
public $sanitize_js_callback;
/**
* Whether or not the setting is initially dirty when created.
*/
public bool $dirty;
}

165
vendor/johnbillion/args/src/WP_Http.php vendored Normal file
View File

@ -0,0 +1,165 @@
<?php
declare(strict_types=1);
namespace Args;
use WP_Http_Cookie;
/**
* Arguments for the `WP_Http::request()` method in WordPress.
*
* @link https://developer.wordpress.org/reference/classes/wp_http/request/
*/
class WP_Http extends Shared\Base {
public const METHOD_GET = 'GET';
public const METHOD_POST = 'POST';
public const METHOD_HEAD = 'HEAD';
public const METHOD_PUT = 'PUT';
public const METHOD_DELETE = 'DELETE';
public const METHOD_TRACE = 'TRACE';
public const METHOD_OPTIONS = 'OPTIONS';
public const METHOD_PATCH = 'PATCH';
/** @var array<string, string> */
protected array $map = [
'user_agent' => 'user-agent',
];
/**
* Request method.
*
* Some transports technically allow others, but should not be assumed.
*
* Default 'GET'.
*
* @phpstan-var self::METHOD_*
*/
public string $method;
/**
* How long the connection should stay open in seconds.
*
* Default 5.
*/
public float $timeout;
/**
* Number of allowed redirects. Not supported by all transports.
*
* Default 5.
*/
public int $redirection;
/**
* Version of the HTTP protocol to use.
*
* Accepts '1.0' and '1.1'.
*
* Default '1.0'.
*/
public string $httpversion;
/**
* User-agent value sent.
*
* Default `'WordPress/' . get_bloginfo( 'version' ) . '; ' . get_bloginfo( 'url' )`.
*/
public string $user_agent;
/**
* Whether to pass URLs through `wp_http_validate_url()`.
*
* Default false.
*/
public bool $reject_unsafe_urls;
/**
* Whether the calling code requires the result of the request.
*
* If set to false, the request will be sent to the remote server, and processing returned to the calling code immediately, the caller will know if the request succeeded or failed, but will not receive any response from the remote server.
*
* Default true.
*/
public bool $blocking;
/**
* Array of headers to send with the request.
*
* Default empty array.
*
* @var array<string,string>
*/
public array $headers;
/**
* List of cookies to send with the request.
*
* Default empty array.
*
* @var string[]|WP_Http_Cookie[]
*/
public array $cookies;
/**
* Body to send with the request.
*
* Default null.
*
* @var string|mixed[]
*/
public $body;
/**
* Whether to compress the $body when sending the request.
*
* Default false.
*/
public bool $compress;
/**
* Whether to decompress a compressed response.
*
* If set to false and compressed content is returned in the response anyway, it will need to be separately decompressed.
*
* Default true.
*/
public bool $decompress;
/**
* Whether to verify SSL for the request.
*
* Default true.
*/
public bool $sslverify;
/**
* Absolute path to an SSL certificate `.crt` file.
*
* Default `ABSPATH . WPINC . '/certificates/ca-bundle.crt'`.
*/
public string $sslcertificates;
/**
* Whether to stream to a file.
*
* If set to true and no filename was given, it will be dropped it in the WP temp dir and its name will be set using the basename of the URL.
*
* Default false.
*/
public bool $stream;
/**
* Filename of the file to write to when streaming. `$stream` must be set to true.
*
* Default null.
*/
public string $filename;
/**
* Size in bytes to limit the response to.
*
* Default null.
*/
public int $limit_response_size;
}

527
vendor/johnbillion/args/src/WP_Query.php vendored Normal file
View File

@ -0,0 +1,527 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `WP_Query` class in WordPress.
*
* @link https://developer.wordpress.org/reference/classes/wp_query/parse_query/
*/
class WP_Query extends Shared\Base implements DateQuery\WithArgs, MetaQuery\WithArgs, TaxQuery\WithArgs {
public const COMMENT_STATUS_OPEN = 'open';
public const COMMENT_STATUS_CLOSED = 'closed';
public const FIELD_ALL = '';
public const FIELD_IDS = 'ids';
public const FIELD_ID_PARENT = 'id=>parent';
public const PERM_READABLE = 'readable';
public const PERM_EDITABLE = 'editable';
public const COMMENT_COUNT_COMPARE_EQUALS = '=';
public const COMMENT_COUNT_COMPARE_NOT_EQUALS = '!=';
public const COMMENT_COUNT_COMPARE_GREATER_THAN = '>';
public const COMMENT_COUNT_COMPARE_GREATER_THAN_OR_EQUALS = '>=';
public const COMMENT_COUNT_COMPARE_LESS_THAN = '<';
public const COMMENT_COUNT_COMPARE_LESS_THAN_OR_EQUALS = '<=';
use DateQuery\ProvidesArgs;
use MetaQuery\ProvidesArgs;
use TaxQuery\ProvidesArgs;
/**
* Attachment post ID. Used for 'attachment' post_type.
*/
public int $attachment_id;
/**
* Author ID, or comma-separated list of IDs.
*
* @var int|string
*/
public $author;
/**
* User 'user_nicename'.
*/
public string $author_name;
/**
* An array of author IDs to query from.
*
* @var array<int, int>
*/
public array $author__in;
/**
* An array of author IDs not to query from.
*
* @var array<int, int>
*/
public array $author__not_in;
/**
* Whether to cache post information.
*
* Default true.
*/
public bool $cache_results;
/**
* Category ID or comma-separated list of IDs (this or any children).
*
* @var int|string
*/
public $cat;
/**
* An array of category IDs (AND in).
*
* @var array<int, int>
*/
public array $category__and;
/**
* An array of category IDs (OR in, no children).
*
* @var array<int, int>
*/
public array $category__in;
/**
* An array of category IDs (NOT in).
*
* @var array<int, int>
*/
public array $category__not_in;
/**
* Use category slug (not name, this or any children).
*/
public string $category_name;
/**
* Filter results by comment count.
*
* Provide an integer to match comment count exactly. Provide an array with integer 'value' and 'compare' operator ('=', '!=', '>', '>=', '<', '<=' ) to compare against comment_count in a specific way.
*
* @var array<string,(int|string)>|int
* @phpstan-var array{
* value: int,
* compare: self::COMMENT_COUNT_COMPARE_*,
* }|int
*/
public $comment_count;
/**
* Comment status.
*
* @phpstan-var self::COMMENT_STATUS_*
*/
public string $comment_status;
/**
* The number of comments to return per page.
*
* Default 'comments_per_page' option.
*/
public int $comments_per_page;
/**
* Day of the month.
*
* Default empty. Accepts numbers 1-31.
*
* @phpstan-var int<1, 31>
*/
public int $day;
/**
* Whether to search by exact keyword.
*
* Default false.
*/
public bool $exact;
/**
* Post fields to query for.
*
* Accepts:
*
* - '' Returns an array of complete post objects (`WP_Post[]`).
* - 'ids' Returns an array of post IDs (`int[]`).
* - 'id=>parent' Returns an associative array of parent post IDs, keyed by post ID (`int[]`).
*
* Default ''.
*
* @phpstan-var self::FIELD_*
*/
public string $fields;
/**
* Hour of the day.
*
* Default empty. Accepts numbers 0-23.
*
* @phpstan-var int<0, 23>
*/
public int $hour;
/**
* Whether to ignore sticky posts or not. Setting this to false excludes stickies from 'post__in'.
*
* Default false.
*/
public bool $ignore_sticky_posts;
/**
* Combination YearMonth. Accepts any four-digit year and month numbers 1-12.
*
* Default empty.
*/
public int $m;
/**
* The menu order of the posts.
*/
public int $menu_order;
/**
* Second of the minute.
*
* Default empty. Accepts numbers 0-59.
*
* @phpstan-var int<0, 59>
*/
public int $minute;
/**
* The two-digit month.
*
* Default empty. Accepts numbers 1-12.
*
* @phpstan-var int<1, 12>
*/
public int $monthnum;
/**
* Post slug.
*/
public string $name;
/**
* Show all posts (true) or paginate (false).
*
* Default false.
*/
public bool $nopaging;
/**
* Whether to skip counting the total rows found. Enabling can improve performance.
*
* Default false.
*/
public bool $no_found_rows;
/**
* The number of posts to offset before retrieval.
*/
public int $offset;
/**
* Designates ascending or descending order of posts.
*
* Default 'DESC'. Accepts 'ASC', 'DESC'.
*
* @phpstan-var Shared\Base::ORDER_*
*/
public string $order;
/**
* Sort retrieved posts by parameter. One or more options may be passed.
*
* To use 'meta_value', or 'meta_value_num', 'meta_key=keyname' must be also be defined. To sort by a specific `$meta_query` clause, use that clause's array key.
*
* Accepts:
*
* - 'none'
* - 'name'
* - 'author'
* - 'date'
* - 'title'
* - 'modified'
* - 'menu_order'
* - 'parent'
* - 'ID'
* - 'rand'
* - 'relevance'
* - 'RAND(x)' (where 'x' is an integer seed value)
* - 'comment_count'
* - 'meta_value'
* - 'meta_value_num'
* - 'post__in'
* - 'post_name__in'
* - 'post_parent__in'
* - The array keys of `$meta_query`
*
* Default is 'date', except when a search is being performed, when the default is 'relevance'.
*
* @var string|array<int,string>
*/
public $orderby;
/**
* Post ID.
*/
public int $p;
/**
* Show the number of posts that would show up on page X of a static front page.
*/
public int $page;
/**
* The number of the current page.
*/
public int $paged;
/**
* Page ID.
*/
public int $page_id;
/**
* Page slug.
*/
public string $pagename;
/**
* Show posts if user has the appropriate capability.
*
* @phpstan-var self::PERM_*
*/
public string $perm;
/**
* Ping status.
*
* @phpstan-var self::COMMENT_STATUS_*
*/
public string $ping_status;
/**
* An array of post IDs to retrieve, sticky posts will be included.
*
* @var array<int, int>
*/
public array $post__in;
/**
* An array of post IDs not to retrieve.
*
* @var array<int, int>
*/
public array $post__not_in;
/**
* The mime type of the post. Used for 'attachment' post_type.
*/
public string $post_mime_type;
/**
* An array of post slugs that results must match.
*
* @var array<int, string>
*/
public array $post_name__in;
/**
* Page ID to retrieve child pages for. Use 0 to only retrieve top-level pages.
*/
public int $post_parent;
/**
* An array containing parent page IDs to query child pages from.
*
* @var array<int, int>
*/
public array $post_parent__in;
/**
* An array containing parent page IDs not to query child pages from.
*
* @var array<int, int>
*/
public array $post_parent__not_in;
/**
* A post type slug (string) or array of post type slugs.
*
* Default 'any' if using 'tax_query'.
*
* @var string|array<int, string>
*/
public $post_type;
/**
* A post status (string) or array of post statuses.
*
* @var string|array<int, string>
*/
public $post_status;
/**
* The number of posts to query for. Use -1 to request all posts.
*
* @phpstan-var positive-int | -1
*/
public int $posts_per_page;
/**
* The number of posts to query for by archive page. Overrides 'posts_per_page' when is_archive(), or is_search() are true.
*
* @phpstan-var positive-int | -1
*/
public int $posts_per_archive_page;
/**
* Search keyword(s).
*
* Prepending a term with a hyphen will exclude posts matching that term. Eg, 'pillow -sofa' will return posts containing 'pillow' but not 'sofa'.
*
* The character used for exclusion can be modified using the the 'wp_query_search_exclusion_prefix' filter.
*/
public string $s;
/**
* Array of column names to be searched.
*
* Accepts 'post_title', 'post_excerpt', and 'post_content'.
*
* Default empty array.
*
* @var array<int, string>
* @phpstan-var list<'post_title'|'post_excerpt'|'post_content'>
*/
public array $search_columns;
/**
* Second of the minute.
*
* Default empty. Accepts numbers 0-59.
*
* @phpstan-var int<0, 59>
*/
public int $second;
/**
* Whether to search by phrase.
*
* Default false.
*/
public bool $sentence;
/**
* Whether to suppress filters.
*
* Default false.
*/
public bool $suppress_filters;
/**
* Tag slug. Comma-separated (either), Plus-separated (all).
*/
public string $tag;
/**
* An array of tag IDs (AND in).
*
* @var array<int, int>
*/
public array $tag__and;
/**
* An array of tag IDs (OR in).
*
* @var array<int, int>
*/
public array $tag__in;
/**
* An array of tag IDs (NOT in).
*
* @var array<int, int>
*/
public array $tag__not_in;
/**
* Tag id or comma-separated list of IDs.
*/
public int $tag_id;
/**
* An array of tag slugs (AND in).
*
* @var array<int, string>
*/
public array $tag_slug__and;
/**
* An array of tag slugs (OR in). unless 'ignore_sticky_posts' is true.
*
* @var array<int, string>
*/
public array $tag_slug__in;
/**
* Post title.
*/
public string $title;
/**
* Whether to update the post meta cache.
*
* Default true.
*/
public bool $update_post_meta_cache;
/**
* Whether to update the post term cache.
*
* Default true.
*/
public bool $update_post_term_cache;
/**
* Whether to update the menu item cache.
*
* Default true.
*/
public bool $update_menu_item_cache;
/**
* Whether to lazy-load term meta. Setting to false will disable cache priming for term meta, so that each get_term_meta() call will hit the database.
*
* Defaults to the value of `$update_post_term_cache`.
*/
public bool $lazy_load_term_meta;
/**
* The week number of the year.
*
* Default empty. Accepts numbers 0-53.
*
* @phpstan-var int<0, 53>
*/
public int $w;
/**
* The four-digit year.
*
* Default empty. Accepts any four-digit year.
*/
public int $year;
}

View File

@ -0,0 +1,245 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `WP_Term_Query` class in WordPress.
*
* @link https://developer.wordpress.org/reference/classes/wp_term_query/__construct/
*/
class WP_Term_Query extends Shared\Base implements MetaQuery\WithArgs {
public const FIELD_ALL = 'all';
public const FIELD_ALL_WITH_OBJECT_ID = 'all_with_object_id';
public const FIELD_IDS = 'ids';
public const FIELD_TT_IDS = 'tt_ids';
public const FIELD_NAMES = 'names';
public const FIELD_SLUGS = 'slugs';
public const FIELD_COUNT = 'count';
public const FIELD_ID_PARENT = 'id=>parent';
public const FIELD_ID_NAME = 'id=>name';
public const FIELD_ID_SLUG = 'id=>slug';
use MetaQuery\ProvidesArgs;
/**
* Taxonomy name, or array of taxonomies, to which results should be limited.
*
* @var string|array<int,string>
*/
public $taxonomy;
/**
* Object ID, or array of object IDs. Results will be limited to terms associated with these objects.
*
* @var int|array<int,int>
*/
public $object_ids;
/**
* Field(s) to order terms by.
*
* Accepts:
*
* - Term fields ('name', 'slug', 'term_group', 'term_id', 'id',
* 'description', 'parent', 'term_order'). Unless `$object_ids`
* is not empty, 'term_order' is treated the same as 'term_id'.
* - 'count' to use the number of objects associated with the term.
* - 'include' to match the 'order' of the $include param.
* - 'slug__in' to match the 'order' of the $slug param.
* - 'meta_value', 'meta_value_num'.
* - The value of `$meta_key`.
* - The array keys of `$meta_query`.
* - 'none' to omit the ORDER BY clause.
*
* Default 'name'.
*/
public string $orderby;
/**
* Whether to order terms in ascending or descending order. Accepts 'ASC' (ascending) or 'DESC' (descending).
*
* Default 'ASC'.
*
* @phpstan-var Shared\Base::ORDER_*
*/
public string $order;
/**
* Whether to hide terms not assigned to any posts.
*
* Default true.
*/
public bool $hide_empty;
/**
* Array of term IDs to include.
*
* @var array<int,int>
*/
public array $include;
/**
* Array of term IDs to exclude. If `$include` is non-empty, `$exclude` is ignored.
*
* @var array<int,int>
*/
public array $exclude;
/**
* Array of term IDs to exclude along with all of their descendant terms. If `$include` is non-empty, `$exclude_tree` is ignored.
*
* @var array<int,int>
*/
public array $exclude_tree;
/**
* Maximum number of terms to return. Accepts 0 (all) or any positive number.
*
* Note that `$number` may not return accurate results when coupled with `$object_ids`. See #41796 for details.
*
* Default 0 (all).
*
* @phpstan-var positive-int | 0
*/
public int $number;
/**
* The number by which to offset the terms query.
*
* @phpstan-var positive-int | 0
*/
public int $offset;
/**
* Term fields to query for.
*
* Accepts:
*
* - 'all' Returns an array of complete term objects (`WP_Term[]`).
* - 'all_with_object_id' Returns an array of term objects
* with the 'object_id' param (`WP_Term[]`). Works only
* when the `$object_ids` parameter is populated.
* - 'ids' Returns an array of term IDs (`int[]`).
* - 'tt_ids' Returns an array of term taxonomy IDs (`int[]`).
* - 'names' Returns an array of term names (`string[]`).
* - 'slugs' Returns an array of term slugs (`string[]`).
* - 'count' Returns the number of matching terms (`int`).
* - 'id=>parent' Returns an associative array of parent term IDs,
* keyed by term ID (`int[]`).
* - 'id=>name' Returns an associative array of term names,
* keyed by term ID (`string[]`).
* - 'id=>slug' Returns an associative array of term slugs,
* keyed by term ID (`string[]`).
*
* Default 'all'.
*
* @phpstan-var self::FIELD_*
*/
public string $fields;
/**
* Whether to return a term count. If true, will take precedence over `$fields`.
*
* Default false.
*/
public bool $count;
/**
* Name or array of names to return term(s) for.
*
* @var string|array<int,string>
*/
public $name;
/**
* Slug or array of slugs to return term(s) for.
*
* @var string|array<int,string>
*/
public $slug;
/**
* Term taxonomy ID, or array of term taxonomy IDs, to match when querying terms.
*
* @var int|array<int,int>
*/
public $term_taxonomy_id;
/**
* Whether to include terms that have non-empty descendants (even if `$hide_empty` is set to true).
*
* Default true.
*/
public bool $hierarchical;
/**
* Search criteria to match terms. Will be SQL-formatted with wildcards before and after.
*/
public string $search;
/**
* Retrieve terms with criteria by which a term is LIKE `$name__like`.
*/
public string $name__like;
/**
* Retrieve terms where the description is LIKE `$description__like`.
*/
public string $description__like;
/**
* Whether to pad the quantity of a term's children in the quantity of each term's "count" object variable.
*
* Default false.
*/
public bool $pad_counts;
/**
* Whether to return terms regardless of ancestry or whether the terms are empty. Accepts 'all' or empty (disabled).
*
* Default ''.
*
* @phpstan-var 'all' | ''
*/
public string $get;
/**
* Term ID to retrieve child terms of. If multiple taxonomies are passed, `$child_of` is ignored.
*/
public int $child_of;
/**
* Parent term ID to retrieve direct-child terms of.
*/
public int $parent;
/**
* True to limit results to terms that have no children. This parameter has no effect on non-hierarchical taxonomies.
*
* Default false.
*/
public bool $childless;
/**
* Unique cache key to be produced when this query is stored in an object cache.
*
* Default 'core'.
*/
public string $cache_domain;
/**
* Whether to cache term information.
*
* Default true.
*/
public bool $cache_results;
/**
* Whether to prime meta caches for matched terms.
*
* Default true.
*/
public bool $update_term_meta_cache;
}

View File

@ -0,0 +1,292 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `WP_User_Query::prepare_query()` method in WordPress.
*
* @link https://developer.wordpress.org/reference/classes/wp_user_query/prepare_query/
*/
class WP_User_Query extends Shared\Base implements MetaQuery\WithArgs {
public const FIELD_ID = 'ID';
public const FIELD_LOGIN = 'user_login';
public const FIELD_EMAIL = 'user_email';
public const FIELD_URL = 'user_url';
public const FIELD_NICENAME = 'user_nicename';
public const FIELD_DISPLAY_NAME = 'display_name';
public const FIELD_REGISTERED = 'user_registered';
public const SEARCH_COLUMN_ID = self::FIELD_ID;
public const SEARCH_COLUMN_LOGIN = self::FIELD_LOGIN;
public const SEARCH_COLUMN_EMAIL = self::FIELD_EMAIL;
public const SEARCH_COLUMN_URL = self::FIELD_URL;
public const SEARCH_COLUMN_NICENAME = self::FIELD_NICENAME;
public const SEARCH_COLUMN_DISPLAY_NAME = self::FIELD_DISPLAY_NAME;
public const WHO_ALL = '';
public const WHO_AUTHORS = 'authors';
use MetaQuery\ProvidesArgs;
/**
* The site ID.
*
* Default is the current site.
*/
public int $blog_id;
/**
* An array or a comma-separated list of role names that users must match to be included in results. Note that this is an inclusive list: users must match *each* role.
*
* Default empty.
*
* @var string|array<int,string>
*/
public $role;
/**
* An array of role names. Matched users must have at least one of these roles.
*
* Default empty array.
*
* @var array<int,string>
*/
public array $role__in;
/**
* An array of role names to exclude. Users matching one or more of these roles will not be included in results.
*
* Default empty array.
*
* @var array<int,string>
*/
public array $role__not_in;
/**
* An array of user IDs to include.
*
* Default empty array.
*
* @var array<int,int>
*/
public array $include;
/**
* An array of user IDs to exclude.
*
* Default empty array.
*
* @var array<int,int>
*/
public array $exclude;
/**
* Search keyword. Searches for possible string matches on columns. When `$search_columns` is left empty, it tries to determine which column to search in based on search string.
*
* Default empty.
*/
public string $search;
/**
* Array of column names to be searched. Accepts 'ID', 'user_login', 'user_email', 'user_url', 'user_nicename', 'display_name'.
*
* Default empty array.
*
* @var array<int,string>
* @phpstan-var array<int,self::SEARCH_COLUMN_*>
*/
public array $search_columns;
/**
* Field(s) to sort the retrieved users by.
*
* May be a single value, an array of values, or a multi-dimensional array with fields as keys and orders ('ASC' or 'DESC') as values. Accepted values are:
*
* - 'ID', 'display_name' (or 'name')
* - 'include'
* - 'user_login' (or 'login')
* - 'login__in'
* - 'user_nicename' (or 'nicename')
* - 'nicename__in'
* - 'user_email (or 'email')
* - 'user_url' (or 'url')
* - 'user_registered' (or 'registered')
* - 'post_count'
* - 'meta_value'
* - 'meta_value_num'
* - the value of `$meta_key`
* - or an array key of `$meta_query`.
*
* To use 'meta_value' or 'meta_value_num', `$meta_key` must be also be defined.
*
* Default 'user_login'.
*
* @var string|mixed[]
*/
public $orderby;
/**
* Designates ascending or descending order of users. Order values passed as part of an `$orderby` array take precedence over this parameter. Accepts 'ASC', 'DESC'.
*
* Default 'ASC'.
*
* @phpstan-var Shared\Base::ORDER_*
*/
public string $order;
/**
* Number of users to offset in retrieved results. Can be used in conjunction with pagination.
*
* Default 0.
*/
public int $offset;
/**
* Number of users to limit the query for. Can be used in conjunction with pagination. Value -1 (all) is supported, but should be used with caution on larger sites.
*
* Default -1 (all users).
*/
public int $number;
/**
* When used with number, defines the page of results to return.
*
* Default 1.
*/
public int $paged;
/**
* Whether to count the total number of users found. If pagination is not needed, setting this to false can improve performance.
*
* Default true.
*/
public bool $count_total;
/**
* Which fields to return. Single or all fields (string), or array of fields.
*
* Accepts:
*
* - 'ID'
* - 'display_name'
* - 'user_login'
* - 'user_nicename'
* - 'user_email'
* - 'user_url'
* - 'user_registered'
*
* Use 'all' for all fields and 'all_with_meta' to include meta fields.
*
* Default 'all'.
*
* @var string|array<int, string>
* @phpstan-var (self::FIELD_*|'all'|'all_with_meta')|array<int,(self::FIELD_*)>
*/
public $fields;
/**
* Type of users to query. Accepts 'authors'.
*
* Default empty (all users).
*
* @phpstan-var self::WHO_*
*/
public string $who;
/**
* Pass an array of post types to filter results to users who have published posts in those post types.
*
* `true` is an alias for all public post types.
*
* @var true|array<int,string>
*/
public $has_published_posts;
/**
* The user nicename.
*
* Default empty.
*/
public string $nicename;
/**
* An array of nicenames to include. Users matching one of these nicenames will be included in results.
*
* Default empty array.
*
* @var array<int,string>
*/
public array $nicename__in;
/**
* An array of nicenames to exclude. Users matching one of these nicenames will not be included in results.
*
* Default empty array.
*
* @var array<int,string>
*/
public array $nicename__not_in;
/**
* The user login.
*
* Default empty.
*/
public string $login;
/**
* An array of logins to include. Users matching one of these logins will be included in results.
*
* Default empty array.
*
* @var array<int,string>
*/
public array $login__in;
/**
* An array of logins to exclude. Users matching one of these logins will not be included in results.
*
* Default empty array.
*
* @var array<int,string>
*/
public array $login__not_in;
/**
* Whether to cache user information.
*
* Default true.
*/
public bool $cache_results;
/**
* An array or a comma-separated list of capability names that users must match to be included in results.
*
* Note that this is an inclusive list: users must match *each* capability.
*
* Does NOT work for capabilities not in the database or filtered via {@see 'map_meta_cap'}.
*
* @var string|array<int,string>
*/
public $capability;
/**
* An array of capability names. Matched users must have at least one of these capabilities.
*
* Does NOT work for capabilities not in the database or filtered via {@see 'map_meta_cap'}.
*
* @var array<int,string>
*/
public array $capability__in;
/**
* An array of capability names to exclude. Users matching one or more of these capabilities will not be included in results.
*
* Does NOT work for capabilities not in the database or filtered via {@see 'map_meta_cap'}.
*
* @var array<int,string>
*/
public array $capability__not_in;
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `get_categories()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/get_categories/
* @link https://developer.wordpress.org/reference/classes/wp_term_query/__construct/
*/
class get_categories extends WP_Term_Query {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `get_comments()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/get_comments/
* @link https://developer.wordpress.org/reference/classes/wp_comment_query/__construct/
*/
class get_comments extends WP_Comment_Query {}

View File

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `get_posts()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/get_posts/
* @link https://developer.wordpress.org/reference/classes/wp_query/parse_query/
*/
class get_posts extends WP_Query {
/**
* Total number of posts to retrieve. Is an alias of `$posts_per_page` in `WP_Query`.
*
* Accepts -1 for all.
*
* Default 5.
*
* @phpstan-var positive-int|-1
*/
public int $numberposts;
/**
* Category ID or comma-separated list of IDs (this or any children). Is an alias of `$cat` in `WP_Query`.
*
* Default 0.
*
* @var int|string
*/
public $category;
/**
* An array of post IDs to retrieve, sticky posts will be included. Is an alias of `$post__in` in `WP_Query`.
*
* Default empty array.
*
* @var array<int, int>
*/
public array $include;
/**
* An array of post IDs not to retrieve.
*
* Default empty array.
*
* @var array<int, int>
*/
public array $exclude;
/**
* Whether to suppress filters.
*
* Default true.
*/
public bool $suppress_filters;
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `get_tags()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/get_tags/
* @link https://developer.wordpress.org/reference/classes/wp_term_query/__construct/
*/
class get_tags extends WP_Term_Query {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `get_terms()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/get_terms/
* @link https://developer.wordpress.org/reference/classes/wp_term_query/__construct/
*/
class get_terms extends WP_Term_Query {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `get_users()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/get_users/
* @link https://developer.wordpress.org/reference/classes/wp_user_query/prepare_query/
*/
class get_users extends WP_User_Query {}

View File

@ -0,0 +1,128 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `paginate_links()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/paginate_links/
*/
class paginate_links extends Shared\Base {
/**
* Base of the paginated url.
*
* Default empty.
*/
public string $base;
/**
* Format for the pagination structure.
*
* Default empty.
*/
public string $format;
/**
* The total amount of pages.
*
* Default is the value WP_Query's `max_num_pages` or 1.
*/
public int $total;
/**
* The current page number.
*
* Default is 'paged' query var or 1.
*/
public int $current;
/**
* The value for the aria-current attribute. Possible values are 'page', 'step', 'location', 'date', 'time', 'true', 'false'.
*
* Default is 'page'.
*
* @phpstan-var 'page'|'step'|'location'|'date'|'time'|'true'|'false'
*/
public string $aria_current;
/**
* Whether to show all pages.
*
* Default false.
*/
public bool $show_all;
/**
* How many numbers on either the start and the end list edges.
*
* Default 1.
*/
public int $end_size;
/**
* How many numbers to either side of the current pages.
*
* Default 2.
*/
public int $mid_size;
/**
* Whether to include the previous and next links in the list.
*
* Default true.
*/
public bool $prev_next;
/**
* The previous page text.
*
* Default '&laquo; Previous'.
*/
public string $prev_text;
/**
* The next page text.
*
* Default 'Next &raquo;'.
*/
public string $next_text;
/**
* Controls format of the returned value. Possible values are 'plain', 'array' and 'list'.
*
* Default is 'plain'.
*/
public string $type;
/**
* An array of query args to add.
*
* Default false.
*
* @var mixed[]
*/
public array $add_args;
/**
* A string to append to each link.
*
* Default empty.
*/
public string $add_fragment;
/**
* A string to appear before the page number.
*
* Default empty.
*/
public string $before_page_number;
/**
* A string to append after the page number.
*
* Default empty.
*/
public string $after_page_number;
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `register_block_type` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/register_block_type/
*/
class register_block_type extends WP_Block_Type {}

View File

@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `register_meta()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/register_meta/
*/
class register_meta extends Shared\Base {
public const TYPE_STRING = 'string';
public const TYPE_BOOLEAN = 'boolean';
public const TYPE_INTEGER = 'integer';
public const TYPE_NUMBER = 'number';
public const TYPE_ARRAY = 'array';
public const TYPE_OBJECT = 'object';
/**
* A subtype; e.g. if the object type is "post", the post type.
*
* If left empty, the meta key will be registered on the entire object type.
*
* Default empty.
*/
public string $object_subtype;
/**
* The type of data associated with this meta key.
*
* Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'.
*
* @phpstan-var self::TYPE_*
*/
public string $type;
/**
* A description of the data attached to this meta key.
*/
public string $description;
/**
* Whether the meta key has one value per object, or an array of values per object.
*/
public bool $single;
/**
* The default value returned from `get_metadata()` if no value has been set yet.
*
* When using a non-single meta key, the default value is for the first entry. In other words, when calling `get_metadata()` with `$single` set to `false`, the default value given here will be wrapped in an array.
*
* @var mixed
*/
public $default;
/**
* A function or method to call when sanitizing `$meta_key` data.
*
* @var callable
* @phpstan-var (callable(mixed,string,string,string): mixed)|(callable(mixed,string,string): mixed)
*/
public $sanitize_callback;
/**
* A function or method to call when performing `edit_post_meta`, `add_post_meta`, and `delete_post_meta` capability checks.
*
* @var callable
* @phpstan-var (callable(bool,string,string,string): bool)|(callable(bool,string,string): bool)
*/
public $auth_callback;
/**
* Whether data associated with this meta key can be considered public and should be accessible via the REST API.
*
* A custom post type must also declare support for custom fields for registered meta to be accessible via REST. When registering complex meta values this argument may optionally be an array with 'schema' or 'prepare_callback' keys instead of a boolean.
*
* @var bool|array<string, mixed>
* @phpstan-var bool|array{
* schema: array<string,mixed>,
* prepare_callback: callable(mixed,\WP_REST_Request,array<string,mixed>): mixed,
* }
*/
public $show_in_rest;
/**
* Whether to enable revisions support for this meta_key.
*
* Can only be used when the object type is 'post'.
*/
public bool $revisions_enabled;
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `register_post_meta()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/register_post_meta/
* @link https://developer.wordpress.org/reference/functions/register_meta/
*/
class register_post_meta extends register_meta {}

View File

@ -0,0 +1,98 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `register_post_status()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/register_post_status/
*/
class register_post_status extends Shared\Base {
/**
* A descriptive name for the post status marked for translation.
*
* Defaults to value of `$post_status`.
*/
public string $label;
/**
* Descriptive text to use for nooped plurals.
*
* Default array of `$label`, twice.
*
* @var mixed[]
*/
public array $label_count;
/**
* Whether to exclude posts with this post status from search results.
*
* Default is value of `$internal`.
*/
public bool $exclude_from_search;
/**
* FOR INTERNAL USE ONLY! Whether the status is built-in.
*
* Default false.
*/
protected bool $_builtin;
/**
* Whether posts of this status should be shown in the front end of the site.
*
* Default false.
*/
public bool $public;
/**
* Whether the status is for internal use only.
*
* Default false.
*/
public bool $internal;
/**
* Whether posts with this status should be protected.
*
* Default false.
*/
public bool $protected;
/**
* Whether posts with this status should be private.
*
* Default false.
*/
public bool $private;
/**
* Whether posts with this status should be publicly-queryable.
*
* Default is value of `$public`.
*/
public bool $publicly_queryable;
/**
* Whether to include posts in the edit listing for their post type.
*
* Default is the opposite value of `$internal`.
*/
public bool $show_in_admin_all_list;
/**
* Show in the list of statuses with post counts at the top of the edit listings, e.g. All (12) | Published (9) | My Custom Status (2)
*
* Default is the opposite value of `$internal`.
*/
public bool $show_in_admin_status_list;
/**
* Whether the post has a floating creation date.
*
* Default `false`.
*/
public bool $date_floating;
}

View File

@ -0,0 +1,381 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `register_post_type()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/register_post_type/
*/
class register_post_type extends Shared\Base {
public const TEMPLATE_LOCK_ALL = 'all';
public const TEMPLATE_LOCK_INSERT = 'insert';
public const TEMPLATE_LOCK_FALSE = false;
/**
* Name of the post type shown in the menu. Usually plural.
*
* Default is value of `$labels['name']`.
*/
public string $label;
/**
* An array of labels for this post type.
*
* If not set, post labels are inherited for non-hierarchical types and page labels for hierarchical ones.
*
* See `get_post_type_labels()` for a full list of supported labels.
*
* @var array<string,string>
*/
public array $labels;
/**
* A short descriptive summary of what the post type is.
*
* Default empty.
*/
public string $description;
/**
* Whether a post type is intended for use publicly either via the admin interface or by front-end users.
*
* While the default settings of `$exclude_from_search`, `$publicly_queryable`, `$show_ui`, and `$show_in_nav_menus`
* are inherited from `$public`, each does not rely on this relationship and controls a very specific intention.
*
* Default false.
*/
public bool $public;
/**
* Whether the post type is hierarchical (e.g. page).
*
* Default false.
*/
public bool $hierarchical;
/**
* Whether to exclude posts with this post type from front end search results.
*
* Default is the opposite value of `$public`.
*/
public bool $exclude_from_search;
/**
* Whether queries can be performed on the front end for the post type as part of `parse_request()`.
*
* Endpoints would include:
*
* - `?post_type={post_type_key}`
* - `?{post_type_key}={single_post_slug}`
* - `?{post_type_query_var}={single_post_slug}`
*
* If not set, the default is inherited from `$public`.
*/
public bool $publicly_queryable;
/**
* Whether to generate and allow a UI for managing this post type in the admin.
*
* Default is value of `$public`.
*/
public bool $show_ui;
/**
* Where to show the post type in the admin menu. To work, `$show_ui` must be true.
*
* - If true the post type is shown in its own top level menu.
* - If false, no menu is shown.
* - If a string of an existing top level menu (eg. 'tools.php' or 'edit.php?post_type=page'), the post type will be placed as a sub-menu of that.
*
* Default is value of `$show_ui`.
*
* @var bool|string
*/
public $show_in_menu;
/**
* Makes this post type available for selection in navigation menus.
*
* Default is value of `$public`.
*/
public bool $show_in_nav_menus;
/**
* Makes this post type available via the admin bar.
*
* Default is value of `$show_in_menu`.
*/
public bool $show_in_admin_bar;
/**
* Whether to include the post type in the REST API.
*
* Set this to true for the post type to be available in the block editor.
*/
public bool $show_in_rest;
/**
* To change the base URL of REST API route.
*
* Default is `$post_type`.
*/
public string $rest_base;
/**
* To change the namespace URL of REST API route.
*
* Default is wp/v2.
*/
public string $rest_namespace;
/**
* REST API controller class name.
*
* Default is 'WP_REST_Posts_Controller'.
*
* @phpstan-var class-string<\WP_REST_Controller>
*/
public string $rest_controller_class;
/**
* REST API autosave controller class name.
*
* Default is 'WP_REST_Autosaves_Controller'.
*
* @phpstan-var class-string<\WP_REST_Controller>
*/
public string $autosave_rest_controller_class;
/**
* REST API revisions controller class name.
*
* Default is 'WP_REST_Revisions_Controller'.
*
* @phpstan-var class-string<\WP_REST_Controller>
*/
public string $revisions_rest_controller_class;
/**
* A flag to direct the REST API controllers for autosave / revisions should be registered before/after the post type controller.
*/
public bool $late_route_registration;
/**
* The position in the menu order the post type should appear. To work, `$show_in_menu` must be true.
*
* Default null (at the bottom).
*/
public int $menu_position;
/**
* The URL to the icon to be used for this menu.
*
* - Pass a base64-encoded SVG using a data URI, which will be colored to match the color scheme -- this should begin with `data:image/svg+xml;base64,`.
* - Pass the name of a Dashicons helper class to use a font icon, e.g. `dashicons-chart-pie`.
* - Pass `'none'` to leave `div.wp-menu-image` empty so an icon can be added via CSS.
*
* Defaults to use the posts icon.
*/
public string $menu_icon;
/**
* The strings to use to build the read, edit, and delete capabilities.
*
* Passed as an array to allow for alternative plurals when using this argument as a base to construct the capabilities, e.g. array('story', 'stories').
*
* Default [ 'post', 'posts' ].
*
* @var array<int,string>
* @phpstan-var array{
* 0: string,
* 1: string,
* }
*/
public array $capability_type;
/**
* Array of capabilities for this post type.
*
* `$capability_type` is used as a base to construct capabilities by default. See `get_post_type_capabilities()`.
*
* @var array<string,string>
* @phpstan-var array{
* edit_post?: string,
* read_post?: string,
* delete_post?: string,
* edit_posts?: string,
* edit_others_posts?: string,
* delete_posts?: string,
* publish_posts?: string,
* read_private_posts?: string,
* read?: string,
* delete_private_posts?: string,
* delete_published_posts?: string,
* delete_others_posts?: string,
* edit_private_posts?: string,
* edit_published_posts?: string,
* create_posts?: string,
* }
*/
public array $capabilities;
/**
* Whether to use the internal default meta capability handling.
*
* Default false.
*/
public bool $map_meta_cap;
/**
* Core feature(s) the post type supports. Serves as an alias for calling `add_post_type_support()` directly.
*
* Core features include:
*
* - 'title'
* - 'editor'
* - 'comments'
* - 'revisions'
* - 'trackbacks'
* - 'author'
* - 'excerpt'
* - 'page-attributes'
* - 'thumbnail'
* - 'custom-fields'
* - 'post-formats'
*
* Additionally, the 'revisions' feature dictates whether the post type will store revisions, and the 'comments'
* feature dictates whether the comments count will show on the edit screen. A feature can also be specified as
* an array of arguments to provide additional information about supporting that feature. Example:
*
* array( 'my_feature', array( 'field' => 'value' ) )
*
* Default is an array containing 'title' and 'editor'.
*
* @var array<int, (string|array<string, mixed>)>
*/
public array $supports;
/**
* Provide a callback function that sets up the meta boxes for the edit form.
*
* Do `remove_meta_box()` and `add_meta_box()` calls in the callback.
*
* Default null.
*
* @var callable
* @phpstan-var callable(\WP_Post): void
*/
public $register_meta_box_cb;
/**
* An array of taxonomy identifiers that will be registered for the post type.
*
* Taxonomies can be registered later with `register_taxonomy()` or `register_taxonomy_for_object_type()`.
*
* Default empty array.
*
* @var array<int,string>
*/
public array $taxonomies;
/**
* Whether there should be post type archives, or if a string, the archive slug to use.
*
* Will generate the proper rewrite rules if `$rewrite` is enabled.
*
* Default false.
*
* @var bool|string
*/
public $has_archive;
/**
* Triggers the handling of rewrites for this post type.
*
* To prevent rewrite, set to false.
*
* Defaults to true, using `$post_type` as slug. To specify rewrite rules,
* an array can be passed.
*
* @var bool|array<string,mixed>
* @phpstan-var bool|array{
* slug?: string,
* with_front?: bool,
* feeds?: bool,
* pages?: bool,
* ep_mask?: int,
* }
*/
public $rewrite;
/**
* Sets the query_var key for this post type.
*
* Defaults to `$post_type` key.
*
* - If false, a post type cannot be loaded at `?{query_var}={post_slug}`.
* - If specified as a string, the query `?{query_var_string}={post_slug}` will be valid.
*
* @var string|bool
*/
public $query_var;
/**
* Whether to allow this post type to be exported.
*
* Default true.
*/
public bool $can_export;
/**
* Whether to delete posts of this type when deleting a user.
*
* - If true, posts of this type belonging to the user will be moved to Trash when the user is deleted.
* - If false, posts of this type belonging to the user will *not* be trashed or deleted.
* - If not set (the default), posts are trashed if post type supports the 'author' feature. Otherwise posts are not trashed or deleted.
*
* Default null.
*/
public bool $delete_with_user;
/**
* Array of blocks to use as the default initial state for an editor session.
*
* Each item should be an array containing block name and optional attributes.
*
* Default empty array.
*
* @var array<int, array<int, string|array<string, mixed>>>
*/
public array $template;
/**
* Whether the block template should be locked if `$template` is set.
*
* - If set to 'all', the user is unable to insert new blocks, move existing blocks and delete blocks.
* - If set to 'insert', the user is able to move existing blocks but is unable to insert new blocks and delete blocks
*
* Default false.
*
* @var string|false
* @phpstan-var self::TEMPLATE_LOCK_*
*/
public $template_lock;
/**
* FOR INTERNAL USE ONLY! True if this post type is a native or "built-in" post_type.
*
* Default false.
*/
protected bool $_builtin;
/**
* FOR INTERNAL USE ONLY! URL segment to use for edit link of this post type.
*
* Default 'post.php?post=%d'.
*/
protected string $_edit_link;
}

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `register_rest_field()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/register_rest_field/
*/
class register_rest_field extends Shared\Base {
/**
* The callback function used to retrieve the field value.
*
* Default is 'null', the field will not be returned in the response. The function will be passed the prepared object data.
*
* @var callable
* @phpstan-var callable(mixed[],string,\WP_REST_Request): mixed
*/
public $get_callback;
/**
* The callback function used to set and update the field value.
*
* Default is 'null', the value cannot be set or updated. The function will be passed the model object, like `WP_Post`.
*
* @var callable
* @phpstan-var callable(mixed,object,string,\WP_REST_Request,string): mixed
*/
public $update_callback;
/**
* The schema for this field.
*
* Default is 'null', no schema entry will be returned.
*
* @var mixed[]
*/
public array $schema;
}

View File

@ -0,0 +1,205 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `register_taxonomy()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/register_taxonomy/
*/
class register_taxonomy extends Shared\Base {
/**
* An array of labels for this taxonomy. By default, Tag labels are used for non-hierarchical taxonomies, and Category labels are used for hierarchical taxonomies. See accepted values in `get_taxonomy_labels()`.
*
* Default empty array.
*
* @var array<string,string>
*/
public array $labels;
/**
* A short descriptive summary of what the taxonomy is for.
*
* Default empty.
*/
public string $description;
/**
* Whether a taxonomy is intended for use publicly either via the admin interface or by front-end users. The default settings of `$publicly_queryable`, `$show_ui`, and `$show_in_nav_menus` are inherited from `$public`.
*/
public bool $public;
/**
* Whether the taxonomy is publicly queryable. If not set, the default is inherited from `$public`
*/
public bool $publicly_queryable;
/**
* Whether the taxonomy is hierarchical.
*
* Default false.
*/
public bool $hierarchical;
/**
* Whether to generate and allow a UI for managing terms in this taxonomy in the admin. If not set, the default is inherited from `$public` (default true).
*/
public bool $show_ui;
/**
* Whether to show the taxonomy in the admin menu. If true, the taxonomy is shown as a submenu of the object type menu. If false, no menu is shown. `$show_ui` must be true. If not set, default is inherited from `$show_ui` (default true).
*/
public bool $show_in_menu;
/**
* Makes this taxonomy available for selection in navigation menus. If not set, the default is inherited from `$public` (default true).
*/
public bool $show_in_nav_menus;
/**
* Whether to include the taxonomy in the REST API. Set this to true for the taxonomy to be available in the block editor.
*/
public bool $show_in_rest;
/**
* To change the base url of REST API route.
*
* Default is `$taxonomy`.
*/
public string $rest_base;
/**
* To change the namespace URL of REST API route.
*
* Default is wp/v2.
*/
public string $rest_namespace;
/**
* REST API Controller class name.
*
* Default is 'WP_REST_Terms_Controller'.
*
* @phpstan-var class-string<\WP_REST_Controller>
*/
public string $rest_controller_class;
/**
* Whether to list the taxonomy in the Tag Cloud Widget controls. If not set, the default is inherited from `$show_ui` (default true).
*/
public bool $show_tagcloud;
/**
* Whether to show the taxonomy in the quick/bulk edit panel. It not set, the default is inherited from `$show_ui` (default true).
*/
public bool $show_in_quick_edit;
/**
* Whether to display a column for the taxonomy on its post type listing screens.
*
* Default false.
*/
public bool $show_admin_column;
/**
* Provide a callback function for the meta box display. If not set, `post_categories_meta_box()` is used for hierarchical taxonomies, and `post_tags_meta_box()` is used for non-hierarchical. If false, no meta box is shown.
*
* @var false|callable
* @phpstan-var false|callable(\WP_Post,mixed[]): void
*/
public $meta_box_cb;
/**
* Callback function for sanitizing taxonomy data saved from a meta box. If no callback is defined, an appropriate one is determined based on the value of `$meta_box_cb`.
*
* @var callable
* @phpstan-var callable(string,mixed): (int|string)[]
*/
public $meta_box_sanitize_cb;
/**
* Array of capabilities for this taxonomy.
*
* @var array<string,string>
* @phpstan-var array{
* manage_terms: string,
* edit_terms: string,
* delete_terms: string,
* assign_terms: string,
* }
*/
public array $capabilities;
/**
* Triggers the handling of rewrites for this taxonomy.
*
* Default true, using `$taxonomy` as slug.
*
* To prevent rewrite, set to false. To specify rewrite rules, an array can be passed with any of these keys:
*
* @var bool|array<string,mixed>
* @phpstan-var bool|array{
* slug?: string,
* with_front?: bool,
* hierarchical?: bool,
* ep_mask?: int,
* }
*/
public $rewrite;
/**
* Sets the query var key for this taxonomy.
*
* Default `$taxonomy` key. If false, a taxonomy cannot be loaded at `?{query_var}={term_slug}`. If a string, the query `?{query_var}={term_slug}` will be valid.
*
* @var string|bool
*/
public $query_var;
/**
* Works much like a hook, in that it will be called when the count is updated.
*
* Default `_update_post_term_count()` for taxonomies attached to post types, which confirms that the objects are published before counting them.
*
* Default `_update_generic_term_count()` for taxonomies attached to other object types, such as users.
*
* @var callable
* @phpstan-var callable(int[],\WP_Taxonomy): void
*/
public $update_count_callback;
/**
* Default term to be used for the taxonomy.
*
* @var string|array<string,string>
* @phpstan-var string|array{
* name: string,
* slug?: string,
* description?: string,
* }
*/
public $default_term;
/**
* Whether terms in this taxonomy should be sorted in the order they are provided to `wp_set_object_terms()`.
*
* Default false.
*/
public bool $sort;
/**
* Array of arguments to automatically use inside `wp_get_object_terms()` for this taxonomy.
*
* @var array<string,mixed>
*/
public array $args;
/**
* FOR INTERNAL USE ONLY! True if this taxonomy is a native or "built-in" post_type.
*
* Default false.
*/
protected bool $_builtin;
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `register_term_meta()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/register_term_meta/
* @link https://developer.wordpress.org/reference/functions/register_meta/
*/
class register_term_meta extends register_meta {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_count_terms()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_count_terms/
* @link https://developer.wordpress.org/reference/classes/wp_term_query/__construct/
*/
class wp_count_terms extends WP_Term_Query {}

76
vendor/johnbillion/args/src/wp_die.php vendored Normal file
View File

@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_die()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_die/
*/
class wp_die extends Shared\Base {
/**
* The HTTP response code.
*
* Default 200 for Ajax requests, 500 otherwise.
*/
public int $response;
/**
* A URL to include a link to.
*
* Only works in combination with `$link_text`.
*
* Default empty string.
*/
public string $link_url;
/**
* A label for the link to include.
*
* Only works in combination with `$link_url`.
*
* Default empty string.
*/
public string $link_text;
/**
* Whether to include a link to go back.
*
* Default false.
*/
public bool $back_link;
/**
* The text direction.
*
* This is only useful internally, when WordPress is still loading and the site's locale is not set up yet. Accepts 'rtl' and 'ltr'.
*
* Default is the value of is_rtl().
*
* @phpstan-var 'rtl'|'ltr'
*/
public string $text_direction;
/**
* Character set of the HTML output.
*
* Default 'utf-8'.
*/
public string $charset;
/**
* Error code to use.
*
* Default is 'wp_die', or the main error code if `$message` is a `WP_Error`.
*/
public string $code;
/**
* Whether to exit the process after completion.
*
* Default true.
*/
public bool $exit;
}

View File

@ -0,0 +1,123 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_dropdown_categories()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_dropdown_categories/
*/
class wp_dropdown_categories extends WP_Term_Query {
/**
* The 'id' of an element that contains descriptive text for the select.
*
* Default empty.
*/
public string $aria_describedby;
/**
* Text to display for showing all categories.
*
* Default empty.
*/
public string $show_option_all;
/**
* Text to display for showing no categories.
*
* Default empty.
*/
public string $show_option_none;
/**
* Value to use when no category is selected.
*
* Default empty.
*/
public string $option_none_value;
/**
* Whether to include post counts.
*
* Default false.
*/
public bool $show_count;
/**
* Whether to echo or return the generated markup.
*
* Default true.
*/
public bool $echo;
/**
* Maximum depth.
*
* Default 0.
*/
public int $depth;
/**
* Tab index for the select element.
*
* Default 0 (no tabindex).
*/
public int $tab_index;
/**
* Value for the 'id' attribute of the select element.
*
* Defaults to the value of `$name`.
*/
public string $id;
/**
* Value for the 'class' attribute of the select element.
*
* Default 'postform'.
*/
public string $class;
/**
* Value of the option that should be selected.
*
* Default 0.
*
* @var int|string
*/
public $selected;
/**
* Term field that should be used to populate the 'value' attribute of the option elements.
*
* Accepts any valid term field: 'term_id', 'name', 'slug', 'term_group', 'term_taxonomy_id', 'taxonomy', 'description', 'parent', 'count'.
*
* Default 'term_id'.
*/
public string $value_field;
/**
* True to skip generating markup if no categories are found.
*
* Default false (create select element even if no categories are found).
*/
public bool $hide_if_empty;
/**
* Whether the `<select>` element should have the HTML5 'required' attribute.
*
* Default false.
*/
public bool $required;
/**
* Walker object to use to build the output.
*
* Default empty which results in a `Walker_CategoryDropdown` instance being used.
*
* @var \Walker
*/
public $walker;
}

View File

@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_dropdown_languages()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_dropdown_languages/
*/
class wp_dropdown_languages extends Shared\Base {
/**
* ID attribute of the select element.
*
* Default 'locale'.
*/
public string $id;
/**
* Name attribute of the select element.
*
* Default 'locale'.
*/
public string $name;
/**
* List of installed languages, contain only the locales.
*
* Default empty array.
*
* @var mixed[]
*/
public array $languages;
/**
* List of available translations.
*
* Default result of wp_get_available_translations().
*
* @var mixed[]
*/
public array $translations;
/**
* Language which should be selected.
*
* Default empty.
*/
public string $selected;
/**
* Whether to echo the generated markup.
*
* Default true.
*/
public bool $echo;
/**
* Whether to show available translations.
*
* Default true.
*/
public bool $show_available_translations;
/**
* Whether to show an option to fall back to the site's locale.
*
* Default false.
*/
public bool $show_option_site_default;
/**
* Whether to show an option for English (United States).
*
* Default true.
*/
public bool $show_option_en_us;
/**
* Whether the English (United States) option uses an explicit value of en_US instead of an empty value.
*
* Default true.
*/
public bool $explicit_option_en_us;
}

View File

@ -0,0 +1,133 @@
<?php
declare(strict_types=1);
namespace Args;
use WP_Term;
/**
* Arguments for the `$args` parameter of the `wp_generate_tag_cloud()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_generate_tag_cloud/
*/
class wp_generate_tag_cloud extends Shared\Base {
/**
* Smallest font size used to display tags.
*
* Paired with the value of `$unit`, to determine CSS text size unit.
*
* Default 8 (pt).
*/
public int $smallest;
/**
* Largest font size used to display tags.
*
* Paired with the value of `$unit`, to determine CSS text size unit.
*
* Default 22 (pt).
*/
public int $largest;
/**
* CSS text size unit to use with the `$smallest` and `$largest` values.
*
* Accepts any valid CSS text size unit.
*
* Default 'pt'.
*/
public string $unit;
/**
* The number of tags to return.
*
* Accepts any positive integer or zero to return all.
*
* Default 0.
*
* @phpstan-var positive-int | 0
*/
public int $number;
/**
* Format to display the tag cloud in.
*
* Accepts 'flat' (tags separated with spaces), 'list' (tags displayed in an unordered list), or 'array' (returns an array).
*
* Default 'flat'.
*/
public string $format;
/**
* HTML or text to separate the tags.
*
* Default "\n" (newline).
*/
public string $separator;
/**
* Value to order tags by.
*
* Accepts 'name' or 'count'.
*
* The {@see 'tag_cloud_sort'} filter can also affect how tags are sorted.
*
* Default 'name'.
*/
public string $orderby;
/**
* How to order the tags.
*
* Accepts 'ASC' (ascending), 'DESC' (descending), or 'RAND' (random).
*
* Default 'ASC'.
*
* @phpstan-var 'ASC'|'DESC'|'RAND'
*/
public string $order;
/**
* Whether to enable filtering of the final output via {@see 'wp_generate_tag_cloud'}.
*
* Default true.
*/
public bool $filter;
/**
* Nooped plural text from _n_noop() to supply to tag counts.
*
* Default null.
*
* @var mixed[]
*/
public array $topic_count_text;
/**
* Callback used to generate nooped plural text for tag counts based on the count.
*
* Default null.
*
* @var callable
* @phpstan-var callable(int,WP_Term,mixed[]): int
*/
public $topic_count_text_callback;
/**
* Callback used to determine the tag count scaling value.
*
* Default default_topic_count_scale().
*
* @var callable
* @phpstan-var callable(int): int
*/
public $topic_count_scale_callback;
/**
* Whether to display the tag counts.
*
* Default false.
*/
public bool $show_count;
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_get_nav_menus()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_get_nav_menus/
* @link https://developer.wordpress.org/reference/classes/wp_term_query/__construct/
*/
class wp_get_nav_menus extends WP_Term_Query {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_get_object_terms()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_get_object_terms/
* @link https://developer.wordpress.org/reference/classes/wp_term_query/__construct/
*/
class wp_get_object_terms extends WP_Term_Query {}

View File

@ -0,0 +1,209 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_insert_post()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_insert_post/
*/
class wp_insert_post extends Shared\Base {
public const COMMENT_STATUS_OPEN = 'open';
public const COMMENT_STATUS_CLOSED = 'closed';
/**
* The post ID. If equal to something other than 0, the post with that ID will be updated.
*
* Default 0.
*/
public int $ID;
/**
* The ID of the user who added the post.
*
* Default is the current user ID.
*/
public int $post_author;
/**
* The date of the post.
*
* Default is the current time.
*/
public string $post_date;
/**
* The date of the post in the GMT timezone.
*
* Default is the value of `$post_date`.
*/
public string $post_date_gmt;
/**
* The post content.
*
* Default empty.
*/
public string $post_content;
/**
* The filtered post content.
*
* Default empty.
*/
public string $post_content_filtered;
/**
* The post title.
*
* Default empty.
*/
public string $post_title;
/**
* The post excerpt.
*
* Default empty.
*/
public string $post_excerpt;
/**
* The post status.
*
* Default 'draft'.
*/
public string $post_status;
/**
* The post type.
*
* Default 'post'.
*/
public string $post_type;
/**
* Whether the post can accept comments. Accepts 'open' or 'closed'.
*
* Default is the value of 'default_comment_status' option.
*
* @phpstan-var self::COMMENT_STATUS_*
*/
public string $comment_status;
/**
* Whether the post can accept pings. Accepts 'open' or 'closed'.
*
* Default is the value of 'default_ping_status' option.
*
* @phpstan-var self::COMMENT_STATUS_*
*/
public string $ping_status;
/**
* The password to access the post.
*
* Default empty.
*/
public string $post_password;
/**
* The post name.
*
* Default is the sanitized post title when creating a new post.
*/
public string $post_name;
/**
* Space or carriage return-separated list of URLs to ping.
*
* Default empty.
*/
public string $to_ping;
/**
* Space or carriage return-separated list of URLs that have been pinged.
*
* Default empty.
*/
public string $pinged;
/**
* Set this for the post it belongs to, if any.
*
* Default 0.
*/
public int $post_parent;
/**
* The order the post should be displayed in.
*
* Default 0.
*/
public int $menu_order;
/**
* The mime type of the post.
*
* Default empty.
*/
public string $post_mime_type;
/**
* Global Unique ID for referencing the post.
*
* Default empty.
*/
public string $guid;
/**
* Page template to use.
*
* Default empty.
*/
public string $page_template;
/**
* Array of category IDs.
*
* Defaults to value of the 'default_category' option.
*
* @var array<int,int>
*/
public array $post_category;
/**
* Array of tag names, slugs, or IDs.
*
* Default empty.
*
* @var array<int,(int|string)>
*/
public array $tags_input;
/**
* Array of taxonomy terms keyed by their taxonomy name.
*
* Default empty.
*
* @var array<string,mixed>
*/
public array $tax_input;
/**
* Array of post meta values keyed by their post meta key.
*
* Default empty.
*
* @var array<string,mixed>
*/
public array $meta_input;
/**
* The post ID to be used when inserting a new post. If specified, must not match any existing post ID.
*
* Default 0.
*/
public int $import_id;
}

View File

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `$args` parameter of the `wp_insert_term()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_insert_term/
*/
class wp_insert_term extends Shared\Base {
/**
* Slug of the term to make this term an alias of. Accepts a term slug.
*
* Default empty string.
*/
public string $alias_of;
/**
* The term description.
*
* Default empty string.
*/
public string $description;
/**
* The id of the parent term.
*
* Default 0.
*/
public int $parent;
/**
* The term slug to use.
*
* Default empty string.
*/
public string $slug;
}

View File

@ -0,0 +1,161 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_insert_user()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_insert_user/
*/
class wp_insert_user extends Shared\Base {
/**
* User ID. If supplied, the user will be updated.
*/
public int $ID;
/**
* The plain-text user password.
*/
public string $user_pass;
/**
* The user's login username.
*/
public string $user_login;
/**
* The URL-friendly user name.
*/
public string $user_nicename;
/**
* The user URL.
*/
public string $user_url;
/**
* The user email address.
*/
public string $user_email;
/**
* The user's display name.
*
* Default is the user's username.
*/
public string $display_name;
/**
* The user's nickname.
*
* Default is the user's username.
*/
public string $nickname;
/**
* The user's first name. For new users, will be used to build the first part of the user's display name if `$display_name` is not specified.
*/
public string $first_name;
/**
* The user's last name. For new users, will be used to build the second part of the user's display name if `$display_name` is not specified.
*/
public string $last_name;
/**
* The user's biographical description.
*/
public string $description;
/**
* Whether to enable the rich-editor for the user. Accepts 'true' or 'false' as a string literal, not boolean.
*
* Default 'true'.
*
* @phpstan-var 'true'|'false'
*/
public string $rich_editing;
/**
* Whether to enable the rich code editor for the user. Accepts 'true' or 'false' as a string literal, not boolean.
*
* Default 'true'.
*
* @phpstan-var 'true'|'false'
*/
public string $syntax_highlighting;
/**
* Whether to enable comment moderation keyboard shortcuts for the user. Accepts 'true' or 'false' as a string literal, not boolean.
*
* Default 'false'.
*
* @phpstan-var 'true'|'false'
*/
public string $comment_shortcuts;
/**
* Admin color scheme for the user.
*
* Default 'fresh'.
*/
public string $admin_color;
/**
* Whether the user should always access the admin over https.
*
* Default false.
*/
public bool $use_ssl;
/**
* Date the user registered. Format is 'Y-m-d H:i:s'.
*/
public string $user_registered;
/**
* Password reset key.
*
* Default empty.
*/
public string $user_activation_key;
/**
* Multisite only. Whether the user is marked as spam.
*
* Default false.
*/
public bool $spam;
/**
* Whether to display the Admin Bar for the user on the site's front end. Accepts 'true' or 'false' as a string literal, not boolean.
*
* Default 'true'.
*
* @phpstan-var 'true'|'false'
*/
public string $show_admin_bar_front;
/**
* User's role.
*/
public string $role;
/**
* User's locale.
*
* Default empty.
*/
public string $locale;
/**
* Array of user meta values keyed by their meta key.
*
* Default empty.
*
* @var array<string,mixed>
*/
public array $meta_input;
}

View File

@ -0,0 +1,148 @@
<?php
declare(strict_types=1);
namespace Args;
use Walker;
use WP_Term;
/**
* Arguments for the `wp_nav_menu()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_nav_menu/
*/
class wp_nav_menu extends Shared\Base {
/**
* Desired menu. Accepts a menu ID, slug, name, or object.
*
* Default empty.
*
* @var int|string|WP_Term
*/
public $menu;
/**
* CSS class to use for the ul element which forms the menu.
*
* Default 'menu'.
*/
public string $menu_class;
/**
* The ID that is applied to the ul element which forms the menu.
*
* Default is the menu slug, incremented.
*/
public string $menu_id;
/**
* Whether to wrap the ul, and what to wrap it with.
*
* Default 'div'.
*/
public string $container;
/**
* Class that is applied to the container.
*
* Default 'menu-{menu slug}-container'.
*/
public string $container_class;
/**
* The ID that is applied to the container.
*
* Default empty.
*/
public string $container_id;
/**
* The aria-label attribute that is applied to the container when it's a nav element.
*
* Default empty.
*/
public string $container_aria_label;
/**
* If the menu doesn't exist, a callback function will fire.
*
* Default is 'wp_page_menu'. Set to false for no fallback.
*
* @var callable|false
* @phpstan-var (callable(mixed[]): (string|void))|false
*/
public $fallback_cb;
/**
* Text before the link markup.
*
* Default empty.
*/
public string $before;
/**
* Text after the link markup.
*
* Default empty.
*/
public string $after;
/**
* Text before the link text.
*
* Default empty.
*/
public string $link_before;
/**
* Text after the link text.
*
* Default empty.
*/
public string $link_after;
/**
* Whether to echo the menu or return it.
*
* Default true.
*/
public bool $echo;
/**
* How many levels of the hierarchy are to be included. 0 means all.
*
* Default 0.
*/
public int $depth;
/**
* Instance of a custom walker class.
*
* Default empty.
*
* @var Walker
*/
public object $walker;
/**
* Theme location to be used. Must be registered with register_nav_menu() in order to be selectable by the user.
*/
public string $theme_location;
/**
* How the list items should be wrapped. Uses printf() format with numbered placeholders.
*
* Default is a ul with an id and class.
*/
public string $items_wrap;
/**
* Whether to preserve whitespace within the menu's HTML. Accepts 'preserve' or 'discard'.
*
* Default 'preserve'.
*
* @phpstan-var 'preserve'|'discard'
*/
public string $item_spacing;
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_remote_get()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_remote_get/
* @link https://developer.wordpress.org/reference/classes/wp_http/request/
*/
class wp_remote_get extends WP_Http {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_remote_head()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_remote_head/
* @link https://developer.wordpress.org/reference/classes/wp_http/request/
*/
class wp_remote_head extends WP_Http {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_remote_post()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_remote_post/
* @link https://developer.wordpress.org/reference/classes/wp_http/request/
*/
class wp_remote_post extends WP_Http {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_remote_request()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_remote_request/
* @link https://developer.wordpress.org/reference/classes/wp_http/request/
*/
class wp_remote_request extends WP_Http {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_safe_remote_get()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_safe_remote_get/
* @link https://developer.wordpress.org/reference/classes/wp_http/request/
*/
class wp_safe_remote_get extends WP_Http {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_safe_remote_head()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_safe_remote_head/
* @link https://developer.wordpress.org/reference/classes/wp_http/request/
*/
class wp_safe_remote_head extends WP_Http {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_safe_remote_post()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_safe_remote_post/
* @link https://developer.wordpress.org/reference/classes/wp_http/request/
*/
class wp_safe_remote_post extends WP_Http {}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_safe_remote_request()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_safe_remote_request/
* @link https://developer.wordpress.org/reference/classes/wp_http/request/
*/
class wp_safe_remote_request extends WP_Http {}

View File

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_update_post()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_update_post/
* @link https://developer.wordpress.org/reference/functions/wp_insert_post/
*/
class wp_update_post extends wp_insert_post {
}

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `$args` parameter of the `wp_update_term()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_update_term/
*/
class wp_update_term extends Shared\Base {
/**
* Slug of the term to make this term an alias of. Accepts a term slug.
*
* Default empty string.
*
*/
public string $alias_of;
/**
* The term description.
*
* Default empty string.
*/
public string $description;
/**
* The id of the parent term.
*
* Default 0.
*/
public int $parent;
/**
* The term slug to use.
*
* Default empty string.
*/
public string $slug;
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Args;
/**
* Arguments for the `wp_update_user()` function in WordPress.
*
* @link https://developer.wordpress.org/reference/functions/wp_update_user/
* @link https://developer.wordpress.org/reference/functions/wp_insert_user/
*/
class wp_update_user extends wp_insert_user {}

339
vendor/johnbillion/extended-cpts/LICENSE vendored Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{{description}}
Copyright (C) {{year}} {{fullname}}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -0,0 +1,189 @@
[![Build Status](https://img.shields.io/github/actions/workflow/status/johnbillion/extended-cpts/integration-tests.yml?branch=develop&style=flat-square)](https://github.com/johnbillion/extended-cpts/actions)
[![Stable Release](https://img.shields.io/packagist/v/johnbillion/extended-cpts.svg?style=flat-square)](https://packagist.org/packages/johnbillion/extended-cpts)
[![License](https://img.shields.io/badge/license-GPL_v2%2B-blue.svg?style=flat-square)](https://github.com/johnbillion/extended-cpts/blob/trunk/LICENSE)
[![PHP 7 and 8](https://img.shields.io/badge/php-7%20/%208-blue.svg?style=flat-square)](https://wordpress.org/support/update-php/)
[![Documentation](https://img.shields.io/badge/documentation-wiki-blue.svg?style=flat-square)](https://github.com/johnbillion/extended-cpts/wiki)
# Extended CPTs #
Extended CPTs is a library which provides extended functionality to WordPress custom post types and taxonomies. This allows developers to quickly build post types and taxonomies without having to write the same code again and again.
Extended CPTs works with both the block editor and the classic editor.
[See the wiki for full documentation.](https://github.com/johnbillion/extended-cpts/wiki)
Not your first time here? See [Recent Changes for Developers](https://github.com/johnbillion/extended-cpts/wiki/Recent-Changes-for-Developers) to see what features are new in recent versions of Extended CPTs.
## Improved Defaults for Post Types ##
* Automatically generated labels and post updated messages (in English)
* Public post type with admin UI and post thumbnails enabled
* Hierarchical with `page` capability type
* Optimal admin menu placement
## Improved Defaults for Taxonomies ##
* Automatically generated labels and term updated messages (in English)
* Hierarchical public taxonomy with admin UI enabled
## Extended Admin Features ##
* Declarative creation of table columns on the post type listing screen:
* Columns for post meta, taxonomy terms, featured images, post fields, [Posts 2 Posts](https://wordpress.org/plugins/posts-to-posts/) connections, and custom functions
* Sortable columns for post meta, taxonomy terms, and post fields
* User capability restrictions
* Default sort column and sort order
* Declarative creation of table columns on the taxonomy term listing screen:
* Columns for term meta and custom functions
* User capability restrictions
* Filter controls on the post type listing screen to enable filtering posts by post meta, taxonomy terms, post author, and post dates
* Override the 'Featured Image' and 'Enter title here' text
* Several custom meta boxes available for taxonomies on the post editing screen:
* Simplified list of checkboxes
* Radio buttons
* Dropdown menu
* Custom function
* Post types and taxonomies automatically added to the 'At a Glance' section on the dashboard
* Post types optionally added to the 'Recently Published' section on the dashboard
## Extended Front-end Features for Post Types ##
* Specify a custom permalink structure:
* For example `reviews/%year%/%month%/%review%`
* Supports all relevant rewrite tags including dates and custom taxonomies
* Automatic integration with the [Rewrite Rule Testing](https://wordpress.org/plugins/rewrite-testing/) plugin
* Specify public query vars which enable filtering by post meta and post dates
* Specify public query vars which enable sorting by post meta, taxonomy terms, and post fields
* Override default public or private query vars such as `posts_per_page`, `orderby`, `order`, and `nopaging`
* Add the post type to the site's main RSS feed
## Minimum Requirements ##
* **PHP:** 7.4
- Tested up to PHP 8.4
* **WordPress:** 5.8
- Tested up to WP 6.7
## Installation ##
Extended CPTs is a developer library, not a plugin, which means you need to include it as a dependency in your project. Install it using Composer:
```bash
composer require johnbillion/extended-cpts
```
Other means of installation or usage, particularly bundling within a plugin, is not officially supported and done at your own risk.
## Usage ##
Need a simple post type with no frills? You can register a post type with a single parameter:
```php
add_action( 'init', function() {
register_extended_post_type( 'article' );
} );
```
And you can register a taxonomy with just two parameters:
```php
add_action( 'init', function() {
register_extended_taxonomy( 'location', 'article' );
} );
```
Try it. You'll have a hierarchical public post type with an admin UI, a hierarchical public taxonomy with an admin UI, and all the labels and updated messages for them will be automatically generated.
Or for a bit more functionality:
```php
add_action( 'init', function() {
register_extended_post_type( 'story', [
# Add the post type to the site's main RSS feed:
'show_in_feed' => true,
# Show all posts on the post type archive:
'archive' => [
'nopaging' => true,
],
# Add some custom columns to the admin screen:
'admin_cols' => [
'story_featured_image' => [
'title' => 'Illustration',
'featured_image' => 'thumbnail'
],
'story_published' => [
'title_icon' => 'dashicons-calendar-alt',
'meta_key' => 'published_date',
'date_format' => 'd/m/Y'
],
'story_genre' => [
'taxonomy' => 'genre'
],
],
# Add some dropdown filters to the admin screen:
'admin_filters' => [
'story_genre' => [
'taxonomy' => 'genre'
],
'story_rating' => [
'meta_key' => 'star_rating',
],
],
], [
# Override the base names used for labels:
'singular' => 'Story',
'plural' => 'Stories',
'slug' => 'stories',
] );
register_extended_taxonomy( 'genre', 'story', [
# Use radio buttons in the meta box for this taxonomy on the post editing screen:
'meta_box' => 'radio',
# Add a custom column to the admin screen:
'admin_cols' => [
'updated' => [
'title_cb' => function() {
return '<em>Last</em> Updated';
},
'meta_key' => 'updated_date',
'date_format' => 'd/m/Y'
],
],
] );
} );
```
Bam, we now have:
* A 'Stories' post type, with correctly generated labels and post updated messages, three custom columns in the admin area (two of which are sortable), stories added to the main RSS feed, and all stories displayed on the post type archive.
* A 'Genre' taxonomy attached to the 'Stories' post type, with correctly generated labels and term updated messages, and a custom column in the admin area.
The `register_extended_post_type()` and `register_extended_taxonomy()` functions are ultimately wrappers for the `register_post_type()` and `register_taxonomy()` functions in WordPress core, so any of the parameters from those functions can be used.
There's quite a bit more you can do. [See the wiki for full documentation.](https://github.com/johnbillion/extended-cpts/wiki)
## Contributing and Testing ##
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for information on contributing.
## License: GPLv2 or later ##
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

View File

@ -0,0 +1,80 @@
{
"name": "johnbillion/extended-cpts",
"description": "A library which provides extended functionality to WordPress custom post types and taxonomies.",
"license": "GPL-2.0-or-later",
"authors": [
{
"name": "John Blackbourn",
"homepage": "https://johnblackbourn.com/"
}
],
"homepage": "https://github.com/johnbillion/extended-cpts/",
"require": {
"php": ">= 7.4.0",
"johnbillion/args": "^1.4.1 || ^2.0"
},
"require-dev": {
"automattic/phpcs-neutron-standard": "1.7.0",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7",
"johnbillion/falsey-assertequals-detector": "*",
"johnbillion/plugin-infrastructure": "dev-trunk",
"johnbillion/wp-compat": "0.3.1",
"lucatume/wp-browser": "3.2.3",
"phpcompatibility/phpcompatibility-wp": "2.1.5",
"phpstan/phpstan": "1.12.12",
"phpstan/phpstan-phpunit": "1.4.1",
"roots/wordpress-core-installer": "1.100.0",
"roots/wordpress-full": "*",
"szepeviktor/phpstan-wordpress": "1.3.5",
"wp-coding-standards/wpcs": "2.3.0"
},
"autoload": {
"psr-4": {
"ExtCPTs\\": "src",
"ExtCPTs\\Tests\\": "tests/integration"
},
"files": [
"functions.php"
]
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true,
"roots/wordpress-core-installer": true
},
"preferred-install": "dist",
"sort-packages": true
},
"extra": {
"wordpress-install-dir": "vendor/wordpress/wordpress"
},
"scripts": {
"test": [
"@composer validate --strict --no-check-lock",
"@test:phpstan",
"@test:phpcs",
"@test:start",
"@test:integration",
"@test:stop"
],
"test:destroy": [
"tests-destroy"
],
"test:integration": [
"integration-tests"
],
"test:phpcs": [
"phpcs -nps --colors --report-code --report-summary --report-width=80 --cache=tests/cache/phpcs.json --basepath='./' ."
],
"test:phpstan": [
"codecept build",
"phpstan analyze -v --memory-limit=1024M"
],
"test:start": [
"tests-start"
],
"test:stop": [
"tests-stop"
]
}
}

View File

@ -0,0 +1,32 @@
<?php
declare( strict_types=1 );
/**
* Extended custom post types and taxonomies for WordPress.
*
* @package ExtendedCPTs
* @author John Blackbourn <https://johnblackbourn.com>
* @link https://github.com/johnbillion/extended-cpts
* @copyright 2012-2024 John Blackbourn
* @license GPL v2 or later
* @version 5.0.11
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
require_once __DIR__ . '/functions.php';
require_once __DIR__ . '/src/PostType.php';
require_once __DIR__ . '/src/PostTypeAdmin.php';
require_once __DIR__ . '/src/Taxonomy.php';
require_once __DIR__ . '/src/TaxonomyAdmin.php';
require_once __DIR__ . '/src/Walker/Checkboxes.php';
require_once __DIR__ . '/src/Walker/Dropdown.php';
require_once __DIR__ . '/src/Walker/Radios.php';

View File

@ -0,0 +1,136 @@
<?php
declare( strict_types=1 );
use ExtCPTs\PostType;
use ExtCPTs\PostTypeAdmin;
use ExtCPTs\Taxonomy;
use ExtCPTs\TaxonomyAdmin;
/**
* Registers a custom post type.
*
* The `$args` parameter accepts all the standard arguments for `register_post_type()` in addition to several custom
* arguments that provide extended functionality. Some of the default arguments differ from the defaults in
* `register_post_type()`.
*
* @link https://github.com/johnbillion/extended-cpts/wiki/Registering-Post-Types
* @see register_post_type() for default arguments.
*
* @param string $post_type The post type name.
* @param mixed[] $args {
* Optional. The post type arguments.
*
* @type array $admin_cols Associative array of admin screen columns to show for this post type.
* @type array $admin_filters Associative array of admin screen filters to show for this post type.
* @type array $archive Associative array of query vars to override on this post type's archive.
* @type bool $block_editor Force the use of the block editor for this post type. Must be used in
* combination with the `show_in_rest` argument. The primary use of this argument
* is to prevent the block editor from being used by setting it to false when
* `show_in_rest` is set to true.
* @type bool $dashboard_glance Whether to show this post type on the 'At a Glance' section of the admin
* dashboard. Default true.
* @type bool $dashboard_activity Whether to show this post type on the 'Recently Published' section of the
* admin dashboard. Default true.
* @type string $enter_title_here Placeholder text which appears in the title field for this post type.
* @type string $featured_image Text which replaces the 'Featured Image' phrase for this post type.
* @type bool $quick_edit Whether to show Quick Edit links for this post type. Default true.
* @type bool $show_in_feed Whether to include this post type in the site's main feed. Default false.
* @type array $site_filters Associative array of query vars and their parameters for front end filtering.
* @type array $site_sortables Associative array of query vars and their parameters for front end sorting.
* }
* @param string[] $names {
* Optional. The plural, singular, and slug names.
*
* @type string $plural The plural form of the post type name.
* @type string $singular The singular form of the post type name.
* @type string $slug The slug used in the permalinks for this post type.
* }
* @phpstan-param array{
* plural?: string,
* singular?: string,
* slug?: string,
* } $names
* @return PostType
*/
function register_extended_post_type( string $post_type, array $args = [], array $names = [] ): PostType {
if ( ! did_action( 'init' ) ) {
trigger_error( esc_html__( 'Post types must be registered on the "init" hook.', 'extended-cpts' ), E_USER_WARNING );
}
$cpt = new PostType( $post_type, $args, $names );
$cpt->init();
if ( is_admin() ) {
$admin = new PostTypeAdmin( $cpt, $cpt->args );
$admin->init();
}
return $cpt;
}
/**
* Registers a custom taxonomy.
*
* The `$args` parameter accepts all the standard arguments for `register_taxonomy()` in addition to several custom
* arguments that provide extended functionality. Some of the default arguments differ from the defaults in
* `register_taxonomy()`.
*
* @link https://github.com/johnbillion/extended-cpts/wiki/Registering-taxonomies
* @see register_taxonomy() for default arguments.
*
* @param string $taxonomy The taxonomy name.
* @param string|string[] $object_type Name(s) of the object type(s) for the taxonomy.
* @param mixed[] $args {
* Optional. The taxonomy arguments.
*
* @type string $meta_box The name of the custom meta box to use on the post editing screen for this
* taxonomy. Three custom meta boxes are provided: 'radio' for a meta box with radio
* inputs, 'simple' for a meta box with a simplified list of checkboxes, and
* 'dropdown' for a meta box with a dropdown menu. You can also pass the name of a
* callback function, eg my_super_meta_box(), or boolean false to remove the meta
* box. Default null, meaning the standard meta box is used.
* @type bool $checked_ontop Whether to always show checked terms at the top of the meta box. This allows you
* to override WordPress' default behaviour if necessary. Default false if you're
* using a custom meta box (see the $meta_box argument), default true otherwise.
* @type bool $dashboard_glance Whether to show this taxonomy on the 'At a Glance' section of the admin dashboard.
* Default false.
* @type array $admin_cols Associative array of admin screen columns to show for this taxonomy. See the
* `TaxonomyAdmin::cols()` method for more information.
* @type bool $exclusive This parameter isn't feature complete. All it does currently is set the meta box
* to the 'radio' meta box, thus meaning any given post can only have one term
* associated with it for that taxonomy. 'exclusive' isn't really the right name for
* this, as terms aren't exclusive to a post, but rather each post can exclusively
* have only one term. It's not feature complete because you can edit a post in
* Quick Edit and give it more than one term from the taxonomy.
* @type bool $allow_hierarchy All this does currently is disable hierarchy in the taxonomy's rewrite rules.
* Default false.
* }
* @param string[] $names {
* Optional. The plural, singular, and slug names.
*
* @type string $plural The plural form of the taxonomy name.
* @type string $singular The singular form of the taxonomy name.
* @type string $slug The slug used in the term permalinks for this taxonomy.
* }
* @phpstan-param array{
* plural?: string,
* singular?: string,
* slug?: string,
* } $names
* @return Taxonomy
*/
function register_extended_taxonomy( string $taxonomy, $object_type, array $args = [], array $names = [] ): Taxonomy {
if ( ! did_action( 'init' ) ) {
trigger_error( esc_html__( 'Taxonomies must be registered on the "init" hook.', 'extended-cpts' ), E_USER_WARNING );
}
$taxo = new Taxonomy( $taxonomy, (array) $object_type, $args, $names );
$taxo->init();
if ( is_admin() ) {
$admin = new TaxonomyAdmin( $taxo, $taxo->args );
$admin->init();
}
return $taxo;
}

View File

@ -0,0 +1,91 @@
<?php
declare( strict_types=1 );
namespace ExtCPTs\Args;
class PostType extends \Args\register_post_type {
/**
* Associative array of admin screen columns to show for this post type.
*
* @var array<string,mixed>
*/
public array $admin_cols;
/**
* Associative array of admin screen filters to show for this post type.
*
* @var array<string,mixed>
*/
public array $admin_filters;
/**
* Associative array of query vars to override on this post type's archive.
*
* @var array<string,mixed>
*/
public array $archive;
/**
* Force the use of the block editor for this post type. Must be used in
* combination with the `show_in_rest` argument.
*
* The primary use of this argument
* is to prevent the block editor from being used by setting it to false when
* `show_in_rest` is set to true.
*/
public bool $block_editor;
/**
* Whether to show this post type on the 'At a Glance' section of the admin
* dashboard.
*
* Default true.
*/
public bool $dashboard_glance;
/**
* Whether to show this post type on the 'Recently Published' section of the
* admin dashboard.
*
* Default true.
*/
public bool $dashboard_activity;
/**
* Placeholder text which appears in the title field for this post type.
*/
public string $enter_title_here;
/**
* Text which replaces the 'Featured Image' phrase for this post type.
*/
public string $featured_image;
/**
* Whether to show Quick Edit links for this post type.
*
* Default true.
*/
public bool $quick_edit;
/**
* Whether to include this post type in the site's main feed.
*
* Default false.
*/
public bool $show_in_feed;
/**
* Associative array of query vars and their parameters for front end filtering.
*
* @var array<string,mixed>
*/
public array $site_filters;
/**
* Associative array of query vars and their parameters for front end sorting.
*
* @var array<string,mixed>
*/
public array $site_sortables;
}

View File

@ -0,0 +1,67 @@
<?php
declare( strict_types=1 );
namespace ExtCPTs\Args;
class Taxonomy extends \Args\register_taxonomy {
/**
* The name of the custom meta box to use on the post editing screen for this taxonomy.
*
* Three custom meta boxes are provided:
*
* - 'radio' for a meta box with radio inputs
* - 'simple' for a meta box with a simplified list of checkboxes
* - 'dropdown' for a meta box with a dropdown menu
*
* You can also pass the name of a callback function, eg `my_super_meta_box()`,
* or boolean `false` to remove the meta box.
*
* Default `null`, meaning the standard meta box is used.
*/
public string $meta_box;
/**
* Whether to always show checked terms at the top of the meta box.
*
* This allows you to override WordPress' default behaviour if necessary.
*
* Default false if you're using a custom meta box (see the `$meta_box` argument), default true otherwise.
*/
public bool $checked_ontop;
/**
* Whether to show this taxonomy on the 'At a Glance' section of the admin dashboard.
*
* Default false.
*/
public bool $dashboard_glance;
/**
* Associative array of admin screen columns to show for this taxonomy.
*
* See the `TaxonomyAdmin::cols()` method for more information.
*
* @var array<string,mixed>
*/
public array $admin_cols;
/**
* This parameter isn't feature complete. All it does currently is set the meta box
* to the 'radio' meta box, thus meaning any given post can only have one term
* associated with it for that taxonomy.
*
* 'exclusive' isn't really the right name for this, as terms aren't exclusive to a
* post, but rather each post can exclusively have only one term. It's not feature
* complete because you can edit a post in Quick Edit and give it more than one term
* from the taxonomy.
*/
public bool $exclusive;
/**
* All this does currently is disable hierarchy in the taxonomy's rewrite rules.
*
* Default false.
*/
public bool $allow_hierarchy;
}

View File

@ -0,0 +1,74 @@
<?php
declare( strict_types=1 );
namespace ExtCPTs;
/**
* @codeCoverageIgnore
*/
abstract class ExtendedRewriteTesting {
/**
* @return array<string,array<string,string>>
*/
abstract public function get_tests(): array;
/**
* @param array<string,mixed> $struct
* @param array<string,mixed> $additional
* @return array<string,string>
*/
public function get_rewrites( array $struct, array $additional ): array {
global $wp_rewrite;
if ( ! $wp_rewrite->using_permalinks() ) {
return [];
}
$new = [];
$rules = $wp_rewrite->generate_rewrite_rules(
$struct['struct'],
$struct['ep_mask'],
$struct['paged'],
$struct['feed'],
$struct['forcomments'],
$struct['walk_dirs'],
$struct['endpoints']
);
$rules = array_merge( $rules, $additional );
$feedregex = implode( '|', $wp_rewrite->feeds );
$replace = [
'(.+?)' => 'hello',
'.+?' => 'hello',
'([^/]+)' => 'world',
'[^/]+' => 'world',
'(?:/([0-9]+))?' => '/456',
'([0-9]{4})' => date( 'Y' ),
'[0-9]{4}' => date( 'Y' ),
'([0-9]{1,2})' => date( 'm' ),
'[0-9]{1,2}' => date( 'm' ),
'([0-9]{1,})' => '123',
'[0-9]{1,}' => '789',
'([0-9]+)' => date( 'd' ),
'[0-9]+' => date( 'd' ),
"({$feedregex})" => end( $wp_rewrite->feeds ),
'/?' => '/',
'$' => '',
];
foreach ( $rules as $regex => $result ) {
$regex = str_replace( array_keys( $replace ), $replace, $regex );
// Change '$2' to '$matches[2]'
$result = preg_replace( '/\$([0-9]+)/', '\$matches[$1]', $result );
$new[ "/{$regex}" ] = $result;
if ( false !== strpos( $regex, $replace['(?:/([0-9]+))?'] ) ) {
// Add an extra rule for this optional block
$regex = str_replace( $replace['(?:/([0-9]+))?'], '', $regex );
$new[ "/{$regex}" ] = $result;
}
}
return $new;
}
}

View File

@ -0,0 +1,837 @@
<?php
declare( strict_types=1 );
namespace ExtCPTs;
use WP_Post_Type;
use WP_Post;
use WP_Query;
use WP_Taxonomy;
use WP_Term;
use WP;
class PostType {
/**
* Default arguments for custom post types.
*
* The arguments listed are the ones which differ from the defaults in `register_post_type()`.
*
* @var array<string,mixed>
*/
protected array $defaults = [
'public' => true,
'menu_position' => 6,
'capability_type' => 'page',
'hierarchical' => true,
'supports' => [
'title',
'editor',
'thumbnail',
],
'site_filters' => null, # Custom arg
'site_sortables' => null, # Custom arg
'show_in_feed' => false, # Custom arg
'archive' => null, # Custom arg
'featured_image' => null, # Custom arg
];
public string $post_type;
public string $post_slug;
public string $post_singular;
public string $post_plural;
public string $post_singular_low;
public string $post_plural_low;
/**
* @var array<string,mixed>
*/
public array $args;
/**
* Class constructor.
*
* @see register_extended_post_type()
*
* @param string $post_type The post type name.
* @param array<string,mixed> $args Optional. The post type arguments.
* @param array<string,string> $names Optional. The plural, singular, and slug names.
* @phpstan-param array{
* plural?: string,
* singular?: string,
* slug?: string,
* } $names
*/
public function __construct( string $post_type, array $args = [], array $names = [] ) {
/**
* Filter the arguments for a post type.
*
* @since 4.4.1
*
* @param array<string,mixed> $args The post type arguments.
* @param string $post_type The post type name.
*/
$args = apply_filters( 'ext-cpts/args', $args, $post_type );
/**
* Filter the arguments for this post type.
*
* @since 2.4.0
*
* @param array<string,mixed> $args The post type arguments.
*/
$args = apply_filters( "ext-cpts/{$post_type}/args", $args );
/**
* Filter the plural, singular, and slug names for a post type.
*
* @since 4.4.1
*
* @param array<string,string> $names The plural, singular, and slug names (if any were specified).
* @param string $post_type The post type name.
*/
$names = apply_filters( 'ext-cpts/names', $names, $post_type );
/**
* Filter the plural, singular, and slug names for this post type.
*
* @since 2.4.0
*
* @param array<string,string> $names The plural, singular, and slug names (if any were specified).
*/
$names = apply_filters( "ext-cpts/{$post_type}/names", $names );
if ( isset( $names['singular'] ) ) {
$this->post_singular = $names['singular'];
} else {
$this->post_singular = ucwords(
str_replace(
[
'-',
'_',
],
' ',
$post_type
)
);
}
if ( isset( $names['slug'] ) ) {
$this->post_slug = $names['slug'];
} elseif ( isset( $names['plural'] ) ) {
$this->post_slug = $names['plural'];
} else {
$this->post_slug = $post_type . 's';
}
if ( isset( $names['plural'] ) ) {
$this->post_plural = $names['plural'];
} else {
$this->post_plural = $this->post_singular . 's';
}
$this->post_type = strtolower( $post_type );
$this->post_slug = strtolower( $this->post_slug );
# Build our base post type names:
# Lower-casing is not forced if the name looks like an initialism, eg. FAQ.
if ( ! preg_match( '/[A-Z]{2,}/', $this->post_singular ) ) {
$this->post_singular_low = strtolower( $this->post_singular );
} else {
$this->post_singular_low = $this->post_singular;
}
if ( ! preg_match( '/[A-Z]{2,}/', $this->post_plural ) ) {
$this->post_plural_low = strtolower( $this->post_plural );
} else {
$this->post_plural_low = $this->post_plural;
}
# Build our labels:
# Why aren't these translatable?
# Answer: https://github.com/johnbillion/extended-cpts/pull/5#issuecomment-33756474
$this->defaults['labels'] = [
'name' => $this->post_plural,
'singular_name' => $this->post_singular,
'menu_name' => $this->post_plural,
'name_admin_bar' => $this->post_singular,
'add_new' => sprintf( 'Add New %s', $this->post_singular ),
'add_new_item' => sprintf( 'Add New %s', $this->post_singular ),
'edit_item' => sprintf( 'Edit %s', $this->post_singular ),
'new_item' => sprintf( 'New %s', $this->post_singular ),
'view_item' => sprintf( 'View %s', $this->post_singular ),
'view_items' => sprintf( 'View %s', $this->post_plural ),
'search_items' => sprintf( 'Search %s', $this->post_plural ),
'not_found' => sprintf( 'No %s found.', $this->post_plural_low ),
'not_found_in_trash' => sprintf( 'No %s found in trash.', $this->post_plural_low ),
'parent_item_colon' => sprintf( 'Parent %s:', $this->post_singular ),
'all_items' => sprintf( 'All %s', $this->post_plural ),
'archives' => sprintf( '%s Archives', $this->post_singular ),
'attributes' => sprintf( '%s Attributes', $this->post_singular ),
'insert_into_item' => sprintf( 'Insert into %s', $this->post_singular_low ),
'uploaded_to_this_item' => sprintf( 'Uploaded to this %s', $this->post_singular_low ),
'filter_items_list' => sprintf( 'Filter %s list', $this->post_plural_low ),
'filter_by_date' => 'Filter by date',
'items_list_navigation' => sprintf( '%s list navigation', $this->post_plural ),
'items_list' => sprintf( '%s list', $this->post_plural ),
'item_published' => sprintf( '%s published.', $this->post_singular ),
'item_published_privately' => sprintf( '%s published privately.', $this->post_singular ),
'item_reverted_to_draft' => sprintf( '%s reverted to draft.', $this->post_singular ),
'item_scheduled' => sprintf( '%s scheduled.', $this->post_singular ),
'item_updated' => sprintf( '%s updated.', $this->post_singular ),
'item_link' => sprintf( '%s Link', $this->post_singular ),
'item_link_description' => sprintf( 'A link to a %s.', $this->post_singular_low ),
'item_trashed' => sprintf( '%s trashed.', $this->post_singular ),
'template_name' => sprintf( 'Single item: %s', $this->post_singular ),
];
# Build the featured image labels:
if ( isset( $args['featured_image'] ) ) {
$featured_image_low = strtolower( $args['featured_image'] );
$this->defaults['labels']['featured_image'] = $args['featured_image'];
$this->defaults['labels']['set_featured_image'] = sprintf( 'Set %s', $featured_image_low );
$this->defaults['labels']['remove_featured_image'] = sprintf( 'Remove %s', $featured_image_low );
$this->defaults['labels']['use_featured_image'] = sprintf( 'Use as %s', $featured_image_low );
}
# Only set default rewrites if we need them
if ( isset( $args['public'] ) && ! $args['public'] ) {
$this->defaults['rewrite'] = false;
} else {
$this->defaults['rewrite'] = [
'slug' => $this->post_slug,
'with_front' => false,
];
}
# Merge our args with the defaults:
$this->args = array_merge( $this->defaults, $args );
# This allows the 'labels' and 'rewrite' args to contain all, some, or no values:
foreach ( [ 'labels', 'rewrite' ] as $arg ) {
if ( isset( $args[ $arg ] ) && is_array( $args[ $arg ] ) && is_array( $this->defaults[ $arg ] ) ) {
$this->args[ $arg ] = array_merge( $this->defaults[ $arg ], $args[ $arg ] );
}
}
# Enable post type archives by default
if ( ! isset( $this->args['has_archive'] ) ) {
$this->args['has_archive'] = $this->args['public'];
}
}
/**
* Initialise the post type by adding the necessary actions and filters.
*/
public function init(): void {
# Front-end sortables:
if ( $this->args['site_sortables'] && ! is_admin() ) {
add_action( 'pre_get_posts', [ $this, 'maybe_sort_by_fields' ] );
add_filter( 'posts_clauses', [ $this, 'maybe_sort_by_taxonomy' ], 10, 2 );
}
# Front-end filters:
if ( $this->args['site_filters'] && ! is_admin() ) {
add_action( 'pre_get_posts', [ $this, 'maybe_filter' ] );
add_filter( 'query_vars', [ $this, 'add_query_vars' ] );
}
# Post type in the site's main feed:
if ( $this->args['show_in_feed'] ) {
add_filter( 'request', [ $this, 'add_to_feed' ] );
}
# Post type archive query vars:
if ( $this->args['archive'] && ! is_admin() ) {
add_filter( 'parse_request', [ $this, 'override_private_query_vars' ], 1 );
}
# Custom post type permastruct:
if ( $this->args['rewrite'] && ! empty( $this->args['rewrite']['permastruct'] ) ) {
add_action( 'registered_post_type', [ $this, 'registered_post_type' ], 1, 2 );
add_filter( 'post_type_link', [ $this, 'post_type_link' ], 1, 2 );
}
# Rewrite testing:
if ( $this->args['rewrite'] ) {
add_filter( 'rewrite_testing_tests', [ $this, 'rewrite_testing_tests' ], 1 );
}
# Register post type:
$this->register_post_type();
/**
* Fired when the extended post type instance is set up.
*
* @since 3.1.0
*
* @param \ExtCPTs\PostType $instance The extended post type instance.
*/
do_action( "ext-cpts/{$this->post_type}/instance", $this );
}
/**
* Set the relevant query vars for filtering posts by our front-end filters.
*
* @param WP_Query $wp_query The current WP_Query object.
*/
public function maybe_filter( WP_Query $wp_query ): void {
if ( empty( $wp_query->query['post_type'] ) || ! in_array( $this->post_type, (array) $wp_query->query['post_type'], true ) ) {
return;
}
$vars = self::get_filter_vars( $wp_query->query, $this->args['site_filters'], $this->post_type );
if ( empty( $vars ) ) {
return;
}
foreach ( $vars as $key => $value ) {
if ( is_array( $value ) ) {
$query = $wp_query->get( $key );
if ( empty( $query ) ) {
$query = [];
}
$value = array_merge( $query, $value );
}
$wp_query->set( $key, $value );
}
}
/**
* Set the relevant query vars for sorting posts by our front-end sortables.
*
* @param WP_Query $wp_query The current WP_Query object.
*/
public function maybe_sort_by_fields( WP_Query $wp_query ): void {
if ( empty( $wp_query->query['post_type'] ) || ! in_array( $this->post_type, (array) $wp_query->query['post_type'], true ) ) {
return;
}
// If we've not specified an order:
if ( empty( $wp_query->query['orderby'] ) ) {
// Loop over our sortables to find the default sort field (if there is one):
foreach ( $this->args['site_sortables'] as $id => $col ) {
if ( is_array( $col ) && isset( $col['default'] ) ) {
// @TODO Don't set 'order' if 'orderby' is an array (WP 4.0+)
$wp_query->query['orderby'] = $id;
$wp_query->query['order'] = ( 'desc' === strtolower( $col['default'] ) ? 'desc' : 'asc' );
break;
}
}
}
$sort = self::get_sort_field_vars( $wp_query->query, $this->args['site_sortables'] );
if ( empty( $sort ) ) {
return;
}
foreach ( $sort as $key => $value ) {
$wp_query->set( $key, $value );
}
}
/**
* Filter the query's SQL clauses so we can sort posts by taxonomy terms.
*
* @param array<string,string> $clauses Array of the current query's SQL clauses.
* @param WP_Query $wp_query The current `WP_Query` object.
* @return array<string,string> Array of SQL clauses.
*/
public function maybe_sort_by_taxonomy( array $clauses, WP_Query $wp_query ): array {
if ( empty( $wp_query->query['post_type'] ) || ! in_array( $this->post_type, (array) $wp_query->query['post_type'], true ) ) {
return $clauses;
}
$sort = self::get_sort_taxonomy_clauses( $clauses, $wp_query->query, $this->args['site_sortables'] );
if ( empty( $sort ) ) {
return $clauses;
}
return array_merge( $clauses, $sort );
}
/**
* Get the array of private query vars for the given filters, to apply to the current query in order to filter it by the
* given public query vars.
*
* @param array<string,mixed> $query The public query vars, usually from `$wp_query->query`.
* @param array<string,mixed> $filters The filters valid for this query (usually the value of the `admin_filters` or
* `site_filters` argument when registering an extended post type).
* @param string $post_type The post type name.
* @return array<string,mixed> The list of private query vars to apply to the query.
*/
public static function get_filter_vars( array $query, array $filters, string $post_type ): array {
$return = [];
foreach ( $filters as $filter_key => $filter ) {
$meta_query = [];
$date_query = [];
if ( ! isset( $query[ $filter_key ] ) || ( '' === $query[ $filter_key ] ) ) {
continue;
}
if ( isset( $filter['cap'] ) && ! current_user_can( $filter['cap'] ) ) {
continue;
}
$hook = "ext-cpts/{$post_type}/filter-query/{$filter_key}";
if ( has_filter( $hook ) ) {
/**
* Allows a filter's private query vars to be overridden.
*
* @since 4.3.0
*
* @param array<string,mixed> $return The private query vars.
* @param array<string,mixed> $query The public query vars.
* @param array<string,mixed> $filter The filter arguments.
*/
$return = apply_filters( $hook, $return, $query, $filter );
continue;
}
if ( isset( $filter['meta_key'] ) ) {
$meta_query = [
'key' => $filter['meta_key'],
'value' => wp_unslash( $query[ $filter_key ] ),
];
} elseif ( isset( $filter['meta_search_key'] ) ) {
$meta_query = [
'key' => $filter['meta_search_key'],
'value' => wp_unslash( $query[ $filter_key ] ),
'compare' => 'LIKE',
];
} elseif ( isset( $filter['meta_key_exists'] ) ) {
$meta_query = [
'key' => wp_unslash( $query[ $filter_key ] ),
'compare' => 'EXISTS',
];
} elseif ( isset( $filter['meta_exists'] ) ) {
$meta_query = [
'key' => wp_unslash( $query[ $filter_key ] ),
'compare' => 'NOT IN',
'value' => [ '', '0', 'false', 'null' ],
];
} elseif ( isset( $filter['post_date'] ) ) {
$date_query = [
$filter['post_date'] => wp_unslash( $query[ $filter_key ] ),
'inclusive' => true,
];
} else {
continue;
}
if ( isset( $filter['meta_query'] ) ) {
$meta_query = array_merge( $meta_query, $filter['meta_query'] );
}
if ( isset( $filter['date_query'] ) ) {
$date_query = array_merge( $date_query, $filter['date_query'] );
}
if ( ! empty( $meta_query ) ) {
$return['meta_query'][] = $meta_query;
}
if ( ! empty( $date_query ) ) {
$return['date_query'][] = $date_query;
}
}
return $return;
}
/**
* Get the array of private and public query vars for the given sortables, to apply to the current query in order to
* sort it by the requested orderby field.
*
* @param array<string,mixed> $vars The public query vars, usually from `$wp_query->query`.
* @param array<string,mixed> $sortables The sortables valid for this query (usually the value of the `admin_cols` or
* `site_sortables` argument when registering an extended post type.
* @return array<string,mixed> The list of private and public query vars to apply to the query.
*/
public static function get_sort_field_vars( array $vars, array $sortables ): array {
if ( ! isset( $vars['orderby'] ) ) {
return [];
}
if ( ! is_string( $vars['orderby'] ) ) {
return [];
}
if ( ! isset( $sortables[ $vars['orderby'] ] ) ) {
return [];
}
$orderby = $sortables[ $vars['orderby'] ];
if ( ! is_array( $orderby ) ) {
return [];
}
if ( isset( $orderby['sortable'] ) && ! $orderby['sortable'] ) {
return [];
}
$return = [];
if ( isset( $orderby['meta_key'] ) ) {
$return['meta_key'] = $orderby['meta_key'];
$return['orderby'] = 'meta_value';
// @TODO meta_value_num
} elseif ( isset( $orderby['post_field'] ) ) {
$field = str_replace( 'post_', '', $orderby['post_field'] );
$return['orderby'] = $field;
}
if ( isset( $vars['order'] ) ) {
$return['order'] = $vars['order'];
}
return $return;
}
/**
* Get the array of SQL clauses for the given sortables, to apply to the current query in order to
* sort it by the requested orderby field.
*
* @param array<string,string> $clauses The query's SQL clauses.
* @param array<string,mixed> $vars The public query vars, usually from `$wp_query->query`.
* @param array<string,mixed> $sortables The sortables valid for this query (usually the value of the `admin_cols` or
* `site_sortables` argument when registering an extended post type).
* @return array<string,string> The list of SQL clauses to apply to the query.
*/
public static function get_sort_taxonomy_clauses( array $clauses, array $vars, array $sortables ): array {
global $wpdb;
if ( ! isset( $vars['orderby'] ) ) {
return [];
}
if ( ! is_string( $vars['orderby'] ) ) {
return [];
}
if ( ! isset( $sortables[ $vars['orderby'] ] ) ) {
return [];
}
$orderby = $sortables[ $vars['orderby'] ];
if ( ! is_array( $orderby ) ) {
return [];
}
if ( isset( $orderby['sortable'] ) && ! $orderby['sortable'] ) {
return [];
}
if ( ! isset( $orderby['taxonomy'] ) ) {
return [];
}
# Taxonomy term ordering courtesy of http://scribu.net/wordpress/sortable-taxonomy-columns.html
$clauses['join'] .= "
LEFT OUTER JOIN {$wpdb->term_relationships} as ext_cpts_tr
ON ( {$wpdb->posts}.ID = ext_cpts_tr.object_id )
LEFT OUTER JOIN {$wpdb->term_taxonomy} as ext_cpts_tt
ON ( ext_cpts_tr.term_taxonomy_id = ext_cpts_tt.term_taxonomy_id )
LEFT OUTER JOIN {$wpdb->terms} as ext_cpts_t
ON ( ext_cpts_tt.term_id = ext_cpts_t.term_id )
";
$clauses['where'] .= $wpdb->prepare( ' AND ( taxonomy = %s OR taxonomy IS NULL )', $orderby['taxonomy'] );
$clauses['groupby'] = 'ext_cpts_tr.object_id';
$clauses['orderby'] = 'GROUP_CONCAT( ext_cpts_t.name ORDER BY name ASC ) ';
$clauses['orderby'] .= ( isset( $vars['order'] ) && ( 'ASC' === strtoupper( $vars['order'] ) ) ) ? 'ASC' : 'DESC';
return $clauses;
}
/**
* Add our filter names to the public query vars.
*
* @param array<int,string> $vars Public query variables.
* @return array<int,string> Updated public query variables.
*/
public function add_query_vars( array $vars ): array {
/** @var array<string,mixed[]> */
$site_filters = $this->args['site_filters'];
$filters = array_keys( $site_filters );
return array_merge( $vars, $filters );
}
/**
* Add our post type to the feed.
*
* @param array<string,mixed> $vars Request parameters.
* @return array<string,mixed> Updated request parameters.
*/
public function add_to_feed( array $vars ): array {
# If it's not a feed, we're not interested:
if ( ! isset( $vars['feed'] ) ) {
return $vars;
}
if ( ! isset( $vars['post_type'] ) ) {
$vars['post_type'] = [
'post',
$this->post_type,
];
} elseif ( is_array( $vars['post_type'] ) && ( count( $vars['post_type'] ) > 1 ) ) {
$vars['post_type'][] = $this->post_type;
}
return $vars;
}
/**
* Add to or override our post type archive's private query vars.
*
* @param WP $wp The WP request object.
* @return WP Updated WP request object.
*/
public function override_private_query_vars( WP $wp ): WP {
# If it's not our post type, bail out:
if ( ! isset( $wp->query_vars['post_type'] ) || ( $this->post_type !== $wp->query_vars['post_type'] ) ) {
return $wp;
}
# If it's a single post, bail out:
if ( isset( $wp->query_vars['name'] ) ) {
return $wp;
}
# Set the vars:
foreach ( $this->args['archive'] as $var => $value ) {
$wp->query_vars[ $var ] = $value;
}
return $wp;
}
/**
* Action fired after a PostType is registered in order to set up the custom permalink structure for the post type.
*
* @param string $post_type Post type name.
* @param WP_Post_Type $post_type_object Post type object.
*/
public function registered_post_type( string $post_type, WP_Post_Type $post_type_object ): void {
if ( $post_type !== $this->post_type ) {
return;
}
if ( ! $post_type_object->rewrite ) {
return;
}
if ( ! is_string( $post_type_object->rewrite['permastruct'] ) ) {
return;
}
$struct = str_replace( "%{$this->post_type}_slug%", $this->post_slug, $post_type_object->rewrite['permastruct'] );
$struct = str_replace( '%postname%', "%{$this->post_type}%", $struct );
add_permastruct( $this->post_type, $struct, $post_type_object->rewrite );
}
/**
* Filter the post type permalink in order to populate its rewrite tags.
*
* @param string $post_link The post's permalink.
* @param WP_Post $post The post in question.
* @return string The post's permalink.
*/
public function post_type_link( string $post_link, WP_Post $post ): string {
# If it's not our post type, bail out:
if ( $this->post_type !== $post->post_type ) {
return $post_link;
}
/** @var string */
$date = mysql2date( 'Y m d H i s', $post->post_date );
$date = explode( ' ', $date );
$replacements = [
'%year%' => $date[0],
'%monthnum%' => $date[1],
'%day%' => $date[2],
'%hour%' => $date[3],
'%minute%' => $date[4],
'%second%' => $date[5],
'%post_id%' => $post->ID,
];
if ( false !== strpos( $post_link, '%author%' ) ) {
$author = get_userdata( (int) $post->post_author );
if ( $author ) {
$replacements['%author%'] = $author->user_nicename;
} else {
$replacements['%author%'] = '-';
}
}
/** @var string $tax */
foreach ( get_object_taxonomies( $post ) as $tax ) {
if ( false === strpos( $post_link, "%{$tax}%" ) ) {
continue;
}
$terms = get_the_terms( $post, $tax );
if ( $terms && ! is_wp_error( $terms ) ) {
/**
* Filter the term that gets used in the `$tax` permalink token.
*
* @param WP_Term $term The `$tax` term to use in the permalink.
* @param WP_Term[] $terms Array of all `$tax` terms associated with the post.
* @param WP_Post $post The post in question.
*/
$term_object = apply_filters( "post_link_{$tax}", reset( $terms ), $terms, $post );
$term = $term_object->slug;
} else {
$term = $post->post_type;
/**
* Filter the default term that gets used in the `$tax` permalink token.
*
* @param int $term The ID of the term to use in the permalink.
* @param WP_Post $post The post in question.
*/
$default_term_id = (int) apply_filters( "default_{$tax}", get_option( "default_{$tax}", 0 ), $post );
if ( $default_term_id ) {
$default_term = get_term( $default_term_id, $tax );
if ( $default_term instanceof WP_Term ) {
$term = $default_term->slug;
}
}
}
$replacements[ "%{$tax}%" ] = $term;
}
$post_link = str_replace( array_keys( $replacements ), $replacements, $post_link );
return $post_link;
}
/**
* Add our rewrite tests to the Rewrite Rule Testing tests array.
*
* @codeCoverageIgnore
*
* @param array<string,array<string,string>> $tests The existing rewrite rule tests.
* @return array<string,array<string,string>> Updated rewrite rule tests.
*/
public function rewrite_testing_tests( array $tests ): array {
require_once __DIR__ . '/ExtendedRewriteTesting.php';
require_once __DIR__ . '/PostTypeRewriteTesting.php';
$extended = new PostTypeRewriteTesting( $this );
return array_merge( $tests, $extended->get_tests() );
}
/**
* Registers our post type.
*
* The only difference between this and regular `register_post_type()` calls is this will trigger an error of
* `E_USER_ERROR` level if a `WP_Error` is returned.
*
*/
public function register_post_type(): void {
if ( ! isset( $this->args['query_var'] ) || ( true === $this->args['query_var'] ) ) {
$query_var = $this->post_type;
} else {
$query_var = $this->args['query_var'];
}
$existing = get_post_type_object( $this->post_type );
$taxonomies = get_taxonomies(
[
'query_var' => $query_var,
],
'objects'
);
if ( $query_var && count( $taxonomies ) ) {
// https://core.trac.wordpress.org/ticket/35089
foreach ( $taxonomies as $tax ) {
if ( $tax->query_var === $query_var ) {
trigger_error(
esc_html(
sprintf(
/* translators: %s: Post type query variable name */
__( 'Post type query var "%s" clashes with a taxonomy query var of the same name', 'extended-cpts' ),
$query_var
)
),
E_USER_ERROR
);
}
}
}
if ( empty( $existing ) ) {
$cpt = register_post_type( $this->post_type, $this->args );
if ( is_wp_error( $cpt ) ) {
trigger_error( esc_html( $cpt->get_error_message() ), E_USER_ERROR );
}
} else {
# This allows us to call `register_extended_post_type()` on an existing post type to add custom functionality
# to the post type.
$this->extend( $existing );
}
}
/**
* Extends an existing post type object. Currently only handles labels.
*
* @param WP_Post_Type $pto A post type object.
*/
public function extend( WP_Post_Type $pto ): void {
# Merge core with overridden labels
$this->args['labels'] = array_merge( (array) get_post_type_labels( $pto ), $this->args['labels'] );
$GLOBALS['wp_post_types'][ $pto->name ]->labels = (object) $this->args['labels'];
}
/**
* Helper function for registering a taxonomy and adding it to this post type.
*
* Accepts the same parameters as `register_extended_taxonomy()`, minus the `$object_type` parameter.
*
* Example usage:
*
* $events = register_extended_post_type( 'event' );
* $location = $events->add_taxonomy( 'location' );
*
* @param string $taxonomy The taxonomy name.
* @param array<string,mixed> $args Optional. The taxonomy arguments.
* @param array<string,string> $names Optional. An associative array of the plural, singular, and slug names.
* @return WP_Taxonomy Taxonomy object.
*/
public function add_taxonomy( string $taxonomy, array $args = [], array $names = [] ): WP_Taxonomy {
if ( taxonomy_exists( $taxonomy ) ) {
register_taxonomy_for_object_type( $taxonomy, $this->post_type );
} else {
register_extended_taxonomy( $taxonomy, $this->post_type, $args, $names );
}
/** @var WP_Taxonomy */
$tax = get_taxonomy( $taxonomy );
return $tax;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
<?php
declare( strict_types=1 );
namespace ExtCPTs;
/**
* @codeCoverageIgnore
*/
class PostTypeRewriteTesting extends ExtendedRewriteTesting {
public PostType $cpt;
public function __construct( PostType $cpt ) {
$this->cpt = $cpt;
}
/**
* @return array<string,array<string,string>>
*/
public function get_tests(): array {
global $wp_rewrite;
/** @var \WP_Rewrite $wp_rewrite */
if ( ! $wp_rewrite->using_permalinks() ) {
return [];
}
if ( ! isset( $wp_rewrite->extra_permastructs[ $this->cpt->post_type ] ) ) {
return [];
}
$struct = $wp_rewrite->extra_permastructs[ $this->cpt->post_type ];
/** @var \WP_Post_Type */
$pto = get_post_type_object( $this->cpt->post_type );
$name = sprintf( '%s (%s)', $pto->labels->name, $this->cpt->post_type );
$additional = [];
// Post type archive rewrites are generated separately. See the `has_archive` handling in `register_post_type()`.
if ( $pto->has_archive && $pto->rewrite ) {
$archive_slug = ( true === $pto->has_archive ) ? $pto->rewrite['slug'] : $pto->has_archive;
if ( $pto->rewrite['with_front'] ) {
$archive_slug = substr( $wp_rewrite->front, 1 ) . $archive_slug;
} else {
$archive_slug = $wp_rewrite->root . $archive_slug;
}
$additional[ "{$archive_slug}/?$" ] = "index.php?post_type={$this->cpt->post_type}";
if ( $pto->rewrite['feeds'] && $wp_rewrite->feeds ) {
$feeds = '(' . trim( implode( '|', $wp_rewrite->feeds ) ) . ')';
$additional[ "{$archive_slug}/feed/{$feeds}/?$" ] = "index.php?post_type={$this->cpt->post_type}" . '&feed=$matches[1]';
$additional[ "{$archive_slug}/{$feeds}/?$" ] = "index.php?post_type={$this->cpt->post_type}" . '&feed=$matches[1]';
}
if ( $pto->rewrite['pages'] ) {
$additional[ "{$archive_slug}/{$wp_rewrite->pagination_base}/([0-9]{1,})/?$" ] = "index.php?post_type={$this->cpt->post_type}" . '&paged=$matches[1]';
}
}
return [
$name => $this->get_rewrites( $struct, $additional ),
];
}
}

View File

@ -0,0 +1,273 @@
<?php
declare( strict_types=1 );
namespace ExtCPTs;
class Taxonomy {
/**
* Default arguments for custom taxonomies.
* Several of these differ from the defaults in WordPress' register_taxonomy() function.
*
* @var array<string,mixed>
*/
protected array $defaults = [
'public' => true,
'show_ui' => true,
'hierarchical' => true,
'query_var' => true,
'exclusive' => false, # Custom arg
'allow_hierarchy' => false, # Custom arg
];
public string $taxonomy;
/**
* @var array<int,string>
*/
public array $object_type;
public string $tax_slug;
public string $tax_singular;
public string $tax_plural;
public string $tax_singular_low;
public string $tax_plural_low;
/**
* @var array<string,mixed>
*/
public array $args;
/**
* Class constructor.
*
* @see register_extended_taxonomy()
*
* @param string $taxonomy The taxonomy name.
* @param array<int,string> $object_type Names of the object types for the taxonomy.
* @param array<string,mixed> $args Optional. The taxonomy arguments.
* @param array<string,string> $names Optional. An associative array of the plural, singular, and slug names.
* @phpstan-param array{
* plural?: string,
* singular?: string,
* slug?: string,
* } $names
*/
public function __construct( string $taxonomy, array $object_type, array $args = [], array $names = [] ) {
/**
* Filter the arguments for a taxonomy.
*
* @since 4.4.1
*
* @param array<string,mixed> $args The taxonomy arguments.
* @param string $taxonomy The taxonomy name.
*/
$args = apply_filters( 'ext-taxos/args', $args, $taxonomy );
/**
* Filter the arguments for this taxonomy.
*
* @since 2.0.0
*
* @param array<string,mixed> $args The taxonomy arguments.
*/
$args = apply_filters( "ext-taxos/{$taxonomy}/args", $args );
/**
* Filter the plural, singular, and slug for a taxonomy.
*
* @since 4.4.1
*
* @param array<string,string> $names The plural, singular, and slug names (if any were specified).
* @param string $taxonomy The taxonomy name.
*/
$names = apply_filters( 'ext-taxos/names', $names, $taxonomy );
/**
* Filter the plural, singular, and slug for this taxonomy.
*
* @since 2.0.0
*
* @param array<string,string> $names The plural, singular, and slug names (if any were specified).
*/
$names = apply_filters( "ext-taxos/{$taxonomy}/names", $names );
if ( isset( $names['singular'] ) ) {
$this->tax_singular = $names['singular'];
} else {
$this->tax_singular = ucwords( str_replace( [ '-', '_' ], ' ', $taxonomy ) );
}
if ( isset( $names['slug'] ) ) {
$this->tax_slug = $names['slug'];
} elseif ( isset( $names['plural'] ) ) {
$this->tax_slug = $names['plural'];
} else {
$this->tax_slug = $taxonomy . 's';
}
if ( isset( $names['plural'] ) ) {
$this->tax_plural = $names['plural'];
} else {
$this->tax_plural = ucwords( str_replace( [ '-', '_' ], ' ', $this->tax_slug ) );
}
$this->object_type = $object_type;
$this->taxonomy = strtolower( $taxonomy );
$this->tax_slug = strtolower( $this->tax_slug );
# Build our base taxonomy names:
# Lower-casing is not forced if the name looks like an initialism, eg. FAQ.
if ( ! preg_match( '/[A-Z]{2,}/', $this->tax_singular ) ) {
$this->tax_singular_low = strtolower( $this->tax_singular );
} else {
$this->tax_singular_low = $this->tax_singular;
}
if ( ! preg_match( '/[A-Z]{2,}/', $this->tax_plural ) ) {
$this->tax_plural_low = strtolower( $this->tax_plural );
} else {
$this->tax_plural_low = $this->tax_plural;
}
# Build our labels:
$this->defaults['labels'] = [
'menu_name' => $this->tax_plural,
'name' => $this->tax_plural,
'singular_name' => $this->tax_singular,
'name_admin_bar' => $this->tax_singular,
'search_items' => sprintf( 'Search %s', $this->tax_plural ),
'popular_items' => sprintf( 'Popular %s', $this->tax_plural ),
'all_items' => sprintf( 'All %s', $this->tax_plural ),
'archives' => sprintf( '%s Archives', $this->tax_plural ),
'parent_item' => sprintf( 'Parent %s', $this->tax_singular ),
'parent_item_colon' => sprintf( 'Parent %s:', $this->tax_singular ),
'edit_item' => sprintf( 'Edit %s', $this->tax_singular ),
'view_item' => sprintf( 'View %s', $this->tax_singular ),
'update_item' => sprintf( 'Update %s', $this->tax_singular ),
'add_new_item' => sprintf( 'Add New %s', $this->tax_singular ),
'new_item_name' => sprintf( 'New %s Name', $this->tax_singular ),
'separate_items_with_commas' => sprintf( 'Separate %s with commas', $this->tax_plural_low ),
'add_or_remove_items' => sprintf( 'Add or remove %s', $this->tax_plural_low ),
'choose_from_most_used' => sprintf( 'Choose from most used %s', $this->tax_plural_low ),
'not_found' => sprintf( 'No %s found', $this->tax_plural_low ),
'no_terms' => sprintf( 'No %s', $this->tax_plural_low ),
'filter_by_item' => sprintf( 'Filter by %s', $this->tax_singular_low ),
'items_list_navigation' => sprintf( '%s list navigation', $this->tax_plural ),
'items_list' => sprintf( '%s list', $this->tax_plural ),
'most_used' => 'Most Used',
'back_to_items' => sprintf( '&larr; Back to %s', $this->tax_plural ),
'item_link' => sprintf( '%s Link', $this->tax_singular ),
'item_link_description' => sprintf( 'A link to a %s.', $this->tax_singular_low ),
'template_name' => sprintf( '%s Archives', $this->tax_singular ),
'no_item' => sprintf( 'No %s', $this->tax_singular_low ), # Custom label
'filter_by' => sprintf( 'Filter by %s', $this->tax_singular_low ), # Custom label
];
# Only set rewrites if we need them
if ( isset( $args['public'] ) && ! $args['public'] ) {
$this->defaults['rewrite'] = false;
} else {
$this->defaults['rewrite'] = [
'slug' => $this->tax_slug,
'with_front' => false,
'hierarchical' => isset( $args['allow_hierarchy'] ) ? $args['allow_hierarchy'] : $this->defaults['allow_hierarchy'],
];
}
# Merge our args with the defaults:
$this->args = array_merge( $this->defaults, $args );
# This allows the 'labels' arg to contain some, none or all labels:
if ( isset( $args['labels'] ) ) {
$this->args['labels'] = array_merge( $this->defaults['labels'], $args['labels'] );
}
}
/**
* Initialise the taxonomy by adding the necessary actions and filters.
*/
public function init(): void {
# Rewrite testing:
if ( $this->args['rewrite'] ) {
add_filter( 'rewrite_testing_tests', [ $this, 'rewrite_testing_tests' ], 1 );
}
# Register taxonomy:
$this->register_taxonomy();
/**
* Fired when the extended taxonomy instance is set up.
*
* @since 4.0.0
*
* @param \ExtCPTs\Taxonomy $instance The extended taxonomy instance.
*/
do_action( "ext-taxos/{$this->taxonomy}/instance", $this );
}
/**
* Add our rewrite tests to the Rewrite Rule Testing tests array.
*
* @codeCoverageIgnore
*
* @param array<string,array<string,string>> $tests The existing rewrite rule tests.
* @return array<string,array<string,string>> Updated rewrite rule tests.
*/
public function rewrite_testing_tests( array $tests ): array {
require_once __DIR__ . '/ExtendedRewriteTesting.php';
require_once __DIR__ . '/TaxonomyRewriteTesting.php';
$extended = new TaxonomyRewriteTesting( $this );
return array_merge( $tests, $extended->get_tests() );
}
/**
* Registers our taxonomy.
*/
public function register_taxonomy(): void {
if ( true === $this->args['query_var'] ) {
$query_var = $this->taxonomy;
} else {
$query_var = $this->args['query_var'];
}
$post_types = get_post_types(
[
'query_var' => $query_var,
]
);
if ( $query_var && count( $post_types ) ) {
trigger_error(
esc_html(
sprintf(
/* translators: %s: Taxonomy query variable name */
__( 'Taxonomy query var "%s" clashes with a post type query var of the same name', 'extended-cpts' ),
$query_var
)
),
E_USER_ERROR
);
} elseif ( in_array( $query_var, [ 'type', 'tab' ], true ) ) {
trigger_error(
esc_html(
sprintf(
/* translators: %s: Taxonomy query variable name */
__( 'Taxonomy query var "%s" is not allowed', 'extended-cpts' ),
$query_var
)
),
E_USER_ERROR
);
} else {
register_taxonomy( $this->taxonomy, $this->object_type, $this->args );
}
}
}

View File

@ -0,0 +1,663 @@
<?php
declare( strict_types=1 );
namespace ExtCPTs;
use WP_Post;
use WP_Taxonomy;
class TaxonomyAdmin {
/**
* Default arguments for custom taxonomies.
*
* @var array<string,mixed>
*/
protected array $defaults = [
'meta_box' => null, # Custom arg
'dashboard_glance' => false, # Custom arg
'checked_ontop' => null, # Custom arg
'admin_cols' => null, # Custom arg
'required' => false, # Custom arg
];
public Taxonomy $taxo;
/**
* @var array<string,mixed>
*/
public array $args;
/**
* @var array<string,string>
*/
protected array $_cols;
/**
* @var array<string,string>
*/
protected ?array $the_cols = null;
/**
* Class constructor.
*
* @param Taxonomy $taxo An extended taxonomy object.
* @param array<string,mixed> $args Optional. The admin arguments.
*/
public function __construct( Taxonomy $taxo, array $args = [] ) {
$this->taxo = $taxo;
# Merge our args with the defaults:
$this->args = array_merge( $this->defaults, $args );
# Set checked on top to false unless we're using the default meta box:
if ( null === $this->args['checked_ontop'] ) {
$this->args['checked_ontop'] = empty( $this->args['meta_box'] );
}
}
/**
* Initialise the admin features of the taxonomy by adding the necessary actions and filters.
*/
public function init(): void {
# Meta boxes:
if ( $this->taxo->args['exclusive'] || isset( $this->args['meta_box'] ) ) {
add_action( 'add_meta_boxes', [ $this, 'meta_boxes' ], 10, 2 );
}
# 'At a Glance' dashboard panels:
if ( $this->args['dashboard_glance'] ) {
add_filter( 'dashboard_glance_items', [ $this, 'glance_items' ] );
}
# Term updated messages:
add_filter( 'term_updated_messages', [ $this, 'term_updated_messages' ], 1 );
# Admin columns:
if ( $this->args['admin_cols'] ) {
add_filter( "manage_edit-{$this->taxo->taxonomy}_columns", [ $this, '_log_default_cols' ], 0 );
add_filter( "manage_edit-{$this->taxo->taxonomy}_columns", [ $this, 'cols' ] );
add_filter( "manage_{$this->taxo->taxonomy}_custom_column", [ $this, 'col' ], 10, 3 );
}
/**
* Fired when the extended taxonomy admin instance is set up.
*
* @since 5.0.0
*
* @param \ExtCPTs\TaxonomyAdmin $instance The extended taxonomy admin instance.
*/
do_action( "ext-taxos/{$this->taxo->taxonomy}/admin-instance", $this );
}
/**
* Logs the default columns so we don't remove any custom columns added by other plugins.
*
* @param array<string,string> $cols The default columns for this taxonomy screen.
* @return array<string,string> The default columns for this taxonomy screen.
*/
public function _log_default_cols( array $cols ): array {
$this->_cols = $cols;
return $this->_cols;
}
/**
* Add columns to the admin screen for this taxonomy.
*
* Each item in the `admin_cols` array is either a string name of an existing column, or an associative
* array of information for a custom column.
*
* Defining a custom column is easy. Just define an array which includes the column title, column
* type, and optional callback function. You can display columns for term meta or custom functions.
*
* The example below adds two columns; one which displays the value of the term's `term_updated` meta
* key, and one which calls a custom callback function:
*
* register_extended_taxonomy( 'foo', 'bar', array(
* 'admin_cols' => array(
* 'foo_updated' => array(
* 'title' => 'Updated',
* 'meta_key' => 'term_updated'
* ),
* 'foo_bar' => array(
* 'title' => 'Example',
* 'function' => 'my_custom_callback'
* )
* )
* ) );
*
* That's all you need to do. The columns will handle safely outputting the data
* (escaping text, and comma-separating taxonomy terms). No more messing about with all of those
* annoyingly named column filters and actions.
*
* Each item in the `admin_cols` array must contain one of the following elements which defines the column type:
*
* - meta_key - A term meta key
* - function - The name of a callback function
*
* The value for the corresponding term meta are safely escaped and output into the column.
*
* There are a few optional elements:
*
* - title - Generated from the field if not specified.
* - function - The name of a callback function for the column (eg. `my_function`) which gets called
* instead of the built-in function for handling that column. The function is passed the term ID as
* its first parameter.
* - date_format - This is used with the `meta_key` column type. The value of the meta field will be
* treated as a timestamp if this is present. Unix and MySQL format timestamps are supported in the
* meta value. Pass in boolean true to format the date according to the 'Date Format' setting, or pass
* in a valid date formatting string (eg. `d/m/Y H:i:s`).
* - cap - A capability required in order for this column to be displayed to the current user. Defaults
* to null, meaning the column is shown to all users.
*
* Note that sortable admin columns are not yet supported.
*
* @param array<string,string> $cols Associative array of columns.
* @return array<string,string> Updated array of columns.
*/
public function cols( array $cols ): array {
// This function gets called multiple times, so let's cache it for efficiency:
if ( isset( $this->the_cols ) ) {
return $this->the_cols;
}
$new_cols = [];
$keep = [
'cb',
'name',
'description',
'slug',
];
# Add existing columns we want to keep:
foreach ( $cols as $id => $title ) {
if ( in_array( $id, $keep, true ) && ! isset( $this->args['admin_cols'][ $id ] ) ) {
$new_cols[ $id ] = $title;
}
}
/** @var array<string,(string|mixed[])> */
$admin_cols = array_filter( $this->args['admin_cols'] );
# Add our custom columns:
foreach ( $admin_cols as $id => $col ) {
if ( is_string( $col ) && isset( $cols[ $col ] ) ) {
# Existing (ie. built-in) column with id as the value
$new_cols[ $col ] = $cols[ $col ];
} elseif ( is_string( $col ) && isset( $cols[ $id ] ) ) {
# Existing (ie. built-in) column with id as the key and title as the value
$new_cols[ $id ] = esc_html( $col );
} elseif ( is_array( $col ) ) {
if ( isset( $col['cap'] ) && ! current_user_can( $col['cap'] ) ) {
continue;
}
if ( isset( $col['title_cb'] ) ) {
$new_cols[ $id ] = call_user_func( $col['title_cb'], $col );
} else {
$title = esc_html( $this->get_item_title( $col, $id ) );
if ( isset( $col['title_icon'] ) ) {
$title = sprintf(
'<span class="dashicons %s" aria-hidden="true"></span><span class="screen-reader-text">%s</span>',
esc_attr( $col['title_icon'] ),
$title
);
}
$new_cols[ $id ] = $title;
}
}
}
# Re-add any custom columns:
$custom = array_diff_key( $cols, $this->_cols );
$new_cols = array_merge( $new_cols, $custom );
$this->the_cols = $new_cols;
return $this->the_cols;
}
/**
* Output the column data for our custom columns.
*
* @param string $string Blank string.
* @param string $col Name of the column.
* @param int $term_id Term ID.
* @return string Blank string.
*/
public function col( string $string, string $col, int $term_id ): string {
# Shorthand:
$c = $this->args['admin_cols'];
# We're only interested in our custom columns:
$custom_cols = array_filter( array_keys( $c ) );
if ( ! in_array( $col, $custom_cols, true ) ) {
return $string;
}
if ( isset( $c[ $col ]['function'] ) ) {
call_user_func( $c[ $col ]['function'], $term_id );
} elseif ( isset( $c[ $col ]['meta_key'] ) ) {
$this->col_term_meta( $c[ $col ]['meta_key'], $c[ $col ], $term_id );
}
return $string;
}
/**
* Output column data for a term meta field.
*
* @param string $meta_key The term meta key.
* @param array<string,mixed> $args Array of arguments for this field.
* @param int $term_id Term ID.
*/
public function col_term_meta( string $meta_key, array $args, int $term_id ): void {
$vals = get_term_meta( $term_id, $meta_key, false );
$echo = [];
sort( $vals );
if ( isset( $args['date_format'] ) ) {
if ( true === $args['date_format'] ) {
$args['date_format'] = get_option( 'date_format' );
}
foreach ( $vals as $val ) {
if ( is_numeric( $val ) ) {
$echo[] = date( $args['date_format'], (int) $val );
} elseif ( ! empty( $val ) ) {
$echo[] = mysql2date( $args['date_format'], $val );
}
}
} else {
foreach ( $vals as $val ) {
if ( ! empty( $val ) || ( '0' === $val ) ) {
$echo[] = $val;
}
}
}
if ( empty( $echo ) ) {
echo '&#8212;';
} else {
echo esc_html( implode( ', ', $echo ) );
}
}
/**
* Returns a sensible title for the current item (usually the arguments array for a column).
*
* @param array<string,mixed> $item An array of arguments.
* @param string $fallback Fallback item title.
* @return string The item title.
*/
protected function get_item_title( array $item, string $fallback = '' ): string {
if ( isset( $item['title'] ) ) {
return $item['title'];
} elseif ( isset( $item['meta_key'] ) ) {
return ucwords( trim( str_replace( [ '_', '-' ], ' ', $item['meta_key'] ) ) );
}
return $fallback;
}
/**
* Removes the default meta box from the post editing screen and adds our custom meta box.
*
* @param string $object_type The object type (eg. the post type).
* @param mixed $object The object (eg. a WP_Post object).
*/
public function meta_boxes( string $object_type, $object ): void {
if ( ! is_a( $object, 'WP_Post' ) ) {
return;
}
$post_type = $object_type;
$post = $object;
$taxos = get_post_taxonomies( $post );
if ( in_array( $this->taxo->taxonomy, $taxos, true ) ) {
/** @var WP_Taxonomy */
$tax = get_taxonomy( $this->taxo->taxonomy );
# Remove default meta box from classic editor:
if ( $this->taxo->args['hierarchical'] ) {
remove_meta_box( "{$this->taxo->taxonomy}div", $post_type, 'side' );
} else {
remove_meta_box( "tagsdiv-{$this->taxo->taxonomy}", $post_type, 'side' );
}
$store = version_compare( $GLOBALS['wp_version'], '6.5', '>=' ) ? 'core/editor' : 'core/edit-post';
# Remove default meta box from block editor:
wp_add_inline_script(
'wp-edit-post',
sprintf(
'wp.data.dispatch( "%s" ).removeEditorPanel( "taxonomy-panel-%s" );',
$store,
$this->taxo->taxonomy
)
);
if ( ! current_user_can( $tax->cap->assign_terms ) ) {
return;
}
if ( $this->args['meta_box'] ) {
# Set the 'meta_box' argument to the actual meta box callback function name:
if ( 'simple' === $this->args['meta_box'] ) {
if ( $this->taxo->args['exclusive'] ) {
$this->args['meta_box'] = [ $this, 'meta_box_radio' ];
} else {
$this->args['meta_box'] = [ $this, 'meta_box_simple' ];
}
} elseif ( 'radio' === $this->args['meta_box'] ) {
$this->taxo->args['exclusive'] = true;
$this->args['meta_box'] = [ $this, 'meta_box_radio' ];
} elseif ( 'dropdown' === $this->args['meta_box'] ) {
$this->taxo->args['exclusive'] = true;
$this->args['meta_box'] = [ $this, 'meta_box_dropdown' ];
}
# Add the meta box, using the plural or singular taxonomy label where relevant:
if ( $this->taxo->args['exclusive'] ) {
add_meta_box( "{$this->taxo->taxonomy}div", $tax->labels->singular_name, $this->args['meta_box'], $post_type, 'side' );
} else {
add_meta_box( "{$this->taxo->taxonomy}div", $tax->labels->name, $this->args['meta_box'], $post_type, 'side' );
}
} elseif ( false !== $this->args['meta_box'] ) {
# This must be an 'exclusive' taxonomy. Add the radio meta box:
add_meta_box( "{$this->taxo->taxonomy}div", $tax->labels->singular_name, [ $this, 'meta_box_radio' ], $post_type, 'side' );
}
}
}
/**
* Displays the 'radio' meta box on the post editing screen.
*
* Uses the Walker\Radios class for the walker.
*
* @param WP_Post $post The post object.
* @param array<string,mixed> $meta_box The meta box arguments.
*/
public function meta_box_radio( WP_Post $post, array $meta_box ): void {
$walker = new Walker\Radios();
$this->do_meta_box( $post, $walker, true, 'checklist' );
}
/**
* Displays the 'dropdown' meta box on the post editing screen.
*
* Uses the Walker\Dropdown class for the walker.
*
* @param WP_Post $post The post object.
* @param array<string,mixed> $meta_box The meta box arguments.
*/
public function meta_box_dropdown( WP_Post $post, array $meta_box ): void {
$walker = new Walker\Dropdown();
$this->do_meta_box( $post, $walker, true, 'dropdown' );
}
/**
* Displays the 'simple' meta box on the post editing screen.
*
* @param WP_Post $post The post object.
* @param array<string,mixed> $meta_box The meta box arguments.
*/
public function meta_box_simple( WP_Post $post, array $meta_box ): void {
$this->do_meta_box( $post );
}
/**
* Displays a meta box on the post editing screen.
*
* @param WP_Post $post The post object.
* @param \Walker $walker Optional. A term walker.
* @param bool $show_none Optional. Whether to include a 'none' item in the term list. Default false.
* @param string $type Optional. The taxonomy list type (checklist or dropdown). Default 'checklist'.
*/
protected function do_meta_box( WP_Post $post, ?\Walker $walker = null, bool $show_none = false, string $type = 'checklist' ): void {
$taxonomy = $this->taxo->taxonomy;
/** @var WP_Taxonomy */
$tax = get_taxonomy( $taxonomy );
/** @var array<int,int> */
$selected = wp_get_object_terms(
$post->ID,
$taxonomy,
[
'fields' => 'ids',
]
);
if ( $show_none ) {
if ( isset( $tax->labels->no_item ) ) {
/** @var string $none */
$none = $tax->labels->no_item;
} else {
$none = esc_html__( 'Not specified', 'extended-cpts' );
}
} else {
$none = '';
}
/**
* Execute code before the taxonomy meta box content outputs to the page.
*
* @since 2.0.0
*
* @param WP_Taxonomy $tax The current taxonomy object.
* @param WP_Post $post The current post object.
* @param string $type The taxonomy list type ('checklist' or 'dropdown').
*/
do_action( 'ext-taxos/meta_box/before', $tax, $post, $type );
?>
<div id="taxonomy-<?php echo esc_attr( $taxonomy ); ?>" class="categorydiv">
<?php
switch ( $type ) {
case 'dropdown':
printf(
'<label for="%1$s" class="screen-reader-text">%2$s</label>',
esc_attr( "{$taxonomy}dropdown" ),
esc_html( $tax->labels->singular_name )
);
$dropdown_args = [
'option_none_value' => ( is_taxonomy_hierarchical( $taxonomy ) ? '-1' : '' ),
'show_option_none' => $none,
'hide_empty' => false,
'hierarchical' => true,
'show_count' => false,
'orderby' => 'name',
'selected' => reset( $selected ) ?: 0,
'id' => "{$taxonomy}dropdown",
'name' => is_taxonomy_hierarchical( $taxonomy ) ? "tax_input[{$taxonomy}][]" : "tax_input[{$taxonomy}]",
'taxonomy' => $taxonomy,
'required' => $this->args['required'],
];
if ( $walker instanceof \Walker ) {
$dropdown_args['walker'] = $walker;
}
wp_dropdown_categories( $dropdown_args );
break;
case 'checklist':
default:
?>
<style type="text/css">
/* Style for the 'none' item: */
#<?php echo esc_attr( $taxonomy ); ?>-0 {
color: #888;
border-top: 1px solid #eee;
margin-top: 5px;
padding-top: 5px;
}
</style>
<input type="hidden" name="tax_input[<?php echo esc_attr( $taxonomy ); ?>][]" value="0" />
<ul id="<?php echo esc_attr( $taxonomy ); ?>checklist" class="list:<?php echo esc_attr( $taxonomy ); ?> categorychecklist form-no-clear">
<?php
# Standard WP Walker_Category_Checklist does not cut it
if ( ! $walker ) {
$walker = new Walker\Checkboxes();
}
# Output the terms:
wp_terms_checklist(
$post->ID,
[
'taxonomy' => $taxonomy,
'walker' => $walker,
'selected_cats' => $selected,
'checked_ontop' => $this->args['checked_ontop'],
]
);
# Output the 'none' item:
if ( $show_none ) {
$output = '';
$o = (object) [
'term_id' => 0,
'name' => $none,
'slug' => 'none',
];
if ( empty( $selected ) ) {
$_selected = [ 0 ];
} else {
$_selected = $selected;
}
$args = [
'taxonomy' => $taxonomy,
'selected_cats' => $_selected,
'disabled' => false,
];
$walker->start_el( $output, $o, 1, $args );
$walker->end_el( $output, $o, 1, $args );
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $output;
}
?>
</ul>
<?php
break;
}
?>
</div>
<?php
/**
* Execute code after the taxonomy meta box content outputs to the page.
*
* @since 2.0.0
*
* @param WP_Taxonomy $tax The current taxonomy object.
* @param WP_Post $post The current post object.
* @param string $type The taxonomy list type ('checklist' or 'dropdown').
*/
do_action( 'ext-taxos/meta_box/after', $tax, $post, $type );
}
/**
* Adds our taxonomy to the 'At a Glance' widget on the dashboard.
*
* @param array<int,string> $items Array of items to display on the widget.
* @return array<int,string> Updated array of items.
*/
public function glance_items( array $items ): array {
/** @var WP_Taxonomy */
$taxonomy = get_taxonomy( $this->taxo->taxonomy );
if ( ! current_user_can( $taxonomy->cap->manage_terms ) ) {
return $items;
}
if ( $taxonomy->_builtin ) {
return $items;
}
# Get the labels and format the counts:
$count = wp_count_terms(
[
'taxonomy' => $this->taxo->taxonomy,
]
);
if ( is_wp_error( $count ) ) {
return $items;
}
$text = self::n( $taxonomy->labels->singular_name, $taxonomy->labels->name, (int) $count );
$num = number_format_i18n( (int) $count );
# This is absolutely not localisable. WordPress 3.8 didn't add a new taxonomy label.
$url = add_query_arg(
[
'taxonomy' => $this->taxo->taxonomy,
'post_type' => reset( $taxonomy->object_type ),
],
admin_url( 'edit-tags.php' )
);
$text = '<a href="' . esc_url( $url ) . '" class="taxo-' . esc_attr( $this->taxo->taxonomy ) . '-count">' . esc_html( $num . ' ' . $text ) . '</a>';
# Go!
$items[] = $text;
return $items;
}
/**
* Adds our term updated messages.
*
* The messages are as follows:
*
* 1 => "Term added."
* 2 => "Term deleted."
* 3 => "Term updated."
* 4 => "Term not added."
* 5 => "Term not updated."
* 6 => "Terms deleted."
*
* @param array<string, array<int, string>> $messages An array of term updated message arrays keyed by taxonomy name.
* @return array<string, array<int, string>> Updated array of term updated messages.
*/
public function term_updated_messages( array $messages ): array {
$messages[ $this->taxo->taxonomy ] = [
1 => esc_html( sprintf( '%s added.', $this->taxo->tax_singular ) ),
2 => esc_html( sprintf( '%s deleted.', $this->taxo->tax_singular ) ),
3 => esc_html( sprintf( '%s updated.', $this->taxo->tax_singular ) ),
4 => esc_html( sprintf( '%s not added.', $this->taxo->tax_singular ) ),
5 => esc_html( sprintf( '%s not updated.', $this->taxo->tax_singular ) ),
6 => esc_html( sprintf( '%s deleted.', $this->taxo->tax_plural ) ),
];
return $messages;
}
/**
* A non-localised version of _n()
*
* @param string $single The text that will be used if $number is 1.
* @param string $plural The text that will be used if $number is not 1.
* @param int $number The number to compare against to use either $single or $plural.
* @return string Either $single or $plural text.
*/
public static function n( string $single, string $plural, int $number ): string {
return ( 1 === intval( $number ) ) ? $single : $plural;
}
}

View File

@ -0,0 +1,40 @@
<?php
declare( strict_types=1 );
namespace ExtCPTs;
use WP_Taxonomy;
class TaxonomyRewriteTesting extends ExtendedRewriteTesting {
public Taxonomy $taxo;
public function __construct( Taxonomy $taxo ) {
$this->taxo = $taxo;
}
/**
* @return array<string,array<string,string>>
*/
public function get_tests(): array {
global $wp_rewrite;
if ( ! $wp_rewrite->using_permalinks() ) {
return [];
}
if ( ! isset( $wp_rewrite->extra_permastructs[ $this->taxo->taxonomy ] ) ) {
return [];
}
$struct = $wp_rewrite->extra_permastructs[ $this->taxo->taxonomy ];
/** @var WP_Taxonomy */
$tax = get_taxonomy( $this->taxo->taxonomy );
$name = sprintf( '%s (%s)', $tax->labels->name, $this->taxo->taxonomy );
return [
$name => $this->get_rewrites( $struct, [] ),
];
}
}

View File

@ -0,0 +1,119 @@
<?php
declare( strict_types=1 );
namespace ExtCPTs\Walker;
use WP_Term;
/**
* Walker to output an unordered list of category checkbox <input> elements properly.
*/
class Checkboxes extends \Walker {
/**
* @var string
*/
public $tree_type = 'category';
/**
* @var array<string,string>
*/
public $db_fields = [
'parent' => 'parent',
'id' => 'term_id',
];
/**
* @var string
*/
public $field = null;
/**
* Class constructor.
*
* @param array<string,mixed> $args Optional arguments.
*/
public function __construct( $args = null ) {
if ( $args && isset( $args['field'] ) ) {
$this->field = $args['field'];
}
}
/**
* Starts the list before the elements are added.
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of term in reference to parents.
* @param array<string,mixed> $args Optional arguments.
* @return void
*/
public function start_lvl( &$output, $depth = 0, $args = [] ) {
$indent = str_repeat( "\t", $depth );
$output .= "$indent<ul class='children'>\n";
}
/**
* Ends the list of after the elements are added.
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of term in reference to parents.
* @param array<string,mixed> $args Optional arguments.
* @return void
*/
public function end_lvl( &$output, $depth = 0, $args = [] ) {
$indent = str_repeat( "\t", $depth );
$output .= "$indent</ul>\n";
}
/**
* Start the element output.
*
* @param string $output Passed by reference. Used to append additional content.
* @param WP_Term $object Term data object.
* @param int $depth Depth of term in reference to parents.
* @param array<string,mixed> $args Optional arguments.
* @param int $current_object_id Current object ID.
* @return void
*/
public function start_el( &$output, $object, $depth = 0, $args = [], $current_object_id = 0 ) {
$tax = get_taxonomy( $args['taxonomy'] );
if ( ! $tax ) {
return;
}
if ( $this->field ) {
$value = $object->{$this->field};
} else {
$value = $tax->hierarchical ? $object->term_id : $object->name;
}
if ( empty( $object->term_id ) && ! $tax->hierarchical ) {
$value = '';
}
$output .= "\n<li id='{$args['taxonomy']}-{$object->term_id}'>" .
'<label class="selectit">' .
'<input value="' . esc_attr( $value ) . '" type="checkbox" name="tax_input[' . esc_attr( $args['taxonomy'] ) . '][]" ' .
'id="in-' . esc_attr( $args['taxonomy'] ) . '-' . intval( $object->term_id ) . '"' .
checked( in_array( $object->term_id, (array) $args['selected_cats'] ), true, false ) .
disabled( empty( $args['disabled'] ), false, false ) .
' /> ' .
esc_html( apply_filters( 'the_category', $object->name ) ) .
'</label>';
}
/**
* Ends the element output, if needed.
*
* @param string $output Passed by reference. Used to append additional content.
* @param WP_Term $object Term data object.
* @param int $depth Depth of term in reference to parents.
* @param array<string,mixed> $args Optional arguments.
* @return void
*/
public function end_el( &$output, $object, $depth = 0, $args = [] ) {
$output .= "</li>\n";
}
}

View File

@ -0,0 +1,89 @@
<?php
declare( strict_types=1 );
namespace ExtCPTs\Walker;
use WP_Term;
/**
* A term walker class for a dropdown menu.
*/
class Dropdown extends \Walker {
/**
* @var string
*/
public $tree_type = 'category';
/**
* @var array<string,string>
*/
public $db_fields = [
'parent' => 'parent',
'id' => 'term_id',
];
/**
* @var string
*/
public $field = null;
/**
* Class constructor.
*
* @param array<string,mixed> $args Optional arguments.
*/
public function __construct( $args = null ) {
if ( $args && isset( $args['field'] ) ) {
$this->field = $args['field'];
}
}
/**
* Start the element output.
*
* @param string $output Passed by reference. Used to append additional content.
* @param WP_Term $object Term data object.
* @param int $depth Depth of term in reference to parents.
* @param array<string,mixed> $args Optional arguments.
* @param int $current_object_id Current object ID.
* @return void
*/
public function start_el( &$output, $object, $depth = 0, $args = [], $current_object_id = 0 ) {
$pad = str_repeat( '&nbsp;', $depth * 3 );
$tax = get_taxonomy( $args['taxonomy'] );
if ( ! $tax ) {
return;
}
if ( $this->field ) {
$value = $object->{$this->field};
} else {
$value = $tax->hierarchical ? $object->term_id : $object->name;
}
if ( empty( $object->term_id ) && ! $tax->hierarchical ) {
$value = '';
}
$cat_name = apply_filters( 'list_cats', $object->name, $object );
$output .= "\t<option class=\"level-{$depth}\" value=\"" . esc_attr( $value ) . '"';
if ( isset( $args['selected_cats'] ) && in_array( $value, (array) $args['selected_cats'] ) ) {
$output .= ' selected="selected"';
} elseif ( isset( $args['selected'] ) && in_array( $object->term_id, (array) $args['selected'] ) ) {
$output .= ' selected="selected"';
}
$output .= '>';
$output .= $pad . esc_html( $cat_name );
if ( $args['show_count'] ) {
$output .= '&nbsp;&nbsp;(' . esc_html( number_format_i18n( $object->count ) ) . ')';
}
$output .= "</option>\n";
}
}

View File

@ -0,0 +1,119 @@
<?php
declare( strict_types=1 );
namespace ExtCPTs\Walker;
use WP_Term;
/**
* A term walker class for radio buttons.
*/
class Radios extends \Walker {
/**
* @var string
*/
public $tree_type = 'category';
/**
* @var array<string,string>
*/
public $db_fields = [
'parent' => 'parent',
'id' => 'term_id',
];
/**
* @var string
*/
public $field = null;
/**
* Class constructor.
*
* @param array<string,mixed> $args Optional arguments.
*/
public function __construct( $args = null ) {
if ( $args && isset( $args['field'] ) ) {
$this->field = $args['field'];
}
}
/**
* Starts the list before the elements are added.
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of term in reference to parents.
* @param array<string,mixed> $args Optional arguments.
* @return void
*/
public function start_lvl( &$output, $depth = 0, $args = [] ) {
$indent = str_repeat( "\t", $depth );
$output .= "{$indent}<ul class='children'>\n";
}
/**
* Ends the list of after the elements are added.
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of term in reference to parents.
* @param array<string,mixed> $args Optional arguments.
* @return void
*/
public function end_lvl( &$output, $depth = 0, $args = [] ) {
$indent = str_repeat( "\t", $depth );
$output .= "{$indent}</ul>\n";
}
/**
* Start the element output.
*
* @param string $output Passed by reference. Used to append additional content.
* @param WP_Term $object Term data object.
* @param int $depth Depth of term in reference to parents.
* @param array<string,mixed> $args Optional arguments.
* @param int $current_object_id Current object ID.
* @return void
*/
public function start_el( &$output, $object, $depth = 0, $args = [], $current_object_id = 0 ) {
$tax = get_taxonomy( $args['taxonomy'] );
if ( ! $tax ) {
return;
}
if ( $this->field ) {
$value = $object->{$this->field};
} else {
$value = $tax->hierarchical ? $object->term_id : $object->name;
}
if ( empty( $object->term_id ) && ! $tax->hierarchical ) {
$value = '';
}
$output .= "\n<li id='{$args['taxonomy']}-{$object->term_id}'>" .
'<label class="selectit">' .
'<input value="' . esc_attr( $value ) . '" type="radio" name="tax_input[' . esc_attr( $args['taxonomy'] ) . '][]" ' .
'id="in-' . esc_attr( $args['taxonomy'] ) . '-' . esc_attr( (string) $object->term_id ) . '"' .
checked( in_array( $object->term_id, (array) $args['selected_cats'] ), true, false ) .
disabled( empty( $args['disabled'] ), false, false ) .
' /> ' .
esc_html( apply_filters( 'the_category', $object->name ) ) .
'</label>';
}
/**
* Ends the element output, if needed.
*
* @param string $output Passed by reference. Used to append additional content.
* @param WP_Term $object Term data object.
* @param int $depth Depth of term in reference to parents.
* @param array<string,mixed> $args Optional arguments.
* @return void
*/
public function end_el( &$output, $object, $depth = 0, $args = [] ) {
$output .= "</li>\n";
}
}

View File

@ -0,0 +1,345 @@
{
"menu": 62259,
"admin-site": 62233,
"dashboard": 61990,
"admin-media": 61700,
"admin-page": 61701,
"admin-comments": 61697,
"admin-appearance": 61696,
"admin-plugins": 61702,
"admin-users": 61712,
"admin-tools": 61703,
"admin-settings": 61704,
"admin-network": 61714,
"admin-generic": 61713,
"admin-home": 61698,
"admin-collapse": 61768,
"filter": 62774,
"admin-customizer": 62784,
"admin-multisite": 62785,
"admin-links": 61699,
"admin-post": 61705,
"format-image": 61736,
"format-gallery": 61793,
"format-audio": 61735,
"format-video": 61734,
"format-chat": 61733,
"format-status": 61744,
"format-aside": 61731,
"format-quote": 61730,
"welcome-write-blog": 61721,
"welcome-add-page": 61747,
"welcome-view-site": 61717,
"welcome-widgets-menus": 61718,
"welcome-comments": 61719,
"welcome-learn-more": 61720,
"image-crop": 61797,
"image-rotate": 62769,
"image-rotate-left": 61798,
"image-rotate-right": 61799,
"image-flip-vertical": 61800,
"image-flip-horizontal": 61801,
"image-filter": 62771,
"undo": 61809,
"redo": 61810,
"editor-bold": 61952,
"editor-italic": 61953,
"editor-ul": 61955,
"editor-ol": 61956,
"editor-quote": 61957,
"editor-alignleft": 61958,
"editor-aligncenter": 61959,
"editor-alignright": 61960,
"editor-insertmore": 61961,
"editor-spellcheck": 61968,
"editor-expand": 61969,
"editor-contract": 62726,
"editor-kitchensink": 61970,
"editor-underline": 61971,
"editor-justify": 61972,
"editor-textcolor": 61973,
"editor-paste-word": 61974,
"editor-paste-text": 61975,
"editor-removeformatting": 61976,
"editor-video": 61977,
"editor-customchar": 61984,
"editor-outdent": 61985,
"editor-indent": 61986,
"editor-help": 61987,
"editor-strikethrough": 61988,
"editor-unlink": 61989,
"editor-rtl": 62240,
"editor-break": 62580,
"editor-code": 62581,
"editor-code-duplicate": 62612,
"editor-paragraph": 62582,
"editor-table": 62773,
"align-left": 61749,
"align-right": 61750,
"align-center": 61748,
"align-none": 61752,
"lock": 61792,
"lock-duplicate": 62229,
"unlock": 62760,
"calendar": 61765,
"calendar-alt": 62728,
"visibility": 61815,
"hidden": 62768,
"post-status": 61811,
"edit": 62564,
"edit-large": 62247,
"sticky": 62775,
"external": 62724,
"arrow-up": 61762,
"arrow-up-duplicate": 61763,
"arrow-down": 61760,
"arrow-left": 61761,
"arrow-right": 61753,
"arrow-up-alt": 62274,
"arrow-down-alt": 62278,
"arrow-left-alt": 62272,
"arrow-right-alt": 62276,
"arrow-up-alt2": 62275,
"arrow-down-alt2": 62279,
"arrow-left-alt2": 62273,
"arrow-right-alt2": 62277,
"leftright": 61993,
"sort": 61782,
"randomize": 62723,
"list-view": 61795,
"excerpt-view": 61796,
"grid-view": 62729,
"move": 62789,
"hammer": 62216,
"art": 62217,
"migrate": 62224,
"performance": 62225,
"universal-access": 62595,
"universal-access-alt": 62727,
"tickets": 62598,
"nametag": 62596,
"clipboard": 62593,
"heart": 62599,
"megaphone": 62600,
"schedule": 62601,
"wordpress": 61728,
"wordpress-alt": 62244,
"pressthis": 61783,
"update": 62563,
"screenoptions": 61824,
"cart": 61812,
"feedback": 61813,
"translation": 62246,
"tag": 62243,
"category": 62232,
"archive": 62592,
"tagcloud": 62585,
"text": 62584,
"media-archive": 62721,
"media-audio": 62720,
"media-code": 62617,
"media-default": 62616,
"media-document": 62615,
"media-interactive": 62614,
"media-spreadsheet": 62613,
"media-text": 62609,
"media-video": 62608,
"playlist-audio": 62610,
"playlist-video": 62611,
"controls-play": 62754,
"controls-pause": 62755,
"controls-forward": 62745,
"controls-skipforward": 62743,
"controls-back": 62744,
"controls-skipback": 62742,
"controls-repeat": 62741,
"controls-volumeon": 62753,
"controls-volumeoff": 62752,
"yes": 61767,
"no": 61784,
"no-alt": 62261,
"plus": 61746,
"plus-alt": 62722,
"plus-alt2": 62787,
"minus": 62560,
"dismiss": 61779,
"marker": 61785,
"star-filled": 61781,
"star-half": 62553,
"star-empty": 61780,
"flag": 61991,
"info": 62280,
"warning": 62772,
"share": 62007,
"share1": 62007,
"share-alt": 62016,
"share-alt2": 62018,
"twitter": 62209,
"rss": 62211,
"email": 62565,
"email-alt": 62566,
"facebook": 62212,
"facebook-alt": 62213,
"networking": 62245,
"googleplus": 62562,
"location": 62000,
"location-alt": 62001,
"camera": 62214,
"images-alt": 62002,
"images-alt2": 62003,
"video-alt": 62004,
"video-alt2": 62005,
"video-alt3": 62006,
"vault": 61816,
"shield": 62258,
"shield-alt": 62260,
"sos": 62568,
"search": 61817,
"slides": 61825,
"analytics": 61827,
"chart-pie": 61828,
"chart-bar": 61829,
"chart-line": 62008,
"chart-area": 62009,
"groups": 62215,
"businessman": 62264,
"id": 62262,
"id-alt": 62263,
"products": 62226,
"awards": 62227,
"forms": 62228,
"testimonial": 62579,
"portfolio": 62242,
"book": 62256,
"book-alt": 62257,
"download": 62230,
"upload": 62231,
"backup": 62241,
"clock": 62569,
"lightbulb": 62265,
"microphone": 62594,
"desktop": 62578,
"laptop": 62791,
"tablet": 62577,
"smartphone": 62576,
"phone": 62757,
"smiley": 62248,
"index-card": 62736,
"carrot": 62737,
"building": 62738,
"store": 62739,
"album": 62740,
"palmtree": 62759,
"tickets-alt": 62756,
"money": 62758,
"thumbs-up": 62761,
"thumbs-down": 62786,
"layout": 62776,
"paperclip": 62790,
"email-alt2": 62567,
"menu-alt": 61992,
"trash": 61826,
"heading": 61710,
"insert": 61711,
"align-full-width": 61716,
"button": 61722,
"align-wide": 61723,
"ellipsis": 61724,
"buddicons-activity": 62546,
"buddicons-buddypress-logo": 62536,
"buddicons-community": 62547,
"buddicons-forums": 62537,
"buddicons-friends": 62548,
"buddicons-groups": 62550,
"buddicons-pm": 62551,
"buddicons-replies": 62545,
"buddicons-topics": 62544,
"buddicons-tracking": 62549,
"admin-site-alt": 61725,
"admin-site-alt2": 61726,
"admin-site-alt3": 61727,
"rest-api": 61732,
"yes-alt": 61738,
"buddicons-bbpress-logo": 62583,
"tide": 61709,
"editor-ol-rtl": 61740,
"instagram": 61741,
"businessperson": 61742,
"businesswoman": 61743,
"color-picker": 61745,
"camera-alt": 61737,
"editor-ltr": 61708,
"cloud": 61814,
"twitter-alt": 62210,
"menu-alt2": 62249,
"menu-alt3": 62281,
"plugins-checked": 62597,
"text-page": 61729,
"update-alt": 61715,
"code-standards": 61754,
"align-pull-left": 61706,
"align-pull-right": 61707,
"block-default": 61739,
"cloud-saved": 61751,
"cloud-upload": 61755,
"columns": 61756,
"cover-image": 61757,
"embed-audio": 61758,
"embed-generic": 61759,
"embed-photo": 61764,
"embed-post": 61766,
"embed-video": 61769,
"exit": 61770,
"html": 61771,
"info-outline": 61772,
"insert-after": 61773,
"insert-before": 61774,
"remove": 61775,
"shortcode": 61776,
"table-col-after": 61777,
"table-col-before": 61778,
"table-col-delete": 61786,
"table-row-after": 61787,
"table-row-before": 61788,
"table-row-delete": 61789,
"saved": 61790,
"airplane": 61791,
"amazon": 61794,
"bank": 61802,
"beer": 61804,
"bell": 61805,
"calculator": 61806,
"coffee": 61807,
"database-add": 61808,
"database-export": 61818,
"database-import": 61819,
"database-remove": 61820,
"database-view": 61821,
"database": 61822,
"drumstick": 61823,
"edit-page": 61830,
"food": 61831,
"fullscreen-alt": 61832,
"fullscreen-exit-alt": 61833,
"games": 61834,
"google": 61835,
"hourglass": 61836,
"linkedin": 61837,
"money-alt": 61838,
"open-folder": 61839,
"pdf": 61840,
"pets": 61841,
"pinterest": 61842,
"printer": 61843,
"privacy": 61844,
"reddit": 61845,
"spotify": 61846,
"superhero-alt": 61847,
"superhero": 61848,
"twitch": 61849,
"whatsapp": 61850,
"youtube": 61851,
"car": 61803,
"podio": 61852,
"xing": 61853
}