<?php

// no direct access allowed
if ( ! defined( 'ABSPATH' ) ) {
    die();
}

/**
 * The main challenge here is defining a dynamic dl link
 * for $update_plugins_transient->response[ $plugin_slug ]->package;
 *
 * Version 1.0.3
 */

if ( ! class_exists( 'VillaTheme_Plugin_Updater' ) ) {

    if ( ! class_exists( 'WP_Upgrader' ) ) {
        require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
    }
    if ( ! class_exists( 'Plugin_Upgrader' ) ) {
        require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
    }

    class VillaTheme_Plugin_Updater extends Plugin_Upgrader {
        /**
         * Plugin directory and main file name (e.g myplugin/myplugin.php)
         *
         * @var string
         */
        public $plugin_slug;

        /**
         * Plugin slug
         *
         * @var string
         */
        public $slug;

        /**
         * Set plugin info and add essential hooks
         *
         * @param string $plugin_slug The name of directory and main file name of plugin
         * @param string $slug Then slug name of plugin (optional)
         * @param string $setting_page_url URL of Setting page
         */
        protected $setting_page_url;

        public function __construct( $plugin_slug, $slug = '', $setting_page_url = '#' ) {

            parent::__construct();

            $this->slug             = $slug;
            $this->plugin_slug      = $plugin_slug;
            $this->setting_page_url = $setting_page_url;

            add_action( 'admin_init', array( $this, 'plugin_update_rows' ), PHP_INT_MAX );
            // a custom hook that fires on update.php page while upgrading the packages
            add_action( "update-custom_{$this->slug}-upgrade", array( $this, 'custom_upgrade_plugin' ) );
        }

        /**
         * Fires on the page wp-admin/update.php?{$this->slug}-upgrade page
         *
         * @return void
         */
        public function custom_upgrade_plugin() {
            $plugin = isset( $_REQUEST['plugin'] ) ? trim(sanitize_text_field(wp_unslash( $_REQUEST['plugin'])) ) : '';// phpcs:ignore WordPress.Security.NonceVerification.Recommended

            if ( ! current_user_can( 'update_plugins' ) ) {
                wp_die( esc_html( 'You do not have sufficient permissions to update plugins for this site.' ) );
            }

            check_admin_referer( 'upgrade-plugin_' . $plugin );

            wp_enqueue_script( 'updates' );

            require_once( ABSPATH . 'wp-admin/admin-header.php' );

            $nonce = 'upgrade-plugin_' . $plugin;
            $url   = 'update.php?action=upgrade-plugin&plugin=' . urlencode( $plugin );

            if ( $this->update_plugin() ) {
                do_action( $plugin . "_updated" );
            }

            // return to plugins page link
            ?>
            <a href="<?php echo esc_url( self_admin_url( 'plugins.php' ) ) ?>"
               title="<?php echo esc_attr( 'Go to plugins page' ) ?>"
               target="_parent"><?php echo esc_html( 'Return to Plugins page' ) ?></a>
            <?php

            include( ABSPATH . 'wp-admin/admin-footer.php' );
        }


        /**
         * Upgrade a plugin.
         *
         * @param string $plugin The basename path to the main plugin file.
         *
         * @return bool|WP_Error True if the upgrade was successful, false or a {@see WP_Error} object otherwise.
         */
        public function update_plugin() {
            /**
             * Initialize the WP_Filesystem
             */
            global $wp_filesystem;
            if ( empty( $wp_filesystem ) ) {
                require_once( ABSPATH . '/wp-admin/includes/file.php' );
                WP_Filesystem();
            }

            $plugin = $this->plugin_slug;

            $this->init();

            $current = get_site_transient( 'update_plugins' );
            if ( ! isset( $current->response[ $plugin ] ) ) {
                $this->skin->before();
                $this->skin->set_result( false );
                $this->skin->error( 'up_to_date' );
                $this->skin->after();

                return false;
            }

            // Get the URL to the zip file
            $r = $current->response[ $plugin ];

            add_filter( 'upgrader_pre_install', array( $this, 'deactivate_plugin_before_upgrade' ), 10, 2 );
            add_filter( 'upgrader_clear_destination', array( $this, 'delete_old_plugin' ), 10, 4 );

            $this->run( array(
                'package'           => $r->package,
                'destination'       => WP_PLUGIN_DIR,
                'clear_destination' => true,
                'clear_working'     => true,
                'hook_extra'        => array(
                    'plugin' => $plugin,
                    'type'   => 'plugin',
                    'action' => 'update',
                ),
            ) );

            // Cleanup our hooks, in case something else does a upgrade on this connection.
            remove_filter( 'upgrader_pre_install', array( $this, 'deactivate_plugin_before_upgrade' ) );
            remove_filter( 'upgrader_clear_destination', array( $this, 'delete_old_plugin' ) );

            if ( ! $this->result || is_wp_error( $this->result ) ) {
                return $this->result;
            }

            // Force refresh of plugin update information
            delete_site_transient( 'update_plugins' );
            wp_cache_delete( 'plugins', 'plugins' );

            return true;
        }

        /**
         * Add hooks for modifying the plugin row context
         */
        public function plugin_update_rows() {
            remove_action( "after_plugin_row_{$this->plugin_slug}", 'wp_plugin_update_row', 10 );
            add_action( "after_plugin_row_{$this->plugin_slug}", array( $this, 'plugin_update_row' ), 10, 2 );
        }

        /**
         * Override the plugin row context
         *
         * @param string $file The plugin file path
         * @param array $plugin_data Plugin information
         *
         * @return void
         */
        public function plugin_update_row( $file, $plugin_data ) {
            $current = get_site_transient( 'update_plugins' );

            if ( ! isset( $current->response[ $file ] ) ) {
                return;
            }

            $r = $current->response[ $file ];

            // Package URL is available: use core row so "Update now" works (token is minted on download).
            if ( ! empty( $r->package ) ) {
                wp_plugin_update_row( $file, $plugin_data );

                return;
            }

            $plugins_allowedtags = array(
                'a'       => array(
                    'href'  => array(),
                    'title' => array()
                ),
                'abbr'    => array(
                    'title' => array()
                ),
                'acronym' => array(
                    'title' => array()
                ),
                'code'    => array(),
                'em'      => array(),
                'strong'  => array()
            );

            $plugin_name   = wp_kses( $plugin_data['Name'], $plugins_allowedtags );
            $details_url   = add_query_arg( array(
                'tab'       => 'plugin-information',
                'plugin'    => $this->slug,
                'section'   => 'changelog',
                'TB_iframe' => 'true',
                'width'     => '772',
                'height'    => '909',
            ), admin_url( 'plugin-install.php' ) );
            $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );

            if ( is_network_admin() || ! is_multisite() ) {
                ?>
                <tr class="plugin-update-tr">
                    <td colspan="<?php echo esc_attr( $wp_list_table->get_column_count() ) ?>"
                        class="plugin-update colspanchange">
                        <div class="notice inline notice-warning notice-alt">
                            <p>
                                <?php
                                echo wp_kses_post( sprintf('New version of %1$s available. You can download or <a href="%2$s" class="thickbox open-plugin-details-modal" title="%3$s">view version %4$s</a>. Please make sure that you fill your auto-update key in <a href="%5$s">Setting page</a>.'  ,// phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
                                        $plugin_name, esc_url( $details_url ), esc_attr( $plugin_name ), $r->new_version, esc_url( $this->setting_page_url ))
                                );
                                do_action( "in_plugin_update_message-{$file}", $plugin_data, $r );
                                ?>
                            </p>
                        </div>
                    </td>
                </tr>
                <?php
            }
        }
    }
}
