* @param LegacyDataCleanup $data_cleanup The legacy data cleanup instance to use. * @param OrdersTableRefundDataStore $refund_data_store The refund data store to use. * @param BatchProcessingController $batch_processing_controller The batch processing controller to use. * @param FeaturesController $features_controller The features controller instance to use. * @param OrderCache $order_cache The order cache engine to use. * @param OrderCacheController $order_cache_controller The order cache controller to use. * @param PluginUtil $plugin_util The plugin util to use. */ final public function init( OrdersTableDataStore $data_store, DataSynchronizer $data_synchronizer, LegacyDataCleanup $data_cleanup, OrdersTableRefundDataStore $refund_data_store, BatchProcessingController $batch_processing_controller, FeaturesController $features_controller, OrderCache $order_cache, OrderCacheController $order_cache_controller, PluginUtil $plugin_util ) { $this->data_store = $data_store; $this->data_synchronizer = $data_synchronizer; $this->data_cleanup = $data_cleanup; $this->batch_processing_controller = $batch_processing_controller; $this->refund_data_store = $refund_data_store; $this->features_controller = $features_controller; $this->order_cache = $order_cache; $this->order_cache_controller = $order_cache_controller; $this->plugin_util = $plugin_util; } /** * Is the custom orders table usage enabled via settings? * This can be true only if the feature is enabled and a table regeneration has been completed. * * @return bool True if the custom orders table usage is enabled */ public function custom_orders_table_usage_is_enabled(): bool { return get_option( self::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION ) === 'yes'; } /** * Gets the instance of the orders data store to use. * * @param \WC_Object_Data_Store_Interface|string $default_data_store The default data store (as received via the woocommerce_order_data_store hook). * * @return \WC_Object_Data_Store_Interface|string The actual data store to use. */ private function get_orders_data_store( $default_data_store ) { return $this->get_data_store_instance( $default_data_store, 'order' ); } /** * Gets the instance of the refunds data store to use. * * @param \WC_Object_Data_Store_Interface|string $default_data_store The default data store (as received via the woocommerce_order-refund_data_store hook). * * @return \WC_Object_Data_Store_Interface|string The actual data store to use. */ private function get_refunds_data_store( $default_data_store ) { return $this->get_data_store_instance( $default_data_store, 'order_refund' ); } /** * Gets the instance of a given data store. * * @param \WC_Object_Data_Store_Interface|string $default_data_store The default data store (as received via the appropriate hooks). * @param string $type The type of the data store to get. * * @return \WC_Object_Data_Store_Interface|string The actual data store to use. */ private function get_data_store_instance( $default_data_store, string $type ) { if ( $this->custom_orders_table_usage_is_enabled() ) { switch ( $type ) { case 'order_refund': return $this->refund_data_store; default: return $this->data_store; } } else { return $default_data_store; } } /** * Add an entry to Status - Tools to create or regenerate the custom orders table, * and also an entry to delete the table as appropriate. * * @param array $tools_array The array of tools to add the tool to. * @return array The updated array of tools- */ private function add_hpos_tools( array $tools_array ): array { if ( ! $this->data_synchronizer->check_orders_table_exists() ) { return $tools_array; } // Cleanup tool. $tools_array = array_merge( $tools_array, $this->data_cleanup->get_tools_entries() ); // Delete HPOS tables tool. if ( $this->custom_orders_table_usage_is_enabled() || $this->data_synchronizer->data_sync_is_enabled() ) { $disabled = true; $message = __( 'This will delete the custom orders tables. The tables can be deleted only if the "High-Performance order storage" is not authoritative and sync is disabled (via Settings > Advanced > Features).', 'woocommerce' ); } else { $disabled = false; $message = __( 'This will delete the custom orders tables. To create them again enable the "High-Performance order storage" feature (via Settings > Advanced > Features).', 'woocommerce' ); } $tools_array['delete_custom_orders_table'] = array( 'name' => __( 'Delete the custom orders tables', 'woocommerce' ), 'desc' => sprintf( '%1$s %2$s', __( 'Note:', 'woocommerce' ), $message ), 'requires_refresh' => true, 'callback' => function () { $this->features_controller->change_feature_enable( self::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION, false ); $this->delete_custom_orders_tables(); return __( 'Custom orders tables have been deleted.', 'woocommerce' ); }, 'button' => __( 'Delete', 'woocommerce' ), 'disabled' => $disabled, ); return $tools_array; } /** * Delete the custom orders tables and any related options and data in response to the user pressing the tool button. * * @throws \Exception Can't delete the tables. */ private function delete_custom_orders_tables() { if ( $this->custom_orders_table_usage_is_enabled() ) { throw new \Exception( "Can't delete the custom orders tables: they are currently in use (via Settings > Advanced > Features)." ); } delete_option( self::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION ); $this->data_synchronizer->delete_database_tables(); } /** * Handler for the individual setting updated hook. * * @param string $option Setting name. * @param mixed $old_value Old value of the setting. * @param mixed $value New value of the setting. */ private function process_updated_option( $option, $old_value, $value ) { if ( DataSynchronizer::ORDERS_DATA_SYNC_ENABLED_OPTION === $option && 'no' === $value ) { $this->data_synchronizer->cleanup_synchronization_state(); } } /** * Handler for the setting pre-update hook. * We use it to verify that authoritative orders table switch doesn't happen while sync is pending. * * @param mixed $value New value of the setting. * @param string $option Setting name. * @param mixed $old_value Old value of the setting. * * @throws \Exception Attempt to change the authoritative orders table while orders sync is pending. */ private function process_pre_update_option( $value, $option, $old_value ) { if ( DataSynchronizer::ORDERS_DATA_SYNC_ENABLED_OPTION === $option && $value !== $old_value ) { $this->order_cache->flush(); return $value; } if ( self::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION !== $option ) { return $value; } if ( $old_value === $value ) { return $value; } $this->order_cache->flush(); if ( ! $this->data_synchronizer->check_orders_table_exists() ) { $this->data_synchronizer->create_database_tables(); } $tables_created = get_option( DataSynchronizer::ORDERS_TABLE_CREATED ) === 'yes'; if ( ! $tables_created ) { return 'no'; } $sync_is_pending = 0 !== $this->data_synchronizer->get_current_orders_pending_sync_count(); if ( $sync_is_pending && ! $this->changing_data_source_with_sync_pending_is_allowed() ) { throw new \Exception( "The authoritative table for orders storage can't be changed while there are orders out of sync" ); } return $value; } /** * Callback to trigger a sync immediately by clicking a button on the Features screen. * * @return void */ private function sync_now() { $section = filter_input( INPUT_GET, 'section' ); if ( 'features' !== $section ) { return; } if ( ! filter_input( INPUT_GET, self::SYNC_QUERY_ARG, FILTER_VALIDATE_BOOLEAN ) ) { return; } if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ?? '' ) ), 'hpos-sync-now' ) ) { WC_Admin_Settings::add_error( esc_html__( 'Unable to start synchronization. The link you followed may have expired.', 'woocommerce' ) ); return; } $this->data_cleanup->toggle_flag( false ); $this->batch_processing_controller->enqueue_processor( DataSynchronizer::class ); } /** * Tell WP Admin to remove the sync query arg from the URL. * * @param array $query_args The query args that are removable. * * @return array */ private function register_removable_query_arg( $query_args ) { $query_args[] = self::SYNC_QUERY_ARG; return $query_args; } /** * Handler for the woocommerce_after_register_post_type post, * registers the post type for placeholder orders. * * @return void */ private function register_post_type_for_order_placeholders(): void { wc_register_order_type( DataSynchronizer::PLACEHOLDER_ORDER_POST_TYPE, array( 'public' => false, 'exclude_from_search' => true, 'publicly_queryable' => false, 'show_ui' => false, 'show_in_menu' => false, 'show_in_nav_menus' => false, 'show_in_admin_bar' => false, 'show_in_rest' => false, 'rewrite' => false, 'query_var' => false, 'can_export' => false, 'supports' => array(), 'capabilities' => array(), 'exclude_from_order_count' => true, 'exclude_from_order_views' => true, 'exclude_from_order_reports' => true, 'exclude_from_order_sales_reports' => true, ) ); } /** * Add the definition for the HPOS feature. * * @param FeaturesController $features_controller The instance of FeaturesController. * * @return void */ private function add_feature_definition( $features_controller ) { $definition = array( 'option_key' => self::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION, 'is_experimental' => false, 'enabled_by_default' => false, 'order' => 50, 'setting' => $this->get_hpos_setting_for_feature(), 'additional_settings' => array( $this->get_hpos_setting_for_sync(), ), ); $features_controller->add_feature_definition( 'custom_order_tables', __( 'High-Performance order storage', 'woocommerce' ), $definition ); } /** * Returns the HPOS setting for rendering HPOS vs Post setting block in Features section of the settings page. * * @return array Feature setting object. */ private function get_hpos_setting_for_feature() { if ( 'yes' === get_transient( 'wc_installing' ) ) { return array(); } $get_value = function () { return $this->custom_orders_table_usage_is_enabled() ? 'yes' : 'no'; }; /** * ⚠️The FeaturesController instance must only be accessed from within the callback functions. Otherwise it * gets called while it's still being instantiated and creates and endless loop. */ $get_desc = function () { $plugin_compatibility = $this->features_controller->get_compatible_plugins_for_feature( 'custom_order_tables', true ); return $this->plugin_util->generate_incompatible_plugin_feature_warning( 'custom_order_tables', $plugin_compatibility ); }; $get_disabled = function () { $plugin_compatibility = $this->features_controller->get_compatible_plugins_for_feature( 'custom_order_tables', true ); $sync_complete = 0 === $this->get_orders_pending_sync_count(); $disabled = array(); // Changing something here? might also want to look at `enable|disable` functions in CLIRunner. $incompatible_plugins = array_merge( $plugin_compatibility['uncertain'], $plugin_compatibility['incompatible'] ); $incompatible_plugins = array_diff( $incompatible_plugins, $this->plugin_util->get_plugins_excluded_from_compatibility_ui() ); if ( count( $incompatible_plugins ) > 0 ) { $disabled = array( 'yes' ); } if ( ! $sync_complete && ! $this->changing_data_source_with_sync_pending_is_allowed() ) { $disabled = array( 'yes', 'no' ); } return $disabled; }; return array( 'id' => self::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION, 'title' => __( 'Order data storage', 'woocommerce' ), 'type' => 'radio', 'options' => array( 'no' => __( 'WordPress posts storage (legacy)', 'woocommerce' ), 'yes' => __( 'High-performance order storage (recommended)', 'woocommerce' ), ), 'value' => $get_value, 'disabled' => $get_disabled, 'desc' => $get_desc, 'desc_at_end' => true, 'row_class' => self::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION, ); } /** * Returns the setting for rendering sync enabling setting block in Features section of the settings page. * * @return array Feature setting object. */ private function get_hpos_setting_for_sync() { if ( 'yes' === get_transient( 'wc_installing' ) ) { return array(); } $get_value = function () { return get_option( DataSynchronizer::ORDERS_DATA_SYNC_ENABLED_OPTION ); }; $get_sync_message = function () { $orders_pending_sync_count = $this->get_orders_pending_sync_count(); $sync_in_progress = $this->batch_processing_controller->is_enqueued( get_class( $this->data_synchronizer ) ); $sync_enabled = $this->data_synchronizer->data_sync_is_enabled(); $sync_is_pending = $orders_pending_sync_count > 0; $sync_message = array(); $is_dangerous = $sync_is_pending && $this->changing_data_source_with_sync_pending_is_allowed(); if ( $is_dangerous ) { $sync_message[] = wp_kses_data( sprintf( // translators: %d: number of pending orders. _n( "There's %d order pending sync. Switching data storage while sync is incomplete is dangerous and can lead to order data corruption or loss!", 'There are %d orders pending sync. Switching data storage while sync is incomplete is dangerous and can lead to order data corruption or loss!', $orders_pending_sync_count, 'woocommerce' ), $orders_pending_sync_count, ) ); } if ( ! $sync_enabled && $this->data_synchronizer->background_sync_is_enabled() ) { $sync_message[] = __( 'Background sync is enabled.', 'woocommerce' ); } if ( $sync_in_progress && $sync_is_pending ) { $sync_message[] = sprintf( // translators: %d: number of pending orders. __( 'Currently syncing orders... %d pending', 'woocommerce' ), $orders_pending_sync_count ); } elseif ( $sync_is_pending ) { $sync_now_url = wp_nonce_url( add_query_arg( array( self::SYNC_QUERY_ARG => true, ), wc_get_container()->get( FeaturesController::class )->get_features_page_url() ), 'hpos-sync-now' ); if ( ! $is_dangerous ) { $sync_message[] = wp_kses_data( sprintf( // translators: %d: number of pending orders. _n( "There's %d order pending sync. You can switch order data storage only when the posts and orders tables are in sync.", 'There are %d orders pending sync. You can switch order data storage only when the posts and orders tables are in sync.', $orders_pending_sync_count, 'woocommerce' ), $orders_pending_sync_count ) ); } $sync_message[] = sprintf( '%2$s', esc_url( $sync_now_url ), sprintf( // translators: %d: number of pending orders. _n( 'Sync %s pending order', 'Sync %s pending orders', $orders_pending_sync_count, 'woocommerce' ), number_format_i18n( $orders_pending_sync_count ) ) ); } return implode( '
', $sync_message ); }; $get_description_is_error = function () { $sync_is_pending = $this->get_orders_pending_sync_count() > 0; return $sync_is_pending && $this->changing_data_source_with_sync_pending_is_allowed(); }; return array( 'id' => DataSynchronizer::ORDERS_DATA_SYNC_ENABLED_OPTION, 'title' => '', 'type' => 'checkbox', 'desc' => __( 'Enable compatibility mode (synchronizes orders to the posts table).', 'woocommerce' ), 'value' => $get_value, 'desc_tip' => $get_sync_message, 'description_is_error' => $get_description_is_error, 'row_class' => DataSynchronizer::ORDERS_DATA_SYNC_ENABLED_OPTION, ); } /** * Returns a value indicating if changing the authoritative data source for orders while there are orders pending synchronization is allowed. * * @return bool */ private function changing_data_source_with_sync_pending_is_allowed(): bool { /** * Filter to allow changing where order data is stored, even when there are orders pending synchronization. * * DANGER! This filter is intended for usage when doing manual and automated testing in development environments only, * it should NEVER be used in production environments. Order data corruption or loss can happen! * * @param bool $allow True to allow changing order storage when there are orders pending synchronization, false to disallow. * @returns bool * * @since 8.3.0 */ return apply_filters( 'wc_allow_changing_orders_storage_while_sync_is_pending', false ); } /** * Returns the count of orders pending synchronization. * * @return int */ private function get_orders_pending_sync_count(): int { return $this->data_synchronizer->get_sync_status()['current_pending_count']; } } Water - ENVIEQ

Water level meters and data loggers, conductivity and temperature meters, water quality meters, water sampling solutions, water pumps, water and flow meters.

No products were found matching your selection.

Main Menu