lf::add_filter( 'updated_option', array( $this, 'process_updated_option' ), 999, 3 ); self::add_filter( 'added_option', array( $this, 'process_added_option' ), 999, 2 ); self::add_filter( 'deleted_option', array( $this, 'process_deleted_option' ), 999 ); self::add_action( self::BACKGROUND_SYNC_EVENT_HOOK, array( $this, 'handle_interval_background_sync' ) ); if ( self::BACKGROUND_SYNC_MODE_CONTINUOUS === $this->get_background_sync_mode() ) { self::add_action( 'shutdown', array( $this, 'handle_continuous_background_sync' ) ); } self::add_filter( 'woocommerce_feature_description_tip', array( $this, 'handle_feature_description_tip' ), 10, 3 ); } /** * Class initialization, invoked by the DI container. * * @param OrdersTableDataStore $data_store The data store to use. * @param DatabaseUtil $database_util The database util class to use. * @param PostsToOrdersMigrationController $posts_to_cot_migrator The posts to COT migration class to use. * @param LegacyProxy $legacy_proxy The legacy proxy instance to use. * @param OrderCacheController $order_cache_controller The order cache controller instance to use. * @param BatchProcessingController $batch_processing_controller The batch processing controller to use. * @internal */ final public function init( OrdersTableDataStore $data_store, DatabaseUtil $database_util, PostsToOrdersMigrationController $posts_to_cot_migrator, LegacyProxy $legacy_proxy, OrderCacheController $order_cache_controller, BatchProcessingController $batch_processing_controller ) { $this->data_store = $data_store; $this->database_util = $database_util; $this->posts_to_cot_migrator = $posts_to_cot_migrator; $this->legacy_proxy = $legacy_proxy; $this->error_logger = $legacy_proxy->call_function( 'wc_get_logger' ); $this->order_cache_controller = $order_cache_controller; $this->batch_processing_controller = $batch_processing_controller; } /** * Does the custom orders tables exist in the database? * * @return bool True if the custom orders tables exist in the database. */ public function check_orders_table_exists(): bool { $missing_tables = $this->database_util->get_missing_tables( $this->data_store->get_database_schema() ); if ( count( $missing_tables ) === 0 ) { update_option( self::ORDERS_TABLE_CREATED, 'yes' ); return true; } else { update_option( self::ORDERS_TABLE_CREATED, 'no' ); return false; } } /** * Returns the value of the orders table created option. If it's not set, then it checks the orders table and set it accordingly. * * @return bool Whether orders table exists. */ public function get_table_exists(): bool { $table_exists = get_option( self::ORDERS_TABLE_CREATED ); switch ( $table_exists ) { case 'no': case 'yes': return 'yes' === $table_exists; default: return $this->check_orders_table_exists(); } } /** * Create the custom orders database tables and log an error if that's not possible. * * @return bool True if all the tables were successfully created, false otherwise. */ public function create_database_tables() { $this->database_util->dbdelta( $this->data_store->get_database_schema() ); $success = $this->check_orders_table_exists(); if ( ! $success ) { $missing_tables = $this->database_util->get_missing_tables( $this->data_store->get_database_schema() ); $missing_tables = implode( ', ', $missing_tables ); $this->error_logger->error( "HPOS tables are missing in the database and couldn't be created. The missing tables are: $missing_tables" ); } return $success; } /** * Delete the custom orders database tables. */ public function delete_database_tables() { $table_names = $this->data_store->get_all_table_names(); foreach ( $table_names as $table_name ) { $this->database_util->drop_database_table( $table_name ); } delete_option( self::ORDERS_TABLE_CREATED ); } /** * Is the real-time data sync between old and new tables currently enabled? * * @return bool */ public function data_sync_is_enabled(): bool { return 'yes' === get_option( self::ORDERS_DATA_SYNC_ENABLED_OPTION ); } /** * Get the current background data sync mode. * * @return string */ public function get_background_sync_mode(): string { $default = $this->data_sync_is_enabled() ? self::BACKGROUND_SYNC_MODE_INTERVAL : self::BACKGROUND_SYNC_MODE_OFF; return get_option( self::BACKGROUND_SYNC_MODE_OPTION, $default ); } /** * Is the background data sync between old and new tables currently enabled? * * @return bool */ public function background_sync_is_enabled(): bool { $enabled_modes = array( self::BACKGROUND_SYNC_MODE_INTERVAL, self::BACKGROUND_SYNC_MODE_CONTINUOUS ); $mode = $this->get_background_sync_mode(); return in_array( $mode, $enabled_modes, true ); } /** * Process an option change for specific keys. * * @param string $option_key The option key. * @param string $old_value The previous value. * @param string $new_value The new value. * * @return void */ private function process_updated_option( $option_key, $old_value, $new_value ) { $sync_option_keys = array( self::ORDERS_DATA_SYNC_ENABLED_OPTION, self::BACKGROUND_SYNC_MODE_OPTION ); if ( ! in_array( $option_key, $sync_option_keys, true ) || $new_value === $old_value ) { return; } if ( self::BACKGROUND_SYNC_MODE_OPTION === $option_key ) { $mode = $new_value; } else { $mode = $this->get_background_sync_mode(); } switch ( $mode ) { case self::BACKGROUND_SYNC_MODE_INTERVAL: $this->schedule_background_sync(); break; case self::BACKGROUND_SYNC_MODE_CONTINUOUS: case self::BACKGROUND_SYNC_MODE_OFF: default: $this->unschedule_background_sync(); break; } if ( self::ORDERS_DATA_SYNC_ENABLED_OPTION === $option_key ) { if ( ! $this->check_orders_table_exists() ) { $this->create_database_tables(); } if ( $this->data_sync_is_enabled() ) { wc_get_container()->get( LegacyDataCleanup::class )->toggle_flag( false ); $this->batch_processing_controller->enqueue_processor( self::class ); } else { $this->batch_processing_controller->remove_processor( self::class ); } } } /** * Process an option change when the key didn't exist before. * * @param string $option_key The option key. * @param string $value The new value. * * @return void */ private function process_added_option( $option_key, $value ) { $this->process_updated_option( $option_key, false, $value ); } /** * Process an option deletion for specific keys. * * @param string $option_key The option key. * * @return void */ private function process_deleted_option( $option_key ) { if ( self::BACKGROUND_SYNC_MODE_OPTION !== $option_key ) { return; } $this->unschedule_background_sync(); $this->batch_processing_controller->remove_processor( self::class ); } /** * Get the time interval, in seconds, between background syncs. * * @return int */ public function get_background_sync_interval(): int { $interval = filter_var( get_option( self::BACKGROUND_SYNC_INTERVAL_OPTION, HOUR_IN_SECONDS ), FILTER_VALIDATE_INT, array( 'options' => array( 'default' => HOUR_IN_SECONDS, ), ) ); return $interval; } /** * Keys that can be ignored during synchronization or verification. * * @since 8.6.0 * * @return string[] */ public function get_ignored_order_props() { /** * Allows modifying the list of order properties that are ignored during HPOS synchronization or verification. * * @param string[] List of order properties or meta keys. * @since 8.6.0 */ $ignored_props = apply_filters( 'woocommerce_hpos_sync_ignored_order_props', array() ); $ignored_props = array_filter( array_map( 'trim', array_filter( $ignored_props, 'is_string' ) ) ); return array_merge( $ignored_props, array( '_paid_date', // This has been deprecated and replaced by '_date_paid' in the CPT datastore. '_completed_date', // This has been deprecated and replaced by '_date_completed' in the CPT datastore. EditLock::META_KEY_NAME, ) ); } /** * Schedule an event to run background sync when the mode is set to interval. * * @return void */ private function schedule_background_sync() { $interval = $this->get_background_sync_interval(); // Calling Action Scheduler directly because WC_Action_Queue doesn't support the unique parameter yet. as_schedule_recurring_action( time() + $interval, $interval, self::BACKGROUND_SYNC_EVENT_HOOK, array(), '', true ); } /** * Remove any pending background sync events. * * @return void */ private function unschedule_background_sync() { WC()->queue()->cancel_all( self::BACKGROUND_SYNC_EVENT_HOOK ); } /** * Callback to check for pending syncs and enqueue the background data sync processor when in interval mode. * * @return void */ private function handle_interval_background_sync() { if ( self::BACKGROUND_SYNC_MODE_INTERVAL !== $this->get_background_sync_mode() ) { $this->unschedule_background_sync(); return; } $pending_count = $this->get_total_pending_count(); if ( $pending_count > 0 ) { $this->batch_processing_controller->enqueue_processor( self::class ); } } /** * Callback to keep the background data sync processor enqueued when in continuous mode. * * @return void */ private function handle_continuous_background_sync() { if ( self::BACKGROUND_SYNC_MODE_CONTINUOUS !== $this->get_background_sync_mode() ) { $this->batch_processing_controller->remove_processor( self::class ); return; } // This method already checks if a processor is enqueued before adding it to avoid duplication. $this->batch_processing_controller->enqueue_processor( self::class ); } /** * Get the current sync process status. * The information is meaningful only if pending_data_sync_is_in_progress return true. * * @return array */ public function get_sync_status() { return array( 'initial_pending_count' => (int) get_option( self::INITIAL_ORDERS_PENDING_SYNC_COUNT_OPTION, 0 ), 'current_pending_count' => $this->get_total_pending_count(), ); } /** * Get the total number of orders pending synchronization. * * @return int */ public function get_current_orders_pending_sync_count_cached(): int { return $this->get_current_orders_pending_sync_count( true ); } /** * Calculate how many orders need to be synchronized currently. * A database query is performed to get how many orders match one of the following: * * - Existing in the authoritative table but not in the backup table. * - Existing in both tables, but they have a different update date. * * @param bool $use_cache Whether to use the cached value instead of fetching from database. */ public function get_current_orders_pending_sync_count( $use_cache = false ): int { global $wpdb; if ( $use_cache ) { $pending_count = wp_cache_get( 'woocommerce_hpos_pending_sync_count' ); if ( false !== $pending_count ) { return (int) $pending_count; } } $order_post_types = wc_get_order_types( 'cot-migration' ); $order_post_type_placeholder = implode( ', ', array_fill( 0, count( $order_post_types ), '%s' ) ); $orders_table = $this->data_store::get_orders_table_name(); if ( empty( $order_post_types ) ) { $this->error_logger->debug( sprintf( /* translators: 1: method name. */ esc_html__( '%1$s was called but no order types were registered: it may have been called too early.', 'woocommerce' ), __METHOD__ ) ); return 0; } // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,WordPress.DB.PreparedSQL.NotPrepared -- // -- $order_post_type_placeholder, $orders_table, self::PLACEHOLDER_ORDER_POST_TYPE are all safe to use in queries. if ( ! $this->get_table_exists() ) { $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts where post_type in ( $order_post_type_placeholder )", $order_post_types ) ); return $count; } if ( $this->custom_orders_table_is_authoritative() ) { $missing_orders_count_sql = $wpdb->prepare( " SELECT COUNT(1) FROM $wpdb->posts posts RIGHT JOIN $orders_table orders ON posts.ID=orders.id WHERE (posts.post_type IS NULL OR posts.post_type = '" . self::PLACEHOLDER_ORDER_POST_TYPE . "') AND orders.status NOT IN ( 'auto-draft' ) AND orders.type IN ($order_post_type_placeholder)", $order_post_types ); $operator = '>'; } else { $missing_orders_count_sql = $wpdb->prepare( " SELECT COUNT(1) FROM $wpdb->posts posts LEFT JOIN $orders_table orders ON posts.ID=orders.id WHERE posts.post_type in ($order_post_type_placeholder) AND posts.post_status != 'auto-draft' AND orders.id IS NULL", $order_post_types ); $operator = '<'; } $sql = $wpdb->prepare( " SELECT( ($missing_orders_count_sql) + (SELECT COUNT(1) FROM ( SELECT orders.id FROM $orders_table orders JOIN $wpdb->posts posts on posts.ID = orders.id WHERE posts.post_type IN ($order_post_type_placeholder) AND orders.date_updated_gmt $operator posts.post_modified_gmt ) x) ) count", $order_post_types ); // phpcs:enable // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $pending_count = (int) $wpdb->get_var( $sql ); $deleted_from_table = $this->get_current_deletion_record_meta_value(); $deleted_count = $wpdb->get_var( $wpdb->prepare( "SELECT count(1) FROM {$wpdb->prefix}wc_orders_meta WHERE meta_key=%s AND meta_value=%s", array( self::DELETED_RECORD_META_KEY, $deleted_from_table ) ) ); $pending_count += $deleted_count; wp_cache_set( 'woocommerce_hpos_pending_sync_count', $pending_count ); return $pending_count; } /** * Get the meta value for order deletion records based on which table is currently authoritative. * * @return string self::DELETED_FROM_ORDERS_META_VALUE if the orders table is authoritative, self::DELETED_FROM_POSTS_META_VALUE otherwise. */ private function get_current_deletion_record_meta_value() { return $this->custom_orders_table_is_authoritative() ? self::DELETED_FROM_ORDERS_META_VALUE : self::DELETED_FROM_POSTS_META_VALUE; } /** * Is the custom orders table the authoritative data source for orders currently? * * @return bool Whether the custom orders table the authoritative data source for orders currently. */ public function custom_orders_table_is_authoritative(): bool { return wc_string_to_bool( get_option( CustomOrdersTableController::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION ) ); } /** * Get a list of ids of orders than are out of sync. * * Valid values for $type are: * * ID_TYPE_MISSING_IN_ORDERS_TABLE: orders that exist in posts table but not in orders table. * ID_TYPE_MISSING_IN_POSTS_TABLE: orders that exist in orders table but not in posts table (the corresponding post entries are placeholders). * ID_TYPE_DIFFERENT_UPDATE_DATE: orders that exist in both tables but have different last update dates. * ID_TYPE_DELETED_FROM_ORDERS_TABLE: orders deleted from the orders table but not yet from the posts table. * ID_TYPE_DELETED_FROM_POSTS_TABLE: orders deleted from the posts table but not yet from the orders table. * * @param int $type One of ID_TYPE_MISSING_IN_ORDERS_TABLE, ID_TYPE_MISSING_IN_POSTS_TABLE, ID_TYPE_DIFFERENT_UPDATE_DATE. * @param int $limit Maximum number of ids to return. * @return array An array of order ids. * @throws \Exception Invalid parameter. */ public function get_ids_of_orders_pending_sync( int $type, int $limit ) { global $wpdb; if ( $limit < 1 ) { throw new \Exception( '$limit must be at least 1' ); } $orders_table = $this->data_store::get_orders_table_name(); $order_post_types = wc_get_order_types( 'cot-migration' ); $order_post_type_placeholders = implode( ', ', array_fill( 0, count( $order_post_types ), '%s' ) ); // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,WordPress.DB.PreparedSQL.NotPrepared switch ( $type ) { case self::ID_TYPE_MISSING_IN_ORDERS_TABLE: $sql = $wpdb->prepare( " SELECT posts.ID FROM $wpdb->posts posts LEFT JOIN $orders_table orders ON posts.ID = orders.id WHERE posts.post_type IN ($order_post_type_placeholders) AND posts.post_status != 'auto-draft' AND orders.id IS NULL ORDER BY posts.ID ASC", $order_post_types ); break; case self::ID_TYPE_MISSING_IN_POSTS_TABLE: $sql = $wpdb->prepare( " SELECT orders.id FROM $wpdb->posts posts RIGHT JOIN $orders_table orders ON posts.ID=orders.id WHERE (posts.post_type IS NULL OR posts.post_type = '" . self::PLACEHOLDER_ORDER_POST_TYPE . "') AND orders.status NOT IN ( 'auto-draft' ) AND orders.type IN ($order_post_type_placeholders) ORDER BY posts.ID ASC", $order_post_types ); break; case self::ID_TYPE_DIFFERENT_UPDATE_DATE: $operator = $this->custom_orders_table_is_authoritative() ? '>' : '<'; $sql = $wpdb->prepare( " SELECT orders.id FROM $orders_table orders JOIN $wpdb->posts posts on posts.ID = orders.id WHERE posts.post_type IN ($order_post_type_placeholders) AND orders.date_updated_gmt $operator posts.post_modified_gmt ORDER BY orders.id ASC ", $order_post_types ); break; case self::ID_TYPE_DELETED_FROM_ORDERS_TABLE: return $this->get_deleted_order_ids( true, $limit ); case self::ID_TYPE_DELETED_FROM_POSTS_TABLE: return $this->get_deleted_order_ids( false, $limit ); default: throw new \Exception( 'Invalid $type, must be one of the ID_TYPE_... constants.' ); } // phpcs:enable // phpcs:ignore WordPress.DB return array_map( 'intval', $wpdb->get_col( $sql . " LIMIT $limit" ) ); } /** * Get the ids of the orders that are marked as deleted in the orders meta table. * * @param bool $deleted_from_orders_table True to get the ids of the orders deleted from the orders table, false o get the ids of the orders deleted from the posts table. * @param int $limit The maximum count of orders to return. * @return array An array of order ids. */ private function get_deleted_order_ids( bool $deleted_from_orders_table, int $limit ) { global $wpdb; $deleted_from_table = $this->get_current_deletion_record_meta_value(); $order_ids = $wpdb->get_col( // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->prepare( "SELECT DISTINCT(order_id) FROM {$wpdb->prefix}wc_orders_meta WHERE meta_key=%s AND meta_value=%s LIMIT {$limit}", self::DELETED_RECORD_META_KEY, $deleted_from_table ) // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared ); return array_map( 'absint', $order_ids ); } /** * Cleanup all the synchronization status information, * because the process has been disabled by the user via settings, * or because there's nothing left to synchronize. */ public function cleanup_synchronization_state() { delete_option( self::INITIAL_ORDERS_PENDING_SYNC_COUNT_OPTION ); } /** * Process data for current batch. * * @param array $batch Batch details. */ public function process_batch( array $batch ): void { if ( empty( $batch ) ) { return; } $batch = array_map( 'absint', $batch ); $this->order_cache_controller->temporarily_disable_orders_cache_usage(); $custom_orders_table_is_authoritative = $this->custom_orders_table_is_authoritative(); $deleted_order_ids = $this->process_deleted_orders( $batch, $custom_orders_table_is_authoritative ); $batch = array_diff( $batch, $deleted_order_ids ); if ( ! empty( $batch ) ) { if ( $custom_orders_table_is_authoritative ) { foreach ( $batch as $id ) { $order = wc_get_order( $id ); if ( ! $order ) { $this->error_logger->error( "Order $id not found during batch process, skipping." ); continue; } $data_store = $order->get_data_store(); $data_store->backfill_post_record( $order ); } } else { $this->posts_to_cot_migrator->migrate_orders( $batch ); } } if ( 0 === $this->get_total_pending_count() ) { $this->cleanup_synchronization_state(); $this->order_cache_controller->maybe_restore_orders_cache_usage(); } } /** * Take a batch of order ids pending synchronization and process those that were deleted, ignoring the others * (which will be orders that were created or modified) and returning the ids of the orders actually processed. * * @param array $batch Array of ids of order pending synchronization. * @param bool $custom_orders_table_is_authoritative True if the custom orders table is currently authoritative. * @return array Order ids that have been actually processed. */ private function process_deleted_orders( array $batch, bool $custom_orders_table_is_authoritative ): array { global $wpdb; $deleted_from_table_name = $this->get_current_deletion_record_meta_value(); $data_store_for_deletion = $custom_orders_table_is_authoritative ? new \WC_Order_Data_Store_CPT() : wc_get_container()->get( OrdersTableDataStore::class ); $order_ids_as_sql_list = '(' . implode( ',', $batch ) . ')'; $deleted_order_ids = array(); $meta_ids_to_delete = array(); // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared $deletion_data = $wpdb->get_results( $wpdb->prepare( "SELECT id, order_id FROM {$wpdb->prefix}wc_orders_meta WHERE meta_key=%s AND meta_value=%s AND order_id IN $order_ids_as_sql_list ORDER BY order_id DESC", self::DELETED_RECORD_META_KEY, $deleted_from_table_name ), ARRAY_A ); // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared if ( empty( $deletion_data ) ) { return array(); } foreach ( $deletion_data as $item ) { $meta_id = $item['id']; $order_id = $item['order_id']; if ( isset( $deleted_order_ids[ $order_id ] ) ) { $meta_ids_to_delete[] = $meta_id; continue; } if ( ! $data_store_for_deletion->order_exists( $order_id ) ) { $this->error_logger->warning( "Order {$order_id} doesn't exist in the backup table, thus it can't be deleted" ); $deleted_order_ids[] = $order_id; $meta_ids_to_delete[] = $meta_id; continue; } try { $order = new \WC_Order(); $order->set_id( $order_id ); $data_store_for_deletion->read( $order ); $data_store_for_deletion->delete( $order, array( 'force_delete' => true, 'suppress_filters' => true, ) ); } catch ( \Exception $ex ) { $this->error_logger->error( "Couldn't delete order {$order_id} from the backup table: {$ex->getMessage()}" ); continue; } $deleted_order_ids[] = $order_id; $meta_ids_to_delete[] = $meta_id; } if ( ! empty( $meta_ids_to_delete ) ) { $order_id_rows_as_sql_list = '(' . implode( ',', $meta_ids_to_delete ) . ')'; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->query( "DELETE FROM {$wpdb->prefix}wc_orders_meta WHERE id IN {$order_id_rows_as_sql_list}" ); } return $deleted_order_ids; } /** * Get total number of pending records that require update. * * @return int Number of pending records. */ public function get_total_pending_count(): int { return $this->get_current_orders_pending_sync_count(); } /** * Returns the batch with records that needs to be processed for a given size. * * @param int $size Size of the batch. * * @return array Batch of records. */ public function get_next_batch_to_process( int $size ): array { $orders_table_is_authoritative = $this->custom_orders_table_is_authoritative(); $order_ids = $this->get_ids_of_orders_pending_sync( $orders_table_is_authoritative ? self::ID_TYPE_MISSING_IN_POSTS_TABLE : self::ID_TYPE_MISSING_IN_ORDERS_TABLE, $size ); if ( count( $order_ids ) >= $size ) { return $order_ids; } $updated_order_ids = $this->get_ids_of_orders_pending_sync( self::ID_TYPE_DIFFERENT_UPDATE_DATE, $size - count( $order_ids ) ); $order_ids = array_merge( $order_ids, $updated_order_ids ); if ( count( $order_ids ) >= $size ) { return $order_ids; } $deleted_order_ids = $this->get_ids_of_orders_pending_sync( $orders_table_is_authoritative ? self::ID_TYPE_DELETED_FROM_ORDERS_TABLE : self::ID_TYPE_DELETED_FROM_POSTS_TABLE, $size - count( $order_ids ) ); $order_ids = array_merge( $order_ids, $deleted_order_ids ); return array_map( 'absint', $order_ids ); } /** * Default batch size to use. * * @return int Default batch size. */ public function get_default_batch_size(): int { $batch_size = self::ORDERS_SYNC_BATCH_SIZE; if ( $this->custom_orders_table_is_authoritative() ) { // Back-filling is slower than migration. $batch_size = absint( self::ORDERS_SYNC_BATCH_SIZE / 10 ) + 1; } /** * Filter to customize the count of orders that will be synchronized in each step of the custom orders table to/from posts table synchronization process. * * @since 6.6.0 * * @param int Default value for the count. */ return apply_filters( 'woocommerce_orders_cot_and_posts_sync_step_size', $batch_size ); } /** * A user friendly name for this process. * * @return string Name of the process. */ public function get_name(): string { return 'Order synchronizer'; } /** * A user friendly description for this process. * * @return string Description. */ public function get_description(): string { return 'Synchronizes orders between posts and custom order tables.'; } /** * Prevents deletion of order backup posts (regardless of sync setting) when HPOS is authoritative and the order * still exists in HPOS. * This should help with edge cases where wp_delete_post() would delete the HPOS record too or backfill would sync * incorrect data from an order with no metadata from the posts table. * * @since 8.8.0 * * @param WP_Post|false|null $delete Whether to go forward with deletion. * @param WP_Post $post Post object. * @return WP_Post|false|null */ private function maybe_prevent_deletion_of_post( $delete, $post ) { if ( self::PLACEHOLDER_ORDER_POST_TYPE !== $post->post_type && $this->custom_orders_table_is_authoritative() && $this->data_store->order_exists( $post->ID ) ) { $delete = false; } return $delete; } /** * Handle the 'deleted_post' action. * * When posts is authoritative and sync is enabled, deleting a post also deletes COT data. * * @param int $postid The post id. * @param WP_Post $post The deleted post. */ private function handle_deleted_post( $postid, $post ): void { global $wpdb; $order_post_types = wc_get_order_types( 'cot-migration' ); if ( ! in_array( $post->post_type, $order_post_types, true ) ) { return; } if ( ! $this->get_table_exists() ) { return; } if ( $this->data_sync_is_enabled() ) { $this->data_store->delete_order_data_from_custom_order_tables( $postid ); } elseif ( $this->custom_orders_table_is_authoritative() ) { return; } // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.SlowDBQuery if ( $wpdb->get_var( $wpdb->prepare( "SELECT EXISTS (SELECT id FROM {$this->data_store::get_orders_table_name()} WHERE ID=%d) AND NOT EXISTS (SELECT order_id FROM {$this->data_store::get_meta_table_name()} WHERE order_id=%d AND meta_key=%s AND meta_value=%s)", $postid, $postid, self::DELETED_RECORD_META_KEY, self::DELETED_FROM_POSTS_META_VALUE ) ) ) { $wpdb->insert( $this->data_store::get_meta_table_name(), array( 'order_id' => $postid, 'meta_key' => self::DELETED_RECORD_META_KEY, 'meta_value' => self::DELETED_FROM_POSTS_META_VALUE, ) ); } // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.SlowDBQuery } /** * Handle the 'woocommerce_update_order' action. * * When posts is authoritative and sync is enabled, updating a post triggers a corresponding change in the COT table. * * @param int $order_id The order id. */ private function handle_updated_order( $order_id ): void { if ( ! $this->custom_orders_table_is_authoritative() && $this->data_sync_is_enabled() ) { $this->posts_to_cot_migrator->migrate_orders( array( $order_id ) ); } } /** * Handles deletion of auto-draft orders in sync with WP's own auto-draft deletion. * * @since 7.7.0 * * @return void */ private function delete_auto_draft_orders() { if ( ! $this->custom_orders_table_is_authoritative() ) { return; } // Fetch auto-draft orders older than 1 week. $to_delete = wc_get_orders( array( 'date_query' => array( array( 'column' => 'date_created', 'before' => '-1 week', ), ), 'orderby' => 'date', 'order' => 'ASC', 'status' => 'auto-draft', ) ); foreach ( $to_delete as $order ) { $order->delete( true ); } /** * Fires after schedueld deletion of auto-draft orders has been completed. * * @since 7.7.0 */ do_action( 'woocommerce_scheduled_auto_draft_delete' ); } /** * Handles deletion of trashed orders after `EMPTY_TRASH_DAYS` as defined by WordPress. * * @since 8.5.0 * * @return void */ private function delete_trashed_orders() { if ( ! $this->custom_orders_table_is_authoritative() ) { return; } $delete_timestamp = $this->legacy_proxy->call_function( 'time' ) - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS ); $args = array( 'status' => 'trash', 'limit' => self::ORDERS_SYNC_BATCH_SIZE, 'date_modified' => '<' . $delete_timestamp, ); $orders = wc_get_orders( $args ); if ( ! $orders || ! is_array( $orders ) ) { return; } foreach ( $orders as $order ) { if ( $order->get_status() !== 'trash' ) { continue; } if ( $order->get_date_modified()->getTimestamp() >= $delete_timestamp ) { continue; } $order->delete( true ); } } /** * Handle the 'woocommerce_feature_description_tip' filter. * * When the COT feature is enabled and there are orders pending sync (in either direction), * show a "you should ync before disabling" warning under the feature in the features page. * Skip this if the UI prevents changing the feature enable status. * * @param string $desc_tip The original description tip for the feature. * @param string $feature_id The feature id. * @param bool $ui_disabled True if the UI doesn't allow to enable or disable the feature. * @return string The new description tip for the feature. */ private function handle_feature_description_tip( $desc_tip, $feature_id, $ui_disabled ): string { if ( 'custom_order_tables' !== $feature_id || $ui_disabled ) { return $desc_tip; } $features_controller = wc_get_container()->get( FeaturesController::class ); $feature_is_enabled = $features_controller->feature_is_enabled( 'custom_order_tables' ); if ( ! $feature_is_enabled ) { return $desc_tip; } $pending_sync_count = $this->get_current_orders_pending_sync_count(); if ( ! $pending_sync_count ) { return $desc_tip; } if ( $this->custom_orders_table_is_authoritative() ) { $extra_tip = sprintf( _n( "⚠ There's one order pending sync from the orders table to the posts table. The feature shouldn't be disabled until this order is synchronized.", "⚠ There are %1\$d orders pending sync from the orders table to the posts table. The feature shouldn't be disabled until these orders are synchronized.", $pending_sync_count, 'woocommerce' ), $pending_sync_count ); } else { $extra_tip = sprintf( _n( "⚠ There's one order pending sync from the posts table to the orders table. The feature shouldn't be disabled until this order is synchronized.", "⚠ There are %1\$d orders pending sync from the posts table to the orders table. The feature shouldn't be disabled until these orders are synchronized.", $pending_sync_count, 'woocommerce' ), $pending_sync_count ); } $cot_settings_url = add_query_arg( array( 'page' => 'wc-settings', 'tab' => 'advanced', 'section' => 'custom_data_stores', ), admin_url( 'admin.php' ) ); /* translators: %s = URL of the custom data stores settings page */ $manage_cot_settings_link = sprintf( __( "Manage orders synchronization", 'woocommerce' ), $cot_settings_url ); return $desc_tip ? "{$desc_tip}
{$extra_tip} {$manage_cot_settings_link}" : "{$extra_tip} {$manage_cot_settings_link}"; } } BN1 Type PD C charger adapter – alibabatelecom
ADD ANYTHING HERE OR JUST REMOVE IT…
  • NEWSLETTER
  • CONTACT US
  • FAQs
alibabatelecom
Select category
  • Select category
  • Accessories
    • Mouse , Keyboard
    • phone card holder
    • Phone holder
    • Pop socket
    • Selfi
    • USB-SD card
  • brands
    • ACEFAST
    • Adidas
    • AMA Book Case
    • AMA Extra pas Book Case
    • Anti shock
      • Iphone
    • Apple
    • Back case card holder
    • back case color
      • Luxury clear magnetic back case
    • BOROFONE
    • Fashion Case
    • Hoco
    • ideal of Sweden
    • KEY Book Case
    • kingston Memory
    • Magnet leather case
    • OG Tempered Glass
    • Samsung
    • selly
  • Childeren toys
    • Car , Motor
  • Electronics
    • Adapters
    • Air Tag
    • Bluetooth Speaker
    • Cables
    • Car adapter , cables
    • Gaming
    • HDMI , converter
    • Headset , audio jack
    • Oudio Other
    • Wirless charger
  • Mobile , Tab , Watch parts
    • Ipad
      • Ipad battery
      • Ipad charging port
      • Ipad display
    • Iphone
      • Iphone back camera
      • Iphone Back cover
      • Iphone battery
      • Iphone camera lens
      • Iphone charging port
      • Iphone display
      • Iphone earspeaker
      • Iphone front camera
      • Iphone loudspeaker
      • iphone parts
      • Iphone Simcard holder
    • Samsung
      • Main Flex
      • Power And Volume Flex Cable
      • Samsung back camera
      • Samsung back cover
      • Samsung battery
      • Samsung camera lens
      • Samsung charging port
      • Samsung display
      • Samsung earspeaker
      • Samsung front camera
      • Samsung LCD Flex
      • Samsung loudspeaker
      • Samsung Signal Antenna
      • Samsung Simcard holder
  • Mobile , Tablets Accessories
    • Apple
      • AirPods
      • Apple Watch
        • Apple watch 3 serie 40mm
        • Apple watch 3 serie 42mm
        • Apple watch 4 serie 38mm
        • Apple watch 4 serie 42mm
        • Apple watch 5 serie 40mm
        • Apple watch 5 serie 44mm
        • Apple watch 6 serie 40mm
        • Apple watch 6 serie 44mm
        • Apple watch 7 serie 41mm
        • Apple watch 7 serie 45mm
        • Apple watch 8 serie 41mm
        • Apple watch 8 serie 45mm
        • Apple watch Ultra 49mm 1st Gen
      • IPad
        • iPad 10.2 7th Ge (2019)
        • iPad 10.2 8th Ge (2020)
        • iPad 10.2 9th Ge (2021)
        • iPad 10.9 (10th 2022)
        • iPad 11 (11Gen 2025 )
        • Ipad 3
        • Ipad 4
        • iPad 9.7 (5th 2017)
        • iPad 9.7 (6th 2018)
        • iPad Air (2013)
        • iPad Air 11 (2024)
        • iPad Air 11 (2025)
        • iPad Air 13 (2024)
        • iPad Air 13 (2025)
        • Ipad Air 2 (2014)
        • iPad Air 3rd Ge (2019)
        • iPad Air 4th Ge (2020)
        • iPad Air 5th Ge (2022)
        • ipad mini 4th Ge (2015)
        • ipad mini 5th Ge (2019)
        • ipad mini 6th Ge (2021)
        • iPad Pro 10.5 (2017)
        • iPad Pro 11 (1Gen 2018)
        • iPad Pro 11 (2 Gen: 2020)
        • iPad Pro 11 (3Gen 2021)
        • iPad Pro 11 (4 Gen: 2022)
        • iPad Pro 11 (5 Gen: 2024) M4
        • iPad Pro 12.9 (1nd 2015)
        • iPad Pro 12.9 (2nd 2017)
        • iPad Pro 12.9 (3nd 2018)
        • iPad Pro 12.9 (4nd 2020)
        • iPad Pro 12.9 (5nd 2021)
        • iPad Pro 12.9 (6nd 2022)
        • IPad Pro 13 (2024)(13-inch (M4)
        • iPad Pro 13 (2025)(13-inch (M5)
        • iPad Pro 9.7 (2016)
      • Iphone
        • iphone 11
        • iphone 11 pro
        • iphone 11 pro max
        • iphone 12
        • iphone 12 mini
        • iphone 12 pro
        • iphone 12 pro max
        • iphone 13
        • iphone 13 mini
        • iphone 13 pro
        • iphone 13 pro max
        • iphone 14
        • iphone 14 plus
        • iphone 14 pro
        • iphone 14 pro max
        • Iphone 15
        • Iphone 15 Plus
        • Iphone 15 Pro
        • Iphone 15 Pro Max
        • Iphone 16
        • Iphone 16 Plus
        • Iphone 16 Pro
        • Iphone 16 Pro Max
        • Iphone 16e
        • Iphone 17
        • Iphone 17 Air
        • Iphone 17 Pro
        • Iphone 17 Pro Max
        • Iphone 17e
        • iphone 5
        • iphone 5S
        • Iphone 6
        • iphone 6 plus
        • iphone 6s
        • iphone 6s plus
        • iphone 7
        • iphone 7 plus
        • iphone 8
        • iphone 8 plus
        • iphone SE
        • iphone SE 2020
        • Iphone SE 2022
        • iphone X
        • iphone XR
        • iphone XS
        • iphone XS max
    • google
      • Google Pixel 5
      • Google Pixel 5A
      • Google Pixel 6
      • Google Pixel 6 Pro
      • Google Pixel 6A
      • Google Pixel 7
      • Google Pixel 7 Pro
      • Google Pixel 7A
      • Google Pixel 8
      • Google Pixel 8 Pro
      • Google Pixel 8A
      • Google Pixel 9
      • Google Pixel 9 Pro
      • Google Pixel 9 Pro XL
    • Huawei
      • Huawei Honor Models
        • Huawei Honor 10
        • Huawei Honor 20
        • Huawei Honor 20 Lite
        • Huawei Honor 20 Pro
        • Huawei Honor 6
        • Huawei Honor 7
        • Huawei Honor 8
        • Huawei Honor 8 Lite
        • Huawei Honor 9
        • Huawei Honor View 10
        • Huawei Honor View 20
      • Huawei Mate Models
        • Huawei Mate 10
        • Huawei Mate 10 Lite
        • Huawei Mate 10 Pro
        • Huawei Mate 20
        • Huawei Mate 20 Lite
        • Huawei Mate 20 Pro
        • Huawei Mate 30
        • Huawei Mate 30 Lite
        • Huawei Mate 30 Pro
        • Huawei Mate 40
        • Huawei Mate 40 Pro
        • Huawei Mate 7
        • Huawei Mate 8
        • Huawei Mate 9
        • Huawei Mate 9 pro
      • Huawei P Models
        • Huawei P10
        • Huawei P10 Lite
        • Huawei P20
        • Huawei P20 Lite
        • Huawei P20 Lite 2019
        • Huawei P20 Pro
        • Huawei P30
        • Huawei P30 Lite
        • Huawei P30 Pro
        • Huawei P40
        • Huawei P40 Lite
        • Huawei P40 pro
        • Huawei P7
        • Huawei P8
        • Huawei P8 Lite
        • Huawei P9
        • Huawei P9 Lite
      • Huawei P smart Models
        • Huawei P smart
        • Huawei P smart 2019
        • Huawei P smart 2020
        • Huawei P smart 2021
        • Huawei P smart pro
        • Huawei P smart Z
    • Nokia
      • HMD Series
        • Nokia 2.4
        • Nokia 5.4
    • Samsung
      • Samsung A model
        • |Samsung A34 (A346)
        • Samsung A01
        • Samsung A02
        • samsung A02s
        • Samsung A03
        • Samsung A03s
        • Samsung A04s
        • Samsung A05S
        • Samsung A06
        • Samsung A07
        • Samsung A10
        • Samsung A10s
        • Samsung A11
        • Samsung A12
        • Samsung A13 4G
        • Samsung A13 5G
        • Samsung A14 4G
        • Samsung A14 5G
        • Samsung A15
        • Samsung A16 4G (A165F)
        • Samsung A16 5G (A166B)
        • Samsung A17
        • Samsung A20e (A202F)
        • Samsung A20s (A207F)
        • Samsung A21 (A215)
        • Samsung A21s (A217F)
        • Samsung A22 4G (A225F)
        • Samsung A22 5G (A226B)
        • Samsung A23 4G (SM-A236)
        • Samsung A23 5G (SM-A236)
        • Samsung A24 (A245F)
        • Samsung A25 (A256)
        • Samsung A26 (A266)
        • Samsung A27
        • Samsung A30 (A305F)
        • Samsung A30s (A307F)
        • Samsung A31 (A315F)
        • Samsung A32 4G (A325)
        • Samsung A32 5G (A326)
        • Samsung A33 5G (A336B)
        • Samsung A35 (A356)
        • Samsung A36 (A366)
        • Samsung A37
        • Samsung A40 (A405F)
        • Samsung A41 (A415F)
        • Samsung A42 (A426B)
        • Samsung A5 2015
        • Samsung A50 (A505F)
        • Samsung A50s
        • Samsung A51 (A515F)
        • Samsung A52 (A525F)
        • Samsung A52s (A528B)
        • Samsung A53 (A536B/DS)
        • Samsung A54 (A546B)
        • Samsung A55 (A556)
        • Samsung A56 (A566)
        • Samsung A60 (A606F)
        • Samsung A70 (A705F)
        • Samsung A71 5G (A716F)
        • Samsung A72 (A725)
        • Samsung A73
        • Samsung A80 (A805F)
        • Samsung A90 (A908F)
      • Samsung Buds case
      • Samsung note model
        • Samsung Note 10
        • Samsung Note 10 Lite
        • Samsung Note 10 plus
        • Samsung Note 20
        • Samsung Note 20 ultra
        • Samsung Note 8
        • Samsung Note 9
      • Samsung S model
        • Samsung s10
        • Samsung S10 lite
        • Samsung s10 plus
        • Samsung s10e
        • Samsung s20
        • Samsung s20 FE
        • Samsung s20 plus
        • Samsung s20 ultra
        • Samsung s21
        • Samsung s21 FE
        • Samsung s21 plus
        • Samsung s21 ultra
        • Samsung s22
        • Samsung s22 plus
        • Samsung s22 ultra
        • Samsung S23
        • Samsung S23 FE
        • Samsung S23 Plus
        • Samsung S23 Ultra
        • Samsung S24
        • Samsung S24 FE
        • Samsung S24 Plus
        • Samsung S24 Ultra
        • Samsung S25
        • Samsung S25 Edge
        • Samsung S25 FE
        • Samsung S25 Plus
        • Samsung S25 Ultra
        • Samsung S26
        • Samsung S26 Edge
        • Samsung S26 FE
        • Samsung S26 Plus
        • Samsung S26 Ultra
        • Samsung s4
        • Samsung s5
        • Samsung s6
        • Samsung s6 edge
        • Samsung s7
        • Samsung s7 edge
        • Samsung s8
        • Samsung s8 plus
        • Samsung s9
        • Samsung s9 plus
      • Samsung X cover model
        • Samsung x cover 3
        • Samsung x cover 4
        • Samsung x cover 4s
        • Samsung x cover 5
        • Samsung x cover 6 pro
        • Samsung X cover 7
        • Samsung x cover pro
      • Samsung Z Fold , Z flip models
        • Samsung Z Flip 3
        • Samsung Z Flip 4
        • Samsung Z Fold 3
        • Samsung Z Fold 4
  • Mobile, tablet , smart watches
    • Mobile
      • Android Mobile
      • IOS Mobile
    • Smart watches
  • Personal care, beauty and well-being
    • Hair dryer
    • Shaving and hair removal
  • Tempered Glass
    • Apple Watch
    • Ipad 3D
    • Iphone camera Lens
    • OG tempered Glass
      • Iphone
      • Samsung
    • Samsung camera lens
    • UV tempered Glass
      • Samsung
Login / Register
0 Wishlist
0 Compare
2 items / 668.00 kr
Menu
alibabatelecom
2 items / 668.00 kr
Browse Categories
  • Mobile, tablet , smart watches
    • Mobile
      • IOS Mobile
      • Android Mobile
      • Doro
    • Tablets
      • Ipad
      • Samsung TAB
    • Smart watches
Browse Categories
  • Apple
    • Iphone
      • Iphone 17 Pro Max
      • Iphone 17 Air
      • Iphone 17 Pro
      • Iphone 17e
      • Iphone 17
      • Iphone 16 Pro Max
      • Iphone 16 Plus
      • Iphone 16 Pro
      • Iphone 16e
      • Iphone 16
      • Iphone 15 Pro Max
      • Iphone 15 Plus
      • Iphone 15 Pro
      • Iphone 15
      • iphone 14 pro max
      • iphone 14 plus
      • iphone 14 pro
      • iphone 14
      • iphone 13 pro max
      • iphone 13 pro
      • iphone 13 mini
      • iphone 13
      • iphone 12 pro max
      • iphone 12 pro
      • iphone 12 mini
      • iphone 12
      • iphone 11 pro max
      • iphone 11 pro
      • iphone 11
      • iphone XS max
      • iphone XR
      • iphone XS
      • iphone X
      • iphone 8 plus
      • iphone 8
      • Iphone SE 2022
      • iphone SE 2020
      • iphone 7 plus
      • iphone 7
      • iphone 6s plus
      • iphone 6s
      • iphone 6 plus
      • Iphone 6
      • iphone SE
      • iphone 5S
      • iphone 5
    • IPad
      • iPad Pro 13 (2025)(13-inch (M5)
      • IPad Pro 13 (2024)(13-inch (M4)
      • iPad Pro 12.9 (6nd 2022)
      • iPad Pro 12.9 (5Gen 2021)
      • iPad Pro 12.9 (4Gen 2020)
      • iPad Pro 12.9 (3Gen 2018)
      • iPad Pro 12.9 (2Gen 2017)
      • iPad Pro 12.9 (1Gen 2015)
      • iPad Pro 11 (5 Gen: 2024) M4
      • iPad Pro 11 (4 Gen: 2022)
      • iPad Pro 11 (3Gen 2021)
      • iPad Pro 11 (2 Gen: 2020)
      • iPad Pro 11 (1Gen 2018)
      • iPad Pro 10.5 (2017)
      • iPad Pro 9.7 (2016)
      • iPad 10.9 (10th 2022)
      • iPad 10.2 9th Ge (2021)
      • iPad 10.2 8th Ge (2020)
      • iPad 10.2 7th Ge (2019)
      • iPad 9.7 (6th 2018)
      • iPad 9.7 (5th 2017)
      • iPad Air 13 (2024)
      • iPad Air 11 (2024) M2
      • iPad Air 5th Ge (2022)
      • iPad Air 4th Ge (2020)
      • iPad Air 3rd Ge (2019)
      • Ipad Air 2 (2014)
      • iPad Air (2013)
      • Ipad 4
      • Ipad 3
      • Ipad 2
      • Ipad mini 7th Ge (2023)
      • ipad mini 6th Ge (2021)
      • ipad mini 5th Ge (2019)
      • ipad mini 4th Ge (2015)
      • ipad mini 3rd Ge (2014)
      • ipad mini 2 (2013)
    • Apple Watch
      • Apple watch Ultra 49mm 2st Gen
      • Apple watch Ultra 49mm 1st Gen
      • Apple watch 9 serie 45mm
      • Apple watch 9 serie 41mm
      • Apple watch 8 serie 45mm
      • Apple watch 8 serie 41mm
      • Apple watch 7 serie 45mm
      • Apple watch 7 serie 41mm
      • Apple watch 6 serie 44mm
      • Apple watch 6 serie 40mm
      • Apple watch SE 2022 serie 44mm
      • Apple watch SE 2022 serie 40mm
      • Apple watch SE serie 44mm
      • Apple watch SE serie 40mm
      • Apple watch 5 serie 44mm
      • Apple watch 5 serie 40mm
      • Apple watch 4 serie 42mm
      • Apple watch 4 serie 38mm
      • Apple watch 3 serie 42mm
      • Apple watch 3 serie 40mm
    • AirPods
      • AirPods Pro (2st generation)
      • AirPods Pro (1st generation)
      • AirPods 4 (4st generation)
      • AirPods 3 (3st generation)
      • AirPods 2 (2st generation)
      • AirPods 1 (1st generation)
Browse Categories
  • Motorola
    • Moto G Models
      • Moto G200
      • Moto G100
      • Moto G85
      • Moto G84
      • Moto G82
      • Moto G75
      • Moto G73
      • Moto G72
      • Moto G71 5G
      • Moto G64
      • Moto G62
      • Moto G60s
      • Moto G60
      • Moto G56
      • Moto G55
      • Moto G54 Power
      • Moto G54
      • Moto G53
      • Moto G52
      • Moto G51 5G
      • Moto G50 5G
      • Moto G50 4G
      • Moto G45
      • Moto G42
      • Moto G41
      • Moto G35
      • Moto G34
      • Moto G32
      • Moto G31
      • Moto G30
      • Moto G24
      • Moto G23
      • Moto G22
      • Moto G20
      • Moto G15
      • Moto G14
      • Moto G13
      • Moto G10 play
      • Moto G10
      • Moto G Power (2021)
    • Moto E Models
      • Moto E40
      • Motorola Moto E32s
      • Motorola Moto E32
      • Motorola Moto E30
      • Motorola Moto E22
      • Motorola Moto E22i
      • Motorola Moto E20
      • Motorola Moto E14
      • Motorola Moto E15
      • Motorola Moto E13
Browse Categories
  • Accessories
    • Mouse , Keyboard
    • touch pen
    • Phone holder
    • phone card holder
    • Pop socket
    • USB-SD card
    • Selfi
Browse Categories
  • Samsung
    • Samsung S model
      • Samsung S25 Ultra
      • Samsung S25 Plus
      • Samsung S25 Edge
      • Samsung S25 FE
      • Samsung S25
      • Samsung S24 Ultra
      • Samsung S24 Plus
      • Samsung S24 FE
      • Samsung S24
      • Samsung S23 Ultra
      • Samsung S23 Plus
      • Samsung S23 FE
      • Samsung S23
      • Samsung s22 ultra
      • Samsung s22 plus
      • Samsung s22
      • Samsung s21 ultra
      • Samsung s21 plus
      • Samsung s21 FE
      • Samsung s21
      • Samsung s20 ultra
      • Samsung s20 plus
      • Samsung s20 FE
      • Samsung s20
      • Samsung s10 plus
      • Samsung S10 lite
      • Samsung s10e
      • Samsung s10
      • Samsung s9 plus
      • Samsung s9
      • Samsung s8 plus
      • Samsung s8
      • Samsung s7 edge
      • Samsung s7
      • Samsung s6 edge
      • Samsung s6
      • Samsung s5
      • Samsung s4
    • Samsung A model,
      • Samsung A90 (A908F)
      • Samsung A80 (A805F)
      • Samsung A73
      • Samsung A50 (A505F)
      • Samsung A72 (A725)
      • Samsung A71 5G (A716F)
      • Samsung A71 (A715F)
      • Samsung A70 (A705F)
      • Samsung A60 (A606F)
      • Samsung A56 (A566)
      • Samsung A55 (A556)
      • Samsung A54 (A546B)
      • Samsung A53 (A536B/DS)
      • Samsung A52s (A528B)
      • Samsung A52 (A525F)
      • Samsung A51 5G (A516B/DS)
      • Samsung A51 (A515F)
      • Samsung A50s
      • Samsung A42 (A426B)
      • Samsung A41 (A415F)
      • Samsung A40 (A405F)
      • Samsung A36 (A366)
      • Samsung A35 (A356)
      • |Samsung A34 (A346)
      • Samsung A33 5G (A336B)
      • Samsung A32 5G (A326)
      • Samsung A32 4G (A325)
      • Samsung A31 (A315F)
      • Samsung A30s (A307F)
      • Samsung A30 (A305F)
      • Samsung A26 (A266)
      • Samsung A25 (A256)
      • Samsung A24 (A245F)
      • Samsung A23 5G (SM-A236)
      • Samsung A23 4G (SM-A236)
      • Samsung A22 5G (A226B)
      • Samsung A22 4G (A225F)
      • Samsung A21s (A217F)
      • Samsung A21 (A215)
      • Samsung A20e (A202F)
      • Samsung A17
      • Samsung A16 5G (A166B)
      • Samsung A16 4G (A165F)
      • Samsung A15
      • Samsung A14 5G
      • Samsung A14 4G
      • Samsung A13 5G
      • Samsung A13 4G
      • Samsung A12
      • Samsung A11
      • Samsung A10s
      • Samsung A10
      • Samsung A07
      • Samsung A06
      • Samsung A05S
      • Samsung A04s
      • Samsung A03s
      • Samsung A03
      • samsung A02s
      • Samsung A02
      • Samsung A01
    • Samsung note model
      • Samsung Note 20 ultra
      • Samsung Note 20
      • Samsung Note 10 plus
      • Samsung Note 10 Lite
      • Samsung Note 10
      • Samsung Note 9
      • Samsung Note 8
      • Samsung Note 5
      • Samsung Note 4
    • Samsung X cover model
      • Samsung X cover 7
      • Samsung x cover 6 pro
      • Samsung x cover pro
      • Samsung x cover 5
      • Samsung x cover 4s
      • Samsung x cover 4
      • Samsung x cover 3
    • Samsung Z Fold , Z flip models
      • Samsung Z flip 7
      • Samsung Z flip 6
      • Samsung Z flip 5
      • Samsung Z Flip 4
      • Samsung Z Flip 3
      • Samsung Z fold 7
      • Samsung Z fold 7 FE
      • Samsung Z fold 6
      • Samsung Z fold 5
      • Samsung Z Fold 4
      • Samsung Z Fold 3
  • Samsung TAB models
  • Samsung TAB A series
  • Samsung TAB S Series
  • Samsung TAB E series
Browse Categories
  • Personal care, beauty and well-being
    • Hair dryer
    • Shaving and hair removal
Browse Categories
  • Huawei
    • Huawei P Models
      • Huawei P40 pro
      • Huawei P40 Lite
      • Huawei P40
      • Huawei P30 Pro
      • Huawei P30 Lite
      • Huawei P30
      • Huawei P20 Pro
      • Huawei P20 Lite 2019
      • Huawei P20 Lite
      • Huawei P20
      • Huawei P10 Lite
      • Huawei P10
      • Huawei P9 Lite
      • Huawei P9
      • Huawei P8 Lite
      • Huawei P8
      • Huawei P7
    • Huawei Mate Models
      • Huawei Mate 40 Pro
      • Huawei Mate 40
      • Huawei Mate 30 Pro
      • Huawei Mate 30 Lite
      • Huawei Mate 30
      • Huawei Mate 20 Pro
      • Huawei Mate 20 Lite
      • Huawei Mate 20
      • Huawei Mate 10 Pro
      • Huawei Mate 10 Lite
      • Huawei Mate 10
      • Huawei Mate 9 pro
      • Huawei Mate 9
      • Huawei Mate 8
      • Huawei Mate 7
    • Huawei P smart Models
      • Huawei P smart 2021
      • Huawei P smart 2020
      • Huawei P smart 2019
      • Huawei P smart pro
      • Huawei P smart Z
    • Huawei Honor Models
      • Huawei Honor 20 Pro
      • Huawei Honor 20 Lite
      • Huawei Honor View 20
      • Huawei Honor 20
      • Huawei Honor View 10
      • Huawei Honor 10
      • Huawei Honor 9
      • Huawei Honor 8 Lite
      • Huawei Honor 8
      • Huawei Honor 7
      • Huawei Honor 6
Browse Categories
  • Electronics
    • Headset , audio jack
    • Adapters
    • Cables
    • Car adapter , cables
    • Wirless charger
    • Bluetooth Speaker
    • HDMI , converter
    • Oudio Other
    • Gaming
    • Internet cables
    • Power bank
Browse Categories
  • Tempered Glass
    • OG tempered Glass
      • Iphone
      • Samsung
    • UV tempered Glass
      • Samsung
      • Huawei
    • Iphone camera Lens
    • Samsung camera lens
    • Ipad 3D
    • Samsung TAB
    • Apple Watch
    • Samsung watch
Browse Categories
  • Childeren toys
    • Car , Motor
Reparation
  • Home
  • Electronics
  • Mobile, tablet , smart watches
  • Repare Phone Price
  • Accessories
  • Tempered Glass
View cart “IDeal Wireless QI Charger” has been added to your cart.
Click to enlarge
HomebrandsHoco BN1 Type PD C charger adapter
Previous product
N1 Ardent single port charger set(for Type-C 1M 279.00 kr
Back to products
Next product
BN1 Iphone PD charger adapter 279.00 kr

BN1 Type PD C charger adapter

279.00 kr

1. Material: Flame-retardant PC material
2. Output: USB-A: 5V/2.1A
3. EU plug
5. With 1m charging cable

16 in stock

Compare
Add to wishlist
SKU: A12A Categories: Adapters, Cables, Electronics, Hoco Tags: adapter, cabels, electronics
  • Description
  • Reviews (0)
  • Shipping & Delivery
Description

1. Material: Flame-retardant PC material
2. Output: USB-A: 5V/2.1A
3. EU plug EU
4. Size: 85*43*26mm, total weight: 64g
5. With 1m charging cable

Reviews (0)

Reviews

There are no reviews yet.

Be the first to review “BN1 Type PD C charger adapter” Cancel reply

Your email address will not be published. Required fields are marked *

Shipping & Delivery

MAECENAS IACULIS

Vestibulum curae torquent diam diam commodo parturient penatibus nunc dui adipiscing convallis bulum parturient suspendisse parturient a.Parturient in parturient scelerisque nibh lectus quam a natoque adipiscing a vestibulum hendrerit et pharetra fames nunc natoque dui.

ADIPISCING CONVALLIS BULUM

  • Vestibulum penatibus nunc dui adipiscing convallis bulum parturient suspendisse.
  • Abitur parturient praesent lectus quam a natoque adipiscing a vestibulum hendre.
  • Diam parturient dictumst parturient scelerisque nibh lectus.

Scelerisque adipiscing bibendum sem vestibulum et in a a a purus lectus faucibus lobortis tincidunt purus lectus nisl class eros.Condimentum a et ullamcorper dictumst mus et tristique elementum nam inceptos hac parturient scelerisque vestibulum amet elit ut volutpat.

Related products

Compare
Quick view
Add to wishlist
Close

EW42 True wireless headset

Rated 0 out of 5
5 left in stock
1,299.00 kr
Add to cart
Compare
Quick view
Add to wishlist
Close

X71 charging cable for IPhone 1M

Rated 0 out of 5
24 left in stock
149.00 kr
Add to cart
Compare
Quick view
Add to wishlist
Close

Samsung music Headset AKG

Rated 0 out of 5
4 left in stock
349.00 kr
Add to cart
Samsung Jack USB-C til 3.5 mm
Compare
Quick view
Add to wishlist
Close

Samsung Jack USB-C til 3.5 mm

Rated 0 out of 5
18 left in stock
179.00 kr
Add to cart
Compare
Quick view
Add to wishlist
Close

X71 charging cable for Micro 1M

Rated 0 out of 5
75 left in stock
149.00 kr
Add to cart
Compare
Quick view
Add to wishlist
Close

Apple 20W USB-C Adapter

Rated 0 out of 5
10 left in stock
249.00 kr
Add to cart
Compare
Quick view
Add to wishlist
Close

IDeal Wireless QI Charger

Rated 0 out of 5
13 left in stock
399.00 kr
Add to cart
Compare
Quick view
Add to wishlist
Close

IDeal Wireless QI Charger

Rated 0 out of 5
16 left in stock
399.00 kr
Add to cart
Samsung
OG
Luxury clear magnetic
IDEAL OF SWEDEN
Hoco
Gorilla Anti-Shock
Fashion
Celly Hello world
BOROFONE
Apple
AMA Extra pas
AMA
Adidas

Vi startet reisen vår i 2017, da etterspørselen etter reparasjoner og reservedeler til mobiltelefoner og nettbrett økte betraktelig. Alibaba Telecom AS åpnet sin første butikk på AMFI sentrum i Larvik og videre åpnet nye avdelinger i forskjellige byer. Alibaba Telecom AS ble en av de største leverandøren i Norden, med et stort lager på mer enn 100 000 høykvalitetsprodukter. .

Storgata 107, 3921 Porsgrunn, Norway
Phone: (0047) 48473337
Phone: (0047) 41201616
Recent Posts
  • Protected: drammen
    December 12, 2022 No Comments
  • Protected: stathelle
    December 12, 2022 No Comments
Useful links
  • ALIBABA TELECOM
  • Electronics
  • Accessories
  • Contact Us
  • Abuot US
Footer Menu
  • Home
  • reparation
  • faq
  • Contact Us
  • abute us
  • Shop
Hinet.co 2022 All rights of this website belong to alibabatelecom
payments
  • Home
  • Electronics
  • Mobile, tablet , smart watches
  • Repare Phone Price
  • Accessories
  • Tempered Glass
Shopping cart
close
Select your currency
NOK Norwegian krone
USD United States (US) dollar
EUR Euro

Sign in

close

Lost your password?

No account yet?

Create an Account