단일 사이트 설치 (다중 사이트에서 테스트하지는 않음)의 경우 github 또는 gitlab과 같은 외부 서비스에서 업데이트해야하는 후크는 두 개뿐입니다. 아래 코드에서 gitlab을 사용하므로 코드를 호스팅하는 데 사용됩니다. 아마도 gitlab 부분을 추상화해야합니다 ...
가장 먼저 사용해야 할 것은 pre_set_site_transient_update_themes
입니다. 사용 가능한 업데이트가 있는지 표시하기 위해 WordPress에서 site_transient를 설정하는 데 사용하는 필터입니다. 이 후크를 사용하여 원격 버전에 연결하고 사용 가능한 업데이트가 있는지 확인하십시오. 있는 경우 WordPress에 업데이트가 있음을 알리고 사용자에게 알림을 표시 할 수 있도록 임시 항목을 수정하십시오.
사용해야 할 다른 후크는 upgrader_source_selection
입니다. 다운로드 한 폴더의 이름이 테마와 다르기 때문에 gitlab에이 필터가 필요하므로이 후크를 사용하여 이름을 올바른 이름으로 바꿉니다. 원격 저장소가 올바른 이름의 zip을 제공하는 경우이 후크가 필요하지 않습니다.
세 번째 옵션 인 후크는 auto_update_theme
테마를 자동 업데이트하려는 경우입니다. 아래 예에서이 후크를 사용하여이 특정 테마 만 자동 업데이트합니다.
이 코드는 WordPress 4.9.x에서만 테스트되었습니다. PHP> 7.0이 필요합니다.
functions.php
//* Load the updater.
require PATH_TO . 'updater.php';
$updater = new updater();
\add_action( 'init', [ $updater, 'init' ] );
updater.php
/**
* @package StackExchange\WordPress
*/
declare( strict_types = 1 );
namespace StackExchange\WordPress;
/**
* Class for updating the theme.
*/
class updater {
/**
* @var Theme slug.
*/
protected $theme = 'theme';
/**
* @var Theme repository name.
*/
protected $repository = 'project/theme';
/**
* @var Repository domain.
*/
protected $domain = 'https://gitlab.com/';
/**
* @var CSS endpoint for repository.
*/
protected $css_endpoint = '/raw/master/style.css';
/**
* @var ZIP endpoint for repository.
*/
protected $zip_endpoint = '/repository/archive.zip';
/**
* @var Remote CSS URI.
*/
protected $remote_css_uri;
/**
* @var Remote ZIP URI.
*/
protected $remote_zip_uri;
/**
* @var Remote version.
*/
protected $remote_version;
/**
* @var Local version.
*/
protected $local_version;
/**
* Method called from the init hook to initiate the updater
*/
public function init() {
\add_filter( 'auto_update_theme', [ $this, 'auto_update_theme' ], 20, 2 );
\add_filter( 'upgrader_source_selection', [ $this, 'upgrader_source_selection' ], 10, 4 );
\add_filter( 'pre_set_site_transient_update_themes', [ $this, 'pre_set_site_transient_update_themes' ] );
}
/**
* Method called from the auto_update_theme hook.
* Only auto update this theme.
* This hook and method are only needed if you want to auto update the theme.
*
* @return bool Whether to update the theme.
*/
public function auto_update_theme( bool $update, \stdClass $item ) : bool {
return $this->theme === $item->theme;
}
/**
* Rename the unzipped folder to be the same as the existing folder
*
* @param string $source File source location
* @param string $remote_source Remote file source location
* @param \WP_Upgrader $upgrader \WP_Upgrader instance
* @param array $hook_extra Extra arguments passed to hooked filters
*
* @return string | \WP_Error The updated source location or a \WP_Error object on failure
*/
public function upgrader_source_selection( string $source, string $remote_source, \WP_Upgrader $upgrader, array $hook_extra ) {
global $wp_filesystem;
$update = [ 'update-selected', 'update-selected-themes', 'upgrade-theme' ];
if( ! isset( $_GET[ 'action' ] ) || ! in_array( $_GET[ 'action' ], $update, true ) ) {
return $source;
}
if( ! isset( $source, $remote_source ) ) {
return $source;
}
if( false === stristr( basename( $source ), $this->theme ) ) {
return $source;
}
$basename = basename( $source );
$upgrader->skin->feedback( esc_html_e( 'Renaming theme directory.', 'bootstrap' ) );
$corrected_source = str_replace( $basename, $this->theme, $source );
if( $wp_filesystem->move( $source, $corrected_source, true ) ) {
$upgrader->skin->feedback( esc_html_e( 'Rename successful.', 'bootstrap' ) );
return $corrected_source;
}
return new \WP_Error();
}
/**
* Add respoinse to update transient if theme has an update.
*
* @param $transient
*
* @return
*/
public function pre_set_site_transient_update_themes( $transient ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
$this->local_version = ( \wp_get_theme( $this->theme ) )->get( 'Version' );
if( $this->hasUpdate() ) {
$response = [
'theme' => $this->theme,
'new_version' => $this->remote_version,
'url' => $this->construct_repository_uri(),
'package' => $this->construct_remote_zip_uri(),
'branch' => 'master',
];
$transient->response[ $this->theme ] = $response;
}
return $transient;
}
/**
* Construct and return the URI to the remote stylesheet
*
* @return string The remote stylesheet URI
*/
protected function construct_remote_stylesheet_uri() : string {
return $this->remote_css_uri = $this->domain . $this->repository . $this->css_endpoint;
}
/**
* Construct and return the URI to the remote ZIP file
*
* @return string The remote ZIP URI
*/
protected function construct_remote_zip_uri() : string {
return $this->remote_zip_uri = $this->domain . $this->repository . $this->zip_endpoint;
}
/**
* Construct and return the URI to remote repository
*
* @access protected
* @since 1.0
*
* @return string The remote repository URI
*/
protected function construct_repository_uri() : string {
return $this->repository_uri = $this->domain . \trailingslashit( $this->repository );
}
/**
* Get and return the remote version
*
* @return string The remote version
*/
protected function get_remote_version() : string {
$this->remote_stylesheet_uri = $this->construct_remote_stylesheet_uri();
$response = $this->remote_get( $this->remote_stylesheet_uri );
$response = str_replace( "\r", "\n", \wp_remote_retrieve_body( $response ) );
$headers = [ 'Version' => 'Version' ];
foreach( $headers as $field => $regex ) {
if( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $response, $match ) && $match[1] ) {
$headers[ $field ] = _cleanup_header_comment( $match[1] );
}
else {
$headers[ $field ] = '';
}
}
return $this->remote_version = ( '' === $headers[ 'Version' ] ) ? '' : $headers[ 'Version' ];
}
/**
* Return whether the theme has an update
*
* @return bool Whether the theme has an update
*/
protected function hasUpdate() : bool {
if( ! $this->remote_version ) $this->remote_version = $this->get_remote_version();
return version_compare( $this->remote_version, $this->local_version, '>' );
}
/**
* Wrapper for \wp_remote_get()
*
* @param string $url The URL to get
* @param array $args Array or arguments to pass through to \wp_remote_get()
*
* @return array|WP_Error Return the request or an error object
*/
protected function remote_get( string $url, array $args = [] ) {
return \wp_remote_get( $url, $args );
}
}