fix: Maintenance and tweaks

This commit is contained in:
Sibin Grasic 2024-02-09 22:39:23 +01:00
parent 0bb0c1927e
commit 9a8726f5e6
No known key found for this signature in database
GPG key ID: 50E9E60C329EC8C1
5 changed files with 438 additions and 226 deletions

3
.gitattributes vendored
View file

@ -1,12 +1,11 @@
/.github export-ignore
/.yarn export-ignore
/docs export-ignore
/tests export-ignore
/.codeclimate.yml export-ignore
/.editorconfig export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/CODE_OF_CONDUCT.md export-ignore
/composer.lock export-ignore
/CONTRIBUTING.md export-ignore
/LICENSE export-ignore
/README.md export-ignore

12
.gitignore vendored
View file

@ -1,12 +1,2 @@
node_modules
languages/*.php
vendor
test.php
php_errors.log

.yarn/*
.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

168
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "a762970ddcb11ee1a26bab32fbc7f6bc",
"content-hash": "7d2bb0da0dd22ced214347a658af3460",
"packages": [
{
"name": "automattic/jetpack-constants",
@ -761,16 +761,16 @@
},
{
"name": "oblak/wordpress-coding-standard",
"version": "v1.0.1",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/oblakstudio/wordpress-coding-standards.git",
"reference": "1200c99b65b7ea0698bce345bbe10e3b635fab58"
"reference": "b1f62524c09c639a9fdf4272ad3fd113259a8952"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/oblakstudio/wordpress-coding-standards/zipball/1200c99b65b7ea0698bce345bbe10e3b635fab58",
"reference": "1200c99b65b7ea0698bce345bbe10e3b635fab58",
"url": "https://api.github.com/repos/oblakstudio/wordpress-coding-standards/zipball/b1f62524c09c639a9fdf4272ad3fd113259a8952",
"reference": "b1f62524c09c639a9fdf4272ad3fd113259a8952",
"shasum": ""
},
"require": {
@ -780,7 +780,8 @@
"phpcompatibility/phpcompatibility-wp": "2.1.4",
"phpcsstandards/phpcsextra": "1.1.0",
"phpcsstandards/phpcsutils": "1.0.8",
"squizlabs/php_codesniffer": "3.7.2",
"slevomat/coding-standard": "^8.14",
"squizlabs/php_codesniffer": "3.8.1",
"wp-coding-standards/wpcs": "^3"
},
"require-dev": {
@ -808,9 +809,9 @@
],
"support": {
"issues": "https://github.com/oblakstudio/wordpress-coding-standards/issues",
"source": "https://github.com/oblakstudio/wordpress-coding-standards/tree/v1.0.1"
"source": "https://github.com/oblakstudio/wordpress-coding-standards/tree/v1.1.1"
},
"time": "2023-12-09T17:30:35+00:00"
"time": "2024-01-24T23:43:48+00:00"
},
{
"name": "phpcompatibility/php-compatibility",
@ -1123,17 +1124,129 @@
"time": "2023-07-16T21:39:41+00:00"
},
{
"name": "squizlabs/php_codesniffer",
"version": "3.7.2",
"name": "phpstan/phpdoc-parser",
"version": "1.25.0",
"source": {
"type": "git",
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
"reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879"
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879",
"reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bd84b629c8de41aa2ae82c067c955e06f1b00240",
"reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"doctrine/annotations": "^2.0",
"nikic/php-parser": "^4.15",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.5",
"phpstan/phpstan-phpunit": "^1.1",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.5",
"symfony/process": "^5.2"
},
"type": "library",
"autoload": {
"psr-4": {
"PHPStan\\PhpDocParser\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.25.0"
},
"time": "2024-01-04T17:06:16+00:00"
},
{
"name": "slevomat/coding-standard",
"version": "8.14.1",
"source": {
"type": "git",
"url": "https://github.com/slevomat/coding-standard.git",
"reference": "fea1fd6f137cc84f9cba0ae30d549615dbc6a926"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slevomat/coding-standard/zipball/fea1fd6f137cc84f9cba0ae30d549615dbc6a926",
"reference": "fea1fd6f137cc84f9cba0ae30d549615dbc6a926",
"shasum": ""
},
"require": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0",
"php": "^7.2 || ^8.0",
"phpstan/phpdoc-parser": "^1.23.1",
"squizlabs/php_codesniffer": "^3.7.1"
},
"require-dev": {
"phing/phing": "2.17.4",
"php-parallel-lint/php-parallel-lint": "1.3.2",
"phpstan/phpstan": "1.10.37",
"phpstan/phpstan-deprecation-rules": "1.1.4",
"phpstan/phpstan-phpunit": "1.3.14",
"phpstan/phpstan-strict-rules": "1.5.1",
"phpunit/phpunit": "8.5.21|9.6.8|10.3.5"
},
"type": "phpcodesniffer-standard",
"extra": {
"branch-alias": {
"dev-master": "8.x-dev"
}
},
"autoload": {
"psr-4": {
"SlevomatCodingStandard\\": "SlevomatCodingStandard/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.",
"keywords": [
"dev",
"phpcs"
],
"support": {
"issues": "https://github.com/slevomat/coding-standard/issues",
"source": "https://github.com/slevomat/coding-standard/tree/8.14.1"
},
"funding": [
{
"url": "https://github.com/kukulich",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard",
"type": "tidelift"
}
],
"time": "2023-10-08T07:28:08+00:00"
},
{
"name": "squizlabs/php_codesniffer",
"version": "3.8.1",
"source": {
"type": "git",
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7",
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7",
"shasum": ""
},
"require": {
@ -1143,11 +1256,11 @@
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4"
},
"bin": [
"bin/phpcs",
"bin/phpcbf"
"bin/phpcbf",
"bin/phpcs"
],
"type": "library",
"extra": {
@ -1162,20 +1275,29 @@
"authors": [
{
"name": "Greg Sherwood",
"role": "lead"
"role": "Former lead"
},
{
"name": "Juliette Reinders Folmer",
"role": "Current lead"
},
{
"name": "Contributors",
"homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors"
}
],
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
"homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
"keywords": [
"phpcs",
"standards",
"static analysis"
],
"support": {
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
"issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
"security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
"source": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
"wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki"
},
"funding": [
{
@ -1191,7 +1313,7 @@
"type": "open_collective"
}
],
"time": "2023-02-22T23:07:41+00:00"
"time": "2024-01-11T20:47:48+00:00"
},
{
"name": "wp-coding-standards/wpcs",

View file

@ -1,2 +0,0 @@
<?php
return ['project-id-version'=>'','report-msgid-bugs-to'=>'','po-revision-date'=>'2022-10-25 13:08+0200','last-translator'=>'','language-team'=>'','language'=>'sr_RS','mime-version'=>'1.0','content-type'=>'text/plain; charset=UTF-8','content-transfer-encoding'=>'8bit','plural-forms'=>'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);','x-generator'=>'Poedit 3.2','x-domain'=>'oblak-plugin-installer','messages'=>['%1$d update functions completed. Database version is %2$s'=>'%1$d ажурирања је извршено. Везрија базе података је %2$s','All database tables are up to date.'=>'Све табеле базе података су ажурне.','Creating missing tables...'=>'Креирам недостајуће табеле...','Found %1$d updates (%2$s)'=>'Нађено %1$d ажурирања (%2$s)','Missing'=>'Недостаје','No updates required. Database version is %s'=>'Ажурирање није потребно. Верзија базе података је %s','Plugin schema version not set'=>'Верзија шеме базе података додатка није подешена','Plugin slug not set'=>'Подложак додатка није подешен','Plugin version not set'=>'Верзија додатка није подешена','Run the command again with --create to create the missing tables.'=>'Покрените команду поново са --create параметром како бисте креирали недостајуће табеле.','Table %1$s: %2$s'=>'Табела %1$s: %2$s','The following database tables are out of sync with the schema:'=>'Следеће табеле нису синхронизоване са шемом:','The following tables are missing: '=>'Следеће табеле недостају: ','There was an error creating the missing tables.'=>'Дошло је до грешке приликом креирања табела.','Updating database'=>'Ажурирам базу података']];

View file

@ -10,8 +10,6 @@ namespace Oblak\WP;

use Automattic\Jetpack\Constants;
use Oblak\WP\Admin_Notice_Manager;

use Exception;
use WP_CLI;

use function WP_CLI\Utils\make_progress_bar;
@ -69,7 +67,7 @@ abstract class Base_Plugin_Installer {
$this->set_defaults();
$this->verify_defaults();

$this->db_version = $this->db_version ?? $this->version;
$this->db_version ??= $this->version;
}

/**
@ -88,9 +86,9 @@ abstract class Base_Plugin_Installer {
* @return string
*/
private static function class_basename( $classname ) {
$classname = is_object( $classname ) ? get_class( $classname ) : $classname;
$classname = \is_object( $classname ) ? $classname::class : $classname;

return str_replace( '\\', '/', $classname );
return \str_replace( '\\', '/', $classname );
}

/**
@ -103,48 +101,53 @@ abstract class Base_Plugin_Installer {
/**
* Verifies the class defaults.
*
* @throws Exception If the plugin slug is not set, or if the plugin version is not set.
* @throws \Exception If the plugin slug is not set, or if the plugin version is not set.
*/
final protected function verify_defaults() {
protected function verify_defaults() {
if ( '' === $this->version ) {
throw new Exception( esc_html__( 'Plugin version not set', 'oblak-plugin-installer' ) );
throw new \Exception( \esc_html__( 'Plugin version not set', 'oblak-plugin-installer' ) );
}

if ( '' === $this->slug ) {
throw new Exception( esc_html__( 'Plugin slug not set', 'oblak-plugin-installer' ) );
throw new \Exception( \esc_html__( 'Plugin slug not set', 'oblak-plugin-installer' ) );
}

if ( '' === $this->db_version && ! empty( $this->get_schema() ) ) {
throw new Exception( esc_html__( 'Plugin schema version not set', 'oblak-plugin-installer' ) );
if ( '' === $this->db_version && '' !== $this->get_schema() ) {
throw new \Exception( \esc_html__( 'Plugin schema version not set', 'oblak-plugin-installer' ) );
}
}

/**
* Initialize and hook me baby one more time
*/
final public function init() {
add_action( 'init', array( $this, 'load_textdomain' ) );
add_action( 'init', array( $this, 'check_version' ) );
add_action( 'admin_init', array( $this, 'install_actions' ) );
add_action( 'cli_init', array( $this, 'register_commands' ) );
add_filter( 'woocommerce_debug_tools', array( $this, 'add_debug_tools' ), ( 99 + count( static::$instances ) ), 1 );
public function init() {
\add_action( 'init', array( $this, 'load_textdomain' ) );
\add_action( 'init', array( $this, 'check_version' ) );
\add_action( 'admin_init', array( $this, 'install_actions' ) );
\add_action( 'cli_init', array( $this, 'register_commands' ) );
\add_filter(
'woocommerce_debug_tools',
array( $this, 'add_debug_tools' ),
99 + \count( static::$instances ),
1,
);

add_action( "{$this->slug}_run_update_callback", array( $this, 'run_update_callback' ), 10, 2 );
\add_action( "{$this->slug}_run_update_callback", array( $this, 'run_update_callback' ), 10, 2 );
}

/**
* Loads our textdomain file for translations
*/
final public function load_textdomain() {
$locale = get_locale();
public function load_textdomain() {
$locale = \get_locale();

$mofile_path = dirname( __DIR__ ) . "/languages/oblak-plugin-installer-{$locale}.mo";
$mofile_path = \dirname( __DIR__ ) . "/languages/oblak-plugin-installer-{$locale}.mo";

if ( ! file_exists( $mofile_path ) ) {
if ( ! \file_exists( $mofile_path ) ) {
return;
}

load_textdomain( 'oblak-plugin-installer', $mofile_path );
\load_textdomain( 'oblak-plugin-installer', $mofile_path );
}

/**
@ -153,38 +156,40 @@ abstract class Base_Plugin_Installer {
* @return bool
*/
public function is_new_install() {
return is_null( get_option( "{$this->slug}_version", null ) );
return \is_null( \get_option( "{$this->slug}_version", null ) );
}

/**
* Checks the plugin version and runs the updater if required
*/
final public function check_version() {
$plugin_version = get_option( "{$this->slug}_version" );
public function check_version() {
$plugin_version = \get_option( "{$this->slug}_version" );
$code_version = $this->version;
$needs_update = version_compare( $plugin_version, $code_version, '<' );
$needs_update = \version_compare( $plugin_version, $code_version, '<' );

if ( ! Constants::is_defined( 'IFRAME_REQUEST' ) && $needs_update ) {
$this->install();
/**
* Action fired after plugin is updated
*
* @since 5.4.0
*/
do_action( "{$this->slug}_updated" );
if ( Constants::is_defined( 'IFRAME_REQUEST' ) || ! $needs_update ) {
return;
}

$this->install();
/**
* Action fired after plugin is updated
*
* @since 5.4.0
*/
\do_action( "{$this->slug}_updated" );
}

/**
* Runs the plugin installation
*/
final public function install() {
if ( ! is_blog_installed() || get_transient( "{$this->slug}_installing" ) === 'yes' ) {
public function install() {
if ( ! \is_blog_installed() || 'yes' === \get_transient( "{$this->slug}_installing" ) ) {
return;
}

set_transient( "{$this->slug}_installing", 'yes', MINUTE_IN_SECONDS * 5 );
Constants::set_constant( str_replace( '-', '_', strtoupper( $this->slug ) . '_INSTALLING' ), true );
\set_transient( "{$this->slug}_installing", 'yes', MINUTE_IN_SECONDS * 5 );
Constants::set_constant( \str_replace( '-', '_', \strtoupper( $this->slug ) . '_INSTALLING' ), true );

if ( $this->get_schema() ) {
$this->create_tables();
@ -204,10 +209,10 @@ abstract class Base_Plugin_Installer {
*
* @since 1.0.0
*/
do_action( "{$this->slug}_install" );
\do_action( "{$this->slug}_install" );
}

delete_transient( "{$this->slug}_installing" );
\delete_transient( "{$this->slug}_installing" );
}

/**
@ -218,14 +223,14 @@ abstract class Base_Plugin_Installer {
*
* @since 2.0.0
*/
final public function create_tables() {
public function create_tables() {
global $wpdb;

$wpdb->hide_errors();

require_once ABSPATH . 'wp-admin/includes/upgrade.php';

dbDelta( $this->get_schema() );
\dbDelta( $this->get_schema() );
}

/**
@ -237,6 +242,57 @@ abstract class Base_Plugin_Installer {
return null;
}

/**
* Get the database table names which are not in sync
*
* @return array<int, string>
*/
protected function get_unsynced_tables(): array {
global $wpdb;

$queries = \dbDelta( $this->get_schema(), false );
$tables = array();

foreach ( $queries as $table_name => $result ) {
if ( \is_numeric( $table_name ) || ! \str_contains( $table_name, $wpdb->prefix ) ) {
continue;
}

$tables[] = \strtok( $table_name, '.' );
}

return $tables;
}

/**
* Display a notice if the database tables are missing or out of sync
*
* @param bool $modify_notice Can we modify the notice.
* @param array<int, string> $missing_tables List of missing tables.
*/
protected function display_missing_tables_notice( bool $modify_notice, array $missing_tables = array() ) {
if ( ! $modify_notice || ! $this->show_admin_notices ) {
return;
}

Admin_Notice_Manager::get_instance()->add_notice(
"{$this->slug}_missing_tables",
array(
'caps' => 'manage_woocommerce',
'dismissible' => false,
'message' => \sprintf(
'<p><strong>%s</strong> - %s: %s</p>',
\esc_html( $this->slug ),
\esc_html__( 'The following tables are missing: ', 'oblak-plugin-installer' ),
\implode( ', ', $missing_tables ),
),
'persistent' => true,
'type' => 'error',
),
true,
);
}

/**
* Verifies if the database tables have been created.
*
@ -244,50 +300,21 @@ abstract class Base_Plugin_Installer {
* @param bool $execute Are we executing table creation.
* @return string[] List of missing tables.
*/
final public function verify_base_tables( $modify_notice = true, $execute = false ) {
public function verify_base_tables( $modify_notice = true, $execute = false ) {
require_once ABSPATH . 'wp-admin/includes/upgrade.php';

global $wpdb;

if ( $execute ) {
$this->create_tables();
}

$queries = dbDelta( $this->get_schema(), false );
$missing_tables = array();
$missing_tables = $this->get_unsynced_tables();

foreach ( $queries as $table_name => $result ) {
if ( is_numeric( $table_name ) || ! str_contains( $table_name, $wpdb->prefix ) ) {
continue;
}

$missing_tables[] = strtok( $table_name, '.' );
}

if ( 0 < count( $missing_tables ) ) {
if ( $modify_notice && $this->show_admin_notices ) {
Admin_Notice_Manager::get_instance()->add_notice(
"{$this->slug}_missing_tables",
array(
'type' => 'error',
'caps' => 'manage_woocommerce',
'message' => sprintf(
'<p><strong>%s</strong> - %s: %s</p>',
esc_html( $this->slug ),
esc_html__( 'The following tables are missing: ', 'oblak-plugin-installer' ),
implode( ', ', $missing_tables ),
),
'dismissible' => false,
'persistent' => true,
),
true
);
}
} else {
if ( $modify_notice && $this->show_admin_notices ) {
if ( 0 < \count( $missing_tables ) ) {
$this->display_missing_tables_notice( $modify_notice );
} elseif ( $modify_notice && $this->show_admin_notices ) {
Admin_Notice_Manager::get_instance()->remove_notice( "{$this->slug}_missing_tables", true );
}
update_option( "{$this->slug}_schema_version", $this->db_version );
} else {
\update_option( "{$this->slug}_schema_version", $this->db_version );
}

return $missing_tables;
@ -297,12 +324,14 @@ abstract class Base_Plugin_Installer {
* Creates the default plugin options, if needed
*/
public function create_options() {
// Does nothing.
}

/**
* Creates the default roles for the plugin.
*/
public function create_roles() {
// Does nothing.
}

/**
@ -311,12 +340,66 @@ abstract class Base_Plugin_Installer {
* CPT registration, taxonomies, etc.
*/
public function setup_environment() {
// Does nothing.
}

/**
* Creates terms for the plugin.
*/
public function create_terms() {
// Does nothing.
}

/**
* Get the admin update notice args.
*
* Enables users to change the plugin name, slug, update URL, etc...
*
* @param string $file_name Template name to get the args for.
* @return array{cli_update_faq: string, how_to_update: string, plugin_name: string, plugin_slug: string, scheduler_url: string, update_url: string}
*/
protected function get_notice_args( string $file_name ): array {
$file_args = array(
'cli_update_faq' => '#',
'how_to_update' => '#',
'plugin_name' => $this->name,
'plugin_slug' => $this->slug,
'scheduler_url' => "tools.php?page=action-scheduler&s={$this->slug}_run_update&status=pending",
'update_url' => '',
);

/**
* Filters the template variables for the admin update notice.
*
* @param array $file_args Template variables.
* @param string $file_name Template name.
* @return array
*
* @since 1.0.0
*/
return \apply_filters( "{$this->slug}_update_notice_args", $file_args, $file_name );
}

/**
* Get the admin update notice template.
*
* @return string
*/
protected function get_update_notice_template(): string {
if ( $this->get_update_handler()?->needs_update() ) {
$next_scheduled_date = \as_next_scheduled_action(
"{$this->slug}_run_update_callback",
null,
"{$this->slug}-db-updates",
);

//phpcs:ignore WordPress.Security.NonceVerification.Recommended
$doing_updates = \sanitize_text_field( \wp_unslash( $_GET[ "do-update_{$this->slug}" ] ?? '' ) );

return $next_scheduled_date || '' !== $doing_updates ? 'update-in-progress' : 'update-needed';
}

return 'update-complete';
}

/**
@ -329,53 +412,21 @@ abstract class Base_Plugin_Installer {
return;
}

$file_name = '';
if ( $this->get_update_handler()?->needs_update() ) {
$next_scheduled_date = as_next_scheduled_action( "{$this->slug}_run_update_callback", null, "{$this->slug}-db-updates" );

//phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( $next_scheduled_date || ! empty( $_GET[ "do-update_{$this->slug}" ] ) ) {
$file_name = 'update-in-progress';
} else {
$file_name = 'update-needed';
}
} else {
$file_name = 'update-complete';
}

$file = $this->get_template_file( $file_name );

$file_args = array(
'plugin_name' => $this->name,
'plugin_slug' => $this->slug,
'scheduler_url' => "tools.php?page=action-scheduler&s={$this->slug}_run_update&status=pending",
'update_url' => '',
'how_to_update' => '#',
'cli_update_faq' => '#',
);

/**
* Filters the template variables for the admin update notice.
*
* @param array $file_args Template variables.
* @param string $file_name Template name.
* @return array
*
* @since 1.0.0
*/
$file_args = apply_filters( "{$this->slug}_update_notice_args", $file_args, $file_name );
$name = $this->get_update_notice_template();
$file = $this->get_template_file( $name );
$args = $this->get_notice_args( $name );

Admin_Notice_Manager::get_instance()->add_notice(
"{$this->slug}_update_notice",
array(
'type' => 'info',
'caps' => 'manage_options',
'dismissible' => 'update-complete' === $file,
'file_args' => $args,
'message' => $file,
'file_args' => $file_args,
'dismissible' => 'update-complete' === $file ? true : false,
'persistent' => false,
'type' => 'info',
),
true
true,
);
}

@ -385,8 +436,8 @@ abstract class Base_Plugin_Installer {
* @param string $template_name Template name.
* @return string Template file path.
*/
final protected function get_template_file( $template_name ) {
$default_path = dirname( __DIR__ ) . "/templates/notice-{$template_name}.php";
protected function get_template_file( $template_name ) {
$default_path = \dirname( __DIR__ ) . "/templates/notice-{$template_name}.php";

/**
* Filters the template path for the plugin.
@ -397,13 +448,13 @@ abstract class Base_Plugin_Installer {
*
* @since 1.0.0
*/
return apply_filters( "{$this->slug}_get_update_notice_template_file", $default_path, $template_name );
return \apply_filters( "{$this->slug}_get_update_notice_template_file", $default_path, $template_name );
}

/**
* See if we need to show or run database updates during install.
*/
final protected function maybe_update_db_version() {
protected function maybe_update_db_version() {
if ( $this->get_update_handler()?->needs_update() ) {
//phpcs:ignore
if ( apply_filters( "{$this->slug}_enable_auto_update_db", !$this->show_admin_notices ) ) {
@ -419,12 +470,14 @@ abstract class Base_Plugin_Installer {
/**
* Push all needed updates to the queue for processing.
*/
final public function update() {
$current_version = get_option( "{$this->slug}_db_version", null );
public function update() {
$current_version = \get_option( "{$this->slug}_db_version", null );

if ( $current_version ) {
$this->get_update_handler()?->update( $current_version );
if ( ! $current_version ) {
return;
}

$this->get_update_handler()?->update( $current_version );
}

/**
@ -441,7 +494,7 @@ abstract class Base_Plugin_Installer {
*
* @param string $update_callback Callback name.
*/
final public function run_update_callback( $update_callback ) {
public function run_update_callback( $update_callback ) {
$this->get_update_handler()->run_update_callback( $update_callback );
}

@ -450,19 +503,21 @@ abstract class Base_Plugin_Installer {
*
* This function is hooked into admin_init to affect admin only.
*/
final public function install_actions() {
if ( ! empty( $_GET[ "do_update_{$this->slug}" ] ) ) { // WPCS: input var ok.
check_admin_referer( "{$this->slug}_db_update", "{$this->slug}_db_update_nonce" );
$this->update();
$this->add_admin_update_notice();
public function install_actions() {
if ( '' === \sanitize_text_field( \wp_unslash( $_GET[ "do_update_{$this->slug}" ] ?? '' ) ) ) {
return;
}

\check_admin_referer( "{$this->slug}_db_update", "{$this->slug}_db_update_nonce" );
$this->update();
$this->add_admin_update_notice();
}

/**
* Update plugin version to current.
*/
final public function update_plugin_version() {
update_option( "{$this->slug}_version", $this->version );
public function update_plugin_version() {
\update_option( "{$this->slug}_version", $this->version );
}

/**
@ -470,11 +525,13 @@ abstract class Base_Plugin_Installer {
*
* @param string|null $version New plugin DB version or null.
*/
final public function update_db_version( $version = null ) {
$version = $version ?? $this->db_version;
if ( '0.0.0' !== $version ) {
update_option( "{$this->slug}_db_version", is_null( $version ) ? $this->version : $version );
public function update_db_version( $version = null ) {
$version ??= $this->db_version;
if ( '0.0.0' === $version ) {
return;
}

\update_option( "{$this->slug}_db_version", \is_null( $version ) ? $this->version : $version );
}

/**
@ -483,9 +540,11 @@ abstract class Base_Plugin_Installer {
public function register_commands() {
WP_CLI::add_command( "{$this->slug} update", array( $this, 'cli_update' ) );

if ( $this->get_schema() ) {
WP_CLI::add_command( "{$this->slug} verify_tables", array( $this, 'cli_verify_tables' ) );
if ( ! $this->get_schema() ) {
return;
}

WP_CLI::add_command( "{$this->slug} verify_tables", array( $this, 'cli_verify_tables' ) );
}

// phpcs:disable Squiz.Commenting.FunctionComment.MissingParamTag
@ -502,13 +561,14 @@ abstract class Base_Plugin_Installer {
* [--force]
* : Force the update even if the database is already up to date.
*/
final public function cli_update( $args = array(), $assoc_args = array() ) {
$assoc_args = wp_parse_args(
public function cli_update( $args = array(), $assoc_args = array() ) {
//phpcs:ignore SlevomatCodingStandard.Functions.RequireSingleLineCall.RequiredSingleLineCall
$assoc_args = \wp_parse_args(
$assoc_args,
array(
'force' => false,
'from' => null,
)
'from' => null,
),
);

global $wpdb;
@ -518,30 +578,57 @@ abstract class Base_Plugin_Installer {
$handler = $this->get_update_handler();

$current_db_version = $assoc_args['from'] ??
( $assoc_args['force'] ? '0.0.0' : get_option( "{$this->slug}_db_version", '0.0.1' ) );
( $assoc_args['force'] ? '0.0.0' : \get_option( "{$this->slug}_db_version", '0.0.1' ) );

$update_count = 0;
$callbacks_to_run = $handler?->get_needed_update_callbacks( $current_db_version, $assoc_args['force'] ) ?? array();
$callbacks_to_run = $handler?->get_needed_update_callbacks(
$current_db_version,
$assoc_args['force'],
) ?? array();

if ( empty( $callbacks_to_run ) ) {
if ( 0 === \count( $callbacks_to_run ) ) {
// Ensure DB version is set to the current plugin version to match WP-Admin update routine.
$this->update_db_version();
/* translators: %s Database version number */
WP_CLI::success( sprintf( __( 'No updates required. Database version is %s', 'oblak-plugin-installer' ), $current_db_version ) );
WP_CLI::success(
\sprintf(
// translators: %s Database version number.
\__( 'No updates required. Database version is %s', 'oblak-plugin-installer' ),
$current_db_version,
),
);
return;
}

/* translators: 1: Number of database updates 2: List of update callbacks */
WP_CLI::log( sprintf( __( 'Found %1$d updates (%2$s)', 'oblak-plugin-installer' ), count( $callbacks_to_run ), implode( ', ', wp_list_pluck( $callbacks_to_run, 'details' ) ) ) );
WP_CLI::log(
\sprintf(
// Translators: 1: Number of database updates 2: List of update callbacks.
\__( 'Found %1$d updates (%2$s)', 'oblak-plugin-installer' ),
\count( $callbacks_to_run ),
\implode( ', ', \wp_list_pluck( $callbacks_to_run, 'details' ) ),
),
);

$progress = make_progress_bar( __( 'Updating database', 'oblak-plugin-installer' ), count( $callbacks_to_run ) );
$progress = make_progress_bar(
\__( 'Updating database', 'oblak-plugin-installer' ),
\count( $callbacks_to_run ),
);

foreach ( $callbacks_to_run as $index => $callback_data ) {
// Translators: 1: update callback details, 2: update callback version, 3: update callback index, 4: total number of update callbacks.
$progress->tick( 0, sprintf( esc_html__( 'Updating to %2$s: %1$s (%3$d/%4$d)', 'oblak-plugin-installer' ), $callback_data['details'], WP_CLi::colorize( "%C{$callback_data['version']}%n" ), $index + 1, count( $callbacks_to_run ) ) );

$progress->tick(
0,
\sprintf(
// Translators: 1: update callback details, 2: update callback version, 3: update callback index, 4: total number of update callbacks.
\esc_html__( 'Updating to %2$s: %1$s (%3$d/%4$d)', 'oblak-plugin-installer' ),
$callback_data['details'],
WP_CLi::colorize( "%C{$callback_data['version']}%n" ),
$index + 1,
\count( $callbacks_to_run ),
),
);

$status = $handler->run_update_callback( $callback_data['method'] );
sleep( 3 );
\sleep( 3 );

$progress->tick( 1 );

@ -553,12 +640,12 @@ abstract class Base_Plugin_Installer {
Admin_Notice_Manager::get_instance()->remove_notice( "{$this->slug}_update_notice", true );

WP_CLI::success(
sprintf(
\sprintf(
/* translators: 1: Number of database updates performed 2: Database version number */
__( '%1$d update functions completed. Database version is %2$s', 'oblak-plugin-installer' ),
absint( $update_count ),
get_option( "{$this->slug}_db_version" )
)
\__( '%1$d update functions completed. Database version is %2$s', 'oblak-plugin-installer' ),
\absint( $update_count ),
\get_option( "{$this->slug}_db_version" ),
),
);
}

@ -570,43 +657,52 @@ abstract class Base_Plugin_Installer {
* [--create]
* : Create the missing tables.
*/
final public function cli_verify_tables( $args = array(), $assoc_args = array() ) {
public function cli_verify_tables( $args = array(), $assoc_args = array() ) {
$results = $this->verify_base_tables();
$assoc_args = wp_parse_args(
$assoc_args,
array(
'create' => false,
)
);
$assoc_args = \wp_parse_args( $assoc_args, array( 'create' => false ) );

if ( empty( $results ) ) {
WP_CLI::success( __( 'All database tables are up to date.', 'oblak-plugin-installer' ) );
if ( 0 === \count( $results ) ) {
WP_CLI::success( \__( 'All database tables are up to date.', 'oblak-plugin-installer' ) );
return;
}

WP_CLI::warning( __( 'The following database tables are out of sync with the schema:', 'oblak-plugin-installer' ) );
WP_CLI::warning(
\__( 'The following database tables are out of sync with the schema:', 'oblak-plugin-installer' ),
);

foreach ( $results as $table ) {
/* Translators: 1: table name, 2: result */
WP_CLI::log( sprintf( __( 'Table %1$s: %2$s', 'oblak-plugin-installer' ), $table, __( 'Missing', 'oblak-plugin-installer' ) ) );

WP_CLI::log(
\sprintf(
// Translators: 1: table name, 2: result.
\__( 'Table %1$s: %2$s', 'oblak-plugin-installer' ),
$table,
\__( 'Missing', 'oblak-plugin-installer' ),
),
);
}

if ( ! $assoc_args['create'] ) {
WP_CLI::line( __( 'Run the command again with --create to create the missing tables.', 'oblak-plugin-installer' ) );
WP_CLI::line(
\__(
'Run the command again with --create to create the missing tables.',
'oblak-plugin-installer',
),
);
return;
}

WP_CLI::line( __( 'Creating missing tables...', 'oblak-plugin-installer' ) );
WP_CLI::line( \__( 'Creating missing tables...', 'oblak-plugin-installer' ) );
$this->verify_base_tables( false, true );

$results = $this->verify_base_tables();

if ( empty( $results ) ) {
WP_CLI::success( __( 'All database tables are up to date.', 'oblak-plugin-installer' ) );
if ( 0 === \count( $results ) ) {
WP_CLI::success( \__( 'All database tables are up to date.', 'oblak-plugin-installer' ) );
return;
}

WP_CLI::error( __( 'There was an error creating the missing tables.', 'oblak-plugin-installer' ) );
WP_CLI::error( \__( 'There was an error creating the missing tables.', 'oblak-plugin-installer' ) );
}

/**
@ -615,22 +711,26 @@ abstract class Base_Plugin_Installer {
* @param array<string, array> $tools Debug tools.
* @return array
*/
final public function add_debug_tools( array $tools ): array {
public function add_debug_tools( array $tools ): array {
if ( ! $this->get_schema() ) {
return $tools;
}

return array_merge(
return \array_merge(
$tools,
array(
"{$this->slug}_verify_db_tables" => array(
'name' => sprintf( '%s: %s', $this->name, __( 'Verify base database tables', 'woocommerce' ) ),
'desc' => __( 'Verify if all base database tables are present.', 'woocommerce' ),
'button' => __( 'Verify database', 'woocommerce' ),
'callback' => array( $this, 'debug_verify_db_tables' ),
'button' => \__( 'Verify database', 'woocommerce' ),
'callback' => array( $this, 'debug_verify_db_tables' ),
'desc' => \__( 'Verify if all base database tables are present.', 'woocommerce' ),
'name' => \sprintf(
'%s: %s',
$this->name,
\__( 'Verify base database tables', 'woocommerce' ),
),

),
)
),
);
}

@ -639,13 +739,16 @@ abstract class Base_Plugin_Installer {
*
* @return string
*/
final public function debug_verify_db_tables() {
public function debug_verify_db_tables() {
Admin_Notice_Manager::get_instance()->remove_notice( "{$this->slug}_missing_tables", true );

$missing_tables = $this->verify_base_tables( false, true );

return 0 === count( $missing_tables )
? __( 'Database verified successfully.', 'woocommerce' )
: __( 'Verifying database... One or more tables are still missing: ', 'woocommerce' ) . implode( ', ', $missing_tables );
return 0 === \count( $missing_tables )
? \__( 'Database verified successfully.', 'woocommerce' )
: \__( 'Verifying database... One or more tables are still missing: ', 'woocommerce' ) . \implode(
', ',
$missing_tables,
);
}
}