feat: initial ACRIB WordPress deployment

- WordPress 6.9.4 (es_ES) with Kadence theme
- Homepage: Hero, La Asociación, Pilares, Beneficios, Eventos, Miembros, Hazte Miembro, Contacto
- Brand identity: #13294b navy, #a12932 burgundy, #c69c48 gold
- Fonts: Raleway (headings) + Source Sans 3 (body) + Lato (UI)
- Plugins: Kadence Blocks, Polylang, Contact Form 7
- Custom CSS with full brand styling and responsive layout
- HTTPS enforced via wp-config.php proxy detection
This commit is contained in:
Malin
2026-05-19 19:25:59 +02:00
commit f3ff7b7186
6119 changed files with 1984255 additions and 0 deletions

View File

@@ -0,0 +1,280 @@
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

View File

@@ -0,0 +1,162 @@
# Schema Builder
[![CI](https://github.com/stellarwp/schema/workflows/CI/badge.svg)](https://github.com/stellarwp/schema/actions?query=branch%3Amain) [![Static Analysis](https://github.com/stellarwp/schema/actions/workflows/static-analysis.yml/badge.svg)](https://github.com/stellarwp/schema/actions/workflows/static-analysis.yml)
A library for simplifying the creation, update, and field modification of custom tables within WordPress.
## Installation
It's recommended that you install Schema as a project dependency via [Composer](https://getcomposer.org/):
```bash
composer require stellarwp/schema
```
> We _actually_ recommend that this library gets included in your project using [Strauss](https://github.com/BrianHenryIE/strauss).
>
> Luckily, adding Strauss to your `composer.json` is only slightly more complicated than adding a typical dependency, so checkout our [strauss docs](https://github.com/stellarwp/global-docs/blob/main/docs/strauss-setup.md).
## Usage prerequisites
To actually _use_ the schema library, you must have two additional libraries in your project:
1. A Dependency Injection Container (DI Container) that is compatible with [di52](https://github.com/lucatume/di52) _(We recommend using di52.)_.
1. The [stellarwp/db](https://github.com/stellarwp/db) library.
In order to keep this library as light as possible, those dependencies are not included in the library itself. To avoid version compatibility issues, those libraries are _also_ not included as Composer dependencies. Instead, you must include them in your project. We recommend including them via composer [using Strauss](https://github.com/stellarwp/global-docs/blob/main/docs/strauss-setup.md), just like you have done with this library.
## Important note on ALL examples
All examples within the documentation for this project will be assuming that you are using [Strauss](#strauss) to prefix the namespaces provided by this library.
The examples will be using:
* `Boom\Shakalaka\` as the namespace prefix, though will sometimes be referenced as `PREFIX\` for the purpose of brevity in the docs.
* `BOOM_SHAKALAKA_` as the constant prefix.
## Getting started
For a full understanding of what is available in this library and how to use it, definitely read through the full [documentation](#documentation). But for folks that want to get rolling with the basics quickly, try out the following.
### Initializing the library
```php
use Boom\Shakalaka\StellarWP\Schema\Config;
// You'll need a Dependency Injection Container that is compatible with https://github.com/lucatume/di52.
use Boom\Shakalaka\lucatume\DI52\Container;
// You'll need to use the StellarWP\DB library for database operations.
use Boom\Shakalaka\StellarWP\DB\DB;
$container = new Boom\Shakalaka\lucatume\DI52\Container();
Config::set_container( $container );
Config::set_db( DB::class );
```
### Creating a table
Let's say you want a new custom table called `sandwiches` (with the default WP prefix, it'd be `wp_sandwiches`). You'll need a class file for the table. For the sake of this example, we'll be assuming this class is going into a `Tables/` directory and is reachable via the `Boom\Shakalaka\Tables` namespace.
```php
<?php
namespace Boom\Shakalaka\Tables;
use Boom\Shakalaka\StellarWP\Schema\Tables\Contracts\Table;
class Sandwiches extends Table {
/**
* {@inheritdoc}
*/
const SCHEMA_VERSION = '1.0.0';
/**
* {@inheritdoc}
*/
protected static $base_table_name = 'sandwiches';
/**
* {@inheritdoc}
*/
protected static $group = 'boom';
/**
* {@inheritdoc}
*/
protected static $schema_slug = 'boom-sandwiches';
/**
* {@inheritdoc}
*/
protected static $uid_column = 'id';
/**
* {@inheritdoc}
*/
protected function get_definition() {
global $wpdb;
$table_name = self::table_name( true );
$charset_collate = $wpdb->get_charset_collate();
return "
CREATE TABLE `{$table_name}` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) {$charset_collate};
";
}
}
```
Here's what the properties and method mean:
* `$base_table_name`: The name of the table without the prefix.
* `$group`: The group that the table belongs to - this is for organizational purposes.
* `$schema_slug`: An identifier for the table. This is used in storing your table's schema version in `wp_options`.
* `$uid_column`: The name of the column that is used to uniquely identify each row.
* `get_definition()`: This should return the base SQL definition used to create your `sandwiches` table. To get the full SQL (with any field schemas included), you can call `get_sql()`!
### Registering the table
The Schema library gets initialized automatically when you register at table or a field schema. To register your table, simply use the handy `Register::table()` method within the `plugins_loaded`:
```php
namespace Boom\Shakalaka;
use Boom\Shakalaka\StellarWP\Schema\Register;
use Boom\Shakalaka\Tables\Sandwiches;
add_action( 'plugins_loaded', static function() {
Register::table( Sandwiches::class );
} );
```
### That's it!
The table will be automatically registered, created, and updated during the `plugins_loaded` action at priority `1000`! _(that priority number is filterable via the `stellarwp_schema_up_plugins_loaded_priority` filter)_
## Documentation
Here's some more advanced documentation to get you rolling on using this library at a deeper level:
1. [Setting up Strauss](/docs/strauss-setup.md)
1. [Schema management](/docs/schemas.md)
1. [Table schemas](/docs/schemas-table.md)
1. [Versioning](/docs/schemas-table.md#versioning)
1. [Registering tables](/docs/schemas-table.md#registering-tables)
1. [Deregistering tables](/docs/schemas-table.md#deregistering-tables)
1. [Table collection](/docs/schemas-table.md#table-collection)
1. [Publicly accessible methods](/docs/schemas-table.md#publicly-accessible-methods)
1. [Field schemas](/docs/schemas-field.md)
1. [Versioning](/docs/schemas-field.md#versioning)
1. [Registering fields](/docs/schemas-field.md#registering-field)
1. [Deregistering fields](/docs/schemas-field.md#deregistering-fields)
1. [Field collection](/docs/schemas-field.md#field-collection)
1. [Publicly accessible methods](/docs/schemas-field.md#publicly-accessible-methods)
1. [Automated testing](/docs/automated-testing.md)
## Acknowledgements
Special props go to [@lucatume](https://github.com/lucatume) and [@stratease](https://github.com/stratease) for their initial work on this structure before it was extracted into a standalone library.

View File

@@ -0,0 +1,84 @@
<?php
/**
* Handles the code that should be executed when the plugin is activated or deactivated.
*
* @since 1.0.0
*
* @package StellarWP\WPTables
*/
namespace KadenceWP\KadenceBlocks\StellarWP\Schema;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Builder;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Config;
/**
* Class Activation
*
* @since 1.0.0
*
* @package StellarWP\WPTables
*/
class Activation {
/**
* The name of the transient that will be used to flag whether the library activated
* or not.
*
* @since 1.0.0
*/
const ACTIVATION_TRANSIENT = 'stellar_schema_builder_initialized';
/**
* Handles the activation of the feature functions.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*/
public static function activate() {
$schema_builder = Config::get_container()->get( Builder::class);
$schema_builder->up();
}
/**
* Checks the state to determine if whether we can create custom tables.
*
* This method will run once a day (using transients).
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*/
public static function init() {
// Check if we ran recently.
$db_hash = get_transient( static::ACTIVATION_TRANSIENT );
$container = Config::get_container();
$schema_builder = $container->get( Builder::class );
$hash = $schema_builder->get_registered_schemas_version_hash();
if ( $db_hash == $hash ) {
return;
}
set_transient( static::ACTIVATION_TRANSIENT, $hash, DAY_IN_SECONDS );
// Sync any schema changes we may have.
if ( $schema_builder->all_tables_exist() ) {
$schema_builder->up();
}
if (
! $container->has( 'stellarwp_schema_fully_activated' )
&& ! $container->get( 'stellarwp_schema_fully_activated' )
) {
/**
* On new installations the full activation code will find an empty state and
* will have not activated at this point, do it now if required.
*/
$container->singleton( Full_Activation_Provider::class, Full_Activation_Provider::class );
$container->get( Full_Activation_Provider::class )->register();
}
}
}

View File

@@ -0,0 +1,294 @@
<?php
namespace KadenceWP\KadenceBlocks\StellarWP\Schema;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Config;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Fields;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Contracts\Schema_Interface as Field_Schema_Interface;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Tables;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Contracts\Schema_Interface as Table_Schema_Interface;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Filters\Group_FilterIterator;
use WP_CLI;
class Builder
{
/**
* Container.
*
* @var object
*/
protected $container;
/**
* StellarWP\DB class.
*
* @var class-string<\KadenceWP\KadenceBlocks\StellarWP\DB\DB>
*/
protected $db;
/**
* Constructor.
*
* @param class-string<\KadenceWP\KadenceBlocks\StellarWP\DB\DB>|null $db StellarWP\DB class.
* @param object $container Container instance.
*/
public function __construct($db = null, $container = null)
{
$this->db = $db ?: Config::get_db();
$this->container = $container ?: Config::get_container();
}
/**
* Whether all the custom tables exist or not. Does not check custom fields.
*
* Note: the method will return `false` if even one table is missing.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @param string|null $group An optional group name to restrict the check to.
*
* @return bool Whether all custom tables exist or not. Does not check custom fields.
*/
public function all_tables_exist($group = null)
{
$table_schemas = $this->get_registered_table_schemas();
if (null !== $group) {
$table_schemas = new Group_FilterIterator((array) $group, $table_schemas);
}
if (count($table_schemas) === 0) {
// No table class was even found, so yeah, all tables exist.
return true;
}
$result = $this->db::get_col('SHOW TABLES');
foreach ($table_schemas as $table_schema) {
if (!in_array($table_schema::table_name(), $result, true)) {
return false;
}
}
return true;
}
/**
* Trigger actions to drop the custom tables.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*/
public function down()
{
/**
* Runs before the custom tables are dropped.
*
* @since 1.0.0
*/
do_action('stellarwp_pre_drop_tables');
$table_schemas = $this->get_registered_table_schemas();
/**
* Filters the tables to be dropped.
*
* @since 1.0.0
*
* @param \Iterator $table_schemas A list of Table_Schema_Interface objects that will have their tables dropped.
*/
$table_schemas = apply_filters('stellarwp_tables_to_drop', $table_schemas);
foreach ($table_schemas as $table_schema) {
$table_schema->drop();
}
/**
* Runs after the custom tables have been dropped by The Events Calendar.
*
* @since 1.0.0
*/
do_action('stellarwp_post_drop_tables');
/**
* Runs before the custom fields are dropped.
*
* @since 1.0.0
*/
do_action('stellarwp_pre_drop_fields');
$field_schemas = $this->get_registered_field_schemas();
/**
* Filters the fields to be dropped.
*
* @since 1.0.0
*
* @param \Iterator $field_classes A list of Field_Schema_Interface objects that will have their fields dropped.
*/
$field_schemas = apply_filters('stellarwp_fields_to_drop', $field_schemas);
foreach ($field_schemas as $field_schema) {
$field_schema->drop();
}
/**
* Runs after the custom tables have been dropped by The Events Calendar.
*
* @since 1.0.0
*/
do_action('stellarwp_post_drop_fields');
}
/**
* Empties the plugin custom tables.
*
* @since 1.0.0
*/
public function empty_custom_tables()
{
$schemas = $this->get_registered_table_schemas();
foreach ($schemas as $custom_table) {
/** @var Table_Schema_Interface $custom_table */
WP_CLI::debug('Emptying table ' . $custom_table::table_name(), 'StellarWP');
$custom_table->empty_table();
}
}
/**
* Get the registered field handlers.
*
* @since 1.0.0
*
* @return Fields\Collection
*/
public function get_registered_field_schemas(): \KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Collection
{
return $this->container->get(\KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Collection::class);
}
/**
* Get the md5 hash of all the registered schemas classes with their versions.
*
* @since 1.0.0
*
* @return string
*/
public function get_registered_schemas_version_hash(): string
{
$schemas = $this->get_registered_table_schemas();
$versions = [];
foreach ($schemas as $schema) {
// Skip if not an Interface of Table.
if (!$schema instanceof Table_Schema_Interface) {
continue;
}
$versions[$schema::base_table_name()] = $schema->get_version();
}
// Sort to avoid hash changing due to order changes.
ksort($versions);
return md5(json_encode($versions));
}
/**
* Get the registered table handlers.
*
* @since 1.0.0
*
* @return Tables\Collection
*/
public function get_registered_table_schemas(): \KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Collection
{
return $this->container->get(\KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Collection::class);
}
/**
* Get the registered table handlers that need updates.
*
* @since 1.0.0
*
* @return Tables\Collection
*/
public function get_table_schemas_that_need_updates()
{
return $this->container->get(\KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Collection::class)->get_tables_needing_updates();
}
/**
* Filters the list of tables for a blog adding the ones created by the plugin.
*
* @since 1.0.0
*
* @param array $tables An array of table names for the blog.
*
* @return array<string> A filtered array of table names, including prefix.
*/
public function filter_tables_list($tables)
{
$schemas = $this->get_registered_table_schemas();
foreach ($schemas as $class) {
$table_name = $class::table_name(true);
$tables[$table_name] = $table_name;
}
return $tables;
}
/**
* Registers the custom table names as properties on the `wpdb` global.
*
* @since 1.0.0
*/
public function register_custom_tables_names()
{
global $wpdb;
$schemas = $this->get_registered_table_schemas();
foreach ($schemas as $class) {
$no_prefix_table_name = $class::table_name(false);
$prefixed_table_name = $class::table_name(true);
$wpdb->{$no_prefix_table_name} = $prefixed_table_name;
if (!in_array($wpdb->{$no_prefix_table_name}, $wpdb->tables, true)) {
$wpdb->tables[] = $no_prefix_table_name;
}
}
}
/**
* Creates or updates the custom tables the plugin will use.
*
* @since 1.0.0
* @since 1.1.8 Decided if we can perform the queries based on blog's status.
*
* @param bool $force Whether to force the creation or update of the tables or not.
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return array<mixed> A list of each creation or update result.
*/
public function up($force = false)
{
if (doing_action('switch_blog')) {
/*
* The `switch_blog` action can be called by the `wp_initialize_site` function, before the blog exists.
* Running `is_blog_installed()` in this case will kill the site with a dead db message since the
* `users` table will be found (it's common for all blogs), but the `options` table will not be found for
* the blog.
* If the blog does not exist, the value will not be cached yet and the value will be `false`.
* Else we can just use the value; this will be the case for a normal `switch_blog` action that does not
* fire while creating the site.
*
* When is the next chance to create the tables? Likely in the `activate_blog` action that will be fired
* in the same request following the blog creation or in the next `switch_blog` action.
*/
$is_blog_installed = wp_cache_get('is_blog_installed');
} else {
$is_blog_installed = is_blog_installed();
}
if (!$is_blog_installed || wp_installing()) {
return [];
}
$results = [];
$table_schemas = $force ? $this->get_registered_table_schemas() : $this->get_table_schemas_that_need_updates();
// Get all registered table classes.
foreach ($table_schemas as $table_schema) {
/** @var Table_Schema_Interface $table_schema */
$results[$table_schema::table_name()] = $table_schema->update();
}
$this->register_custom_tables_names();
return count($results) ? array_merge(...array_values($results)) : [];
}
/**
* A proxy method to update the tables without forcing
* them.
*
* If the `update_tables` was directly hooked to the blog
* switches, then the blog ID, a positive integer, would be
* cast to a truthy value and force the table updates when
* not really required to.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return array<mixed> A list of each creation or update result.
*/
public function update_blog_tables()
{
return $this->up(false);
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace KadenceWP\KadenceBlocks\StellarWP\Schema;
use KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface;
class Config {
/**
* Container object.
*
* @var ContainerInterface
*/
private static $container;
/**
* StellarWP\DB class.
*
* @var class-string<\KadenceWP\KadenceBlocks\StellarWP\DB\DB>
*/
private static $db_class;
/**
* Get the container.
*
* @return ContainerInterface
*/
public static function get_container() : ContainerInterface {
if ( self::$container === null ) {
throw new \RuntimeException( 'You must provide a container via StellarWP\Schema\Config::set_container() before attempting to fetch it.' );
}
return self::$container;
}
/**
* Get the StellarWP\DB class.
*
* @return class-string<\KadenceWP\KadenceBlocks\StellarWP\DB\DB>
*/
public static function get_db() : string {
if ( self::$db_class === null ) {
throw new \RuntimeException( 'You must provide a StellarWP\DB\DB::class via StellarWP\Schema\Config::set_db() before attempting to fetch it.' );
}
return self::$db_class;
}
/**
* Returns whether the container has been set.
*
* @return bool
*/
public static function has_container() : bool {
return self::$container !== null;
}
/**
* Returns whether the db has been set.
*
* @return bool
*/
public static function has_db() : bool {
return self::$db_class !== null;
}
/**
* Set the container object.
*
* @param ContainerInterface $container Container object.
*/
public static function set_container( ContainerInterface $container ) {
self::$container = $container;
}
/**
* Set the StellarWP\DB class.
*
* @param class-string<\KadenceWP\KadenceBlocks\StellarWP\DB\DB> $db_class StellarWP\DB class.
*/
public static function set_db( string $db_class ) {
self::$db_class = $db_class;
}
}

View File

@@ -0,0 +1,175 @@
<?php
namespace KadenceWP\KadenceBlocks\StellarWP\Schema\Fields;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Contracts\Schema_Interface;
class Collection implements \ArrayAccess, \Countable, \Iterator
{
/**
* Table groups.
*
* @var array<string>
*/
private $groups = [];
/**
* Collection of fields.
*
* @var array<mixed>
*/
private $fields = [];
/**
* Adds a table to the collection.
*
* @since 1.0.0
*
* @param Schema_Interface $field Field instance.
*
* @return mixed
*/
public function add(Schema_Interface $field)
{
$this->offsetSet($field::get_schema_slug(), $field);
$this->register_group($field);
return $this->offsetGet($field::get_schema_slug());
}
/**
* @inheritDoc
*/
public function count(): int
{
return count($this->fields);
}
/**
* @inheritDoc
*/
#[\ReturnTypeWillChange]
public function current()
{
return current($this->fields);
}
/**
* Alias method for offsetGet.
*
* @since 1.0.0
*
* @param string $key Field slug.
*
* @return Schema_Interface
*/
public function get(string $key): Schema_Interface
{
return $this->offsetGet($key);
}
/**
* Gets fields by table.
*
* @since 1.0.0
*
* @param array<string>|string $tables Tables to filter fields by.
* @param \Iterator $iterator Optional. Iterator to filter.
*
* @return Filters\Table_FilterIterator
*/
public function get_by_table($tables, $iterator = null): \KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Filters\Table_FilterIterator
{
return new Filters\Table_FilterIterator($tables, $iterator ?: $this);
}
/**
* @inheritDoc
*/
public function key(): string
{
return key($this->fields);
}
/**
* @inheritDoc
*/
public function next(): void
{
next($this->fields);
}
/**
* @inheritDoc
*/
public function offsetExists($offset): bool
{
return isset($this->fields[$offset]);
}
/**
* @inheritDoc
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->fields[$offset];
}
/**
* @inheritDoc
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value): void
{
$this->fields[$offset] = $value;
}
/**
* @inheritDoc
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset): void
{
unset($this->fields[$offset]);
}
/**
* Registers a group in the group array for the given table.
*
* @param Schema_Interface $field Field instance.
*/
private function register_group($field)
{
$group = $field->group_name();
if (!isset($this->groups[$group])) {
$this->groups[$group] = $group;
}
}
/**
* Helper function for removing a table from the collection.
*
* @since 1.0.0
*
* @param string $name Table name.
*/
public function remove($name): void
{
$this->offsetUnset($name);
}
/**
* @inheritDoc
*/
public function rewind(): void
{
reset($this->fields);
}
/**
* Sets a table in the collection.
*
* @since 1.0.0
*
* @param string $name Field name.
* @param Schema_Interface $field Field instance.
*
* @return mixed
*/
public function set($name, Schema_Interface $field)
{
$this->offsetSet($name, $field);
$this->register_group($field);
return $this->offsetGet($name);
}
/**
* @inheritDoc
*/
public function valid(): bool
{
return key($this->fields) !== null;
}
}

View File

@@ -0,0 +1,247 @@
<?php
/**
* Groups the base methods and functions used by all custom field implementations.
*
* @since 1.0.0
*
* @package KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Contracts
*/
namespace KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Contracts;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Config;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Schema;
/**
* Class Field
*
* @since 1.0.0
*
* @package \KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Contracts
*/
abstract class Field implements Schema_Interface
{
/**
* @since 1.0.0
*
* @var string|null The version number for this schema definition.
*/
const SCHEMA_VERSION = null;
/**
* @since 1.0.0
*
* @var string The base table name.
*/
protected static $base_table_name = '';
/**
* @var object The dependency injection container.
*/
protected $container;
/**
* @var class-string<\KadenceWP\KadenceBlocks\StellarWP\DB\DB> The db class.
*/
protected $db;
/**
* @since 1.0.0
*
* @var string The slug used to identify the custom field alterations.
*/
protected static $schema_slug = '';
/**
* @since 1.0.0
*
* @var array<string> Custom fields defined in this field schema.
*/
protected $fields = [];
/**
* @var string The organizational group this field set belongs to.
*/
protected static $group = '';
/**
* Constructor.
*
* @since 1.0.0
*
* @param class-string<\KadenceWP\KadenceBlocks\StellarWP\DB\DB>|null $db StellarWP\DB object.
* @param object $container The container to use.
*/
public function __construct($db = null, $container = null)
{
$this->db = $db ?: Config::get_db();
$this->container = $container ?: Config::get_container();
}
/**
* {@inheritdoc}
*/
public function after_update(array $results)
{
// No-op by default.
return $results;
}
/**
* Gets the base table name.
*
* @since 1.0.0
*
* @return string
*/
public static function base_table_name()
{
return static::$base_table_name;
}
/**
* {@inheritdoc}
*/
public function drop()
{
if (!$this->exists()) {
return false;
}
$schema_slug = static::get_schema_slug();
/**
* Allows for the enabling of field removal.
*
* Defaults to false.
*
* @since 1.0.0
*
* @param bool $can_drop_field Whether or not the field schema can be dropped.
* @param string $schema_slug The slug of the field schema.
*/
$can_drop_field = apply_filters("stellarwp_drop_field_enabled_{$schema_slug}", false, $schema_slug);
/**
* Allows for the enabling of field removal.
*
* Defaults to false.
*
* @since 1.0.0
*
* @param bool $can_drop_field Whether or not the field schema can be dropped.
* @param string $schema_slug The slug of the field schema.
*/
$can_drop_field = apply_filters("stellarwp_drop_field_enabled", $can_drop_field, $schema_slug);
if (!$can_drop_field) {
return false;
}
/**
* Runs before the custom field is dropped.
*
* @since 1.0.0
*
* @param string $schema_slug The schema slug.
* @param Schema_Interface $field_schema The field schema to be dropped.
*/
do_action('stellarwp_pre_drop_field', $schema_slug, $this);
$this_table = $this->table_schema()::table_name(true);
$drop_columns = 'DROP COLUMN `' . implode('`, DROP COLUMN `', $this->fields()) . '`';
$results = $this->db::query(sprintf("ALTER TABLE %s %s", $this_table, $drop_columns));
/**
* Runs after the custom field has been dropped.
*
* @since 1.0.0
*
* @param string $schema_slug The schema slug.
* @param Schema_Interface $field_schema The field schema to be dropped.
*/
do_action('stellarwp_post_drop_field', $schema_slug, $this);
$this->table_schema()->sync_stored_version();
/**
* Runs after the custom field's table schema's version has been synchronized.
*
* @since 1.0.0
*
* @param string $schema_slug The schema slug.
* @param Schema_Interface $field_schema The field schema to be dropped.
*/
do_action('stellarwp_post_drop_field_table_version_sync', $schema_slug, $this);
return $results;
}
/**
* Returns whether a fields' schema definition exists in the table or not.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return bool Whether a set of fields exists in the database or not.
*/
public function exists()
{
$table_schema = $this->table_schema();
if ($table_schema === null) {
return false;
}
$table_name = $table_schema::table_name(true);
$rows = $this->db::table($this->db::raw('information_schema.statistics'))->select('column_name')->whereRaw('WHERE TABLE_SCHEMA = DATABASE()')->where('TABLE_NAME', $table_name)->getAll();
$fields = $this->fields();
$rows = array_map(function ($row) {
return $row->column_name;
}, $rows);
foreach ($fields as $field) {
if (!in_array($field, $rows, true)) {
return false;
}
}
return true;
}
/**
* Fields being added to the table.
*
* @since 1.0.0
*
* @return array<string>
*/
public function fields()
{
return (array) $this->fields;
}
/**
* The base table name of the schema.
*
* @since 1.0.0
*/
public static function get_schema_slug()
{
return static::$schema_slug;
}
/**
* {@inheritdoc}
*/
public function get_sql()
{
return $this->get_definition();
}
/**
* {@inheritdoc}
*/
abstract protected function get_definition();
/**
* Gets the field schema's version.
*
* @since 1.0.0
*
* @return string
*/
public function get_version(): string
{
return static::get_schema_slug() . '-' . static::SCHEMA_VERSION;
}
/**
* {@inheritdoc}
*/
public static function group_name()
{
return static::$group;
}
/**
* {@inheritdoc}
*/
public function table_schema()
{
$tables = Schema::tables();
$base_table_name = static::base_table_name();
if (!isset($tables[$base_table_name])) {
return null;
}
return $tables->offsetGet($base_table_name);
}
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* The API implemented by each custom field. Used in cases where only a portion of an existing table must be modified.
*
* @since 1.0.0
*
* @package KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Contracts
*/
namespace KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Contracts;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Contracts\Table;
/**
* Interface Custom_Field_Interface
*
* @since 1.0.0
*
* @package \KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Contracts
*/
interface Schema_Interface
{
/**
* Allows extending classes that require it to run some methods
* immediately after the table creation or update.
*
* @since 1.0.0
*
* @param array<string,string> $results A map of results in the format
* returned by the `dbDelta` function.
*
* @return array<string,string> A map of results in the format returned by
* the `dbDelta` function.
*/
public function after_update(array $results);
/**
* Drop the custom fields.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return bool `true` if successful operation, `false` to indicate a failure.
*/
public function drop();
/**
* Gets the custom slug identifier that should identify this field schema.
*
* @since 1.0.0
*
* @return string
*/
public static function get_schema_slug();
/**
* Returns the SQL to be injected into CREATE TABLE statement for the fields and indexes being created in the format supported
* by the `dbDelta` function.
*
* @since 1.0.0
*
* @return string The table creation SQL for the fields and indexes being created, in the format supported
* by the `dbDelta` function.
*/
public function get_sql();
/**
* The organizational group this field schema belongs to.
*
* @since 1.0.0
*
* @return string
*/
public static function group_name();
/**
* A reference to the table definition we are modifying with new fields.
*
* @since 1.0.0
*
* @return Table|null
*/
public function table_schema();
}

View File

@@ -0,0 +1,44 @@
<?php
namespace KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Filters;
class Table_FilterIterator extends \FilterIterator implements \Countable {
/**
* Tables to filter.
*
* @since 1.0.0
*
* @var array<string>
*/
private $tables = [];
/**
* Constructor.
*
* @since 1.0.0
*
* @param string|array<string> $tables Tables to filter.
* @param \Iterator $iterator Iterator to filter.
*/
public function __construct( $tables, \Iterator $iterator ) {
parent::__construct( $iterator );
$this->tables = (array) $tables;
}
/**
* @inheritDoc
*/
public function accept(): bool {
$field = $this->getInnerIterator()->current();
return in_array( $field->base_table_name(), $this->tables, true );
}
/**
* @inheritDoc
*/
public function count(): int {
return iterator_count( $this->getInnerIterator() );
}
}

View File

@@ -0,0 +1,108 @@
<?php
/**
* Responsible for registering providers that are only relevant after an appropriate number of steps have been taken to
* fully activate the features of Custom Tables V1.
*
* Should not be registered if the Custom Tables have not been generated yet.
*
* @since 1.0.0
*
* @package StellarWP\Schema
*/
namespace KadenceWP\KadenceBlocks\StellarWP\Schema;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Builder;
use WP_CLI;
/**
* Class Full_Activation_Provider
*
* @since 1.0.0
*
* @package \StellarWP\Schema
*/
class Full_Activation_Provider
{
/**
* Container object.
*
* @var object
*/
private $container;
/**
* A flag property indicating whether the Service Provider did register or not.
*
* @since 1.0.0
*
* @var bool
*/
private $did_register = false;
/**
* Constructor.
*
* @param object $container
*/
public function __construct($container = null)
{
$this->container = $container ?: Config::get_container();
}
/**
* Registers the filters and implementations required by the Custom Tables implementation.
*
* @since 1.0.0
*
* @return bool Whether the Provider did register or not.
*/
public function register()
{
if ($this->did_register) {
// Let's avoid double filtering by making sure we're registering at most once.
return true;
}
$this->did_register = true;
$this->container->bind('stellar_schema_fully_activated', static function () {
return true;
});
/*
* This block should be the only one capturing exceptions thrown in the context of
* the feature. This removes the burden of exception and error handling from the
* actual business code.
*/
try {
$this->register_schema_hooks();
} catch (\Throwable $t) {
/**
* Fires an action when an error or exception happens in the
* context of custom table implementations.
*
* @since 1.0.0
*
* @param \Throwable $t The thrown error.
*/
do_action('stellarwp_schema_error', $t);
}
return true;
}
/**
* Registers the actions and filters required to have the custom table names available
* as properties on the `$wpdb` instance and to hook into some WP_CLI operations to
* empty the tables correctly.
*
* @since 1.0.0
*/
private function register_schema_hooks()
{
$schema_builder = $this->container->get(Builder::class);
$schema_builder->register_custom_tables_names();
if (is_multisite()) {
add_action('activate_blog', [$schema_builder, 'update_blog_tables']);
add_action('activate_blog', [$schema_builder, 'register_custom_tables_names']);
add_action('switch_blog', [$schema_builder, 'update_blog_tables']);
add_action('switch_blog', [$schema_builder, 'register_custom_tables_names']);
add_filter('wpmu_drop_tables', [$schema_builder, 'filter_tables_list']);
}
if (defined('WP_CLI')) {
WP_CLI::add_hook('after_invoke:site empty', [$schema_builder, 'empty_custom_tables']);
}
}
}

View File

@@ -0,0 +1,168 @@
<?php
namespace KadenceWP\KadenceBlocks\StellarWP\Schema;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Builder;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Config;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Fields;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Tables;
/**
* A helper class for registering StellarWP Schema resources.
*/
class Register {
/**
* Register a field schema.
*
* @since 1.0.0
*
* @param string|Fields\Contracts\Field $field Field class.
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return Fields\Contracts\Schema_Interface
*/
public static function field( $field ) {
Schema::init();
if ( is_string( $field ) ) {
$field = new $field();
}
$container = Config::get_container();
Schema::fields()->add( $field );
// If we've already executed plugins_loaded, automatically add the field.
if ( did_action( 'plugins_loaded' ) ) {
$container->get( Builder::class )->up();
}
return $field;
}
/**
* Register multiple field schemas.
*
* @since 1.0.0
*
* @param array<mixed> $fields Fields to register.
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return Fields\Collection
*/
public static function fields( array $fields ) {
foreach ( $fields as $field ) {
static::field( $field );
}
return Schema::fields();
}
/**
* Removes a field from the register.
*
* @since 1.0.0
*
* @param string|Fields\Contracts\Schema_Interface $field Field Schema class.
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return Fields\Contracts\Schema_Interface
*/
public static function remove_field( $field ) {
Schema::init();
if ( is_string( $field ) ) {
$field = new $field();
}
// If we've already executed plugins_loaded, automatically remove the field.
if ( did_action( 'plugins_loaded' ) ) {
$field->drop();
}
Schema::fields()->remove( $field::get_schema_slug() );
return $field;
}
/**
* Removes a table from the register.
*
* @since 1.0.0
*
* @param string|Tables\Contracts\Schema_Interface $table Table Schema class.
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return Tables\Contracts\Schema_Interface
*/
public static function remove_table( $table ) {
Schema::init();
if ( is_string( $table ) ) {
$table = new $table();
}
// If we've already executed plugins_loaded, automatically remove the field.
if ( did_action( 'plugins_loaded' ) ) {
$table->drop();
}
Schema::tables()->remove( $table::base_table_name() );
return $table;
}
/**
* Register a table schema.
*
* @since 1.0.0
*
* @param string|Tables\Contracts\Table $table Table class.
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return Tables\Contracts\Schema_Interface
*/
public static function table( $table ) {
Schema::init();
if ( is_string( $table ) ) {
$table = new $table();
}
$container = Config::get_container();
Schema::tables()->add( $table );
// If we've already executed plugins_loaded, automatically add the table.
if ( did_action( 'plugins_loaded' ) ) {
$container->get( Builder::class )->up();
}
return $table;
}
/**
* Register multiple table schemas.
*
* @since 1.0.0
*
* @param array<mixed> $tables Tables to register.
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return Tables\Collection
*/
public static function tables( array $tables ) {
foreach ( $tables as $table ) {
static::table( $table );
}
return Schema::tables();
}
}

View File

@@ -0,0 +1,127 @@
<?php
namespace KadenceWP\KadenceBlocks\StellarWP\Schema;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Config;
class Schema
{
const VERSION = '1.1.0';
/**
* Container object.
*
* @var object
*/
private $container;
/**
* Gets the Builder.
*
* @since 1.0.0
*
* @return Builder
*/
public static function builder()
{
static::init();
return Config::get_container()->get(Builder::class);
}
/**
* Gets the field collection.
*
* @since 1.0.0
*
* @return Fields\Collection
*/
public static function fields()
{
static::init();
return Config::get_container()->get(\KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Collection::class);
}
/**
* Initializes the service provider.
*
* @since 1.0.0
*/
public static function init(): void
{
if (!Config::has_container() || !Config::has_db()) {
throw new \RuntimeException('You must call StellarWP\Schema\Config::set_container() and StellarWP\Schema\Config::set_db() before calling StellarWP\Schema\Schema::init().');
}
$container = Config::get_container();
if ($container->has('stellarwp_schema_registered') && $container->get('stellarwp_schema_registered')) {
return;
}
$db_class = Config::get_db();
$db_class::init();
$container->singleton(static::class, static::class);
$container->get(static::class)->register();
$container->bind('stellarwp_schema_registered', static function () {
return true;
});
}
/**
* Constructor.
*
* @param object $container
*/
public function __construct($container = null)
{
$this->container = $container ?: Config::get_container();
}
/**
* Binds and sets up implementations.
*
* @since 1.0.0
*/
public function register()
{
$this->container->singleton(static::class, $this);
$this->container->singleton(Builder::class);
$this->container->singleton(\KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Collection::class);
$this->container->singleton(\KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Collection::class);
/**
* These providers should be the ones that extend the bulk of features for CT1,
* with only the bare minimum of providers registered above, to determine important state information.
*/
$this->container->singleton(Full_Activation_Provider::class, Full_Activation_Provider::class);
$this->container->get(Full_Activation_Provider::class)->register();
// Set a flag in the container to indicate there was a full activation of the CT1 component.
$this->container->bind('stellarwp_schema_fully_activated', static function () {
return true;
});
$this->register_hooks();
}
/**
* Registers all hooks.
*
* @since 1.0.0
*/
private function register_hooks(): void
{
if (did_action('plugins_loaded')) {
$this->container->get(Builder::class)->up();
} else {
/**
* Filters the priority of the plugins_loaded action for running Builder::up.
*
* @param int $priority The priority of the action.
*/
$priority = apply_filters('stellarwp_schema_up_plugins_loaded_priority', 1000);
$container = $this->container;
add_action('plugins_loaded', static function () use ($container) {
$container->get(Builder::class)->up();
}, $priority, 0);
}
}
/**
* Gets the table collection.
*
* @since 1.0.0
*
* @return Tables\Collection
*/
public static function tables()
{
static::init();
return Config::get_container()->get(\KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Collection::class);
}
}

View File

@@ -0,0 +1,186 @@
<?php
namespace KadenceWP\KadenceBlocks\StellarWP\Schema\Tables;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Contracts\Schema_Interface;
class Collection implements \ArrayAccess, \Countable, \Iterator
{
/**
* Table groups.
*
* @var array<string>
*/
private $groups = [];
/**
* Collection of tables.
*
* @var array<mixed>
*/
private $tables = [];
/**
* Adds a table to the collection.
*
* @since 1.0.0
*
* @param Schema_Interface $table Table instance.
*
* @return mixed
*/
public function add(Schema_Interface $table)
{
$this->offsetSet($table::base_table_name(), $table);
$this->register_group($table);
return $this->offsetGet($table::base_table_name());
}
/**
* @inheritDoc
*/
public function count(): int
{
return iterator_count($this);
}
/**
* @inheritDoc
*/
#[\ReturnTypeWillChange]
public function current()
{
return current($this->tables);
}
/**
* Alias method for offsetGet.
*
* @since 1.0.0
*
* @param string $key Table base name.
*
* @return Schema_Interface
*/
public function get(string $key): Schema_Interface
{
return $this->offsetGet($key);
}
/**
* Gets tables by group.
*
* @since 1.0.0
*
* @param array<string>|string $groups Groups to filter tables by.
* @param \Iterator $iterator Optional. Iterator to filter.
*
* @return Filters\Group_FilterIterator
*/
public function get_by_group($groups, $iterator = null): \KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Filters\Group_FilterIterator
{
return new Filters\Group_FilterIterator((array) $groups, $iterator ?: $this);
}
/**
* Gets tables that need updates.
*
* @since 1.0.0
*
* @param \Iterator $iterator Optional. Iterator to filter.
*
* @return Filters\Needs_Update_FilterIterator
*/
public function get_tables_needing_updates($iterator = null): \KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Filters\Needs_Update_FilterIterator
{
return new Filters\Needs_Update_FilterIterator($iterator ?: $this);
}
/**
* @inheritDoc
*/
public function key(): string
{
return key($this->tables);
}
/**
* @inheritDoc
*/
public function next(): void
{
next($this->tables);
}
/**
* @inheritDoc
*/
public function offsetExists($offset): bool
{
return isset($this->tables[$offset]);
}
/**
* @inheritDoc
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->tables[$offset];
}
/**
* @inheritDoc
*/
public function offsetSet($offset, $value): void
{
$this->tables[$offset] = $value;
}
/**
* @inheritDoc
*/
public function offsetUnset($offset): void
{
unset($this->tables[$offset]);
}
/**
* Registers a group in the group array for the given table.
*
* @param Schema_Interface $table Table instance.
*/
private function register_group($table)
{
$group = $table->group_name();
if (!isset($this->groups[$group])) {
$this->groups[$group] = $group;
}
}
/**
* Helper function for removing a table from the collection.
*
* @since 1.0.0
*
* @param string $name Table name.
*/
public function remove($name): void
{
$this->offsetUnset($name);
}
/**
* @inheritDoc
*/
public function rewind(): void
{
reset($this->tables);
}
/**
* Sets a table in the collection.
*
* @since 1.0.0
*
* @param string $name Table name.
* @param Schema_Interface $table Table instance.
*
* @return mixed
*/
public function set($name, Schema_Interface $table)
{
$this->offsetSet($name, $table);
$this->register_group($table);
return $this->offsetGet($name);
}
/**
* @inheritDoc
*/
public function valid(): bool
{
return key($this->tables) !== null;
}
}

View File

@@ -0,0 +1,131 @@
<?php
/**
* The API implemented by each custom table.
*
* @since 1.0.0
*
* @package KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Contracts
*/
namespace KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Contracts;
/**
* Interface Schema_Interface
*
* @since 1.0.0
*
* @package \KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Contracts
*/
interface Schema_Interface
{
/**
* Returns the custom table name.
*
* @since 1.0.0
*
* @return string The base custom table name.
*/
public static function base_table_name();
/**
* Drop the custom table.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return boolean `true` if successful operation, `false` to indicate a failure.
*/
public function drop();
/**
* Empties the custom table.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return int|false The number of removed rows, or `false` to indicate a failure.
*/
public function empty_table();
/**
* Returns whether a table exists or not in the database.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return bool
*/
public function exists();
/**
* The base table name of the schema.
*
* @since 1.0.0
*/
public static function get_schema_slug();
/**
* Returns the table creation SQL with all field schema SQL injected,
* in the format supported by the `dbDelta` function.
*
* @since 1.0.0
*
* @return string The table & field schema creation SQL, in the format supported
* by the `dbDelta` function.
*/
public function get_sql();
/**
* Gets the table schema's version.
*
* @since 1.0.0
*
* @return string
*/
public function get_version(): string;
/**
* The organizational group this table belongs to.
*
* @since 1.0.0
*
* @return string
*/
public static function group_name();
/**
* References our stored version versus the version defined in the class.
*
* @since 1.0.0
*
* @return bool Whether our latest schema has been applied.
*/
public function is_schema_current();
/**
* Returns the custom table name.
*
* @since 1.0.0
*
* @param bool $with_prefix Whether to include the table prefix or not.
*
* @return string The custom table name, prefixed by the current `wpdb` prefix,
* if required.
*/
public static function table_name($with_prefix = true);
/**
* Returns the name of the column that is guaranteed to uniquely identify an
* entry across updates.
*
* @since 1.0.0
*
* @return string The name of the column that is guaranteed to uniquely identify an
* entry across updates.
*/
public static function uid_column();
/**
* Creates, or updates, the custom table.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return array<string,string> A map of results in the format returned by
* the `dbDelta` function.
*/
public function update();
}

View File

@@ -0,0 +1,591 @@
<?php
namespace KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Contracts;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Config;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Fields;
use KadenceWP\KadenceBlocks\StellarWP\Schema\Fields\Contracts\Schema_Interface as Field_Schema_Interface;
abstract class Table implements Schema_Interface {
/**
* @var string|null The version number for this schema definition.
*/
const SCHEMA_VERSION = null;
/**
* @var string The base table name.
*/
protected static $base_table_name = '';
/**
* @var class-string<\KadenceWP\KadenceBlocks\StellarWP\DB\DB> The db class.
*/
protected $db;
/**
* @var object The dependency injection container.
*/
protected $container;
/**
* @var \Iterator The filtered field collection that applies to this table.
*/
protected $field_schemas = null;
/**
* @var string The organizational group this table belongs to.
*/
protected static $group = '';
/**
* @since 1.0.0
*
* @var string|null The slug used to identify the custom table.
*/
protected static $schema_slug;
/**
* @var string The field that uniquely identifies a row in the table.
*/
protected static $uid_column = '';
/**
* Ordered collection of table update methods.
*
* Keys should be the SCHEMA_VERSION and the values should be the method to call.
*
* @var array<string>
*/
protected $updates = [];
/**
* Constructor.
*
* @since 1.0.0
*
* @param class-string<\KadenceWP\KadenceBlocks\StellarWP\DB\DB>|null $db StellarWP\DB object.
* @param object $container The container to use.
*/
public function __construct( $db = null, $container = null ) {
$this->db = $db ?: Config::get_db();
$this->container = $container ?: Config::get_container();
}
/**
* Allows extending classes that require it to run some methods
* immediately after the table creation or update.
*
* @since 1.0.0
*
* @param array<string,string> $results A map of results in the format
* returned by the `dbDelta` function.
*
* @return array<string,string> A map of results in the format returned by
* the `dbDelta` function.
*/
protected function after_update( array $results ) {
// No-op by default.
return $results;
}
/**
* Archives the current stored version of the schema.
*/
public function archive_previous_version() {
$current_version = $this->get_stored_version();
// If there's no current version, there's nothing to mark as previous.
if ( ! $current_version ) {
return $current_version;
}
return update_option( $this->get_schema_previous_version_option(), $current_version );
}
/**
* {@inheritdoc}
*/
public static function base_table_name() {
return static::$base_table_name;
}
/**
* Clear our stored version.
*/
protected function clear_stored_version() {
delete_option( $this->get_schema_version_option() );
}
/**
* {@inheritdoc}
*/
public function drop() {
/**
* Permit the prevention of dropping a specific table.
*
* @since 1.0.0
*
* @param bool $do_drop Whether to drop the table.
* @param string $base_table_name The base table name of the table schema.
*/
$do_drop = apply_filters( 'stellarwp_schema_table_drop_' . static::base_table_name(), true, static::base_table_name() );
/**
* Permit the prevention of dropping the table.
*
* @since 1.0.0
*
* @param bool $do_drop Whether to drop the table.
* @param string $base_table_name The base table name of the table schema.
*/
$do_drop = apply_filters( 'stellarwp_schema_table_drop', $do_drop, static::base_table_name() );
if ( ! $do_drop ) {
return false;
}
$this->clear_stored_version();
if ( ! $this->exists() ) {
return false;
}
$base_table_name = static::base_table_name();
$this_table = static::table_name( true );
/**
* Runs before the custom field is dropped.
*
* @since 1.0.0
*
* @param string $base_table_name The base table name.
* @param string $table_name The full table name.
* @param Schema_Interface $table_schema The table schema to be dropped.
*/
do_action( 'stellarwp_pre_drop_table', $base_table_name, $this_table, $this );
global $wpdb;
/**
* Disable foreign key checks so we can drop without issues.
* @var \stdClass $key_check
*/
$key_check = $this->db::get_row( "SHOW VARIABLES LIKE 'foreign_key_checks'" );
if ( strtolower( $key_check->Value ) === 'on' ) {
$this->db::query( "SET foreign_key_checks = 'OFF'" );
}
$result = $this->db::query( "DROP TABLE `{$this_table}`" );
// Put setting back to original value.
$this->db::query( $this->db::prepare( "SET foreign_key_checks = %s", $key_check->Value ) );
/**
* Runs after the custom table has been dropped.
*
* @since 1.0.0
*
* @param string $base_table_name The base table name.
* @param string $table_name The full table name.
* @param Schema_Interface $table_schema The table schema to be dropped.
*/
do_action( 'stellarwp_post_drop_table', $base_table_name, $this_table, $this );
$base_table_name = static::base_table_name();
if ( isset( $wpdb->$base_table_name ) ) {
unset( $wpdb->$base_table_name );
}
/**
* Runs after the custom table has been removed from $wpdb.
*
* @since 1.0.0
*
* @param string $base_table_name The base table name.
* @param string $table_name The full table name.
* @param Schema_Interface $table_schema The table schema to be dropped.
*/
do_action( 'stellarwp_post_drop_table_wpdb_update', $base_table_name, $this_table, $this );
return $result;
}
/**
* Empties the custom table.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return int|false The number of removed rows, or `false` to indicate a failure.
*/
public function empty_table() {
if ( ! $this->exists() ) {
// There is really nothing to empty here.
return 0;
}
$this_table = static::table_name( true );
$this->db::query( "SET foreign_key_checks = 0" );
$result = $this->db::query( "DELETE FROM {$this_table}" );
$this->db::query( "SET foreign_key_checks = 1" );
return $result;
}
/**
* Truncates the custom table.
*
* @since 1.1.8
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return int|false The number of removed rows, or `false` to indicate a failure.
*/
public function truncate() {
if ( ! $this->exists() ) {
// There is really nothing to empty here.
return 0;
}
$this_table = static::table_name( true );
$this->db::query( "SET foreign_key_checks = 0" );
$result = $this->db::query( "TRUNCATE {$this_table}" );
$this->db::query( "SET foreign_key_checks = 1" );
return $result;
}
/**
* Returns whether a table exists in the database or not.
*
* @since 1.0.0
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return bool Whether a table exists in the database or not.
*/
public function exists() {
$table_name = static::table_name( true );
return count( $this->db::get_col( $this->db::prepare( 'SHOW TABLES LIKE %s', $table_name ) ) ) === 1;
}
/**
* Gets the defined fields schemas for the table.
*
* @since 1.0.0
*
* @param bool $force Force a refresh of the field collection.
*
* @return \Iterator
*/
public function get_field_schemas( bool $force = false ) {
if ( $this->field_schemas === null || $force ) {
$this->field_schemas = $this->container->get( Fields\Collection::class )->get_by_table( static::base_table_name() );
}
return $this->field_schemas;
}
/**
* {@inheritdoc}
*/
public static function get_schema_slug() {
return static::$schema_slug;
}
/**
* Gets the properly namespaced schema version option key.
*
* @since 1.0.0
*
* @return string The properly namespaced schema version option key.
*/
public function get_schema_previous_version_option(): string {
return 'stellar_schema_previous_version_' . static::get_schema_slug();
}
/**
* Gets the properly namespaced schema version option key.
*
* @since 1.0.0
*
* @return string The properly namespaced schema version option key.
*/
public function get_schema_version_option(): string {
return 'stellar_schema_version_' . static::get_schema_slug();
}
/**
* {@inheritdoc}
*/
public function get_sql() {
$sql = $this->get_definition();
$field_schemas = $this->get_field_schemas();
foreach ( $field_schemas as $field_schema ) {
$sql = $this->inject_field_schema( $field_schema, $sql );
}
return $sql;
}
/**
* Gets the previous schema version option value.
*
* @since 1.0.0
*
* @return string|null The previous version stored in wp_options.
*/
public function get_stored_previous_version() {
return get_option( $this->get_schema_previous_version_option(), null );
}
/**
* Gets the current schema version option value.
*
* @since 1.0.0
*
* @return string|null The current version stored in wp_options.
*/
public function get_stored_version() {
return get_option( $this->get_schema_version_option(), null );
}
/**
* Returns the table creation SQL in the format supported
* by the `dbDelta` function.
*
* @since 1.0.0
*
* @return string The table creation SQL, in the format supported
* by the `dbDelta` function.
*/
abstract protected function get_definition();
/**
* {@inheritdoc}
*/
public function get_version(): string {
$field_versions = [];
$schema_fields = $this->get_field_schemas( true );
foreach ( $schema_fields as $field ) {
$field_versions[] = $field->get_version();
}
return static::SCHEMA_VERSION . ( $field_versions ? '-' . md5( implode( ':', $field_versions ) ) : '' );
}
/**
* {@inheritdoc}
*/
public static function group_name() {
return static::$group;
}
/**
* Checks if an index already exists on the table.
*
* @since 1.0.0
*
* @param string $index The name of the index to check for.
* @param string|null $table_name The table name to search the index for, or `null`
* to use this table name.
*
* @throws \KadenceWP\KadenceBlocks\StellarWP\DB\Database\Exceptions\DatabaseQueryException If the query fails.
*
* @return bool Whether the table already has an index or not.
*/
public function has_index( $index, $table_name = null ) {
$table_name = $table_name ?: static::table_name( true );
$count = $this->db::table( $this->db::raw( 'information_schema.statistics' ) )
->whereRaw( 'WHERE TABLE_SCHEMA = DATABASE()' )
->where( 'TABLE_NAME', $table_name )
->where( 'INDEX_NAME', $index )
->count();
return $count >= 1;
}
/**
* Inject field schema definitions into the CREATE TABLE SQL.
*
* @since 1.0.0
*
* @param Field_Schema_Interface $field_schema The field schema to inject.
* @param string $sql The CREATE TABLE SQL to inject into.
*
* @return string
*/
protected function inject_field_schema( Field_Schema_Interface $field_schema, $sql ): string {
$fields = trim( $field_schema->get_sql() );
// Inject any extra fields into the table's definition.
// phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation
$find_first_index_regex =
'/'
. '(,' // 1) Final comma before indexes.
. '(\s*)' // 2) Capture whitespace before indexes.
. '(?=' // Followed by the indexes.
. '(?:'
. 'PRIMARY\s+KEY|(?:UNIQUE|FULLTEXT|SPACIAL)\s+(?:KEY|INDEX)|KEY|INDEX'
. ')'
. ')'
. '[^\n]+' // Followed by indice columns and names.
. '(?!' // Not followed by another index.
. '(?:'
. 'PRIMARY\s+KEY|(?:UNIQUE|FULLTEXT|SPACIAL)\s+(?:KEY|INDEX)|KEY|INDEX'
. ')'
. ')'
. ')'
.'/im'; // Case insensitive and multi-line.
if ( preg_match( $find_first_index_regex, $sql ) ) {
// Inject additional fields before the indexes.
$sql = preg_replace(
$find_first_index_regex,
",$2{$fields}$1", // $2 is the captured whitespace. $1 is the whitespace PLUS the first index after the last field.
$sql
);
} else {
// Inject additional fields before the closing parenthesis of the CREATE TABLE statement.
$sql = preg_replace(
'/(?<!,)((\s+)\).+(?!\)))/im', // Match the last closing parenthesis and everything after it.
",$2{$fields}$1", // $2 is the captured whitespace. $1 is the whitespace PLUS the rest of the statement.
$sql
);
}
return $sql;
}
/**
* {@inheritdoc}
*/
public function is_schema_current() {
if ( ! static::SCHEMA_VERSION || ! $this->get_schema_version_option() ) {
// @todo Error?
}
$version_applied = $this->get_stored_version() ?: '';
$current_version = $this->get_version();
return version_compare( $version_applied, $current_version, '==' );
}
/**
* Update our stored version with what we have defined.
*/
public function sync_stored_version() {
$current_version = $this->get_version();
if ( ! add_option( $this->get_schema_version_option(), $current_version ) ) {
update_option( $this->get_schema_version_option(), $current_version );
}
}
/**
* {@inheritdoc}
*/
public static function table_name( $with_prefix = true ) {
$table_name = static::base_table_name();
if ( $with_prefix ) {
global $wpdb;
$table_name = $wpdb->prefix . $table_name;
}
return $table_name;
}
/**
* {@inheritdoc}
*/
public static function uid_column() {
return static::$uid_column;
}
/**
* {@inheritdoc}
*/
public function update() {
// @phpstan-ignore-next-line
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$sql = $this->get_sql();
$field_schemas = $this->get_field_schemas();
/**
* Hookable action before the table schema has updated.
*
* @since 1.1.0
*
* @param string $table_name The prefix-less table name.
* @param Table $table The table object.
* @param \Iterator $field_schemas An iterable collection of field schemas associated with this table.
*/
do_action( 'stellarwp_schema_table_before_updete', static::table_name(), $this, $field_schemas );
$results = (array) $this->db::delta( $sql );
$this->archive_previous_version();
$this->sync_stored_version();
$results = $this->after_update( $results );
/**
* Hookable action before the field schemas have updated.
*
* @since 1.1.0
*
* @param string $table_name The prefix-less table name.
* @param array $results The results of the schema update.
* @param Table $table The table object.
* @param \Iterator $field_schemas An iterable collection of field schemas associated with this table.
*/
do_action( 'stellarwp_schema_table_before_field_schema_updete', static::table_name(), $results, $this, $field_schemas );
foreach ( $field_schemas as $field_schema ) {
$results[] = $field_schema->after_update( $results );
}
/**
* Hookable action after the table schema has updated.
*
* @since 1.1.0
*
* @param string $table_name The prefix-less table name.
* @param array $results The results of the table and field schema updates.
* @param Table $table The table object.
* @param \Iterator $field_schemas An iterable collection of field schemas associated with this table.
*/
do_action( 'stellarwp_schema_table_after_updete', static::table_name(), $results, $this, $field_schemas );
return $results;
}
/**
* Checks if a foreign key exists on a table.
*
* @since 1.1.3
*
* @param string $foreign_key The foreign key to check for.
* @param string $table_name The table name to check. Defaults to the current table.
*
* @return bool Whether the foreign key exists on the table.
*/
public function has_foreign_key( string $foreign_key, string $table_name = '' ): bool {
$table_name = $table_name ?: static::table_name();
$count = $this->db::table( $this->db::raw( 'information_schema.statistics' ) )
->whereRaw( 'WHERE TABLE_SCHEMA = DATABASE()' )
->where( 'TABLE_NAME', $table_name )
->where( 'INDEX_NAME', $foreign_key )
->count();
return $count >= 1;
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Filters;
use CallbackFilterIterator;
use Countable;
use FilterIterator;
use Iterator;
class Group_FilterIterator extends FilterIterator implements Countable {
/**
* Groups to filter.
*
* @since 1.0.0
*
* @var array<string>
*/
private $groups;
/**
* Constructor.
*
* @since 1.0.0
*
* @param array<string> $groups Paths to filter.
* @param Iterator $iterator Iterator to filter.
*/
public function __construct( array $groups, Iterator $iterator ) {
parent::__construct( $iterator );
$this->groups = $groups;
}
/**
* @inheritDoc
*/
public function accept(): bool {
$table = $this->getInnerIterator()->current();
return in_array( $table::group_name(), $this->groups, true );
}
/**
* @inheritDoc
*/
public function count(): int {
return iterator_count( new CallbackFilterIterator( $this->getInnerIterator(), function (): bool {
return $this->accept();
} ) );
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace KadenceWP\KadenceBlocks\StellarWP\Schema\Tables\Filters;
use CallbackFilterIterator;
use Countable;
use FilterIterator;
class Needs_Update_FilterIterator extends FilterIterator implements Countable {
/**
* @inheritDoc
*/
public function accept(): bool {
$table = $this->getInnerIterator()->current();
return ! $table->is_schema_current();
}
/**
* @inheritDoc
*/
public function count(): int {
return iterator_count( new CallbackFilterIterator( $this->getInnerIterator(), function (): bool {
return $this->accept();
} ) );
}
}