Plugin Directory

Changeset 3053833 for woocommerce-pos


Ignore:
Timestamp:
03/18/2024 06:27:15 PM (13 months ago)
Author:
kilbot
Message:

Update to version 1.4.12 from GitHub

Location:
woocommerce-pos
Files:
24 edited
1 copied

Legend:

Unmodified
Added
Removed
  • woocommerce-pos/tags/1.4.12/includes/API/Settings.php

    r3020668 r3053833  
    3535    public function __construct() {
    3636        add_filter( 'option_woocommerce_pos_settings_payment_gateways', array( $this, 'payment_gateways_settings' ) );
     37
     38        // remove this once Pro settings have been moved to the new settings service.
     39        add_filter( 'pre_update_option_woocommerce_pos_pro_settings_license', array( $this, 'remove_license_transient' ) );
    3740    }
    3841
     
    544547        return $options;
    545548    }
     549
     550    /**
     551     * Temporary fix for stale license status transient. Remove when possible.
     552     */
     553    public function remove_license_transient( $value ) {
     554        delete_transient( 'woocommerce_pos_pro_license_status' );
     555        return $value;
     556    }
    546557}
  • woocommerce-pos/tags/1.4.12/includes/Admin/Menu.php

    r3048280 r3053833  
    1313use const HOUR_IN_SECONDS;
    1414use const WCPOS\WooCommercePOS\PLUGIN_NAME;
     15use const WCPOS\WooCommercePOS\VERSION as PLUGIN_VERSION;
    1516
    1617/**
     
    4041            add_filter( 'custom_menu_order', '__return_true' );
    4142            add_filter( 'menu_order', array( $this, 'menu_order' ), 9, 1 );
     43            add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_landing_scripts_and_styles' ) );
    4244        }
    4345
     
    8082     */
    8183    public function display_upgrade_page(): void {
    82         $upgrade = get_transient( 'remote_pro_page' );
    83 
    84         // Check for transient, if none, grab remote HTML file
    85         if ( false === $upgrade ) {
    86             // Get remote HTML file
    87             $response = wp_remote_get( 'http://wcpos.com/pro/?wp-admin=woocommerce-pos' );
    88             // Check for error
    89             if ( is_wp_error( $response ) ) {
    90                 return;
    91             }
    92             // Parse remote HTML file
    93             $upgrade = wp_remote_retrieve_body( $response );
    94             // Check for error
    95             if ( is_wp_error( $upgrade ) ) {
    96                 return;
    97             }
    98             // Store remote HTML file in transient, expire after 24 hours
    99             set_transient( 'remote_pro_page', $upgrade, 24 * HOUR_IN_SECONDS );
    100         }
    10184        include_once 'templates/upgrade.php';
    10285    }
     
    193176        );
    194177    }
     178
     179    /**
     180     * Enqueue landing page scripts and styles.
     181     */
     182    public function enqueue_landing_scripts_and_styles( $hook_suffix ): void {
     183        if ( $hook_suffix === $this->toplevel_screen_id ) {
     184            $is_development = isset( $_ENV['DEVELOPMENT'] ) && $_ENV['DEVELOPMENT'];
     185            $url            = $is_development ? 'http://localhost:9000/' : 'https://cdn.jsdelivr.net/gh/wcpos/wp-admin-landing/assets/';
     186
     187            // Enqueue the landing page CSS from CDN
     188            wp_enqueue_style(
     189                'wcpos-landing',
     190                $url . 'css/landing.css',
     191                array(),
     192                PLUGIN_VERSION
     193            );
     194
     195            // Ensure WordPress bundled React and lodash are loaded as dependencies
     196            wp_enqueue_script( 'react' );
     197            wp_enqueue_script( 'lodash' );
     198
     199            // Enqueue the landing page JS from CDN, with React and lodash as dependencies
     200            wp_enqueue_script(
     201                'wcpos-landing',
     202                $url . 'js/landing.js',
     203                array(
     204                    'react',
     205                    'react-dom',
     206                    'wp-element',
     207                    'lodash',
     208                ),
     209                PLUGIN_VERSION,
     210                true
     211            );
     212        }
     213    }
    195214}
  • woocommerce-pos/tags/1.4.12/includes/Admin/Updaters/Pro_Plugin_Updater.php

    r3021613 r3053833  
    2727
    2828    /**
    29      * The path to the Pro plugin
    30      *
    31      * @var string $pro_plugin_path
    32      */
    33     private $pro_plugin_path = 'woocommerce-pos-pro/woocommerce-pos-pro.php';
    34 
    35     /**
    3629     * The update server URL
    3730     *
     
    4538     * @var string $update_data_transient_key
    4639     */
    47     private $update_data_transient_key = 'woocommerce_pos_pro_update_data';
    48 
     40    public static $update_data_transient_key = 'woocommerce_pos_pro_update_data';
     41
     42    /**
     43     * Transient key for the update data
     44     *
     45     * @var string $license_status_transient_key
     46     */
     47    public static $license_status_transient_key = 'woocommerce_pos_pro_license_status';
     48
     49    /**
     50     * Installed Pro plugins
     51     * Note: Generally this would be an array of 1 installed Pro plugins but
     52     * it's possible an older version of the plugin is installed in a different directory.
     53     *
     54     * @var array $installed_pro_plugins
     55     */
     56    private $installed_pro_plugins = array();
     57
     58    /**
     59     * Constructor.
     60     */
     61    public function __construct() {
    4962        /**
    50          * Transient key for the update data
    51          *
    52          * @var string $update_data_transient_key
     63         * First we need to check if the Pro plugin is installed (one or more versions)
    5364         */
    54     private $license_status_transient_key = 'woocommerce_pos_pro_license_status';
    55 
    56     /**
    57      * Whether the Pro plugin is installed
    58      *
    59      * @var bool $installed
    60      */
    61     private $installed;
    62 
    63     /**
    64      * Whether the Pro plugin is active
    65      *
    66      * @var bool $active
    67      */
    68     private $active;
    69 
    70     /**
    71      * The current version of the Pro plugin
    72      *
    73      * @var string $current_version
    74      */
    75     private $current_version;
    76 
    77     /**
    78      * Constructor.
    79      */
    80     public function __construct() {
    81         // Ensure the necessary functions are available
    8265        include_once ABSPATH . 'wp-admin/includes/plugin.php';
    83 
    84         $status = $this->check_pro_plugin_status();
    85         $this->installed = $status['installed'];
    86         $this->active = $status['active'];
    87         $this->current_version = $status['version'];
     66        $all_plugins = get_plugins();
     67        foreach ( $all_plugins as $plugin_path => $plugin_data ) {
     68            $plugin_dir = dirname( $plugin_path );
     69            if ( strpos( $plugin_dir, $this->pro_plugin_slug ) === 0 ) {
     70                if ( isset( $plugin_data['UpdateURI'] ) && $plugin_data['UpdateURI'] == $this->update_server ) {
     71                    $this->installed_pro_plugins[ $plugin_path ] = $plugin_data;
     72                }
     73            }
     74        }
    8875
    8976        // Allow the update server to be overridden for development.
     
    9279        }
    9380
    94         if ( $this->installed ) {
     81        if ( count( $this->installed_pro_plugins ) > 0 ) {
    9582            add_filter( 'update_plugins_updates.wcpos.com', array( $this, 'update_plugins' ), 10, 4 );
    9683            add_action( 'upgrader_process_complete', array( $this, 'after_plugin_update' ), 10, 2 );
    9784            add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 4 );
    98             add_action( 'in_plugin_update_message-' . $this->pro_plugin_path, array( $this, 'plugin_update_message' ), 10, 2 );
    9985            add_action( 'install_plugins_pre_plugin-information', array( $this, 'plugin_information' ), 5 );
    100         }
    101     }
    102 
    103     /**
    104      * Check the status of the Pro plugin
    105      *
    106      * @return array(
    107      *  'installed' => bool,
    108      *  'active'    => bool,
    109      *  'version'   => string|null,
    110      * )
    111      */
    112     public function check_pro_plugin_status() {
    113         $status = array(
    114             'installed' => false,
    115             'active'    => false,
    116             'version'   => null,
    117         );
    118 
    119         // Check if the Pro plugin file exists.
    120         if ( file_exists( WP_PLUGIN_DIR . '/' . $this->pro_plugin_path ) ) {
    121             $status['installed'] = true;
    122             $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $this->pro_plugin_path );
    123             $status['version'] = $plugin_data['Version'];
    124 
    125             // Check if the Pro plugin is active.
    126             if ( is_plugin_active( $this->pro_plugin_path ) ) {
    127                 $status['active'] = true;
    128             }
    129         }
    130 
    131         /**
    132          * This is a hack to manually trigger Pro update for version < 1.4.0
    133          * TODO: remove this after 1.4.0 is released for a while
    134          */
    135         if ( $status['version'] && version_compare( $status['version'], '1.4.0', '<' ) ) {
    136             // Manually the update_plugins transient
    137             $update_plugins = get_site_transient( 'update_plugins' );
    138             if ( ! is_object( $update_plugins ) ) {
    139                     $update_plugins = new stdClass();
    140             }
    141 
    142             $license_settings = $this->get_license_settings();
    143             $key = isset( $license_settings['key'] ) ? $license_settings['key'] : '';
    144             $instance = isset( $license_settings['instance'] ) ? $license_settings['instance'] : '';
    145 
    146             // Construct the download URL, taking into account the environment
    147             $package_url = add_query_arg(
    148                 array(
    149                     'key' => urlencode( $key ),
    150                     'instance' => urlencode( $instance ),
    151                 ),
    152                 'https://updates.wcpos.com/pro/download/1.4.1'
    153             );
    154 
    155             $update = array(
    156                 'id'             => 'https://updates.wcpos.com',
    157                 'slug'           => 'woocommerce-pos-pro',
    158                 'plugin'         => $this->pro_plugin_path,
    159                 'new_version'    => '1.4.1',
    160                 'url'            => 'https://wcpos.com/pro',
    161                 'package'        => $package_url,
    162                 'requires'       => '5.6',
    163                 'tested'         => '6.5',
    164                 'requires_php'   => '7.4',
    165                 'icons'          => array(
    166                     '1x' => 'https://wcpos.com/wp-content/uploads/2014/06/woopos-pro.png',
    167                 ),
    168                 'upgrade_notice' => $this->maybe_add_upgrade_notice(),
    169             );
    170 
    171             $update_plugins->response[ $this->pro_plugin_path ] = (object) $update;
    172 
    173             set_site_transient( 'update_plugins', $update_plugins );
    174         }
    175 
    176         return $status;
     86            add_action( 'admin_enqueue_scripts', array( $this, 'license_status_styles' ) );
     87
     88            // loop through the installed Pro plugins.
     89            foreach ( $this->installed_pro_plugins as $plugin_path => $plugin_data ) {
     90                add_action( 'in_plugin_update_message-' . $plugin_path, array( $this, 'plugin_update_message' ), 10, 2 );
     91                add_action( 'after_plugin_row_' . $plugin_path, array( $this, 'license_status_notice' ), 99 );
     92
     93                /**
     94                 * This is a hack to manually trigger Pro update for version < 1.4.0
     95                 * TODO: remove this after 1.4.0 is released for a while
     96                 */
     97                if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], '1.4.0', '<' ) ) {
     98                        $this->remove_this_hack_for_older_versions( $plugin_path );
     99                }
     100            }
     101        }
    177102    }
    178103
     
    212137     */
    213138    public function update_plugins( $update, $plugin_data, $plugin_file, $locales ) {
    214         $update_data = $this->check_pro_plugin_updates();
     139        $current_version = isset( $plugin_data['Version'] ) ? $plugin_data['Version'] : '1';
     140        $update_data = $this->check_pro_plugin_updates( $current_version );
    215141        $is_development = isset( $_ENV['DEVELOPMENT'] ) && $_ENV['DEVELOPMENT'];
    216142
    217143        // Check if update data is valid and if a new version is available.
    218         if ( ! is_wp_error( $update_data ) && is_object( $update_data ) && isset( $update_data->version ) ) {
    219             $latest_version = $update_data->version;
    220 
    221             // No update needed if the current version is greater than the latest version.
    222             if ( version_compare( $this->current_version, $latest_version, '>' ) ) {
    223                 return $update;
    224             }
    225 
     144        if ( isset( $update_data['version'] ) && version_compare( $current_version, $update_data['version'], '<' ) ) {
    226145            $license_settings = $this->get_license_settings();
    227146            $key = isset( $license_settings['key'] ) ? $license_settings['key'] : '';
     
    244163                'id'           => 'https://updates.wcpos.com',
    245164                'slug'         => 'woocommerce-pos-pro',
    246                 'plugin'       => $this->pro_plugin_path,
    247                 'version'      => $latest_version,
     165                'plugin'       => $plugin_file,
     166                'version'      => $update_data['version'],
    248167                'url'          => 'https://wcpos.com/pro',
    249168                'package'      => $package_url,
     
    264183     * Check for updates to the Pro plugin
    265184     *
    266      * @param  bool $force Force an update check.
    267      */
    268     public function check_pro_plugin_updates( $force = false ) {
    269         $update_data = get_transient( $this->update_data_transient_key );
     185     * @param  string $version The current plugin version.
     186     * @param  bool   $force Force an update check.
     187     */
     188    public function check_pro_plugin_updates( $version = '1', $force = false ) {
     189        $update_data = get_transient( self::$update_data_transient_key );
    270190
    271191        if ( empty( $update_data ) || $force ) {
    272192            $expiration = 60 * 60 * 12; // 12 hours.
    273             $url = $this->update_server . '/update/' . $this->current_version;
     193            $url = $this->update_server . '/update/' . $version;
    274194
    275195            // make the api call.
     
    277197                $url,
    278198                array(
    279                     'timeout' => wp_doing_cron() ? 10 : 3,
     199                    'timeout' => wp_doing_cron() ? 10 : 5,
    280200                    'headers' => array(
    281201                        'Accept' => 'application/json',
     
    285205
    286206            $data = $this->validate_api_response( $response );
    287 
    288             // Ensure $data has version, download_url and notes.
    289             if ( ! is_wp_error( $data ) ) {
     207            $error = isset( $data['is_error'] ) && $data['is_error'] ? $data : false;
     208
     209            // Ensure $data is an associative array and has version, download_url, and notes.
     210            if ( ! $error && is_array( $data ) ) {
    290211                $expected_properties = array( 'version', 'download_url', 'notes' );
    291212                foreach ( $expected_properties as $property ) {
    292                     if ( ! property_exists( $data, $property ) ) {
     213                    if ( ! array_key_exists( $property, $data ) ) {
    293214                        $data = new WP_Error( 'invalid_response_structure', "Missing expected property: $property" );
    294215                        break;
    295216                    }
    296217                }
    297             }
    298 
    299             if ( is_wp_error( $data ) ) {
     218            } else {
    300219                Logger::log( $data );
    301220                $expiration = 60 * 60 * 1; // try again in an hour if error.
    302221            }
    303222
    304             set_transient( $this->update_data_transient_key, $data, $expiration );
     223            $success = set_transient( self::$update_data_transient_key, $data, $expiration );
     224            if ( ! $success ) {
     225                Logger::log( 'Failed to set update data transient' );
     226            }
     227
     228            return $data;
    305229        }
    306230
     
    314238     */
    315239    private function check_license_status( $force = false ) {
    316         $license_status = get_transient( $this->license_status_transient_key );
     240        $license_status = get_transient( self::$license_status_transient_key );
    317241        $expiration = 60 * 60 * 12; // 12 hours.
    318242
     
    320244         * TODO: How to allow for multisite?
    321245         */
    322         if ( is_multisite() ) {
    323             $error = new WP_Error( 'multisite_update', 'Please go to http://wcpos.com/my-account to download update.' );
    324             set_transient( $this->license_status_transient_key, $error, $expiration );
    325             return $error;
    326         }
     246        // if ( is_multisite() ) {
     247        // $error = array(
     248        // 'code' => 'multisite_update',
     249        // 'message' => 'Please go to http://wcpos.com/my-account to download update.',
     250        // );
     251        // set_transient( $this->license_status_transient_key, $error, $expiration );
     252        // return $error;
     253        // }
    327254
    328255        $license_settings = $this->get_license_settings();
     
    335262        if ( empty( $key ) || empty( $instance ) ) {
    336263            // set the transient to an error.
    337             $error = new WP_Error( 'missing_license_key', 'License key is not activated.' );
    338             set_transient( $this->license_status_transient_key, $error, $expiration );
     264            $error = array(
     265                'is_error' => true,
     266                'code' => 'missing_license_key',
     267                'message' => 'License key is not activated.',
     268            );
     269            set_transient( self::$license_status_transient_key, $error, $expiration );
    339270            return $error;
    340271        }
     
    354285                $url,
    355286                array(
    356                     'timeout' => wp_doing_cron() ? 10 : 3,
     287                    'timeout' => wp_doing_cron() ? 10 : 5,
    357288                    'headers' => array(
    358289                        'Accept' => 'application/json',
     
    362293
    363294            $data = $this->validate_api_response( $response );
    364 
    365             if ( is_wp_error( $data ) ) {
    366                 Logger::log( $data );
    367                 $expiration = 60 * 60 * 1; // try again in an hour if error.
    368             }
    369 
    370             set_transient( $this->license_status_transient_key, $data, $expiration );
     295            $error = isset( $data['is_error'] ) && $data['is_error'] ? $data : false;
     296
     297            if ( $error ) {
     298                Logger::log( $error );
     299            }
     300
     301            $success = set_transient( self::$license_status_transient_key, $data, $expiration );
     302            if ( ! $success ) {
     303                Logger::log( 'Failed to set license status transient' );
     304            }
     305
     306            return $data;
    371307        }
    372308
     
    383319    public function validate_api_response( $response ) {
    384320        if ( is_wp_error( $response ) ) {
    385             return $response;
    386         }
    387 
    388         $decoded_response = json_decode( $response['body'] );
     321            return array(
     322                'is_error' => true,
     323                'code' => $response->get_error_code(),
     324                'message' => $response->get_error_message(),
     325            );
     326        }
     327
     328        $decoded_response = json_decode( $response['body'], true ); // Decode as associative array.
    389329        if ( null === $decoded_response ) {
    390             return new WP_Error( 'invalid_json', 'Invalid JSON in response', $response['body'] );
     330            return array(
     331                'is_error' => true,
     332                'code' => 'invalid_json',
     333                'message' => 'Invalid JSON in response',
     334                'data' => $response['body'],
     335            );
     336        }
     337
     338        if ( $response['response']['code'] === 403 ) {
     339            return array(
     340                'is_error' => true,
     341                'expired' => true,
     342                'code' => 'license_expired',
     343                'message' => isset( $decoded_response['error'] ) ? $decoded_response['error'] : 'License expired.',
     344            );
    391345        }
    392346
    393347        if ( $response['response']['code'] !== 200 ) {
    394             $error = isset( $decoded_response->error ) ? $decoded_response->error : 'No error message returned from server';
    395             return new WP_Error( 'invalid_response_code', $error );
     348            return array(
     349                'is_error' => true,
     350                'code' => 'invalid_response_code',
     351                'message' => isset( $decoded_response['error'] ) ? $decoded_response['error'] : 'No error message returned from server.',
     352            );
    396353        }
    397354
    398355        // Ensure $decoded_response has the expected structure.
    399         if ( ! isset( $decoded_response->data ) ) {
    400             return new WP_Error( 'invalid_response_structure', 'Missing expected property: data' );
    401         }
    402 
    403         return $decoded_response->data;
    404     }
    405 
    406 
    407     /**
    408      * Create an update response object for the WordPress transient
    409      * NOTE: this transient is different to the one we use to store the update data
    410      *
    411      * @param  array $args {
    412      *  Arguments for creating the update data object.
    413      *
    414      *  @type string   $new_version  New plugin version.
    415      *  @type string   $package      Plugin update package URL.
    416      * }
    417      * @return object {
    418      *     An object of metadata about the available plugin update.
    419      *
    420      *     @type string   $id           Plugin ID, e.g. `w.org/plugins/[plugin-name]`.
    421      *     @type string   $slug         Plugin slug.
    422      *     @type string   $plugin       Plugin basename.
    423      *     @type string   $new_version  New plugin version.
    424      *     @type string   $url          Plugin URL.
    425      *     @type string   $package      Plugin update package URL.
    426      *     @type string[] $icons        An array of plugin icon URLs.
    427      *     @type string[] $banners      An array of plugin banner URLs.
    428      *     @type string[] $banners_rtl  An array of plugin RTL banner URLs.
    429      *     @type string   $requires     The version of WordPress which the plugin requires.
    430      *     @type string   $tested       The version of WordPress the plugin is tested against.
    431      *     @type string   $requires_php The version of PHP which the plugin requires.
    432      * }
    433      */
    434     private function create_update_response_object( $args = array() ) {
    435         $defaults = array(
    436             'id'           => '0',
    437             'slug'         => 'woocommerce-pos-pro',
    438             'plugin'       => $this->pro_plugin_path,
    439             'url'          => 'https://wcpos.com/pro',
    440             'requires'     => '5.6',
    441             'tested'       => '6.5',
    442             'requires_php' => '7.4',
    443             'icons' => array(
    444                 '1x' => 'https://wcpos.com/wp-content/uploads/2014/06/woopos-pro.png',
    445             ),
    446         );
    447 
    448         $parsed_args = wp_parse_args( $args, $defaults );
    449 
    450         $update_obj = new \stdClass();
    451         foreach ( $parsed_args as $key => $value ) {
    452             $update_obj->$key = $value;
    453         }
    454 
    455         return $update_obj;
     356        if ( ! isset( $decoded_response['data'] ) ) {
     357            return array(
     358                'is_error' => true,
     359                'code' => 'invalid_response_structure',
     360                'message' => 'Missing expected property: data',
     361            );
     362        }
     363
     364        return $decoded_response['data'];
    456365    }
    457366
     
    465374        if ( $options['action'] == 'update' && $options['type'] == 'plugin' ) {
    466375            if ( isset( $options['plugins'] ) && in_array( 'woocommerce-pos/woocommerce-pos.php', $options['plugins'] ) ) {
    467                 delete_transient( $this->update_data_transient_key );
    468                 $this->check_pro_plugin_updates();
     376                delete_transient( self::$update_data_transient_key );
    469377            }
    470378        }
     
    520428     */
    521429    public function plugin_row_meta( $plugin_meta, $plugin_file, $plugin_data, $status ) {
    522         if ( $plugin_file !== $this->pro_plugin_path ) {
    523             return $plugin_meta;
    524         }
    525 
    526430        // $license_status = 'Your license status here'; // Fetch or generate your license status message
    527431        // $plugin_meta[] = '<span style="color: #d63638;">' . esc_html( $license_status ) . '</span>';
     
    560464     */
    561465    public function plugin_update_message( $plugin_data, $response ) {
    562         if ( $response->plugin !== $this->pro_plugin_path ) {
    563             return;
    564         }
    565 
    566         $license_status = $this->check_license_status();
    567         if ( ! is_wp_error( $license_status ) ) {
    568             return;
    569         }
    570 
    571         $message = 'Your license has expired. <a href="http://wcpos.com/my-account/">Please renew</> to update.';
    572 
    573         if ( $license_status->get_error_code() === 'missing_license_key' ) {
    574             $message = $license_status->get_error_message();
    575         }
    576 
    577         echo '<br /><span style="color: #d63638;">' . wp_kses_post( $message ) . '</span>';
     466        // Nothing at the moment.
     467
     468        // $message = 'Your license has expired. <a href="http://wcpos.com/my-account/">Please renew</> to update.';
     469
     470        // if ( $license_status->get_error_code() === 'missing_license_key' ) {
     471        // $message = $license_status->get_error_message();
     472        // }
     473
     474        // echo '<br /><span style="color: #d63638;">' . wp_kses_post( $message ) . '</span>';
    578475    }
    579476
     
    588485        }
    589486
    590         $update_data = get_transient( $this->update_data_transient_key );
    591         $message = 'Something went wrong. Please try again later.';
     487        $update_data = get_transient( self::$update_data_transient_key );
     488        $message = esc_html__( 'Something went wrong. Please try again later.', 'woocommerce-pos' );
    592489
    593490        if ( is_wp_error( $update_data ) ) {
     
    600497        }
    601498
     499        /* translators: WordPress */
    602500        iframe_header( __( 'Plugin Installation' ) );
    603501
     
    640538    private function maybe_add_upgrade_notice() {
    641539        $license_status = $this->check_license_status();
    642         if ( ! is_wp_error( $license_status ) ) {
     540        $active = isset( $license_status['activated'] ) && $license_status['activated'];
     541        $inactive = isset( $license_status['activated'] ) && ! $license_status['activated'];
     542        $expired = isset( $license_status['expired'] ) && $license_status['expired'];
     543
     544        if ( isset( $license_status['is_error'] ) && $license_status['is_error'] ) {
     545            $inactive = isset( $license_status['code'] ) &&
     546                in_array(
     547                    $license_status['code'],
     548                    array(
     549                        'missing_license_key', // no license key is set.
     550                        'invalid_response_code', // usually the key or instance is wrong length.
     551                    )
     552                );
     553        }
     554
     555        if ( $inactive ) {
     556            return esc_html__( 'Your WooCommerce Pro license is inactive', 'woocommerce-pos' );
     557        }
     558
     559        if ( $expired ) {
     560            return esc_html__( 'Your WooCommerce Pro license has expired', 'woocommerce-pos' );
     561        }
     562
     563        if ( isset( $license_status['is_error'] ) && $license_status['is_error'] ) {
     564            return $license_status['message'];
     565        }
     566    }
     567
     568    /**
     569     * Add a notice to the plugin update table on Dashboard > Updates
     570     */
     571    public function license_status_notice() {
     572        $license_status = $this->check_license_status();
     573        $active = isset( $license_status['activated'] ) && $license_status['activated'];
     574        $inactive = isset( $license_status['activated'] ) && ! $license_status['activated'];
     575        $expired = isset( $license_status['expired'] ) && $license_status['expired'];
     576
     577        if ( isset( $license_status['is_error'] ) && $license_status['is_error'] ) {
     578            $inactive = isset( $license_status['code'] ) &&
     579                in_array(
     580                    $license_status['code'],
     581                    array(
     582                        'missing_license_key', // no license key is set.
     583                        'invalid_response_code', // usually the key or instance is wrong length.
     584                    )
     585                );
     586        }
     587
     588        if ( $active ) {
     589            echo '<tr class="plugin-update-tr installer-plugin-update-tr woocommerce-pos-pro-license">
     590                <td colspan="4" class="plugin-update colspanchange">
     591                    <div class="update-message notice inline wcpos-active" style="margin:0;border:0;border-bottom:1px solid #DCDCDE;border-left:4px solid #5D9B5C;background-color:#F8FFF1;">
     592                        <p class="installer-q-icon">' .
     593                        esc_html__( 'Your WooCommerce Pro license is valid and active.', 'woocommerce-pos' ) .
     594                        ' ' .
     595                        esc_html__( 'You are receiving plugin updates.', 'woocommerce-pos' )
     596                        . '</p>
     597                    </div>
     598                </td>
     599            </tr>';
    643600            return;
    644601        }
    645602
    646         if ( $license_status->get_error_code() === 'missing_license_key' ) {
    647             return $license_status->get_error_message();
    648         }
    649 
    650         return 'Your license has expired. Please renew to update.';
     603        if ( $inactive ) {
     604            echo '<tr class="plugin-update-tr installer-plugin-update-tr woocommerce-pos-pro-license">
     605                <td colspan="4" class="plugin-update colspanchange">
     606                    <div class="update-message notice inline wcpos-inactive" style="margin:0;border:0;border-bottom:1px solid #DCDCDE;border-left:4px solid #BD5858;background-color:#FFF8E1;">
     607                        <p class="installer-q-icon">' .
     608                        esc_html__( 'Your WooCommerce Pro license is inactive.', 'woocommerce-pos' ) .
     609                        ' ' .
     610                        sprintf(
     611                            wp_kses(
     612                                __( '<a href="%s">Click here</a> to activate your license key.', 'woocommerce-pos' ),
     613                                array( 'a' => array( 'href' => array() ) )
     614                            ),
     615                            esc_url( admin_url( 'admin.php?page=woocommerce-pos-settings#license' ) )
     616                        )
     617                        . '</p>
     618                    </div>
     619                </td>
     620            </tr>';
     621            return;
     622        }
     623
     624        if ( $expired ) {
     625            echo '<tr class="plugin-update-tr installer-plugin-update-tr woocommerce-pos-pro-license">
     626                <td colspan="4" class="plugin-update colspanchange">
     627                    <div class="update-message notice inline wcpos-expired" style="margin:0;border:0;border-bottom:1px solid #DCDCDE;border-left:4px solid #D63638;background-color:#FFF7F7;">
     628                        <p class="installer-q-icon">' .
     629                        esc_html__( 'Your WooCommerce Pro license has expired.', 'woocommerce-pos' ) .
     630                        ' ' .
     631                        sprintf(
     632                            wp_kses(
     633                                __( '<a href="%s">Please renew</a> to receive updates.', 'woocommerce-pos' ),
     634                                array( 'a' => array( 'href' => array() ) )
     635                            ),
     636                            'https://wcpos.com/my-account/'
     637                        )
     638                        . '</p>
     639                    </div>
     640                </td>
     641            </tr>';
     642            return;
     643        }
     644
     645        $message = esc_html__( 'Something went wrong. Please try again later.', 'woocommerce-pos' );
     646        if ( isset( $license_status['is_error'] ) && $license_status['is_error'] ) {
     647            $message = $license_status['message'];
     648        }
     649        echo '<tr class="plugin-update-tr installer-plugin-update-tr woocommerce-pos-pro-license">
     650            <td colspan="4" class="plugin-update colspanchange">
     651                <div class="update-message notice inline wcpos-expired" style="margin:0;border:0;border-bottom:1px solid #DCDCDE;border-left:4px solid #D63638;background-color:#FFF7F7;">
     652                    <p class="installer-q-icon">' . $message . '</p>
     653                </div>
     654            </td>
     655        </tr>';
     656    }
     657
     658    /**
     659     * Add some styles for the license status notice
     660     *
     661     * @param string $hook The current admin page.
     662     */
     663    public function license_status_styles( $hook ) {
     664        if ( 'plugins.php' === $hook ) {
     665            wp_register_style( 'woocommerce-pos-styles', false );
     666            wp_enqueue_style( 'woocommerce-pos-styles' );
     667
     668            $css = '
     669                .woocommerce-pos-pro-license .wcpos-active p::before {
     670                    content: "\f12a";
     671                color: #4d7d4c;
     672                width: 25px;
     673                }
     674                .woocommerce-pos-pro-license .wcpos-inactive p::before {
     675                    content: "\f112";
     676                    color: #bd5858;
     677                    width: 25px;
     678                }
     679                .woocommerce-pos-pro-license .wcpos-expired p::before {
     680                    width: 25px;
     681                }
     682            ';
     683            wp_add_inline_style( 'woocommerce-pos-styles', $css );
     684        }
    651685    }
    652686
     
    657691     */
    658692    private function get_license_settings() {
    659         if ( ! $this->active ) {
    660             if ( file_exists( WP_PLUGIN_DIR . '/woocommerce-pos-pro/includes/Services/Settings.php' ) ) {
    661                 include_once WP_PLUGIN_DIR . '/woocommerce-pos-pro/includes/Services/Settings.php';
    662                 if ( method_exists( '\WCPOS\WooCommercePOSPro\Services\Settings', '_get_inactive_license_settings' ) ) {
    663                     return \WCPOS\WooCommercePOSPro\Services\Settings::_get_inactive_license_settings();
    664                 }
    665             }
    666         }
    667         return woocommerce_pos_get_settings( 'license' );
     693        // first check if any Pro plugins are active.
     694        foreach ( $this->installed_pro_plugins as $plugin_path => $plugin_data ) {
     695            if ( is_plugin_active( $plugin_path ) ) {
     696                return woocommerce_pos_get_settings( 'license' );
     697            }
     698        }
     699
     700        // else, try and get the settings from the first Pro plugin.
     701        $first_folder = dirname( array_key_first( $this->installed_pro_plugins ) );
     702        if ( file_exists( WP_PLUGIN_DIR . '/' . $first_folder . '/includes/Services/Settings.php' ) ) {
     703            include_once WP_PLUGIN_DIR . '/' . $first_folder . '/includes/Services/Settings.php';
     704            if ( method_exists( '\WCPOS\WooCommercePOSPro\Services\Settings', '_get_inactive_license_settings' ) ) {
     705                return \WCPOS\WooCommercePOSPro\Services\Settings::_get_inactive_license_settings();
     706            }
     707        }
     708    }
     709
     710    /**
     711     * Temporary fix for older versions of the Pro plugin
     712     *
     713     * @param string $plugin_path The plugin path.
     714     */
     715    private function remove_this_hack_for_older_versions( $plugin_path ) {
     716        // Manually the update_plugins transient
     717        $update_plugins = get_site_transient( 'update_plugins' );
     718        if ( ! is_object( $update_plugins ) ) {
     719                $update_plugins = new stdClass();
     720                $update_plugins->response = array();
     721        }
     722
     723        $license_settings = $this->get_license_settings();
     724        $key = isset( $license_settings['key'] ) ? $license_settings['key'] : '';
     725        $instance = isset( $license_settings['instance'] ) ? $license_settings['instance'] : '';
     726
     727        // Construct the download URL, taking into account the environment.
     728        $package_url = add_query_arg(
     729            array(
     730                'key' => urlencode( $key ),
     731                'instance' => urlencode( $instance ),
     732            ),
     733            'https://updates.wcpos.com/pro/download/1.4.5'
     734        );
     735
     736        $update = array(
     737            'id'             => 'https://updates.wcpos.com',
     738            'slug'           => 'woocommerce-pos-pro',
     739            'plugin'         => $plugin_path,
     740            'new_version'    => '1.4.5',
     741            'url'            => 'https://wcpos.com/pro',
     742            'package'        => $package_url,
     743            'requires'       => '5.6',
     744            'tested'         => '6.5',
     745            'requires_php'   => '7.4',
     746            'icons'          => array(
     747                '1x' => 'https://wcpos.com/wp-content/uploads/2014/06/woopos-pro.png',
     748            ),
     749            'upgrade_notice' => $this->maybe_add_upgrade_notice(),
     750        );
     751
     752        $update_plugins->response[ $plugin_path ] = (object) $update;
     753
     754        set_site_transient( 'update_plugins', $update_plugins );
    668755    }
    669756}
  • woocommerce-pos/tags/1.4.12/includes/Admin/templates/upgrade.php

    r2845568 r3053833  
    55 * @author    Paul Kilmurray <paul@kilbot.com.au>
    66 *
    7  * @see      http://www.kilbot.com.au
     7 * @see      http://www.kilbot.com
    88 */
    99?>
    1010
    11 <!-- temporary inline css, todo: remove this -->
    12 <style type="text/css">
    13     .web-title {
    14         display: none;
    15     }
     11<div class="wrap clear">
    1612
    17     .blurb {
    18         font-size: 14px;
    19         line-height: 1.6em;
    20     }
    21 
    22     .widget-area {
    23         float: right;
    24         width: 33%;
    25         margin-left: 20px;
    26         text-align: center;
    27         margin-bottom: 20px;
    28     }
    29 
    30     .widget-area .btn {
    31         display: inline-block;
    32         margin-bottom: 0;
    33         font-weight: 400;
    34         text-align: center;
    35         vertical-align: middle;
    36         cursor: pointer;
    37         background-image: none;
    38         border: 1px solid transparent;
    39         white-space: nowrap;
    40         text-decoration: none;
    41         margin: 20px 0;
    42     }
    43 
    44     .widget-area .btn-primary {
    45         color: #fff;
    46         background-color: #cd2f19;
    47         border-color: #b62a16;
    48     }
    49 
    50     .widget-area .btn-lg {
    51         padding: 10px 16px;
    52         font-size: 18px;
    53         line-height: 1.33;
    54         border-radius: 6px;
    55     }
    56 
    57     .comparison-table {
    58         width: 100%;
    59         border-spacing: 0;
    60         border-collapse: collapse;
    61         border: 1px solid #e5e5e5;
    62         box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
    63         background-color: #f5f5f5;
    64     }
    65 
    66     .comparison-table thead {
    67         font-size: 18px;
    68     }
    69 
    70     .comparison-table thead tr {
    71         border-bottom: 1px solid #e5e5e5;
    72     }
    73 
    74     .comparison-table thead th {
    75         width: 33%;
    76         font-weight: normal;
    77     }
    78 
    79     .comparison-table thead th:first-of-type {
    80         background-color: #B0B0B0;
    81         color: #f5f5f5;
    82     }
    83 
    84     .comparison-table thead th:last-of-type {
    85         background-color: #d54e21;
    86         color: #f5f5f5;
    87     }
    88 
    89     .comparison-table th, td {
    90         padding: 1% 2%;
    91     }
    92 
    93     .comparison-table tbody th {
    94         font-weight: normal;
    95         text-align: right;
    96     }
    97 
    98     .comparison-table tbody tr {
    99         border-bottom: 1px solid #e5e5e5;
    100     }
    101 
    102     .comparison-table tbody tr td:first-of-type {
    103         background-color: #fafafa;
    104     }
    105 
    106     .comparison-table tbody tr td:last-of-type {
    107         background-color: #fef7f1;
    108     }
    109 
    110     .comparison-table .fa {
    111         font-family: Dashicons !important;;
    112         speak: none;
    113         font-style: normal;
    114         font-weight: normal;
    115         font-variant: normal;
    116         text-transform: none;
    117         -webkit-font-smoothing: antialiased;
    118         -moz-osx-font-smoothing: grayscale;
    119     }
    120 
    121     .comparison-table .fa-check:before {
    122         content: "\f147";
    123         color: #3c763d;
    124         font-size: 24px;
    125     }
    126 
    127     .comparison-table .fa-times:before {
    128         content: "\f335";
    129         color: #a94442;
    130         font-size: 24px;
    131     }
    132 </style>
    133 
    134 <div class="wrap clear woocommerce-pos-upgrade">
    135 
    136     <!--
     13    <!--
    13714    Little trick to get around WP js injection of admin notices
    13815    WP js looks for first h2 in .wrap and appends notices, so we'll make the first one hidden
    13916    https://github.com/WordPress/WordPress/blob/master/wp-admin/js/common.js
    14017    -->
    141     <h2 style="display:none"></h2>
     18    <h2 style="display:none"></h2>
    14219
    143     <h2 style="margin:20px 0;">Thank you for using WooCommerce POS!</h2>
    144 
    145     <?php echo $upgrade; ?>
     20    <div id="woocommerce-pos-upgrade"></div>
    14621
    14722</div>
    148 
  • woocommerce-pos/tags/1.4.12/includes/Form_Handler.php

    r2929317 r3053833  
    11<?php
     2/**
     3 *
     4 */
    25
    36namespace WCPOS\WooCommercePOS;
    47
     8use WCPOS\WooCommercePOS\Services\Auth as AuthService;
     9
     10/**
     11 *
     12 */
    513class Form_Handler {
    614
     
    2836        global $wp;
    2937
    30         if ( woocommerce_pos_request() && isset( $_POST['woocommerce_pay'], $_GET['key'] ) ) {
     38        if ( woocommerce_pos_request() && isset( $_POST['woocommerce_pay'], $_GET['key'], $_GET['token'] ) ) {
    3139            $order_id  = absint( $wp->query_vars['order-pay'] );
    3240            $order     = wc_get_order( $order_id );
    3341
    34             // set customer
     42            // Ensure the order exists.
     43            if ( ! $order ) {
     44                wp_die(
     45                    esc_html__( 'Order does not exist.', 'woocommerce-pos' ),
     46                    esc_html__( 'Error', 'woocommerce-pos' ),
     47                    array( 'response' => 403 )
     48                );
     49            }
     50
     51            // Verify the order key matches the key provided in the URL.
     52            $provided_key = sanitize_text_field( wp_unslash( $_GET['key'] ) );
     53            if ( $provided_key !== $order->get_order_key() ) {
     54                wp_die(
     55                    esc_html__( 'Order key mismatch.', 'woocommerce-pos' ),
     56                    esc_html__( 'Error', 'woocommerce-pos' ),
     57                    array( 'response' => 403 )
     58                );
     59            }
     60
     61            // Verify the cashier is authorized to access the order.
     62            $provided_token = sanitize_text_field( wp_unslash( $_GET['token'] ) );
     63            $auth = AuthService::instance();
     64            $user = $auth->validate_token( $provided_token );
     65            if ( is_wp_error( $user ) ) {
     66                wp_die(
     67                    esc_html__( 'Cashier token mismatch.', 'woocommerce-pos' ),
     68                    esc_html__( 'Error', 'woocommerce-pos' ),
     69                    array( 'response' => 403 )
     70                );
     71            }
     72
     73            // set customer.
    3574            wp_set_current_user( $order->get_customer_id() );
    3675        }
    37 
    3876    }
    3977
     
    71109        }
    72110    }
    73 
    74111}
  • woocommerce-pos/tags/1.4.12/includes/Services/Settings.php

    r3048280 r3053833  
    44
    55use WC_Payment_Gateways;
     6use WP_Error;
    67use const WCPOS\WooCommercePOS\VERSION;
    7 use WP_Error;
    88
    99/**
     
    162162
    163163    /**
    164      * @param string $id
    165      * @param array  $settings
    166      *
    167      * @return null|array|mixed|WP_Error
     164     * Saves settings for a specific section.
     165     *
     166     * @param string $id The ID of the settings section being saved.
     167     * @param array  $settings The settings array to be saved.
     168     *
     169     * @return array|WP_Error Returns the updated settings array on success or WP_Error on failure.
    168170     */
    169171    public function save_settings( string $id, array $settings ) {
    170         $success = update_option(
    171             static::$db_prefix . $id,
    172             array_merge(
    173                 $settings,
    174                 array( 'date_modified_gmt' => current_time( 'mysql', true ) )
    175             ),
    176             false
    177         );
     172        $settings = array_merge(
     173            $settings,
     174            array( 'date_modified_gmt' => current_time( 'mysql', true ) )
     175        );
     176
     177        /**
     178         * Filters the settings before they are saved.
     179         *
     180         * Allows modification of the settings array for a specific section before it is saved to the database.
     181         *
     182         * @since 1.4.12
     183         *
     184         * @param array  $settings The settings array about to be saved.
     185         * @param string $id       The ID of the settings section being saved.
     186         */
     187        $settings = apply_filters( "woocommerce_pos_pre_save_{$id}_settings", $settings, $id );
     188
     189        $success = update_option( static::$db_prefix . $id, $settings, false );
    178190
    179191        if ( $success ) {
    180             return $this->get_settings( $id );
     192            $saved_settings = $this->get_settings( $id );
     193
     194            /**
     195             * Fires after settings for a specific section are successfully saved.
     196             *
     197             * Provides a way to execute additional logic after a specific settings section is updated.
     198             *
     199             * @since 1.4.12
     200             *
     201             * @param array  $saved_settings The settings array that was just saved.
     202             * @param string $id             The ID of the settings section that was saved.
     203             */
     204            do_action( "woocommerce_pos_saved_{$id}_settings", $saved_settings, $id );
     205
     206            return $saved_settings;
    181207        }
    182208
  • woocommerce-pos/tags/1.4.12/readme.txt

    r3048280 r3053833  
    22Contributors: kilbot
    33Tags: cart, e-commerce, ecommerce, inventory, point-of-sale, pos, sales, sell, shop, shopify, store, vend, woocommerce, wordpress-ecommerce
    4 Requires at least: 5.6 & WooCommerce 5.3
    5 Tested up to: 6.4
    6 Stable tag: 1.4.11
     4Requires at least: 5.6
     5Tested up to: 6.5
     6Stable tag: 1.4.12
    77License: GPL-3.0
    88License URI: http://www.gnu.org/licenses/gpl-3.0.html
     
    6363
    6464== Changelog ==
     65
     66= 1.4.12 - 2024/03/18 =
     67* Security: Fix Insufficient Verification of Data Authenticity to Authenticated (Customer+) Information Disclosure (reported by Lucio Sá)
     68* Fix: Pro plugin not showing updates for some users
    6569
    6670= 1.4.11 - 2024/03/09 =
  • woocommerce-pos/tags/1.4.12/vendor/autoload.php

    r3048280 r3053833  
    2323require_once __DIR__ . '/composer/autoload_real.php';
    2424
    25 return ComposerAutoloaderInitd5f742ecdf534f147f5b8e2724165a2d::getLoader();
     25return ComposerAutoloaderInit4381cd7e2816c049c0c912563977ae98::getLoader();
  • woocommerce-pos/tags/1.4.12/vendor/composer/autoload_real.php

    r3048280 r3053833  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInitd5f742ecdf534f147f5b8e2724165a2d
     5class ComposerAutoloaderInit4381cd7e2816c049c0c912563977ae98
    66{
    77    private static $loader;
     
    2323        }
    2424
    25         spl_autoload_register(array('ComposerAutoloaderInitd5f742ecdf534f147f5b8e2724165a2d', 'loadClassLoader'), true, true);
     25        spl_autoload_register(array('ComposerAutoloaderInit4381cd7e2816c049c0c912563977ae98', 'loadClassLoader'), true, true);
    2626        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
    27         spl_autoload_unregister(array('ComposerAutoloaderInitd5f742ecdf534f147f5b8e2724165a2d', 'loadClassLoader'));
     27        spl_autoload_unregister(array('ComposerAutoloaderInit4381cd7e2816c049c0c912563977ae98', 'loadClassLoader'));
    2828
    2929        require __DIR__ . '/autoload_static.php';
    30         call_user_func(\Composer\Autoload\ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::getInitializer($loader));
     30        call_user_func(\Composer\Autoload\ComposerStaticInit4381cd7e2816c049c0c912563977ae98::getInitializer($loader));
    3131
    3232        $loader->register(true);
    3333
    34         $filesToLoad = \Composer\Autoload\ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::$files;
     34        $filesToLoad = \Composer\Autoload\ComposerStaticInit4381cd7e2816c049c0c912563977ae98::$files;
    3535        $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
    3636            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
  • woocommerce-pos/tags/1.4.12/vendor/composer/autoload_static.php

    r3048280 r3053833  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d
     7class ComposerStaticInit4381cd7e2816c049c0c912563977ae98
    88{
    99    public static $files = array (
     
    330330    {
    331331        return \Closure::bind(function () use ($loader) {
    332             $loader->prefixLengthsPsr4 = ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::$prefixLengthsPsr4;
    333             $loader->prefixDirsPsr4 = ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::$prefixDirsPsr4;
    334             $loader->prefixesPsr0 = ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::$prefixesPsr0;
    335             $loader->classMap = ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::$classMap;
     332            $loader->prefixLengthsPsr4 = ComposerStaticInit4381cd7e2816c049c0c912563977ae98::$prefixLengthsPsr4;
     333            $loader->prefixDirsPsr4 = ComposerStaticInit4381cd7e2816c049c0c912563977ae98::$prefixDirsPsr4;
     334            $loader->prefixesPsr0 = ComposerStaticInit4381cd7e2816c049c0c912563977ae98::$prefixesPsr0;
     335            $loader->classMap = ComposerStaticInit4381cd7e2816c049c0c912563977ae98::$classMap;
    336336
    337337        }, null, ClassLoader::class);
  • woocommerce-pos/tags/1.4.12/vendor/composer/installed.php

    r3048280 r3053833  
    22    'root' => array(
    33        'name' => 'wcpos/woocommerce-pos',
    4         'pretty_version' => 'v1.4.11',
    5         'version' => '1.4.11.0',
    6         'reference' => '49a47c823e48eb87ba9a51d7253bcf1d7c05a496',
     4        'pretty_version' => 'v1.4.12',
     5        'version' => '1.4.12.0',
     6        'reference' => '8e655c54f31968b7da74a7f5a1464c958a0147ed',
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../',
     
    9090        ),
    9191        'wcpos/woocommerce-pos' => array(
    92             'pretty_version' => 'v1.4.11',
    93             'version' => '1.4.11.0',
    94             'reference' => '49a47c823e48eb87ba9a51d7253bcf1d7c05a496',
     92            'pretty_version' => 'v1.4.12',
     93            'version' => '1.4.12.0',
     94            'reference' => '8e655c54f31968b7da74a7f5a1464c958a0147ed',
    9595            'type' => 'wordpress-plugin',
    9696            'install_path' => __DIR__ . '/../../',
  • woocommerce-pos/tags/1.4.12/woocommerce-pos.php

    r3048280 r3053833  
    44 * Plugin URI:        https://wordpress.org/plugins/woocommerce-pos/
    55 * Description:       A simple front-end for taking WooCommerce orders at the Point of Sale. Requires <a href="http://wordpress.org/plugins/woocommerce/">WooCommerce</a>.
    6  * Version:           1.4.11
     6 * Version:           1.4.12
    77 * Author:            kilbot
    88 * Author URI:        http://wcpos.com
     
    1111 * License URI:       http://www.gnu.org/licenses/gpl-3.0.txt
    1212 * Domain Path:       /languages
     13 * Requires at least: 5.6
     14 * Requires PHP:      7.4
     15 * Requires Plugins:  woocommerce
     16 * Tested up to:      6.5
    1317 * WC tested up to:   8.6
    14  * WC requires at least: 5.3.
     18 * WC requires at least: 5.3
    1519 *
    1620 * @author    Paul Kilmurray <paul@kilbot.com>
     
    2327
    2428// Define plugin constants.
    25 const VERSION     = '1.4.11';
     29const VERSION     = '1.4.12';
    2630const PLUGIN_NAME = 'woocommerce-pos';
    2731const SHORT_NAME  = 'wcpos';
  • woocommerce-pos/trunk/includes/API/Settings.php

    r3020668 r3053833  
    3535    public function __construct() {
    3636        add_filter( 'option_woocommerce_pos_settings_payment_gateways', array( $this, 'payment_gateways_settings' ) );
     37
     38        // remove this once Pro settings have been moved to the new settings service.
     39        add_filter( 'pre_update_option_woocommerce_pos_pro_settings_license', array( $this, 'remove_license_transient' ) );
    3740    }
    3841
     
    544547        return $options;
    545548    }
     549
     550    /**
     551     * Temporary fix for stale license status transient. Remove when possible.
     552     */
     553    public function remove_license_transient( $value ) {
     554        delete_transient( 'woocommerce_pos_pro_license_status' );
     555        return $value;
     556    }
    546557}
  • woocommerce-pos/trunk/includes/Admin/Menu.php

    r3048280 r3053833  
    1313use const HOUR_IN_SECONDS;
    1414use const WCPOS\WooCommercePOS\PLUGIN_NAME;
     15use const WCPOS\WooCommercePOS\VERSION as PLUGIN_VERSION;
    1516
    1617/**
     
    4041            add_filter( 'custom_menu_order', '__return_true' );
    4142            add_filter( 'menu_order', array( $this, 'menu_order' ), 9, 1 );
     43            add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_landing_scripts_and_styles' ) );
    4244        }
    4345
     
    8082     */
    8183    public function display_upgrade_page(): void {
    82         $upgrade = get_transient( 'remote_pro_page' );
    83 
    84         // Check for transient, if none, grab remote HTML file
    85         if ( false === $upgrade ) {
    86             // Get remote HTML file
    87             $response = wp_remote_get( 'http://wcpos.com/pro/?wp-admin=woocommerce-pos' );
    88             // Check for error
    89             if ( is_wp_error( $response ) ) {
    90                 return;
    91             }
    92             // Parse remote HTML file
    93             $upgrade = wp_remote_retrieve_body( $response );
    94             // Check for error
    95             if ( is_wp_error( $upgrade ) ) {
    96                 return;
    97             }
    98             // Store remote HTML file in transient, expire after 24 hours
    99             set_transient( 'remote_pro_page', $upgrade, 24 * HOUR_IN_SECONDS );
    100         }
    10184        include_once 'templates/upgrade.php';
    10285    }
     
    193176        );
    194177    }
     178
     179    /**
     180     * Enqueue landing page scripts and styles.
     181     */
     182    public function enqueue_landing_scripts_and_styles( $hook_suffix ): void {
     183        if ( $hook_suffix === $this->toplevel_screen_id ) {
     184            $is_development = isset( $_ENV['DEVELOPMENT'] ) && $_ENV['DEVELOPMENT'];
     185            $url            = $is_development ? 'http://localhost:9000/' : 'https://cdn.jsdelivr.net/gh/wcpos/wp-admin-landing/assets/';
     186
     187            // Enqueue the landing page CSS from CDN
     188            wp_enqueue_style(
     189                'wcpos-landing',
     190                $url . 'css/landing.css',
     191                array(),
     192                PLUGIN_VERSION
     193            );
     194
     195            // Ensure WordPress bundled React and lodash are loaded as dependencies
     196            wp_enqueue_script( 'react' );
     197            wp_enqueue_script( 'lodash' );
     198
     199            // Enqueue the landing page JS from CDN, with React and lodash as dependencies
     200            wp_enqueue_script(
     201                'wcpos-landing',
     202                $url . 'js/landing.js',
     203                array(
     204                    'react',
     205                    'react-dom',
     206                    'wp-element',
     207                    'lodash',
     208                ),
     209                PLUGIN_VERSION,
     210                true
     211            );
     212        }
     213    }
    195214}
  • woocommerce-pos/trunk/includes/Admin/Updaters/Pro_Plugin_Updater.php

    r3021613 r3053833  
    2727
    2828    /**
    29      * The path to the Pro plugin
    30      *
    31      * @var string $pro_plugin_path
    32      */
    33     private $pro_plugin_path = 'woocommerce-pos-pro/woocommerce-pos-pro.php';
    34 
    35     /**
    3629     * The update server URL
    3730     *
     
    4538     * @var string $update_data_transient_key
    4639     */
    47     private $update_data_transient_key = 'woocommerce_pos_pro_update_data';
    48 
     40    public static $update_data_transient_key = 'woocommerce_pos_pro_update_data';
     41
     42    /**
     43     * Transient key for the update data
     44     *
     45     * @var string $license_status_transient_key
     46     */
     47    public static $license_status_transient_key = 'woocommerce_pos_pro_license_status';
     48
     49    /**
     50     * Installed Pro plugins
     51     * Note: Generally this would be an array of 1 installed Pro plugins but
     52     * it's possible an older version of the plugin is installed in a different directory.
     53     *
     54     * @var array $installed_pro_plugins
     55     */
     56    private $installed_pro_plugins = array();
     57
     58    /**
     59     * Constructor.
     60     */
     61    public function __construct() {
    4962        /**
    50          * Transient key for the update data
    51          *
    52          * @var string $update_data_transient_key
     63         * First we need to check if the Pro plugin is installed (one or more versions)
    5364         */
    54     private $license_status_transient_key = 'woocommerce_pos_pro_license_status';
    55 
    56     /**
    57      * Whether the Pro plugin is installed
    58      *
    59      * @var bool $installed
    60      */
    61     private $installed;
    62 
    63     /**
    64      * Whether the Pro plugin is active
    65      *
    66      * @var bool $active
    67      */
    68     private $active;
    69 
    70     /**
    71      * The current version of the Pro plugin
    72      *
    73      * @var string $current_version
    74      */
    75     private $current_version;
    76 
    77     /**
    78      * Constructor.
    79      */
    80     public function __construct() {
    81         // Ensure the necessary functions are available
    8265        include_once ABSPATH . 'wp-admin/includes/plugin.php';
    83 
    84         $status = $this->check_pro_plugin_status();
    85         $this->installed = $status['installed'];
    86         $this->active = $status['active'];
    87         $this->current_version = $status['version'];
     66        $all_plugins = get_plugins();
     67        foreach ( $all_plugins as $plugin_path => $plugin_data ) {
     68            $plugin_dir = dirname( $plugin_path );
     69            if ( strpos( $plugin_dir, $this->pro_plugin_slug ) === 0 ) {
     70                if ( isset( $plugin_data['UpdateURI'] ) && $plugin_data['UpdateURI'] == $this->update_server ) {
     71                    $this->installed_pro_plugins[ $plugin_path ] = $plugin_data;
     72                }
     73            }
     74        }
    8875
    8976        // Allow the update server to be overridden for development.
     
    9279        }
    9380
    94         if ( $this->installed ) {
     81        if ( count( $this->installed_pro_plugins ) > 0 ) {
    9582            add_filter( 'update_plugins_updates.wcpos.com', array( $this, 'update_plugins' ), 10, 4 );
    9683            add_action( 'upgrader_process_complete', array( $this, 'after_plugin_update' ), 10, 2 );
    9784            add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 4 );
    98             add_action( 'in_plugin_update_message-' . $this->pro_plugin_path, array( $this, 'plugin_update_message' ), 10, 2 );
    9985            add_action( 'install_plugins_pre_plugin-information', array( $this, 'plugin_information' ), 5 );
    100         }
    101     }
    102 
    103     /**
    104      * Check the status of the Pro plugin
    105      *
    106      * @return array(
    107      *  'installed' => bool,
    108      *  'active'    => bool,
    109      *  'version'   => string|null,
    110      * )
    111      */
    112     public function check_pro_plugin_status() {
    113         $status = array(
    114             'installed' => false,
    115             'active'    => false,
    116             'version'   => null,
    117         );
    118 
    119         // Check if the Pro plugin file exists.
    120         if ( file_exists( WP_PLUGIN_DIR . '/' . $this->pro_plugin_path ) ) {
    121             $status['installed'] = true;
    122             $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $this->pro_plugin_path );
    123             $status['version'] = $plugin_data['Version'];
    124 
    125             // Check if the Pro plugin is active.
    126             if ( is_plugin_active( $this->pro_plugin_path ) ) {
    127                 $status['active'] = true;
    128             }
    129         }
    130 
    131         /**
    132          * This is a hack to manually trigger Pro update for version < 1.4.0
    133          * TODO: remove this after 1.4.0 is released for a while
    134          */
    135         if ( $status['version'] && version_compare( $status['version'], '1.4.0', '<' ) ) {
    136             // Manually the update_plugins transient
    137             $update_plugins = get_site_transient( 'update_plugins' );
    138             if ( ! is_object( $update_plugins ) ) {
    139                     $update_plugins = new stdClass();
    140             }
    141 
    142             $license_settings = $this->get_license_settings();
    143             $key = isset( $license_settings['key'] ) ? $license_settings['key'] : '';
    144             $instance = isset( $license_settings['instance'] ) ? $license_settings['instance'] : '';
    145 
    146             // Construct the download URL, taking into account the environment
    147             $package_url = add_query_arg(
    148                 array(
    149                     'key' => urlencode( $key ),
    150                     'instance' => urlencode( $instance ),
    151                 ),
    152                 'https://updates.wcpos.com/pro/download/1.4.1'
    153             );
    154 
    155             $update = array(
    156                 'id'             => 'https://updates.wcpos.com',
    157                 'slug'           => 'woocommerce-pos-pro',
    158                 'plugin'         => $this->pro_plugin_path,
    159                 'new_version'    => '1.4.1',
    160                 'url'            => 'https://wcpos.com/pro',
    161                 'package'        => $package_url,
    162                 'requires'       => '5.6',
    163                 'tested'         => '6.5',
    164                 'requires_php'   => '7.4',
    165                 'icons'          => array(
    166                     '1x' => 'https://wcpos.com/wp-content/uploads/2014/06/woopos-pro.png',
    167                 ),
    168                 'upgrade_notice' => $this->maybe_add_upgrade_notice(),
    169             );
    170 
    171             $update_plugins->response[ $this->pro_plugin_path ] = (object) $update;
    172 
    173             set_site_transient( 'update_plugins', $update_plugins );
    174         }
    175 
    176         return $status;
     86            add_action( 'admin_enqueue_scripts', array( $this, 'license_status_styles' ) );
     87
     88            // loop through the installed Pro plugins.
     89            foreach ( $this->installed_pro_plugins as $plugin_path => $plugin_data ) {
     90                add_action( 'in_plugin_update_message-' . $plugin_path, array( $this, 'plugin_update_message' ), 10, 2 );
     91                add_action( 'after_plugin_row_' . $plugin_path, array( $this, 'license_status_notice' ), 99 );
     92
     93                /**
     94                 * This is a hack to manually trigger Pro update for version < 1.4.0
     95                 * TODO: remove this after 1.4.0 is released for a while
     96                 */
     97                if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], '1.4.0', '<' ) ) {
     98                        $this->remove_this_hack_for_older_versions( $plugin_path );
     99                }
     100            }
     101        }
    177102    }
    178103
     
    212137     */
    213138    public function update_plugins( $update, $plugin_data, $plugin_file, $locales ) {
    214         $update_data = $this->check_pro_plugin_updates();
     139        $current_version = isset( $plugin_data['Version'] ) ? $plugin_data['Version'] : '1';
     140        $update_data = $this->check_pro_plugin_updates( $current_version );
    215141        $is_development = isset( $_ENV['DEVELOPMENT'] ) && $_ENV['DEVELOPMENT'];
    216142
    217143        // Check if update data is valid and if a new version is available.
    218         if ( ! is_wp_error( $update_data ) && is_object( $update_data ) && isset( $update_data->version ) ) {
    219             $latest_version = $update_data->version;
    220 
    221             // No update needed if the current version is greater than the latest version.
    222             if ( version_compare( $this->current_version, $latest_version, '>' ) ) {
    223                 return $update;
    224             }
    225 
     144        if ( isset( $update_data['version'] ) && version_compare( $current_version, $update_data['version'], '<' ) ) {
    226145            $license_settings = $this->get_license_settings();
    227146            $key = isset( $license_settings['key'] ) ? $license_settings['key'] : '';
     
    244163                'id'           => 'https://updates.wcpos.com',
    245164                'slug'         => 'woocommerce-pos-pro',
    246                 'plugin'       => $this->pro_plugin_path,
    247                 'version'      => $latest_version,
     165                'plugin'       => $plugin_file,
     166                'version'      => $update_data['version'],
    248167                'url'          => 'https://wcpos.com/pro',
    249168                'package'      => $package_url,
     
    264183     * Check for updates to the Pro plugin
    265184     *
    266      * @param  bool $force Force an update check.
    267      */
    268     public function check_pro_plugin_updates( $force = false ) {
    269         $update_data = get_transient( $this->update_data_transient_key );
     185     * @param  string $version The current plugin version.
     186     * @param  bool   $force Force an update check.
     187     */
     188    public function check_pro_plugin_updates( $version = '1', $force = false ) {
     189        $update_data = get_transient( self::$update_data_transient_key );
    270190
    271191        if ( empty( $update_data ) || $force ) {
    272192            $expiration = 60 * 60 * 12; // 12 hours.
    273             $url = $this->update_server . '/update/' . $this->current_version;
     193            $url = $this->update_server . '/update/' . $version;
    274194
    275195            // make the api call.
     
    277197                $url,
    278198                array(
    279                     'timeout' => wp_doing_cron() ? 10 : 3,
     199                    'timeout' => wp_doing_cron() ? 10 : 5,
    280200                    'headers' => array(
    281201                        'Accept' => 'application/json',
     
    285205
    286206            $data = $this->validate_api_response( $response );
    287 
    288             // Ensure $data has version, download_url and notes.
    289             if ( ! is_wp_error( $data ) ) {
     207            $error = isset( $data['is_error'] ) && $data['is_error'] ? $data : false;
     208
     209            // Ensure $data is an associative array and has version, download_url, and notes.
     210            if ( ! $error && is_array( $data ) ) {
    290211                $expected_properties = array( 'version', 'download_url', 'notes' );
    291212                foreach ( $expected_properties as $property ) {
    292                     if ( ! property_exists( $data, $property ) ) {
     213                    if ( ! array_key_exists( $property, $data ) ) {
    293214                        $data = new WP_Error( 'invalid_response_structure', "Missing expected property: $property" );
    294215                        break;
    295216                    }
    296217                }
    297             }
    298 
    299             if ( is_wp_error( $data ) ) {
     218            } else {
    300219                Logger::log( $data );
    301220                $expiration = 60 * 60 * 1; // try again in an hour if error.
    302221            }
    303222
    304             set_transient( $this->update_data_transient_key, $data, $expiration );
     223            $success = set_transient( self::$update_data_transient_key, $data, $expiration );
     224            if ( ! $success ) {
     225                Logger::log( 'Failed to set update data transient' );
     226            }
     227
     228            return $data;
    305229        }
    306230
     
    314238     */
    315239    private function check_license_status( $force = false ) {
    316         $license_status = get_transient( $this->license_status_transient_key );
     240        $license_status = get_transient( self::$license_status_transient_key );
    317241        $expiration = 60 * 60 * 12; // 12 hours.
    318242
     
    320244         * TODO: How to allow for multisite?
    321245         */
    322         if ( is_multisite() ) {
    323             $error = new WP_Error( 'multisite_update', 'Please go to http://wcpos.com/my-account to download update.' );
    324             set_transient( $this->license_status_transient_key, $error, $expiration );
    325             return $error;
    326         }
     246        // if ( is_multisite() ) {
     247        // $error = array(
     248        // 'code' => 'multisite_update',
     249        // 'message' => 'Please go to http://wcpos.com/my-account to download update.',
     250        // );
     251        // set_transient( $this->license_status_transient_key, $error, $expiration );
     252        // return $error;
     253        // }
    327254
    328255        $license_settings = $this->get_license_settings();
     
    335262        if ( empty( $key ) || empty( $instance ) ) {
    336263            // set the transient to an error.
    337             $error = new WP_Error( 'missing_license_key', 'License key is not activated.' );
    338             set_transient( $this->license_status_transient_key, $error, $expiration );
     264            $error = array(
     265                'is_error' => true,
     266                'code' => 'missing_license_key',
     267                'message' => 'License key is not activated.',
     268            );
     269            set_transient( self::$license_status_transient_key, $error, $expiration );
    339270            return $error;
    340271        }
     
    354285                $url,
    355286                array(
    356                     'timeout' => wp_doing_cron() ? 10 : 3,
     287                    'timeout' => wp_doing_cron() ? 10 : 5,
    357288                    'headers' => array(
    358289                        'Accept' => 'application/json',
     
    362293
    363294            $data = $this->validate_api_response( $response );
    364 
    365             if ( is_wp_error( $data ) ) {
    366                 Logger::log( $data );
    367                 $expiration = 60 * 60 * 1; // try again in an hour if error.
    368             }
    369 
    370             set_transient( $this->license_status_transient_key, $data, $expiration );
     295            $error = isset( $data['is_error'] ) && $data['is_error'] ? $data : false;
     296
     297            if ( $error ) {
     298                Logger::log( $error );
     299            }
     300
     301            $success = set_transient( self::$license_status_transient_key, $data, $expiration );
     302            if ( ! $success ) {
     303                Logger::log( 'Failed to set license status transient' );
     304            }
     305
     306            return $data;
    371307        }
    372308
     
    383319    public function validate_api_response( $response ) {
    384320        if ( is_wp_error( $response ) ) {
    385             return $response;
    386         }
    387 
    388         $decoded_response = json_decode( $response['body'] );
     321            return array(
     322                'is_error' => true,
     323                'code' => $response->get_error_code(),
     324                'message' => $response->get_error_message(),
     325            );
     326        }
     327
     328        $decoded_response = json_decode( $response['body'], true ); // Decode as associative array.
    389329        if ( null === $decoded_response ) {
    390             return new WP_Error( 'invalid_json', 'Invalid JSON in response', $response['body'] );
     330            return array(
     331                'is_error' => true,
     332                'code' => 'invalid_json',
     333                'message' => 'Invalid JSON in response',
     334                'data' => $response['body'],
     335            );
     336        }
     337
     338        if ( $response['response']['code'] === 403 ) {
     339            return array(
     340                'is_error' => true,
     341                'expired' => true,
     342                'code' => 'license_expired',
     343                'message' => isset( $decoded_response['error'] ) ? $decoded_response['error'] : 'License expired.',
     344            );
    391345        }
    392346
    393347        if ( $response['response']['code'] !== 200 ) {
    394             $error = isset( $decoded_response->error ) ? $decoded_response->error : 'No error message returned from server';
    395             return new WP_Error( 'invalid_response_code', $error );
     348            return array(
     349                'is_error' => true,
     350                'code' => 'invalid_response_code',
     351                'message' => isset( $decoded_response['error'] ) ? $decoded_response['error'] : 'No error message returned from server.',
     352            );
    396353        }
    397354
    398355        // Ensure $decoded_response has the expected structure.
    399         if ( ! isset( $decoded_response->data ) ) {
    400             return new WP_Error( 'invalid_response_structure', 'Missing expected property: data' );
    401         }
    402 
    403         return $decoded_response->data;
    404     }
    405 
    406 
    407     /**
    408      * Create an update response object for the WordPress transient
    409      * NOTE: this transient is different to the one we use to store the update data
    410      *
    411      * @param  array $args {
    412      *  Arguments for creating the update data object.
    413      *
    414      *  @type string   $new_version  New plugin version.
    415      *  @type string   $package      Plugin update package URL.
    416      * }
    417      * @return object {
    418      *     An object of metadata about the available plugin update.
    419      *
    420      *     @type string   $id           Plugin ID, e.g. `w.org/plugins/[plugin-name]`.
    421      *     @type string   $slug         Plugin slug.
    422      *     @type string   $plugin       Plugin basename.
    423      *     @type string   $new_version  New plugin version.
    424      *     @type string   $url          Plugin URL.
    425      *     @type string   $package      Plugin update package URL.
    426      *     @type string[] $icons        An array of plugin icon URLs.
    427      *     @type string[] $banners      An array of plugin banner URLs.
    428      *     @type string[] $banners_rtl  An array of plugin RTL banner URLs.
    429      *     @type string   $requires     The version of WordPress which the plugin requires.
    430      *     @type string   $tested       The version of WordPress the plugin is tested against.
    431      *     @type string   $requires_php The version of PHP which the plugin requires.
    432      * }
    433      */
    434     private function create_update_response_object( $args = array() ) {
    435         $defaults = array(
    436             'id'           => '0',
    437             'slug'         => 'woocommerce-pos-pro',
    438             'plugin'       => $this->pro_plugin_path,
    439             'url'          => 'https://wcpos.com/pro',
    440             'requires'     => '5.6',
    441             'tested'       => '6.5',
    442             'requires_php' => '7.4',
    443             'icons' => array(
    444                 '1x' => 'https://wcpos.com/wp-content/uploads/2014/06/woopos-pro.png',
    445             ),
    446         );
    447 
    448         $parsed_args = wp_parse_args( $args, $defaults );
    449 
    450         $update_obj = new \stdClass();
    451         foreach ( $parsed_args as $key => $value ) {
    452             $update_obj->$key = $value;
    453         }
    454 
    455         return $update_obj;
     356        if ( ! isset( $decoded_response['data'] ) ) {
     357            return array(
     358                'is_error' => true,
     359                'code' => 'invalid_response_structure',
     360                'message' => 'Missing expected property: data',
     361            );
     362        }
     363
     364        return $decoded_response['data'];
    456365    }
    457366
     
    465374        if ( $options['action'] == 'update' && $options['type'] == 'plugin' ) {
    466375            if ( isset( $options['plugins'] ) && in_array( 'woocommerce-pos/woocommerce-pos.php', $options['plugins'] ) ) {
    467                 delete_transient( $this->update_data_transient_key );
    468                 $this->check_pro_plugin_updates();
     376                delete_transient( self::$update_data_transient_key );
    469377            }
    470378        }
     
    520428     */
    521429    public function plugin_row_meta( $plugin_meta, $plugin_file, $plugin_data, $status ) {
    522         if ( $plugin_file !== $this->pro_plugin_path ) {
    523             return $plugin_meta;
    524         }
    525 
    526430        // $license_status = 'Your license status here'; // Fetch or generate your license status message
    527431        // $plugin_meta[] = '<span style="color: #d63638;">' . esc_html( $license_status ) . '</span>';
     
    560464     */
    561465    public function plugin_update_message( $plugin_data, $response ) {
    562         if ( $response->plugin !== $this->pro_plugin_path ) {
    563             return;
    564         }
    565 
    566         $license_status = $this->check_license_status();
    567         if ( ! is_wp_error( $license_status ) ) {
    568             return;
    569         }
    570 
    571         $message = 'Your license has expired. <a href="http://wcpos.com/my-account/">Please renew</> to update.';
    572 
    573         if ( $license_status->get_error_code() === 'missing_license_key' ) {
    574             $message = $license_status->get_error_message();
    575         }
    576 
    577         echo '<br /><span style="color: #d63638;">' . wp_kses_post( $message ) . '</span>';
     466        // Nothing at the moment.
     467
     468        // $message = 'Your license has expired. <a href="http://wcpos.com/my-account/">Please renew</> to update.';
     469
     470        // if ( $license_status->get_error_code() === 'missing_license_key' ) {
     471        // $message = $license_status->get_error_message();
     472        // }
     473
     474        // echo '<br /><span style="color: #d63638;">' . wp_kses_post( $message ) . '</span>';
    578475    }
    579476
     
    588485        }
    589486
    590         $update_data = get_transient( $this->update_data_transient_key );
    591         $message = 'Something went wrong. Please try again later.';
     487        $update_data = get_transient( self::$update_data_transient_key );
     488        $message = esc_html__( 'Something went wrong. Please try again later.', 'woocommerce-pos' );
    592489
    593490        if ( is_wp_error( $update_data ) ) {
     
    600497        }
    601498
     499        /* translators: WordPress */
    602500        iframe_header( __( 'Plugin Installation' ) );
    603501
     
    640538    private function maybe_add_upgrade_notice() {
    641539        $license_status = $this->check_license_status();
    642         if ( ! is_wp_error( $license_status ) ) {
     540        $active = isset( $license_status['activated'] ) && $license_status['activated'];
     541        $inactive = isset( $license_status['activated'] ) && ! $license_status['activated'];
     542        $expired = isset( $license_status['expired'] ) && $license_status['expired'];
     543
     544        if ( isset( $license_status['is_error'] ) && $license_status['is_error'] ) {
     545            $inactive = isset( $license_status['code'] ) &&
     546                in_array(
     547                    $license_status['code'],
     548                    array(
     549                        'missing_license_key', // no license key is set.
     550                        'invalid_response_code', // usually the key or instance is wrong length.
     551                    )
     552                );
     553        }
     554
     555        if ( $inactive ) {
     556            return esc_html__( 'Your WooCommerce Pro license is inactive', 'woocommerce-pos' );
     557        }
     558
     559        if ( $expired ) {
     560            return esc_html__( 'Your WooCommerce Pro license has expired', 'woocommerce-pos' );
     561        }
     562
     563        if ( isset( $license_status['is_error'] ) && $license_status['is_error'] ) {
     564            return $license_status['message'];
     565        }
     566    }
     567
     568    /**
     569     * Add a notice to the plugin update table on Dashboard > Updates
     570     */
     571    public function license_status_notice() {
     572        $license_status = $this->check_license_status();
     573        $active = isset( $license_status['activated'] ) && $license_status['activated'];
     574        $inactive = isset( $license_status['activated'] ) && ! $license_status['activated'];
     575        $expired = isset( $license_status['expired'] ) && $license_status['expired'];
     576
     577        if ( isset( $license_status['is_error'] ) && $license_status['is_error'] ) {
     578            $inactive = isset( $license_status['code'] ) &&
     579                in_array(
     580                    $license_status['code'],
     581                    array(
     582                        'missing_license_key', // no license key is set.
     583                        'invalid_response_code', // usually the key or instance is wrong length.
     584                    )
     585                );
     586        }
     587
     588        if ( $active ) {
     589            echo '<tr class="plugin-update-tr installer-plugin-update-tr woocommerce-pos-pro-license">
     590                <td colspan="4" class="plugin-update colspanchange">
     591                    <div class="update-message notice inline wcpos-active" style="margin:0;border:0;border-bottom:1px solid #DCDCDE;border-left:4px solid #5D9B5C;background-color:#F8FFF1;">
     592                        <p class="installer-q-icon">' .
     593                        esc_html__( 'Your WooCommerce Pro license is valid and active.', 'woocommerce-pos' ) .
     594                        ' ' .
     595                        esc_html__( 'You are receiving plugin updates.', 'woocommerce-pos' )
     596                        . '</p>
     597                    </div>
     598                </td>
     599            </tr>';
    643600            return;
    644601        }
    645602
    646         if ( $license_status->get_error_code() === 'missing_license_key' ) {
    647             return $license_status->get_error_message();
    648         }
    649 
    650         return 'Your license has expired. Please renew to update.';
     603        if ( $inactive ) {
     604            echo '<tr class="plugin-update-tr installer-plugin-update-tr woocommerce-pos-pro-license">
     605                <td colspan="4" class="plugin-update colspanchange">
     606                    <div class="update-message notice inline wcpos-inactive" style="margin:0;border:0;border-bottom:1px solid #DCDCDE;border-left:4px solid #BD5858;background-color:#FFF8E1;">
     607                        <p class="installer-q-icon">' .
     608                        esc_html__( 'Your WooCommerce Pro license is inactive.', 'woocommerce-pos' ) .
     609                        ' ' .
     610                        sprintf(
     611                            wp_kses(
     612                                __( '<a href="%s">Click here</a> to activate your license key.', 'woocommerce-pos' ),
     613                                array( 'a' => array( 'href' => array() ) )
     614                            ),
     615                            esc_url( admin_url( 'admin.php?page=woocommerce-pos-settings#license' ) )
     616                        )
     617                        . '</p>
     618                    </div>
     619                </td>
     620            </tr>';
     621            return;
     622        }
     623
     624        if ( $expired ) {
     625            echo '<tr class="plugin-update-tr installer-plugin-update-tr woocommerce-pos-pro-license">
     626                <td colspan="4" class="plugin-update colspanchange">
     627                    <div class="update-message notice inline wcpos-expired" style="margin:0;border:0;border-bottom:1px solid #DCDCDE;border-left:4px solid #D63638;background-color:#FFF7F7;">
     628                        <p class="installer-q-icon">' .
     629                        esc_html__( 'Your WooCommerce Pro license has expired.', 'woocommerce-pos' ) .
     630                        ' ' .
     631                        sprintf(
     632                            wp_kses(
     633                                __( '<a href="%s">Please renew</a> to receive updates.', 'woocommerce-pos' ),
     634                                array( 'a' => array( 'href' => array() ) )
     635                            ),
     636                            'https://wcpos.com/my-account/'
     637                        )
     638                        . '</p>
     639                    </div>
     640                </td>
     641            </tr>';
     642            return;
     643        }
     644
     645        $message = esc_html__( 'Something went wrong. Please try again later.', 'woocommerce-pos' );
     646        if ( isset( $license_status['is_error'] ) && $license_status['is_error'] ) {
     647            $message = $license_status['message'];
     648        }
     649        echo '<tr class="plugin-update-tr installer-plugin-update-tr woocommerce-pos-pro-license">
     650            <td colspan="4" class="plugin-update colspanchange">
     651                <div class="update-message notice inline wcpos-expired" style="margin:0;border:0;border-bottom:1px solid #DCDCDE;border-left:4px solid #D63638;background-color:#FFF7F7;">
     652                    <p class="installer-q-icon">' . $message . '</p>
     653                </div>
     654            </td>
     655        </tr>';
     656    }
     657
     658    /**
     659     * Add some styles for the license status notice
     660     *
     661     * @param string $hook The current admin page.
     662     */
     663    public function license_status_styles( $hook ) {
     664        if ( 'plugins.php' === $hook ) {
     665            wp_register_style( 'woocommerce-pos-styles', false );
     666            wp_enqueue_style( 'woocommerce-pos-styles' );
     667
     668            $css = '
     669                .woocommerce-pos-pro-license .wcpos-active p::before {
     670                    content: "\f12a";
     671                color: #4d7d4c;
     672                width: 25px;
     673                }
     674                .woocommerce-pos-pro-license .wcpos-inactive p::before {
     675                    content: "\f112";
     676                    color: #bd5858;
     677                    width: 25px;
     678                }
     679                .woocommerce-pos-pro-license .wcpos-expired p::before {
     680                    width: 25px;
     681                }
     682            ';
     683            wp_add_inline_style( 'woocommerce-pos-styles', $css );
     684        }
    651685    }
    652686
     
    657691     */
    658692    private function get_license_settings() {
    659         if ( ! $this->active ) {
    660             if ( file_exists( WP_PLUGIN_DIR . '/woocommerce-pos-pro/includes/Services/Settings.php' ) ) {
    661                 include_once WP_PLUGIN_DIR . '/woocommerce-pos-pro/includes/Services/Settings.php';
    662                 if ( method_exists( '\WCPOS\WooCommercePOSPro\Services\Settings', '_get_inactive_license_settings' ) ) {
    663                     return \WCPOS\WooCommercePOSPro\Services\Settings::_get_inactive_license_settings();
    664                 }
    665             }
    666         }
    667         return woocommerce_pos_get_settings( 'license' );
     693        // first check if any Pro plugins are active.
     694        foreach ( $this->installed_pro_plugins as $plugin_path => $plugin_data ) {
     695            if ( is_plugin_active( $plugin_path ) ) {
     696                return woocommerce_pos_get_settings( 'license' );
     697            }
     698        }
     699
     700        // else, try and get the settings from the first Pro plugin.
     701        $first_folder = dirname( array_key_first( $this->installed_pro_plugins ) );
     702        if ( file_exists( WP_PLUGIN_DIR . '/' . $first_folder . '/includes/Services/Settings.php' ) ) {
     703            include_once WP_PLUGIN_DIR . '/' . $first_folder . '/includes/Services/Settings.php';
     704            if ( method_exists( '\WCPOS\WooCommercePOSPro\Services\Settings', '_get_inactive_license_settings' ) ) {
     705                return \WCPOS\WooCommercePOSPro\Services\Settings::_get_inactive_license_settings();
     706            }
     707        }
     708    }
     709
     710    /**
     711     * Temporary fix for older versions of the Pro plugin
     712     *
     713     * @param string $plugin_path The plugin path.
     714     */
     715    private function remove_this_hack_for_older_versions( $plugin_path ) {
     716        // Manually the update_plugins transient
     717        $update_plugins = get_site_transient( 'update_plugins' );
     718        if ( ! is_object( $update_plugins ) ) {
     719                $update_plugins = new stdClass();
     720                $update_plugins->response = array();
     721        }
     722
     723        $license_settings = $this->get_license_settings();
     724        $key = isset( $license_settings['key'] ) ? $license_settings['key'] : '';
     725        $instance = isset( $license_settings['instance'] ) ? $license_settings['instance'] : '';
     726
     727        // Construct the download URL, taking into account the environment.
     728        $package_url = add_query_arg(
     729            array(
     730                'key' => urlencode( $key ),
     731                'instance' => urlencode( $instance ),
     732            ),
     733            'https://updates.wcpos.com/pro/download/1.4.5'
     734        );
     735
     736        $update = array(
     737            'id'             => 'https://updates.wcpos.com',
     738            'slug'           => 'woocommerce-pos-pro',
     739            'plugin'         => $plugin_path,
     740            'new_version'    => '1.4.5',
     741            'url'            => 'https://wcpos.com/pro',
     742            'package'        => $package_url,
     743            'requires'       => '5.6',
     744            'tested'         => '6.5',
     745            'requires_php'   => '7.4',
     746            'icons'          => array(
     747                '1x' => 'https://wcpos.com/wp-content/uploads/2014/06/woopos-pro.png',
     748            ),
     749            'upgrade_notice' => $this->maybe_add_upgrade_notice(),
     750        );
     751
     752        $update_plugins->response[ $plugin_path ] = (object) $update;
     753
     754        set_site_transient( 'update_plugins', $update_plugins );
    668755    }
    669756}
  • woocommerce-pos/trunk/includes/Admin/templates/upgrade.php

    r2845568 r3053833  
    55 * @author    Paul Kilmurray <paul@kilbot.com.au>
    66 *
    7  * @see      http://www.kilbot.com.au
     7 * @see      http://www.kilbot.com
    88 */
    99?>
    1010
    11 <!-- temporary inline css, todo: remove this -->
    12 <style type="text/css">
    13     .web-title {
    14         display: none;
    15     }
     11<div class="wrap clear">
    1612
    17     .blurb {
    18         font-size: 14px;
    19         line-height: 1.6em;
    20     }
    21 
    22     .widget-area {
    23         float: right;
    24         width: 33%;
    25         margin-left: 20px;
    26         text-align: center;
    27         margin-bottom: 20px;
    28     }
    29 
    30     .widget-area .btn {
    31         display: inline-block;
    32         margin-bottom: 0;
    33         font-weight: 400;
    34         text-align: center;
    35         vertical-align: middle;
    36         cursor: pointer;
    37         background-image: none;
    38         border: 1px solid transparent;
    39         white-space: nowrap;
    40         text-decoration: none;
    41         margin: 20px 0;
    42     }
    43 
    44     .widget-area .btn-primary {
    45         color: #fff;
    46         background-color: #cd2f19;
    47         border-color: #b62a16;
    48     }
    49 
    50     .widget-area .btn-lg {
    51         padding: 10px 16px;
    52         font-size: 18px;
    53         line-height: 1.33;
    54         border-radius: 6px;
    55     }
    56 
    57     .comparison-table {
    58         width: 100%;
    59         border-spacing: 0;
    60         border-collapse: collapse;
    61         border: 1px solid #e5e5e5;
    62         box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
    63         background-color: #f5f5f5;
    64     }
    65 
    66     .comparison-table thead {
    67         font-size: 18px;
    68     }
    69 
    70     .comparison-table thead tr {
    71         border-bottom: 1px solid #e5e5e5;
    72     }
    73 
    74     .comparison-table thead th {
    75         width: 33%;
    76         font-weight: normal;
    77     }
    78 
    79     .comparison-table thead th:first-of-type {
    80         background-color: #B0B0B0;
    81         color: #f5f5f5;
    82     }
    83 
    84     .comparison-table thead th:last-of-type {
    85         background-color: #d54e21;
    86         color: #f5f5f5;
    87     }
    88 
    89     .comparison-table th, td {
    90         padding: 1% 2%;
    91     }
    92 
    93     .comparison-table tbody th {
    94         font-weight: normal;
    95         text-align: right;
    96     }
    97 
    98     .comparison-table tbody tr {
    99         border-bottom: 1px solid #e5e5e5;
    100     }
    101 
    102     .comparison-table tbody tr td:first-of-type {
    103         background-color: #fafafa;
    104     }
    105 
    106     .comparison-table tbody tr td:last-of-type {
    107         background-color: #fef7f1;
    108     }
    109 
    110     .comparison-table .fa {
    111         font-family: Dashicons !important;;
    112         speak: none;
    113         font-style: normal;
    114         font-weight: normal;
    115         font-variant: normal;
    116         text-transform: none;
    117         -webkit-font-smoothing: antialiased;
    118         -moz-osx-font-smoothing: grayscale;
    119     }
    120 
    121     .comparison-table .fa-check:before {
    122         content: "\f147";
    123         color: #3c763d;
    124         font-size: 24px;
    125     }
    126 
    127     .comparison-table .fa-times:before {
    128         content: "\f335";
    129         color: #a94442;
    130         font-size: 24px;
    131     }
    132 </style>
    133 
    134 <div class="wrap clear woocommerce-pos-upgrade">
    135 
    136     <!--
     13    <!--
    13714    Little trick to get around WP js injection of admin notices
    13815    WP js looks for first h2 in .wrap and appends notices, so we'll make the first one hidden
    13916    https://github.com/WordPress/WordPress/blob/master/wp-admin/js/common.js
    14017    -->
    141     <h2 style="display:none"></h2>
     18    <h2 style="display:none"></h2>
    14219
    143     <h2 style="margin:20px 0;">Thank you for using WooCommerce POS!</h2>
    144 
    145     <?php echo $upgrade; ?>
     20    <div id="woocommerce-pos-upgrade"></div>
    14621
    14722</div>
    148 
  • woocommerce-pos/trunk/includes/Form_Handler.php

    r2929317 r3053833  
    11<?php
     2/**
     3 *
     4 */
    25
    36namespace WCPOS\WooCommercePOS;
    47
     8use WCPOS\WooCommercePOS\Services\Auth as AuthService;
     9
     10/**
     11 *
     12 */
    513class Form_Handler {
    614
     
    2836        global $wp;
    2937
    30         if ( woocommerce_pos_request() && isset( $_POST['woocommerce_pay'], $_GET['key'] ) ) {
     38        if ( woocommerce_pos_request() && isset( $_POST['woocommerce_pay'], $_GET['key'], $_GET['token'] ) ) {
    3139            $order_id  = absint( $wp->query_vars['order-pay'] );
    3240            $order     = wc_get_order( $order_id );
    3341
    34             // set customer
     42            // Ensure the order exists.
     43            if ( ! $order ) {
     44                wp_die(
     45                    esc_html__( 'Order does not exist.', 'woocommerce-pos' ),
     46                    esc_html__( 'Error', 'woocommerce-pos' ),
     47                    array( 'response' => 403 )
     48                );
     49            }
     50
     51            // Verify the order key matches the key provided in the URL.
     52            $provided_key = sanitize_text_field( wp_unslash( $_GET['key'] ) );
     53            if ( $provided_key !== $order->get_order_key() ) {
     54                wp_die(
     55                    esc_html__( 'Order key mismatch.', 'woocommerce-pos' ),
     56                    esc_html__( 'Error', 'woocommerce-pos' ),
     57                    array( 'response' => 403 )
     58                );
     59            }
     60
     61            // Verify the cashier is authorized to access the order.
     62            $provided_token = sanitize_text_field( wp_unslash( $_GET['token'] ) );
     63            $auth = AuthService::instance();
     64            $user = $auth->validate_token( $provided_token );
     65            if ( is_wp_error( $user ) ) {
     66                wp_die(
     67                    esc_html__( 'Cashier token mismatch.', 'woocommerce-pos' ),
     68                    esc_html__( 'Error', 'woocommerce-pos' ),
     69                    array( 'response' => 403 )
     70                );
     71            }
     72
     73            // set customer.
    3574            wp_set_current_user( $order->get_customer_id() );
    3675        }
    37 
    3876    }
    3977
     
    71109        }
    72110    }
    73 
    74111}
  • woocommerce-pos/trunk/includes/Services/Settings.php

    r3048280 r3053833  
    44
    55use WC_Payment_Gateways;
     6use WP_Error;
    67use const WCPOS\WooCommercePOS\VERSION;
    7 use WP_Error;
    88
    99/**
     
    162162
    163163    /**
    164      * @param string $id
    165      * @param array  $settings
    166      *
    167      * @return null|array|mixed|WP_Error
     164     * Saves settings for a specific section.
     165     *
     166     * @param string $id The ID of the settings section being saved.
     167     * @param array  $settings The settings array to be saved.
     168     *
     169     * @return array|WP_Error Returns the updated settings array on success or WP_Error on failure.
    168170     */
    169171    public function save_settings( string $id, array $settings ) {
    170         $success = update_option(
    171             static::$db_prefix . $id,
    172             array_merge(
    173                 $settings,
    174                 array( 'date_modified_gmt' => current_time( 'mysql', true ) )
    175             ),
    176             false
    177         );
     172        $settings = array_merge(
     173            $settings,
     174            array( 'date_modified_gmt' => current_time( 'mysql', true ) )
     175        );
     176
     177        /**
     178         * Filters the settings before they are saved.
     179         *
     180         * Allows modification of the settings array for a specific section before it is saved to the database.
     181         *
     182         * @since 1.4.12
     183         *
     184         * @param array  $settings The settings array about to be saved.
     185         * @param string $id       The ID of the settings section being saved.
     186         */
     187        $settings = apply_filters( "woocommerce_pos_pre_save_{$id}_settings", $settings, $id );
     188
     189        $success = update_option( static::$db_prefix . $id, $settings, false );
    178190
    179191        if ( $success ) {
    180             return $this->get_settings( $id );
     192            $saved_settings = $this->get_settings( $id );
     193
     194            /**
     195             * Fires after settings for a specific section are successfully saved.
     196             *
     197             * Provides a way to execute additional logic after a specific settings section is updated.
     198             *
     199             * @since 1.4.12
     200             *
     201             * @param array  $saved_settings The settings array that was just saved.
     202             * @param string $id             The ID of the settings section that was saved.
     203             */
     204            do_action( "woocommerce_pos_saved_{$id}_settings", $saved_settings, $id );
     205
     206            return $saved_settings;
    181207        }
    182208
  • woocommerce-pos/trunk/readme.txt

    r3048280 r3053833  
    22Contributors: kilbot
    33Tags: cart, e-commerce, ecommerce, inventory, point-of-sale, pos, sales, sell, shop, shopify, store, vend, woocommerce, wordpress-ecommerce
    4 Requires at least: 5.6 & WooCommerce 5.3
    5 Tested up to: 6.4
    6 Stable tag: 1.4.11
     4Requires at least: 5.6
     5Tested up to: 6.5
     6Stable tag: 1.4.12
    77License: GPL-3.0
    88License URI: http://www.gnu.org/licenses/gpl-3.0.html
     
    6363
    6464== Changelog ==
     65
     66= 1.4.12 - 2024/03/18 =
     67* Security: Fix Insufficient Verification of Data Authenticity to Authenticated (Customer+) Information Disclosure (reported by Lucio Sá)
     68* Fix: Pro plugin not showing updates for some users
    6569
    6670= 1.4.11 - 2024/03/09 =
  • woocommerce-pos/trunk/vendor/autoload.php

    r3048280 r3053833  
    2323require_once __DIR__ . '/composer/autoload_real.php';
    2424
    25 return ComposerAutoloaderInitd5f742ecdf534f147f5b8e2724165a2d::getLoader();
     25return ComposerAutoloaderInit4381cd7e2816c049c0c912563977ae98::getLoader();
  • woocommerce-pos/trunk/vendor/composer/autoload_real.php

    r3048280 r3053833  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInitd5f742ecdf534f147f5b8e2724165a2d
     5class ComposerAutoloaderInit4381cd7e2816c049c0c912563977ae98
    66{
    77    private static $loader;
     
    2323        }
    2424
    25         spl_autoload_register(array('ComposerAutoloaderInitd5f742ecdf534f147f5b8e2724165a2d', 'loadClassLoader'), true, true);
     25        spl_autoload_register(array('ComposerAutoloaderInit4381cd7e2816c049c0c912563977ae98', 'loadClassLoader'), true, true);
    2626        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
    27         spl_autoload_unregister(array('ComposerAutoloaderInitd5f742ecdf534f147f5b8e2724165a2d', 'loadClassLoader'));
     27        spl_autoload_unregister(array('ComposerAutoloaderInit4381cd7e2816c049c0c912563977ae98', 'loadClassLoader'));
    2828
    2929        require __DIR__ . '/autoload_static.php';
    30         call_user_func(\Composer\Autoload\ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::getInitializer($loader));
     30        call_user_func(\Composer\Autoload\ComposerStaticInit4381cd7e2816c049c0c912563977ae98::getInitializer($loader));
    3131
    3232        $loader->register(true);
    3333
    34         $filesToLoad = \Composer\Autoload\ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::$files;
     34        $filesToLoad = \Composer\Autoload\ComposerStaticInit4381cd7e2816c049c0c912563977ae98::$files;
    3535        $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
    3636            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
  • woocommerce-pos/trunk/vendor/composer/autoload_static.php

    r3048280 r3053833  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d
     7class ComposerStaticInit4381cd7e2816c049c0c912563977ae98
    88{
    99    public static $files = array (
     
    330330    {
    331331        return \Closure::bind(function () use ($loader) {
    332             $loader->prefixLengthsPsr4 = ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::$prefixLengthsPsr4;
    333             $loader->prefixDirsPsr4 = ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::$prefixDirsPsr4;
    334             $loader->prefixesPsr0 = ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::$prefixesPsr0;
    335             $loader->classMap = ComposerStaticInitd5f742ecdf534f147f5b8e2724165a2d::$classMap;
     332            $loader->prefixLengthsPsr4 = ComposerStaticInit4381cd7e2816c049c0c912563977ae98::$prefixLengthsPsr4;
     333            $loader->prefixDirsPsr4 = ComposerStaticInit4381cd7e2816c049c0c912563977ae98::$prefixDirsPsr4;
     334            $loader->prefixesPsr0 = ComposerStaticInit4381cd7e2816c049c0c912563977ae98::$prefixesPsr0;
     335            $loader->classMap = ComposerStaticInit4381cd7e2816c049c0c912563977ae98::$classMap;
    336336
    337337        }, null, ClassLoader::class);
  • woocommerce-pos/trunk/vendor/composer/installed.php

    r3048280 r3053833  
    22    'root' => array(
    33        'name' => 'wcpos/woocommerce-pos',
    4         'pretty_version' => 'v1.4.11',
    5         'version' => '1.4.11.0',
    6         'reference' => '49a47c823e48eb87ba9a51d7253bcf1d7c05a496',
     4        'pretty_version' => 'v1.4.12',
     5        'version' => '1.4.12.0',
     6        'reference' => '8e655c54f31968b7da74a7f5a1464c958a0147ed',
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../',
     
    9090        ),
    9191        'wcpos/woocommerce-pos' => array(
    92             'pretty_version' => 'v1.4.11',
    93             'version' => '1.4.11.0',
    94             'reference' => '49a47c823e48eb87ba9a51d7253bcf1d7c05a496',
     92            'pretty_version' => 'v1.4.12',
     93            'version' => '1.4.12.0',
     94            'reference' => '8e655c54f31968b7da74a7f5a1464c958a0147ed',
    9595            'type' => 'wordpress-plugin',
    9696            'install_path' => __DIR__ . '/../../',
  • woocommerce-pos/trunk/woocommerce-pos.php

    r3048280 r3053833  
    44 * Plugin URI:        https://wordpress.org/plugins/woocommerce-pos/
    55 * Description:       A simple front-end for taking WooCommerce orders at the Point of Sale. Requires <a href="http://wordpress.org/plugins/woocommerce/">WooCommerce</a>.
    6  * Version:           1.4.11
     6 * Version:           1.4.12
    77 * Author:            kilbot
    88 * Author URI:        http://wcpos.com
     
    1111 * License URI:       http://www.gnu.org/licenses/gpl-3.0.txt
    1212 * Domain Path:       /languages
     13 * Requires at least: 5.6
     14 * Requires PHP:      7.4
     15 * Requires Plugins:  woocommerce
     16 * Tested up to:      6.5
    1317 * WC tested up to:   8.6
    14  * WC requires at least: 5.3.
     18 * WC requires at least: 5.3
    1519 *
    1620 * @author    Paul Kilmurray <paul@kilbot.com>
     
    2327
    2428// Define plugin constants.
    25 const VERSION     = '1.4.11';
     29const VERSION     = '1.4.12';
    2630const PLUGIN_NAME = 'woocommerce-pos';
    2731const SHORT_NAME  = 'wcpos';
Note: See TracChangeset for help on using the changeset viewer.