375 lines
12 KiB
PHP
375 lines
12 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Plugin Name: Gitium
|
||
|
* Version: 1.0.3
|
||
|
* Author: Presslabs
|
||
|
* Author URI: https://www.presslabs.com
|
||
|
* License: GPL2
|
||
|
* Description: Keep all your code on git version control system.
|
||
|
* Text Domain: gitium
|
||
|
* Domain Path: /languages/
|
||
|
*/
|
||
|
/* Copyright 2014-2016 Presslabs SRL <ping@presslabs.com>
|
||
|
|
||
|
This program is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License, version 2, as
|
||
|
published by the Free Software Foundation.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, write to the Free Software
|
||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
*/
|
||
|
|
||
|
define( 'GITIUM_LAST_COMMITS', 20 );
|
||
|
define( 'GITIUM_MIN_GIT_VER', '1.7' );
|
||
|
define( 'GITIUM_MIN_PHP_VER', '5.6' );
|
||
|
|
||
|
if ( is_multisite() ) {
|
||
|
define( 'GITIUM_ADMIN_MENU_ACTION', 'network_admin_menu' );
|
||
|
define( 'GITIUM_ADMIN_NOTICES_ACTION', 'network_admin_notices' );
|
||
|
define( 'GITIUM_MANAGE_OPTIONS_CAPABILITY', 'manage_network_options' );
|
||
|
} else {
|
||
|
define( 'GITIUM_ADMIN_MENU_ACTION', 'admin_menu' );
|
||
|
define( 'GITIUM_ADMIN_NOTICES_ACTION', 'admin_notices' );
|
||
|
define( 'GITIUM_MANAGE_OPTIONS_CAPABILITY', 'manage_options' );
|
||
|
}
|
||
|
|
||
|
require_once __DIR__ . '/functions.php';
|
||
|
require_once __DIR__ . '/inc/class-git-wrapper.php';
|
||
|
require_once __DIR__ . '/inc/class-gitium-requirements.php';
|
||
|
require_once __DIR__ . '/inc/class-gitium-admin.php';
|
||
|
require_once __DIR__ . '/inc/class-gitium-help.php';
|
||
|
require_once __DIR__ . '/inc/class-gitium-menu.php';
|
||
|
require_once __DIR__ . '/inc/class-gitium-menu-bubble.php';
|
||
|
require_once __DIR__ . '/inc/class-gitium-submenu-configure.php';
|
||
|
require_once __DIR__ . '/inc/class-gitium-submenu-status.php';
|
||
|
require_once __DIR__ . '/inc/class-gitium-submenu-commits.php';
|
||
|
require_once __DIR__ . '/inc/class-gitium-submenu-settings.php';
|
||
|
|
||
|
function gitium_load_textdomain() {
|
||
|
load_plugin_textdomain( 'gitium', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
|
||
|
}
|
||
|
add_action( 'plugins_loaded', 'gitium_load_textdomain' );
|
||
|
|
||
|
function _gitium_make_ssh_git_file_exe() {
|
||
|
$ssh_wrapper = dirname( __FILE__ ) . '/inc/ssh-git';
|
||
|
$process = proc_open(
|
||
|
"chmod -f +x $ssh_wrapper",
|
||
|
array(
|
||
|
0 => array( 'pipe', 'r' ), // stdin
|
||
|
1 => array( 'pipe', 'w' ), // stdout
|
||
|
),
|
||
|
$pipes
|
||
|
);
|
||
|
if ( is_resource( $process ) ) {
|
||
|
fclose( $pipes[0] );
|
||
|
proc_close( $process );
|
||
|
}
|
||
|
}
|
||
|
register_activation_hook( __FILE__, '_gitium_make_ssh_git_file_exe' );
|
||
|
|
||
|
function gitium_deactivation() {
|
||
|
delete_transient( 'gitium_git_version' );
|
||
|
}
|
||
|
register_deactivation_hook( __FILE__, 'gitium_deactivation' );
|
||
|
|
||
|
function gitium_uninstall_hook() {
|
||
|
delete_transient( 'gitium_remote_tracking_branch' );
|
||
|
delete_transient( 'gitium_remote_disconnected' );
|
||
|
delete_transient( 'gitium_uncommited_changes' );
|
||
|
delete_transient( 'gitium_git_version' );
|
||
|
delete_transient( 'gitium_versions' );
|
||
|
delete_transient( 'gitium_menu_bubble' );
|
||
|
delete_transient( 'gitium_is_status_working' );
|
||
|
|
||
|
delete_option( 'gitium_keypair' );
|
||
|
delete_option( 'gitium_webhook_key' );
|
||
|
}
|
||
|
register_uninstall_hook( __FILE__, 'gitium_uninstall_hook' );
|
||
|
|
||
|
/* Array
|
||
|
(
|
||
|
[themes] => Array
|
||
|
(
|
||
|
[twentytwelve] => `Twenty Twelve` version 1.3
|
||
|
)
|
||
|
[plugins] => Array
|
||
|
(
|
||
|
[cron-view/cron-gui.php] => `Cron GUI` version 1.03
|
||
|
[hello-dolly/hello.php] => `Hello Dolly` version 1.6
|
||
|
)
|
||
|
|
||
|
) */
|
||
|
function gitium_update_versions() {
|
||
|
$new_versions = [];
|
||
|
|
||
|
// get all themes from WP
|
||
|
$all_themes = wp_get_themes( array( 'allowed' => true ) );
|
||
|
foreach ( $all_themes as $theme_name => $theme ) :
|
||
|
$theme_versions[ $theme_name ] = array(
|
||
|
'name' => $theme->Name,
|
||
|
'version' => null,
|
||
|
'msg' => '',
|
||
|
);
|
||
|
$theme_versions[ $theme_name ]['msg'] = '`' . $theme->Name . '`';
|
||
|
$version = $theme->Version;
|
||
|
if ( ! empty( $version ) ) {
|
||
|
$theme_versions[ $theme_name ]['msg'] .= " version $version";
|
||
|
$theme_versions[ $theme_name ]['version'] .= $version;
|
||
|
}
|
||
|
endforeach;
|
||
|
|
||
|
if ( ! empty( $theme_versions ) ) {
|
||
|
$new_versions['themes'] = $theme_versions;
|
||
|
}
|
||
|
// get all plugins from WP
|
||
|
if ( ! function_exists( 'get_plugins' ) ) {
|
||
|
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||
|
}
|
||
|
$all_plugins = get_plugins();
|
||
|
foreach ( $all_plugins as $name => $data ) :
|
||
|
$plugin_versions[ $name ] = array(
|
||
|
'name' => $data['Name'],
|
||
|
'version' => null,
|
||
|
'msg' => '',
|
||
|
);
|
||
|
$plugin_versions[ $name ]['msg'] = "`{$data['Name']}`";
|
||
|
if ( ! empty( $data['Version'] ) ) {
|
||
|
$plugin_versions[ $name ]['msg'] .= ' version ' . $data['Version'];
|
||
|
$plugin_versions[ $name ]['version'] .= $data['Version'];
|
||
|
}
|
||
|
endforeach;
|
||
|
|
||
|
if ( ! empty( $plugin_versions ) ) {
|
||
|
$new_versions['plugins'] = $plugin_versions;
|
||
|
}
|
||
|
|
||
|
set_transient( 'gitium_versions', $new_versions );
|
||
|
|
||
|
return $new_versions;
|
||
|
}
|
||
|
add_action( 'load-plugins.php', 'gitium_update_versions', 999 );
|
||
|
|
||
|
function gitium_upgrader_post_install( $res, $hook_extra, $result ) {
|
||
|
_gitium_make_ssh_git_file_exe();
|
||
|
|
||
|
$action = null;
|
||
|
$type = null;
|
||
|
|
||
|
// install logic
|
||
|
if ( isset( $hook_extra['type'] ) && ( 'plugin' === $hook_extra['type'] ) ) {
|
||
|
$action = 'installed';
|
||
|
$type = 'plugin';
|
||
|
} else if ( isset( $hook_extra['type'] ) && ( 'theme' === $hook_extra['type'] ) ) {
|
||
|
$action = 'installed';
|
||
|
$type = 'theme';
|
||
|
}
|
||
|
|
||
|
// update/upgrade logic
|
||
|
if ( isset( $hook_extra['plugin'] ) ) {
|
||
|
$action = 'updated';
|
||
|
$type = 'plugin';
|
||
|
} else if ( isset( $hook_extra['theme'] ) ) {
|
||
|
$action = 'updated';
|
||
|
$type = 'theme';
|
||
|
}
|
||
|
|
||
|
// get action if missed above
|
||
|
if ( isset( $hook_extra['action'] ) ) {
|
||
|
$action = $hook_extra['action'];
|
||
|
if ( 'install' === $action ) {
|
||
|
$action = 'installed';
|
||
|
}
|
||
|
if ( 'update' === $action ) {
|
||
|
$action = 'updated';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( WP_DEBUG ) {
|
||
|
error_log( __FUNCTION__ . ':hook_extra:' . serialize( $hook_extra ) );
|
||
|
error_log( __FUNCTION__ . ':action:type:' . $action . ':' . $type );
|
||
|
}
|
||
|
|
||
|
$git_dir = $result['destination'];
|
||
|
$version = '';
|
||
|
|
||
|
if ( ABSPATH == substr( $git_dir, 0, strlen( ABSPATH ) ) ) {
|
||
|
$git_dir = substr( $git_dir, strlen( ABSPATH ) );
|
||
|
}
|
||
|
switch ( $type ) {
|
||
|
case 'theme':
|
||
|
wp_clean_themes_cache();
|
||
|
$theme_data = wp_get_theme( $result['destination_name'] );
|
||
|
$name = $theme_data->get( 'Name' );
|
||
|
$version = $theme_data->get( 'Version' );
|
||
|
break;
|
||
|
case 'plugin':
|
||
|
foreach ( $result['source_files'] as $file ) :
|
||
|
if ( '.php' != substr( $file, -4 ) ) { continue; }
|
||
|
// every .php file is a possible plugin so we check if it's a plugin
|
||
|
$filepath = trailingslashit( $result['destination'] ) . $file;
|
||
|
$plugin_data = get_plugin_data( $filepath );
|
||
|
if ( $plugin_data['Name'] ) :
|
||
|
$name = $plugin_data['Name'];
|
||
|
$version = $plugin_data['Version'];
|
||
|
// We get info from the first plugin in the package
|
||
|
break;
|
||
|
endif;
|
||
|
endforeach;
|
||
|
break;
|
||
|
}
|
||
|
if ( empty( $name ) ) {
|
||
|
$name = $result['destination_name'];
|
||
|
}
|
||
|
$commit_message = _gitium_format_message( $name,$version,"$action $type" );
|
||
|
$commit = _gitium_commit_changes( $commit_message, $git_dir, false );
|
||
|
gitium_merge_and_push( $commit );
|
||
|
|
||
|
return $res;
|
||
|
}
|
||
|
add_filter( 'upgrader_post_install', 'gitium_upgrader_post_install', 10, 3 );
|
||
|
|
||
|
// Checks for local changes, tries to group them by plugin/theme and pushes the changes
|
||
|
function gitium_auto_push( $msg_prepend = '' ) {
|
||
|
global $git;
|
||
|
list( , $git_private_key ) = gitium_get_keypair();
|
||
|
if ( ! $git_private_key )
|
||
|
return;
|
||
|
$git->set_key( $git_private_key );
|
||
|
|
||
|
$commits = gitium_group_commit_modified_plugins_and_themes( $msg_prepend );
|
||
|
gitium_merge_and_push( $commits );
|
||
|
gitium_update_versions();
|
||
|
}
|
||
|
add_action( 'upgrader_process_complete', 'gitium_auto_push', 11, 0 );
|
||
|
|
||
|
function gitium_check_after_activate_modifications( $plugin ) {
|
||
|
gitium_check_after_event( $plugin );
|
||
|
}
|
||
|
add_action( 'activated_plugin', 'gitium_check_after_activate_modifications', 999 );
|
||
|
|
||
|
function gitium_check_after_deactivate_modifications( $plugin ) {
|
||
|
gitium_check_after_event( $plugin, 'deactivation' );
|
||
|
}
|
||
|
add_action( 'deactivated_plugin', 'gitium_check_after_deactivate_modifications', 999 );
|
||
|
|
||
|
function gitium_check_for_plugin_deletions() { // Handle plugin deletion
|
||
|
// $_GET['deleted'] used to resemble if a plugin has been deleted (true)
|
||
|
// ...meanwhile commit b28dd45f3dad19f0e06c546fdc89ed5b24bacd72 in github.com/WordPress/WordPress...
|
||
|
// Now it resembles the number of deleted plugins (a number). Thanks WP
|
||
|
if ( isset( $_GET['deleted'] ) && ( 1 <= (int) $_GET['deleted'] || 'true' == $_GET['deleted'] ) ) {
|
||
|
gitium_auto_push();
|
||
|
}
|
||
|
}
|
||
|
add_action( 'load-plugins.php', 'gitium_check_for_plugin_deletions' );
|
||
|
|
||
|
add_action( 'wp_ajax_wp-plugin-delete-success', 'gitium_auto_push' );
|
||
|
add_action( 'wp_ajax_wp-theme-delete-success', 'gitium_auto_push' );
|
||
|
|
||
|
function gitium_wp_plugin_delete_success() {
|
||
|
?>
|
||
|
<script type='text/javascript'>
|
||
|
jQuery(document).ready(function() {
|
||
|
jQuery(document).on( 'wp-plugin-delete-success', function() {
|
||
|
jQuery.post(ajaxurl, data={'action': 'wp-plugin-delete-success'});
|
||
|
});
|
||
|
});
|
||
|
</script>
|
||
|
<?php
|
||
|
}
|
||
|
add_action( 'admin_head', 'gitium_wp_plugin_delete_success' );
|
||
|
|
||
|
function gitium_wp_theme_delete_success() {
|
||
|
?>
|
||
|
<script type='text/javascript'>
|
||
|
jQuery(document).ready(function() {
|
||
|
jQuery(document).on( 'wp-theme-delete-success', function() {
|
||
|
jQuery.post(ajaxurl, data={'action': 'wp-theme-delete-success'});
|
||
|
});
|
||
|
});
|
||
|
</script>
|
||
|
<?php
|
||
|
}
|
||
|
add_action( 'admin_head', 'gitium_wp_theme_delete_success' );
|
||
|
|
||
|
function gitium_check_for_themes_deletions() { // Handle theme deletion
|
||
|
if ( isset( $_GET['deleted'] ) && 'true' == $_GET['deleted'] ) {
|
||
|
gitium_auto_push();
|
||
|
}
|
||
|
}
|
||
|
add_action( 'load-themes.php', 'gitium_check_for_themes_deletions' );
|
||
|
|
||
|
// Deprecated function - backward compatibility
|
||
|
function gitium_hook_plugin_and_theme_editor_page( $hook )
|
||
|
{
|
||
|
switch ($hook) {
|
||
|
case 'plugin-editor.php':
|
||
|
if (isset($_GET['a']) && 'te' == $_GET['a']) {
|
||
|
gitium_auto_push();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'theme-editor.php':
|
||
|
if (isset($_GET['updated']) && 'true' == $_GET['updated']) {
|
||
|
gitium_auto_push();
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* We execute the "gitium_auto_push" on "wp_die_ajax_handler" filter to make sure we are
|
||
|
* at the end of our request and the latest file is saved on disk.
|
||
|
*/
|
||
|
function gitium_check_ajax_success_call($callback)
|
||
|
{
|
||
|
gitium_auto_push();
|
||
|
|
||
|
return $callback;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* We add this filer on "wp_die_ajax_handler" since our action executes before the actual file is saved on disk
|
||
|
* which results in a race condition that would commit only the previously saved data not the
|
||
|
* currently saved one.
|
||
|
*/
|
||
|
function add_filter_for_ajax_save()
|
||
|
{
|
||
|
add_filter('wp_die_ajax_handler', 'gitium_check_ajax_success_call', 1);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* We need to apply different filters while checking for WP version to maintain
|
||
|
* backworks compatibility since the Code Editor has changed drastically
|
||
|
* with the 4.9 WP update.
|
||
|
*/
|
||
|
if ( version_compare( $GLOBALS['wp_version'], '4.9', '>=' ) )
|
||
|
add_action( 'wp_ajax_edit-theme-plugin-file', 'add_filter_for_ajax_save', 1, 0 );
|
||
|
else
|
||
|
add_action( 'admin_enqueue_scripts', 'gitium_hook_plugin_and_theme_editor_page' );
|
||
|
|
||
|
function gitium_options_page_check() {
|
||
|
global $git;
|
||
|
if ( ! $git->can_exec_git() ) { wp_die( 'Cannot exec git' ); }
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function gitium_remote_disconnected_notice() {
|
||
|
if ( current_user_can( GITIUM_MANAGE_OPTIONS_CAPABILITY ) && $message = get_transient( 'gitium_remote_disconnected' ) ) : ?>
|
||
|
<div class="error-nag error">
|
||
|
<p>
|
||
|
Could not connect to remote repository.
|
||
|
<pre><?php echo esc_html( $message ); ?></pre>
|
||
|
</p>
|
||
|
</div>
|
||
|
<?php endif;
|
||
|
}
|
||
|
add_action( 'admin_notices', 'gitium_remote_disconnected_notice' );
|