mirror of
https://gh.wpcy.net/https://github.com/WP-Autoplugin/hub2wp.git
synced 2026-05-03 21:14:57 +08:00
470 lines
17 KiB
PHP
470 lines
17 KiB
PHP
<?php
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Handles AJAX requests for the hub2wp plugin.
|
|
*/
|
|
class H2WP_Admin_Ajax {
|
|
/**
|
|
* Clean any buffered output started after the given level.
|
|
*
|
|
* @param int $buffer_level Buffer level to return to.
|
|
* @return void
|
|
*/
|
|
private function clean_ajax_buffers( $buffer_level ) {
|
|
while ( ob_get_level() > $buffer_level ) {
|
|
ob_end_clean();
|
|
}
|
|
}
|
|
/**
|
|
* Normalize repository type from request.
|
|
*
|
|
* @return string plugin|theme
|
|
*/
|
|
private function get_repo_type_from_request() {
|
|
$repo_type = isset( $_POST['repo_type'] ) ? sanitize_key( wp_unslash( $_POST['repo_type'] ) ) : 'plugin';
|
|
return in_array( $repo_type, array( 'plugin', 'theme' ), true ) ? $repo_type : 'plugin';
|
|
}
|
|
|
|
/**
|
|
* Check capability for the current repository type.
|
|
*
|
|
* @param string $repo_type Repository type.
|
|
* @return bool
|
|
*/
|
|
private function can_manage_repo_type( $repo_type ) {
|
|
$cap = ( 'theme' === $repo_type ) ? 'install_themes' : 'install_plugins';
|
|
return current_user_can( $cap );
|
|
}
|
|
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
public function __construct() {
|
|
add_action( 'wp_ajax_h2wp_get_plugin_details', array( $this, 'get_plugin_details' ) );
|
|
add_action( 'wp_ajax_h2wp_check_compatibility', array( $this, 'check_compatibility' ) );
|
|
add_action( 'wp_ajax_h2wp_get_changelog', array( $this, 'get_changelog' ) );
|
|
add_action( 'wp_ajax_h2wp_install_plugin', array( $this, 'install_plugin' ) );
|
|
add_action( 'wp_ajax_h2wp_activate_plugin', array( $this, 'activate_plugin' ) );
|
|
}
|
|
|
|
/**
|
|
* Handle AJAX request to get plugin details.
|
|
*/
|
|
public function get_plugin_details() {
|
|
// Check nonce.
|
|
check_ajax_referer( 'h2wp_plugin_details_nonce', 'nonce' );
|
|
|
|
$repo_type = $this->get_repo_type_from_request();
|
|
|
|
// Check user capabilities.
|
|
if ( ! $this->can_manage_repo_type( $repo_type ) ) {
|
|
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'hub2wp' ) ) );
|
|
}
|
|
|
|
// Get and sanitize parameters.
|
|
$owner = isset( $_POST['owner'] ) ? sanitize_text_field( wp_unslash( $_POST['owner'] ) ) : '';
|
|
$repo = isset( $_POST['repo'] ) ? sanitize_text_field( wp_unslash( $_POST['repo'] ) ) : '';
|
|
|
|
if ( empty( $owner ) || empty( $repo ) ) {
|
|
wp_send_json_error( array( 'message' => __( 'Invalid parameters.', 'hub2wp' ) ) );
|
|
}
|
|
|
|
// Get access token from settings.
|
|
$access_token = H2WP_Settings::get_access_token();
|
|
$api = new H2WP_GitHub_API( $access_token );
|
|
|
|
// Fetch data.
|
|
$repo_details = $api->get_repo_details( $owner, $repo );
|
|
if ( is_wp_error( $repo_details ) ) {
|
|
wp_send_json_error( array( 'message' => $repo_details->get_error_message() ) );
|
|
}
|
|
|
|
$readme_html = $api->get_readme_html( $owner, $repo );
|
|
if ( is_wp_error( $readme_html ) ) {
|
|
$readme_html = __( 'No README available.', 'hub2wp' );
|
|
}
|
|
|
|
$readme_html = $this->strip_plugin_headers( $readme_html );
|
|
|
|
$og_image = $api->get_og_image( $owner, $repo );
|
|
if ( is_wp_error( $og_image ) ) {
|
|
$og_image = $repo_details['owner']['avatar_url'];
|
|
}
|
|
|
|
$last_updated = '';
|
|
if ( isset( $repo_details['pushed_at'] ) ) {
|
|
$last_updated = sprintf(
|
|
/* translators: %s: human-readable time difference */
|
|
__( '%s ago', 'hub2wp' ),
|
|
human_time_diff( strtotime( $repo_details['pushed_at'] ) )
|
|
);
|
|
}
|
|
|
|
// Let's try to use the pushed_at date of the default_branch
|
|
if ( isset( $repo_details['default_branch'] ) ) {
|
|
$branch_details = $api->get_branch_details( $owner, $repo, $repo_details['default_branch'] );
|
|
if ( ! is_wp_error( $branch_details ) && isset( $branch_details['commit']['commit']['author']['date'] ) ) {
|
|
$last_updated = sprintf(
|
|
/* translators: %s: human-readable time difference */
|
|
__( '%s ago', 'hub2wp' ),
|
|
human_time_diff( strtotime( $branch_details['commit']['commit']['author']['date'] ) )
|
|
);
|
|
}
|
|
}
|
|
|
|
// Prepare data.
|
|
$data = array(
|
|
'name' => isset( $repo_details['name'] ) ? $repo_details['name'] : '',
|
|
'display_name' => isset( $repo_details['name'] ) ? ucwords( str_replace( array( '-', 'wp', 'wordpress', 'seo' ), array( ' ', 'WP', 'WordPress', 'SEO' ), $repo_details['name'] ) ) : '',
|
|
'owner' => isset( $repo_details['owner']['login'] ) ? sanitize_text_field( $repo_details['owner']['login'] ) : '',
|
|
'repo' => isset( $repo_details['name'] ) ? sanitize_text_field( $repo_details['name'] ) : '',
|
|
'description' => isset( $repo_details['description'] ) ? $repo_details['description'] : '',
|
|
'readme' => $readme_html,
|
|
'stargazers' => isset( $repo_details['stargazers_count'] ) ? number_format_i18n( $repo_details['stargazers_count'] ) : '0',
|
|
'forks' => isset( $repo_details['forks_count'] ) ? number_format_i18n( $repo_details['forks_count'] ) : '0',
|
|
'watchers' => $api->get_watchers_count( $owner, $repo ),
|
|
'open_issues' => isset( $repo_details['open_issues_count'] ) ? number_format_i18n( $repo_details['open_issues_count'] ) : '0',
|
|
'html_url' => isset( $repo_details['html_url'] ) ? esc_url_raw( $repo_details['html_url'] ) : '',
|
|
'homepage' => isset( $repo_details['homepage'] ) ? esc_url_raw( $repo_details['homepage'] ) : '',
|
|
'og_image' => esc_url_raw( $og_image ),
|
|
'owner_avatar_url' => isset( $repo_details['owner']['avatar_url'] ) ? esc_url_raw( $repo_details['owner']['avatar_url'] ) : '',
|
|
'author' => isset( $repo_details['owner']['login'] ) ? sanitize_text_field( $repo_details['owner']['login'] ) : '',
|
|
'author_url' => isset( $repo_details['owner']['html_url'] ) ? esc_url_raw( $repo_details['owner']['html_url'] ) : '',
|
|
'updated_at' => $last_updated,
|
|
'topics' => isset( $repo_details['topics'] ) ? $this->extract_topics( $repo_details['topics'], $repo_type ) : array(),
|
|
'is_installed' => H2WP_Admin_Page::is_repo_installed( $owner, $repo, $repo_type ),
|
|
'repo_type' => $repo_type,
|
|
);
|
|
|
|
wp_send_json_success( $data );
|
|
}
|
|
|
|
/**
|
|
* Try to strip plugin headers like "Contributors: x", "Donate link: Y", "Tags: Z", etc. from the readme because they already appear in the sidebar.
|
|
*
|
|
* @param string $readme Readme HTML.
|
|
* @return string Filtered readme HTML.
|
|
*/
|
|
private function strip_plugin_headers( $readme ) {
|
|
$skip = array(
|
|
'contributors',
|
|
'donate link',
|
|
'tags',
|
|
'requires at least',
|
|
'tested up to',
|
|
'stable tag',
|
|
'requires php',
|
|
'license',
|
|
'license uri',
|
|
);
|
|
|
|
$lines = explode( "\n", $readme );
|
|
$filtered_lines = array();
|
|
$header_section = true;
|
|
|
|
foreach ( $lines as $index => $line ) {
|
|
// Only check first x lines for headers.
|
|
if ( $index >= 40 ) {
|
|
$header_section = false;
|
|
}
|
|
|
|
if ( $header_section ) {
|
|
$skip_line = false;
|
|
foreach ( $skip as $header ) {
|
|
if ( stripos( $line, $header . ':' ) === 0 ) {
|
|
$skip_line = true;
|
|
break;
|
|
}
|
|
}
|
|
if ( $skip_line ) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$filtered_lines[] = $line;
|
|
}
|
|
|
|
return implode( "\n", $filtered_lines );
|
|
}
|
|
|
|
/**
|
|
* Handle AJAX request to install a plugin.
|
|
*/
|
|
public function install_plugin() {
|
|
// Check nonce.
|
|
check_ajax_referer( 'h2wp_plugin_details_nonce', 'nonce' );
|
|
|
|
$repo_type = $this->get_repo_type_from_request();
|
|
|
|
// Check user capabilities.
|
|
if ( ! $this->can_manage_repo_type( $repo_type ) ) {
|
|
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'hub2wp' ) ) );
|
|
}
|
|
|
|
// Get and sanitize parameters.
|
|
$owner = isset( $_POST['owner'] ) ? sanitize_text_field( wp_unslash( $_POST['owner'] ) ) : '';
|
|
$repo = isset( $_POST['repo'] ) ? sanitize_text_field( wp_unslash( $_POST['repo'] ) ) : '';
|
|
|
|
if ( empty( $owner ) || empty( $repo ) ) {
|
|
wp_send_json_error( array( 'message' => __( 'Invalid parameters.', 'hub2wp' ) ) );
|
|
}
|
|
|
|
ob_start();
|
|
|
|
// Check if plugin is compatible.
|
|
$api = new H2WP_GitHub_API( H2WP_Settings::get_access_token() );
|
|
$compatibility = $api->check_compatibility( $owner, $repo, $repo_type );
|
|
if ( ! $compatibility['is_compatible'] ) {
|
|
$this->clean_ajax_buffers( 0 );
|
|
wp_send_json_error( array( 'message' => $compatibility['reason'] ) );
|
|
}
|
|
|
|
$download_url = $api->get_download_url( $owner, $repo );
|
|
|
|
// Install the plugin. Pass the access token so private-repo zips can be
|
|
// downloaded with an Authorization header (the upgrader's built-in
|
|
// download_url() never sends auth headers).
|
|
$installer = new H2WP_Plugin_Installer();
|
|
$result = ( 'theme' === $repo_type )
|
|
? $installer->install_theme( $download_url, H2WP_Settings::get_access_token() )
|
|
: $installer->install_plugin( $download_url, H2WP_Settings::get_access_token() );
|
|
if ( is_wp_error( $result ) ) {
|
|
$this->clean_ajax_buffers( 0 );
|
|
wp_send_json_error( array( 'message' => $result->get_error_message() ) );
|
|
}
|
|
|
|
if ( 'theme' === $repo_type ) {
|
|
$theme_data = $installer->theme_data;
|
|
$theme_data['owner'] = $owner;
|
|
$theme_data['repo'] = $repo;
|
|
$theme_data['repo_type'] = 'theme';
|
|
$theme_data['stylesheet'] = $this->find_theme_stylesheet( $theme_data );
|
|
|
|
$h2wp_themes = get_option( 'h2wp_themes', array() );
|
|
$repo_key = $owner . '/' . $repo;
|
|
$existing = isset( $h2wp_themes[ $repo_key ] ) ? $h2wp_themes[ $repo_key ] : array();
|
|
$h2wp_themes[ $repo_key ] = array_merge( $existing, $theme_data );
|
|
$h2wp_themes[ $repo_key ]['last_checked'] = time();
|
|
$h2wp_themes[ $repo_key ]['last_updated'] = time();
|
|
update_option( 'h2wp_themes', $h2wp_themes, false );
|
|
|
|
$template = ! empty( $theme_data['template'] ) ? $theme_data['template'] : $theme_data['stylesheet'];
|
|
$theme_data['activate_url'] = add_query_arg(
|
|
array(
|
|
'action' => 'activate',
|
|
'stylesheet' => $theme_data['stylesheet'],
|
|
'template' => $template,
|
|
'_wpnonce' => wp_create_nonce( 'switch-theme_' . $theme_data['stylesheet'] ),
|
|
),
|
|
admin_url( 'themes.php' )
|
|
);
|
|
|
|
$this->clean_ajax_buffers( 0 );
|
|
wp_send_json_success( $theme_data );
|
|
}
|
|
|
|
$plugin_data = $installer->plugin_data;
|
|
$plugin_data['owner'] = $owner;
|
|
$plugin_data['repo'] = $repo;
|
|
$plugin_data['repo_type'] = 'plugin';
|
|
|
|
$plugin_data['plugin_file'] = $this->find_plugin_file( $plugin_data );
|
|
|
|
// Store plugin data in the h2wp_plugins option.
|
|
$h2wp_plugins = get_option( 'h2wp_plugins', array() );
|
|
$repo_key = $owner . '/' . $repo;
|
|
// Preserve existing fields (e.g. 'private' flag set when manually monitoring the repo).
|
|
$existing = isset( $h2wp_plugins[ $repo_key ] ) ? $h2wp_plugins[ $repo_key ] : array();
|
|
$h2wp_plugins[ $repo_key ] = array_merge( $existing, $plugin_data );
|
|
$h2wp_plugins[ $repo_key ]['last_checked'] = time();
|
|
$h2wp_plugins[ $repo_key ]['last_updated'] = time();
|
|
update_option( 'h2wp_plugins', $h2wp_plugins, false );
|
|
|
|
$plugin_data['activate_url'] = add_query_arg( array(
|
|
'action' => 'activate',
|
|
'plugin' => $plugin_data['plugin_file'],
|
|
'_wpnonce' => wp_create_nonce( 'activate-plugin_' . $plugin_data['plugin_file'] ),
|
|
), admin_url( 'plugins.php' ) );
|
|
|
|
$this->clean_ajax_buffers( 0 );
|
|
wp_send_json_success( $plugin_data );
|
|
}
|
|
|
|
/**
|
|
* Handle AJAX request to check plugin compatibility.
|
|
*/
|
|
public function check_compatibility() {
|
|
|
|
// Check nonce.
|
|
check_ajax_referer( 'h2wp_plugin_details_nonce', 'nonce' );
|
|
|
|
$repo_type = $this->get_repo_type_from_request();
|
|
|
|
// Check user capabilities.
|
|
if ( ! $this->can_manage_repo_type( $repo_type ) ) {
|
|
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'hub2wp' ) ) );
|
|
}
|
|
|
|
// Get and sanitize parameters.
|
|
$owner = isset( $_POST['owner'] ) ? sanitize_text_field( wp_unslash( $_POST['owner'] ) ) : '';
|
|
$repo = isset( $_POST['repo'] ) ? sanitize_text_field( wp_unslash( $_POST['repo'] ) ) : '';
|
|
|
|
if ( empty( $owner ) || empty( $repo ) ) {
|
|
wp_send_json_error( array( 'message' => __( 'Invalid parameters.', 'hub2wp' ) ) );
|
|
}
|
|
|
|
// Get access token from settings.
|
|
$access_token = H2WP_Settings::get_access_token();
|
|
$api = new H2WP_GitHub_API( $access_token );
|
|
|
|
// Check compatibility.
|
|
$compatibility = $api->check_compatibility( $owner, $repo, $repo_type );
|
|
|
|
wp_send_json_success( array( 'is_compatible' => $compatibility['is_compatible'], 'reason' => $compatibility['reason'], 'headers' => ! empty( $compatibility['headers'] ) ? $compatibility['headers'] : array() ) );
|
|
}
|
|
|
|
/**
|
|
* Handle AJAX request to activate a plugin.
|
|
*/
|
|
public function activate_plugin() {
|
|
// Check nonce.
|
|
check_ajax_referer( 'h2wp_plugin_details_nonce', 'nonce' );
|
|
|
|
// Check user capabilities.
|
|
if ( ! current_user_can( 'activate_plugins' ) ) {
|
|
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'hub2wp' ) ) );
|
|
}
|
|
|
|
// Get and sanitize parameters.
|
|
$plugin_file = isset( $_POST['plugin_file'] ) ? sanitize_text_field( wp_unslash( $_POST['plugin_file'] ) ) : '';
|
|
|
|
if ( empty( $plugin_file ) ) {
|
|
wp_send_json_error( array( 'message' => __( 'Invalid parameters.', 'hub2wp' ) ) );
|
|
}
|
|
|
|
// Activate the plugin.
|
|
activate_plugin( $plugin_file );
|
|
|
|
wp_send_json_success();
|
|
}
|
|
|
|
/**
|
|
* Extract topics from repo details.
|
|
*
|
|
* @param array $topics Topics array.
|
|
* @return array Filtered topics.
|
|
*/
|
|
private function extract_topics( $topics, $repo_type = 'plugin' ) {
|
|
$base_url = ( 'theme' === $repo_type )
|
|
? admin_url( 'themes.php?page=h2wp-theme-browser' )
|
|
: admin_url( 'plugins.php?page=h2wp-plugin-browser' );
|
|
|
|
return array_values( array_filter( array_map( function( $topic ) use ( $repo_type, $base_url ) {
|
|
$skip = ( 'theme' === $repo_type )
|
|
? array( 'wordpress-theme', 'wordpress-themes', 'wordpress', 'theme', 'wp-theme', 'wp' )
|
|
: array( 'wordpress-plugin', 'wordpress-plugins', 'wordpress', 'plugin', 'wp-plugin', 'wp' );
|
|
if ( in_array( strtolower( $topic ), $skip ) ) {
|
|
return;
|
|
}
|
|
|
|
return array(
|
|
'name' => $topic,
|
|
'url' => add_query_arg( 'tag', $topic, $base_url ),
|
|
);
|
|
}, $topics ) ) );
|
|
}
|
|
|
|
/**
|
|
* Find the plugin file in the plugin directory.
|
|
*
|
|
* @param array $plugin_data Plugin data.
|
|
* @return string|bool Plugin file path or false if not found.
|
|
*/
|
|
private function find_plugin_file( $plugin_data ) {
|
|
$plugin_file = false;
|
|
|
|
$plugins = get_plugins();
|
|
foreach ( $plugins as $file => $data ) {
|
|
if ( $data['Name'] === $plugin_data['name'] && $data['Author'] === $plugin_data['author'] ) {
|
|
$plugin_file = $file;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $plugin_file;
|
|
}
|
|
|
|
/**
|
|
* Find the installed stylesheet slug for a theme.
|
|
*
|
|
* @param array $theme_data Theme data.
|
|
* @return string|bool
|
|
*/
|
|
private function find_theme_stylesheet( $theme_data ) {
|
|
if ( ! empty( $theme_data['stylesheet'] ) ) {
|
|
return $theme_data['stylesheet'];
|
|
}
|
|
|
|
$themes = wp_get_themes();
|
|
foreach ( $themes as $stylesheet => $theme ) {
|
|
if ( $theme->get( 'Name' ) === $theme_data['name'] ) {
|
|
return $stylesheet;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Handle AJAX request to get changelog.
|
|
*/
|
|
public function get_changelog() {
|
|
// Check nonce
|
|
check_ajax_referer( 'h2wp_plugin_details_nonce', 'nonce' );
|
|
|
|
$repo_type = $this->get_repo_type_from_request();
|
|
|
|
// Check user capabilities
|
|
if ( ! $this->can_manage_repo_type( $repo_type ) ) {
|
|
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'hub2wp' ) ) );
|
|
}
|
|
|
|
// Get and sanitize parameters
|
|
$owner = isset( $_POST['owner'] ) ? sanitize_text_field( wp_unslash( $_POST['owner'] ) ) : '';
|
|
$repo = isset( $_POST['repo'] ) ? sanitize_text_field( wp_unslash( $_POST['repo'] ) ) : '';
|
|
|
|
if ( empty( $owner ) || empty( $repo ) ) {
|
|
wp_send_json_error( array( 'message' => __( 'Invalid parameters.', 'hub2wp' ) ) );
|
|
}
|
|
|
|
// Get access token from settings
|
|
$access_token = H2WP_Settings::get_access_token();
|
|
$api = new H2WP_GitHub_API( $access_token );
|
|
|
|
// Fetch changelog
|
|
$changelog = $api->get_changelog( $owner, $repo );
|
|
if ( is_wp_error( $changelog ) ) {
|
|
wp_send_json_error( array( 'message' => $changelog->get_error_message() ) );
|
|
}
|
|
|
|
if ( empty( $changelog ) ) {
|
|
wp_send_json_error( array( 'message' => __( 'No changelog available.', 'hub2wp' ) ) );
|
|
}
|
|
|
|
$changelog_html = '<ul class="h2wp-changelog">';
|
|
foreach ( $changelog as $release ) {
|
|
$changelog_html .= '<li>';
|
|
$changelog_html .= '<h4>' . esc_html( $release['version'] ) . ( $release['title'] ? ' (' . esc_html( $release['title'] ) . ')' : '' ) . '</h4>';
|
|
$changelog_html .= '<p><strong>' . __( 'Released:', 'hub2wp' ) . '</strong> ' . date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $release['date'] ) ) . '</p>';
|
|
$changelog_html .= '<p>' . nl2br( $release['description'] ) . '</p>';
|
|
$changelog_html .= '<p><a href="' . $release['url'] . '" target="_blank">' . __( 'View on GitHub', 'hub2wp' ) . '</a></p>';
|
|
$changelog_html .= '</li>';
|
|
}
|
|
$changelog_html .= '</ul>';
|
|
|
|
wp_send_json_success( array( 'changelog_html' => $changelog_html ) );
|
|
}
|
|
}
|