Skip to content

Commit

Permalink
Merge pull request #7 from rtCamp/fix/constants-autoloading
Browse files Browse the repository at this point in the history
fix: cleanup constants and refactor autoload handling
  • Loading branch information
justlevine authored Sep 12, 2024
2 parents a06f97a + 1d4fdc9 commit 09d5ee9
Show file tree
Hide file tree
Showing 12 changed files with 307 additions and 134 deletions.
5 changes: 5 additions & 0 deletions .changeset/giant-buttons-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@wpengine/wp-graphql-content-blocks": minor
---

fix: cleanup constants and refactor autoload handling to improve Composer compatibility.
2 changes: 1 addition & 1 deletion bin/versionPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ async function bumpStableTag(readmeTxt, version) {
async function bumpVersionConstant(pluginFile, version) {
return bumpVersion(
pluginFile,
/^\s*\$this->define\(\s*'WPGRAPHQL_CONTENT_BLOCKS_VERSION', '([0-9.]+)/gm,
/^\s*define\(\s*'WPGRAPHQL_CONTENT_BLOCKS_VERSION', '([0-9.]+)/gm,
version
);
}
Expand Down
125 changes: 125 additions & 0 deletions includes/Autoloader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php
/**
* Includes the Composer Autoloader used for packages and classes in the includes/ directory.
*
* @package WPGraphQL\ContentBlocks
* @since @todo
*/

declare( strict_types = 1 );

namespace WPGraphQL\ContentBlocks;

/**
* Class - Autoloader
*
* @internal
*/
class Autoloader {
/**
* Whether the autoloader has been loaded.
*
* @var bool
*/
protected static bool $is_loaded = false;

/**
* Attempts to autoload the Composer dependencies.
*/
public static function autoload(): bool {
// If we're not *supposed* to autoload anything, then return true.
if ( defined( 'WPGRAPHQL_CONTENT_BLOCKS_AUTOLOAD' ) && false === WPGRAPHQL_CONTENT_BLOCKS_AUTOLOAD ) {
return true;
}

// If the autoloader has already been loaded, then return true.
if ( self::$is_loaded ) {
return self::$is_loaded;
}

// If the main class has already been loaded, then they must be using a different autoloader.
if ( class_exists( 'WPGraphQLContentBlocks' ) ) {
return true;
}

$autoloader = dirname( __DIR__ ) . '/vendor/autoload.php';
self::$is_loaded = self::require_autoloader( $autoloader );

return self::$is_loaded;
}

/**
* Attempts to load the autoloader file, if it exists.
*
* @param string $autoloader_file The path to the autoloader file.
*/
private static function require_autoloader( string $autoloader_file ): bool {
if ( ! is_readable( $autoloader_file ) ) {
self::missing_autoloader_notice();
return false;
}

return (bool) require_once $autoloader_file; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable -- Autoloader is a Composer file.
}

/**
* Displays a notice if the autoloader is missing.
*/
private static function missing_autoloader_notice(): void {
$error_message = __( 'WPGraphQL Content Blocks appears to have been installed without its dependencies. If you meant to download the source code, you can run `composer install` to install dependencies. If you are looking for the production version of the plugin, you can download it from the <a target="_blank" href="https://github.com/wpengine/wp-graphql-content-blocks/releases">GitHub Releases tab.</a>', 'wp-graphql-content-blocks' );

if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- This is a development notice.
sprintf(
wp_kses(
$error_message,
[
'a' => [
'href' => [],
'target' => [],
],
]
)
)
);
}

$hooks = [
'admin_notices',
'network_admin_notices',
];

foreach ( $hooks as $hook ) {
add_action(
$hook,
static function () use ( $error_message ) {

// Only show the notice to admins.
if ( ! current_user_can( 'manage_options' ) ) {
return;
}

?>
<div class="error notice">
<p>
<?php
printf(
wp_kses(
$error_message,
[
'a' => [
'href' => [],
'target' => [],
],
]
)
)
?>
</p>
</div>
<?php
}
);
}
}
}
18 changes: 11 additions & 7 deletions includes/PluginUpdater/UpdateCallbacks.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ function check_for_plugin_updates( $data ) {
}

$response->slug = 'wp-graphql-content-blocks';
$current_plugin_data = \get_plugin_data( WPGRAPHQL_CONTENT_BLOCKS_FILE );
$current_plugin_data = \get_plugin_data( WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_FILE );
$meets_wp_req = version_compare( get_bloginfo( 'version' ), $response->requires_at_least, '>=' );

// Only update the response if there's a newer version, otherwise WP shows an update notice for the same version.
if ( $meets_wp_req && version_compare( $current_plugin_data['Version'], $response->version, '<' ) ) {
$response->plugin = plugin_basename( WPGRAPHQL_CONTENT_BLOCKS_FILE );
$data->response[ WPGRAPHQL_CONTENT_BLOCKS_PATH ] = $response;
$response->plugin = plugin_basename( WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_FILE );
$data->response[ WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_PATH ] = $response;
}

return $data;
Expand All @@ -60,10 +60,13 @@ function check_for_plugin_updates( $data ) {
* @param string $action The type of information being requested from the Plugin Installation API.
* @param object $args Plugin API arguments.
*
* @return false|\WPGraphQL\ContentBlocks\PluginUpdater\stdClass $response Plugin API arguments.
* @return false|object|array $response Plugin API arguments.
*/
function custom_plugin_api_request( $api, $action, $args ) {
if ( empty( $args->slug ) || WPGRAPHQL_CONTENT_BLOCKS_SLUG !== $args->slug ) {
// Bail if it's not our plugin.
$plugin_slug = dirname( plugin_basename( WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_FILE ) );

if ( empty( $args->slug ) || $plugin_slug !== $args->slug ) {
return $api;
}

Expand Down Expand Up @@ -96,7 +99,7 @@ function delegate_plugin_row_notice() {
return;
}

$plugin_basename = plugin_basename( WPGRAPHQL_CONTENT_BLOCKS_FILE );
$plugin_basename = plugin_basename( WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_FILE );

remove_action( "after_plugin_row_{$plugin_basename}", 'wp_plugin_update_row' );
add_action( "after_plugin_row_{$plugin_basename}", __NAMESPACE__ . '\display_plugin_row_notice', 10 );
Expand Down Expand Up @@ -172,8 +175,9 @@ function display_update_page_notice() {
* @return string
*/
function filter_semver_notice_text( $notice_text, $plugin_filename ) {
if ( WPGRAPHQL_CONTENT_BLOCKS_PATH !== $plugin_filename ) {
if ( WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_PATH !== $plugin_filename ) {
return $notice_text;
}

return '<br><br>' . __( '<b>THIS UPDATE MAY CONTAIN BREAKING CHANGES:</b> This plugin uses Semantic Versioning, and this new version is a major release. Please review the changelog before updating.', 'wp-graphql-content-blocks' );
}
8 changes: 5 additions & 3 deletions includes/PluginUpdater/UpdateFunctions.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function get_plugin_data_from_wpe( $args ) {
return $args;
}

$current_plugin_data = \get_plugin_data( WPGRAPHQL_CONTENT_BLOCKS_FILE );
$current_plugin_data = \get_plugin_data( WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_FILE );
$meets_wp_req = version_compare( get_bloginfo( 'version' ), $product_info->requires_at_least, '>=' );

$api = new stdClass();
Expand Down Expand Up @@ -65,7 +65,7 @@ function get_plugin_api_error() {
* @return \stdClass
*/
function get_remote_plugin_info() {
$current_plugin_data = \get_plugin_data( WPGRAPHQL_CONTENT_BLOCKS_FILE );
$current_plugin_data = \get_plugin_data( WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_FILE );
$response = get_transient( 'wpgraphql_content_blocks_product_info' );

if ( false === $response ) {
Expand Down Expand Up @@ -101,7 +101,9 @@ function get_remote_plugin_info() {
);

if ( ! property_exists( $response, 'icons' ) || empty( $response->icons['default'] ) ) {
$response->icons['default'] = WPGRAPHQL_CONTENT_BLOCKS_URL . 'includes/updates/images/wpe-logo-stacked-inverse.svg';
$plugin_url = plugin_dir_url( WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_FILE );

$response->icons['default'] = $plugin_url . 'includes/updates/images/wpe-logo-stacked-inverse.svg';
}

set_transient( 'wpgraphql_content_blocks_product_info', $response, HOUR_IN_SECONDS * 12 );
Expand Down
140 changes: 53 additions & 87 deletions includes/WPGraphQLContentBlocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ final class WPGraphQLContentBlocks {
public static function instance() {
if ( ! isset( self::$instance ) || ! ( self::$instance instanceof self ) ) {
self::$instance = new self();
self::$instance->setup_constants();
// @todo Remove this in a major version bump.
self::$instance->deprecated_constants();

if ( self::$instance->includes() ) {
self::$instance->actions();
}
Expand Down Expand Up @@ -64,96 +66,49 @@ public function __wakeup() {
_doing_it_wrong( __FUNCTION__, esc_html__( 'De-serializing instances of the WPGraphQLContentBlocks class is not allowed', 'wp-graphql-content-blocks' ), '0.0.1' );
}

/**
* Setup plugin constants.
*
* @since 0.0.1
*/
private function setup_constants(): void {

// Set main file path.
$main_file_path = dirname( __DIR__ ) . '/wp-graphql.php';

// Plugin version.
$this->define( 'WPGRAPHQL_CONTENT_BLOCKS_VERSION', '4.1.0' );
// Plugin Folder Path.
$this->define( 'WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_DIR', plugin_dir_path( $main_file_path ) );
// Plugin Root File.
$this->define( 'WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_FILE', $main_file_path );
// Whether to autoload the files or not.
$this->define( 'WPGRAPHQL_CONTENT_BLOCKS_AUTOLOAD', true );
// The minimum version of PHP this plugin requires to work properly
$this->define( 'WPGRAPHQL_CONTENT_BLOCKS_MIN_PHP_VERSION', '7.4' );
}

/**
* Include required files.
* Uses composer's autoload
*
* @since 0.0.1
*/
private function includes(): bool {
/**
* WPGRAPHQL_CONTENT_BLOCKS_AUTOLOAD can be set to "false" to prevent the autoloader from running.
* In most cases, this is not something that should be disabled, but some environments
* may bootstrap their dependencies in a global autoloader that will autoload files
* before we get to this point, and requiring the autoloader again can trigger fatal errors.
*/
if ( defined( 'WPGRAPHQL_CONTENT_BLOCKS_AUTOLOAD' ) && true === WPGRAPHQL_CONTENT_BLOCKS_AUTOLOAD ) {
if ( file_exists( WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_DIR . 'vendor/autoload.php' ) ) {
// Autoload Required Classes.
require_once WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_DIR . 'vendor/autoload.php';
} else {
add_action(
'admin_notices',
static function () {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}

printf(
'<div class="notice notice-error">' .
'<p>%s</p>' .
'</div>',
wp_kses_post(
__( 'WPGraphQL Content Blocks appears to have been installed without its dependencies. If you meant to download the source code, you can run `composer install` to install dependencies. If you are looking for the production version of the plugin, you can download it from the <a target="_blank" href="https://github.com/wpengine/wp-graphql-content-blocks/releases">GitHub Releases tab.</a>', 'wp-graphql-content-blocks' )
)
);
}
);
}//end if

// If GraphQL class doesn't exist, then dependencies cannot be
// detected. This likely means the user cloned the repo from GitHub
// but did not run `composer install`
if ( ! class_exists( 'WPGraphQL' ) ) {
add_action(
'admin_notices',
static function () {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}

printf(
'<div class="notice notice-error is-dismissible">' .
'<p>%s</p>' .
'</div>',
esc_html__( 'WPGraphQL Content Blocks will not work without WPGraphQL installed and active.', 'wp-graphql-content-blocks' )
);
// Holds the status of whether the plugin is active or not so we can load the updater functions regardless.
$success = true;

// If GraphQL class doesn't exist, then that plugin is not active.
if ( ! class_exists( 'WPGraphQL' ) ) {
add_action(
'admin_notices',
static function () {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
);

return false;
}//end if
}//end if
printf(
'<div class="notice notice-error is-dismissible">' .
'<p>%s</p>' .
'</div>',
esc_html__( 'WPGraphQL Content Blocks will not work without WPGraphQL installed and active.', 'wp-graphql-content-blocks' )
);
}
);

require_once WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_DIR . 'includes/PluginUpdater/UpdateFunctions.php';
require_once WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_DIR . 'includes/PluginUpdater/UpdateCallbacks.php';
$success = false;
}

// Include the updater functions.
require_once WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_DIR . '/includes/PluginUpdater/UpdateFunctions.php';
require_once WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_DIR . '/includes/PluginUpdater/UpdateCallbacks.php';

// phpcs:ignore SlevomatCodingStandard.Variables.UnusedVariable.UnusedVariable -- Library bootstraps itself, hence variable is unused.
$semver = new \EnforceSemVer\EnforceSemVer( WPGRAPHQL_CONTENT_BLOCKS_PATH );
// Bail if the Enforce SemVer class doesn't exist.
if ( ! class_exists( 'EnforceSemVer\EnforceSemVer' ) ) {
return false;
}

return true;
new \EnforceSemVer\EnforceSemVer( WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_PATH );

return $success;
}

/**
Expand All @@ -176,16 +131,27 @@ public function init_block_editor_registry( \WPGraphQL\Registry\TypeRegistry $ty
}

/**
* Define constant if not already set.
*
* @param string $name Constant name.
* @param string|bool $value Constant value.
* Sets up deprecated constants.
*
* @since 1.4.0
* @deprecated @todo This can be removed in a major version bump.
*/
private function define( string $name, $value ): void {
if ( ! defined( $name ) ) {
define( $name, $value ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.VariableConstantNameFound
private function deprecated_constants(): void {
if ( defined( 'WPGRAPHQL_CONTENT_BLOCKS_FILE' ) ) {
_doing_it_wrong( 'WPGRAPHQL_CONTENT_BLOCKS_FILE', 'The WPGRAPHQL_CONTENT_BLOCKS_VERSION constant has been deprecated. Use the WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_FILE constant instead.', '@todo' );
} else {
define( 'WPGRAPHQL_CONTENT_BLOCKS_FILE', WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_FILE );
}

if ( defined( 'WPGRAPHQL_CONTENT_BLOCKS_PATH' ) ) {
_doing_it_wrong( 'WPGRAPHQL_CONTENT_BLOCKS_PATH', 'The WPGRAPHQL_CONTENT_BLOCKS_PATH constant has been deprecated. Use the WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_PATH constant instead.', '@todo' );
} else {
define( 'WPGRAPHQL_CONTENT_BLOCKS_PATH', WPGRAPHQL_CONTENT_BLOCKS_PLUGIN_PATH );
}

if ( defined( 'WPGRAPHQL_CONTENT_BLOCKS_MIN_PHP_VERSION' ) ) {
_doing_it_wrong( 'WPGRAPHQL_CONTENT_BLOCKS_MIN_PHP_VERSION', 'The WPGRAPHQL_CONTENT_BLOCKS_VERSION constant has been deprecated, with no replacement. It will be removed in a future release.', '@todo' );
} else {
define( 'WPGRAPHQL_CONTENT_BLOCKS_MIN_PHP_VERSION', WPGRAPHQL_CONTENT_BLOCKS_VERSION );
}
}
}
Loading

0 comments on commit 09d5ee9

Please sign in to comment.