210 lines
7.1 KiB
PHP
210 lines
7.1 KiB
PHP
<?php
|
|
/**
|
|
* Module de mise à jour automatique du thème depuis le dépôt public Gitea.
|
|
*
|
|
* - Interroge directement raw/branch/main/style.css sans aucun token API.
|
|
* - Télécharge /archive/main.zip lors d'une mise à jour en un clic depuis WordPress.
|
|
* - Renomme automatiquement le dossier extrait vers get_stylesheet().
|
|
* - Ne touche jamais aux réglages enregistrés en base (wp_options), menus ou médias.
|
|
*
|
|
* @package CGT_FHA
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
class CGT_FHA_Gitea_Updater {
|
|
|
|
public const REPO_URL = 'https://git.cgt-fha.fr/Union_Locale_CGT_Foix_Haute-Ariege/cgt-wp-theme';
|
|
public const RAW_STYLE_URL = 'https://git.cgt-fha.fr/Union_Locale_CGT_Foix_Haute-Ariege/cgt-wp-theme/raw/branch/main/style.css';
|
|
public const PACKAGE_URL = 'https://git.cgt-fha.fr/Union_Locale_CGT_Foix_Haute-Ariege/cgt-wp-theme/archive/main.zip';
|
|
public const VERSION_TRANSIENT = 'cgt_fha_gitea_remote_version';
|
|
public const ERROR_TRANSIENT = 'cgt_fha_gitea_remote_error';
|
|
public const CACHE_TTL = 6 * HOUR_IN_SECONDS;
|
|
|
|
/**
|
|
* Enregistre les hooks natifs WordPress de vérification et d'installation des mises à jour.
|
|
*/
|
|
public static function init(): void {
|
|
add_filter( 'pre_set_site_transient_update_themes', array( __CLASS__, 'check_for_update' ) );
|
|
add_filter( 'upgrader_source_selection', array( __CLASS__, 'fix_extracted_folder_name' ), 10, 4 );
|
|
add_action( 'upgrader_process_complete', array( __CLASS__, 'purge_version_cache' ), 10, 2 );
|
|
}
|
|
|
|
/**
|
|
* Injecte l'état de mise à jour du thème dans le transient update_themes.
|
|
*
|
|
* @param mixed $transient Objet transient WordPress.
|
|
* @return mixed
|
|
*/
|
|
public static function check_for_update( $transient ) {
|
|
if ( ! is_object( $transient ) || empty( $transient->checked ) ) {
|
|
return $transient;
|
|
}
|
|
|
|
$theme_slug = get_stylesheet();
|
|
$current_version = (string) wp_get_theme( $theme_slug )->get( 'Version' );
|
|
if ( '' === $current_version ) {
|
|
return $transient;
|
|
}
|
|
|
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
$force_check = ! empty( $_GET['force-check'] );
|
|
$remote_version = self::get_remote_version( $force_check );
|
|
if ( null === $remote_version || '' === $remote_version ) {
|
|
return $transient;
|
|
}
|
|
|
|
$update_data = array(
|
|
'theme' => $theme_slug,
|
|
'new_version' => $remote_version,
|
|
'url' => self::REPO_URL,
|
|
'package' => self::PACKAGE_URL,
|
|
);
|
|
|
|
if ( ! isset( $transient->response ) || ! is_array( $transient->response ) ) {
|
|
$transient->response = array();
|
|
}
|
|
if ( ! isset( $transient->no_update ) || ! is_array( $transient->no_update ) ) {
|
|
$transient->no_update = array();
|
|
}
|
|
|
|
if ( version_compare( $remote_version, $current_version, '>' ) ) {
|
|
$transient->response[ $theme_slug ] = $update_data;
|
|
unset( $transient->no_update[ $theme_slug ] );
|
|
} else {
|
|
$transient->no_update[ $theme_slug ] = $update_data;
|
|
unset( $transient->response[ $theme_slug ] );
|
|
}
|
|
|
|
return $transient;
|
|
}
|
|
|
|
/**
|
|
* Récupère la version distante dans style.css sur la branche main (avec cache Transient).
|
|
*
|
|
* @param bool $force_check Ignore le cache si une vérification manuelle est demandée.
|
|
* @return string|null
|
|
*/
|
|
private static function get_remote_version( bool $force_check = false ): ?string {
|
|
if ( ! $force_check ) {
|
|
$cached = get_transient( self::VERSION_TRANSIENT );
|
|
if ( is_string( $cached ) && '' !== $cached ) {
|
|
return $cached;
|
|
}
|
|
if ( false !== get_transient( self::ERROR_TRANSIENT ) ) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
$response = wp_remote_get(
|
|
self::RAW_STYLE_URL,
|
|
array(
|
|
'timeout' => 10,
|
|
'sslverify' => true,
|
|
'headers' => array(
|
|
'Accept' => 'text/plain',
|
|
),
|
|
'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
|
|
)
|
|
);
|
|
|
|
if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
|
|
set_transient( self::ERROR_TRANSIENT, 1, 15 * MINUTE_IN_SECONDS );
|
|
return null;
|
|
}
|
|
|
|
$body = (string) wp_remote_retrieve_body( $response );
|
|
if ( '' === $body || ! preg_match( '/^\s*\*?\s*Version\s*:\s*([0-9]+\.[0-9]+(?:\.[0-9]+)*(?:-[A-Za-z0-9._-]+)?)/mi', $body, $matches ) ) {
|
|
set_transient( self::ERROR_TRANSIENT, 1, 15 * MINUTE_IN_SECONDS );
|
|
return null;
|
|
}
|
|
|
|
$remote_version = trim( $matches[1] );
|
|
delete_transient( self::ERROR_TRANSIENT );
|
|
set_transient( self::VERSION_TRANSIENT, $remote_version, self::CACHE_TTL );
|
|
|
|
return $remote_version;
|
|
}
|
|
|
|
/**
|
|
* Renomme automatiquement le dossier extrait de l'archive Gitea vers get_stylesheet().
|
|
*
|
|
* @param string|WP_Error $source Chemin du dossier extrait.
|
|
* @param string $remote_source Dossier temporaire parent.
|
|
* @param WP_Upgrader $upgrader Instance du gestionnaire de mise à jour.
|
|
* @param array $hook_extra Métadonnées sur l'élément mis à jour.
|
|
* @return string|WP_Error
|
|
*/
|
|
public static function fix_extracted_folder_name( $source, $remote_source, $upgrader, $hook_extra ) {
|
|
if ( is_wp_error( $source ) || empty( $source ) || empty( $remote_source ) ) {
|
|
return $source;
|
|
}
|
|
|
|
$theme_slug = get_stylesheet();
|
|
$is_single = isset( $hook_extra['theme'] ) && $hook_extra['theme'] === $theme_slug;
|
|
$is_bulk = isset( $hook_extra['themes'] ) && is_array( $hook_extra['themes'] ) && in_array( $theme_slug, $hook_extra['themes'], true );
|
|
|
|
if ( ! $is_single && ! $is_bulk ) {
|
|
return $source;
|
|
}
|
|
|
|
// Vérification d'intégrité (indispensable en mise à jour groupée) sur le Text Domain du thème.
|
|
$style_path = trailingslashit( (string) $source ) . 'style.css';
|
|
if ( ! file_exists( $style_path ) ) {
|
|
return $source;
|
|
}
|
|
|
|
$header_chunk = file_get_contents( $style_path, false, null, 0, 2048 );
|
|
if ( false === $header_chunk || ! preg_match( '/^\s*\*?\s*Text\s+Domain\s*:\s*cgt-fha\b/mi', $header_chunk ) ) {
|
|
return $source;
|
|
}
|
|
|
|
$corrected_source = trailingslashit( (string) $remote_source ) . $theme_slug . '/';
|
|
if ( untrailingslashit( (string) $source ) === untrailingslashit( $corrected_source ) ) {
|
|
return $source;
|
|
}
|
|
|
|
global $wp_filesystem;
|
|
if ( ! $wp_filesystem ) {
|
|
require_once ABSPATH . 'wp-admin/includes/file.php';
|
|
WP_Filesystem();
|
|
}
|
|
|
|
if ( ! $wp_filesystem ) {
|
|
return $source;
|
|
}
|
|
|
|
if ( $wp_filesystem->is_dir( $corrected_source ) ) {
|
|
$wp_filesystem->delete( $corrected_source, true );
|
|
}
|
|
|
|
if ( ! $wp_filesystem->move( (string) $source, $corrected_source, true ) ) {
|
|
return new WP_Error(
|
|
'cgt_fha_rename_failed',
|
|
__( 'Impossible de renommer l\'archive du thème vers le dossier actif.', 'cgt-fha' )
|
|
);
|
|
}
|
|
|
|
return $corrected_source;
|
|
}
|
|
|
|
/**
|
|
* Purge uniquement les transients de version après une mise à jour de thème.
|
|
*
|
|
* @param WP_Upgrader $upgrader Instance du gestionnaire de mise à jour.
|
|
* @param array $hook_extra Métadonnées de la mise à jour terminée.
|
|
*/
|
|
public static function purge_version_cache( $upgrader, $hook_extra ): void {
|
|
if ( 'theme' !== ( $hook_extra['type'] ?? '' ) ) {
|
|
return;
|
|
}
|
|
|
|
delete_transient( self::VERSION_TRANSIENT );
|
|
delete_transient( self::ERROR_TRANSIENT );
|
|
}
|
|
}
|
|
|
|
CGT_FHA_Gitea_Updater::init();
|