forked from modiqi/git-it-write
替换 Forgejo API 数据源为本地文件系统读取,支持 30+ 仓库自动发现。 新增 WP-Cron 定时同步、WP-CLI 命令、多站点支持、SEO 字段写入。 base_directory 为空时保留原 API 模式向后兼容。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
176 lines
5.4 KiB
PHP
176 lines
5.4 KiB
PHP
<?php
|
|
|
|
if( ! defined( 'ABSPATH' ) ) exit;
|
|
|
|
class GIW_CLI_Command extends WP_CLI_Command{
|
|
|
|
/**
|
|
* Sync repositories from local file system to WordPress.
|
|
*
|
|
* ## OPTIONS
|
|
*
|
|
* [--repo=<name>]
|
|
* : Sync only this repository (directory name).
|
|
*
|
|
* [--force]
|
|
* : Force full sync, ignoring SHA comparison.
|
|
*
|
|
* [--blog-id=<id>]
|
|
* : Target blog ID for multisite.
|
|
*
|
|
* ## EXAMPLES
|
|
*
|
|
* wp giw sync
|
|
* wp giw sync --repo=woocommerce
|
|
* wp giw sync --force
|
|
* wp giw sync --repo=woocommerce --blog-id=3
|
|
*
|
|
* @subcommand sync
|
|
*/
|
|
public function sync( $args, $assoc_args ){
|
|
|
|
$force = isset( $assoc_args['force'] );
|
|
$repo = isset( $assoc_args['repo'] ) ? $assoc_args['repo'] : '';
|
|
$blog_id = isset( $assoc_args['blog-id'] ) ? (int) $assoc_args['blog-id'] : 0;
|
|
|
|
$settings = Git_It_Write::general_settings();
|
|
$base_dir = $settings['base_directory'];
|
|
|
|
if( empty( $base_dir ) ){
|
|
WP_CLI::error( 'base_directory is not configured. Set it in Settings > Git it Write.' );
|
|
return;
|
|
}
|
|
|
|
// Switch blog if specified.
|
|
if( $blog_id > 0 && is_multisite() ){
|
|
switch_to_blog( $blog_id );
|
|
WP_CLI::log( 'Switched to blog ID: ' . $blog_id );
|
|
}elseif( is_multisite() && !empty( $settings['target_blog_id'] ) ){
|
|
switch_to_blog( (int) $settings['target_blog_id'] );
|
|
WP_CLI::log( 'Switched to configured blog ID: ' . $settings['target_blog_id'] );
|
|
}
|
|
|
|
// Load media functions.
|
|
require_once( ABSPATH . 'wp-admin/includes/media.php' );
|
|
require_once( ABSPATH . 'wp-admin/includes/file.php' );
|
|
require_once( ABSPATH . 'wp-admin/includes/image.php' );
|
|
|
|
if( $force && !defined( 'GIW_PUBLISH_FORCE' ) ){
|
|
define( 'GIW_PUBLISH_FORCE', true );
|
|
}
|
|
|
|
if( !empty( $repo ) ){
|
|
|
|
// Sync single repo.
|
|
$repo_data = GIW_Discovery::find( $base_dir, $repo );
|
|
|
|
if( !$repo_data ){
|
|
WP_CLI::error( "Repository '$repo' not found in $base_dir" );
|
|
return;
|
|
}
|
|
|
|
WP_CLI::log( "Syncing repository: $repo" . ( $force ? ' (force)' : '' ) );
|
|
$result = GIW_Sync::sync_repo( $repo_data, $force );
|
|
self::print_result( $repo, $result );
|
|
|
|
}else{
|
|
|
|
// Sync all repos.
|
|
$repos = GIW_Discovery::discover( $base_dir );
|
|
|
|
if( empty( $repos ) ){
|
|
WP_CLI::warning( 'No repositories discovered in ' . $base_dir );
|
|
return;
|
|
}
|
|
|
|
WP_CLI::log( 'Discovered ' . count( $repos ) . ' repositories' . ( $force ? ' (force sync)' : '' ) );
|
|
|
|
foreach( $repos as $repo_data ){
|
|
WP_CLI::log( '' );
|
|
WP_CLI::log( "--- Syncing: {$repo_data['name']} ---" );
|
|
$result = GIW_Sync::sync_repo( $repo_data, $force );
|
|
self::print_result( $repo_data['name'], $result );
|
|
}
|
|
|
|
}
|
|
|
|
if( is_multisite() ){
|
|
restore_current_blog();
|
|
}
|
|
|
|
WP_CLI::success( 'Sync complete.' );
|
|
|
|
}
|
|
|
|
/**
|
|
* List discovered repositories and their sync status.
|
|
*
|
|
* ## EXAMPLES
|
|
*
|
|
* wp giw list
|
|
*
|
|
* @subcommand list
|
|
*/
|
|
public function list_repos( $args, $assoc_args ){
|
|
|
|
$settings = Git_It_Write::general_settings();
|
|
$base_dir = $settings['base_directory'];
|
|
|
|
if( empty( $base_dir ) ){
|
|
WP_CLI::error( 'base_directory is not configured.' );
|
|
return;
|
|
}
|
|
|
|
$repos = GIW_Discovery::discover( $base_dir );
|
|
$timestamps = get_option( 'giw_sync_timestamps', array() );
|
|
|
|
if( empty( $repos ) ){
|
|
WP_CLI::warning( 'No repositories found in ' . $base_dir );
|
|
return;
|
|
}
|
|
|
|
$table = array();
|
|
|
|
foreach( $repos as $repo ){
|
|
$name = $repo['name'];
|
|
$config = $repo['config'];
|
|
$last_ts = isset( $timestamps[ $name ] ) ? $timestamps[ $name ] : 0;
|
|
|
|
$table[] = array(
|
|
'Name' => $name,
|
|
'Post Type' => $config['post_type'],
|
|
'Folder' => empty( $config['folder'] ) ? '/' : $config['folder'],
|
|
'Category' => empty( $config['category'] ) ? '-' : $config['category'],
|
|
'Has Config' => is_readable( $repo['path'] . '/.giw.yml' ) ? 'yes' : 'no',
|
|
'Last Synced' => $last_ts > 0 ? date( 'Y-m-d H:i:s', $last_ts ) : 'never',
|
|
);
|
|
}
|
|
|
|
WP_CLI\Utils\format_items( 'table', $table, array_keys( $table[0] ) );
|
|
|
|
}
|
|
|
|
/**
|
|
* Print sync result for a single repo.
|
|
*/
|
|
private static function print_result( $name, $result ){
|
|
|
|
if( !$result || !is_array( $result ) ){
|
|
WP_CLI::warning( "$name: no result returned" );
|
|
return;
|
|
}
|
|
|
|
$new = count( $result['stats']['posts']['new'] );
|
|
$updated = count( $result['stats']['posts']['updated'] );
|
|
$failed = $result['stats']['posts']['failed'];
|
|
$images = count( $result['stats']['images']['uploaded'] );
|
|
|
|
WP_CLI::log( "$name: {$result['message']} (new: $new, updated: $updated, failed: $failed, images: $images)" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
WP_CLI::add_command( 'giw', 'GIW_CLI_Command' );
|
|
|
|
?>
|