id && version_compare( WC_VERSION, '2.3.0', '<' ) ) { $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; wp_enqueue_script( 'wc_subscription_downloads_writepanel', plugins_url( 'assets/js/admin/writepanel' . $suffix . '.js', plugin_dir_path( __FILE__ ) ), array( 'ajax-chosen', 'chosen' ), WC_Subscriptions::$version, true ); wp_localize_script( 'wc_subscription_downloads_writepanel', 'wc_subscription_downloads_product', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'security' => wp_create_nonce( 'search-products' ), ) ); } } /** * Simple product write panel options. */ public function simple_write_panel_options() { global $post; ?>

get_var( $wpdb->prepare( "SELECT post_parent AS parent_id FROM {$wpdb->prefix}posts WHERE ID = %d; ", $subscription_product_id ) ); // If the subscription product is a variation, use variation meta key to find related orders. if ( ! empty( $parent_id ) ) { $meta_key = '_variation_id'; } $results = $wpdb->get_results( $wpdb->prepare( "SELECT order_items.order_id AS id FROM {$wpdb->prefix}woocommerce_order_items as order_items LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS itemmeta ON order_items.order_item_id = itemmeta.order_item_id WHERE itemmeta.meta_key = %s AND itemmeta.meta_value = %d; ", $meta_key, $subscription_product_id ) ); foreach ( $results as $order ) { $orders[] = $order->id; } $orders = apply_filters( 'woocommerce_subscription_downloads_get_orders', $orders, $subscription_product_id ); return $orders; } /** * Revoke access to download. * * @param bool $download_id * @param bool $product_id * @param bool $order_id * * @return void */ protected function revoke_access_to_download( $download_id, $product_id, $order_id ) { global $wpdb; $wpdb->query( $wpdb->prepare( " DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE order_id = %d AND product_id = %d AND download_id = %s; ", $order_id, $product_id, $download_id ) ); do_action( 'woocommerce_ajax_revoke_access_to_product_download', $download_id, $product_id, $order_id ); } /** * Update subscription downloads table and orders. * * @param int $product_id * @param array $subscriptions * * @return void */ protected function update_subscription_downloads( $product_id, $subscriptions ) { global $wpdb; if ( version_compare( WC_VERSION, '3.0', '<' ) && ! empty( $subscriptions ) ) { $subscriptions = explode( ',', $subscriptions ); } $current = WC_Subscription_Downloads::get_subscriptions( $product_id ); // Delete items. $delete_ids = array_diff( $current, $subscriptions ); if ( $delete_ids ) { foreach ( $delete_ids as $delete ) { $wpdb->delete( $wpdb->prefix . 'woocommerce_subscription_downloads', array( 'product_id' => $product_id, 'subscription_id' => $delete, ), array( '%d', '%d', ) ); $_orders = $this->get_orders( $delete ); foreach ( $_orders as $order_id ) { $_product = wc_get_product( $product_id ); $downloads = version_compare( WC_VERSION, '3.0', '<' ) ? $_product->get_files() : $_product->get_downloads(); // Adds the downloadable files to the order/subscription. foreach ( array_keys( $downloads ) as $download_id ) { $this->revoke_access_to_download( $download_id, $product_id, $order_id ); } } } } // Add items. $add_ids = array_diff( $subscriptions, $current ); if ( $add_ids ) { foreach ( $add_ids as $add ) { $wpdb->insert( $wpdb->prefix . 'woocommerce_subscription_downloads', array( 'product_id' => $product_id, 'subscription_id' => $add, ), array( '%d', '%d', ) ); $_orders = $this->get_orders( $add ); foreach ( $_orders as $order_id ) { $order = wc_get_order( $order_id ); if ( ! is_a( $order, 'WC_Subscription' ) ) { // avoid adding permissions to orders and it's // subscription for the same user, causing duplicates // to show up continue; } $_product = wc_get_product( $product_id ); $downloads = version_compare( WC_VERSION, '3.0', '<' ) ? $_product->get_files() : $_product->get_downloads(); // Adds the downloadable files to the order/subscription. foreach ( array_keys( $downloads ) as $download_id ) { wc_downloadable_file_permission( $download_id, $product_id, $order ); } } } } } /** * Save simple product data. * * @param int $product_id * * @return void */ public function save_simple_product_data( $product_id ) { $subscription_ids = ! empty( $_POST['_subscription_downloads_ids'] ) ? wc_clean( wp_unslash( $_POST['_subscription_downloads_ids'] ) ) : ''; if ( ! isset( $_POST['_downloadable'] ) || 'publish' !== get_post_status( $product_id ) ) { update_post_meta( $product_id, '_subscription_downloads_ids', $subscription_ids ); return; } delete_post_meta( $product_id, '_subscription_downloads_ids', $subscription_ids ); $subscriptions = $subscription_ids ?: array(); $this->update_subscription_downloads( $product_id, $subscriptions ); } /** * Save variable product data. * * @param int $variation_id * @param int $index * * @return void */ public function save_variation_product_data( $variation_id, $index ) { if ( ! isset( $_POST['variable_is_downloadable'][ $index ] ) ) { return; } $subscriptions = isset( $_POST['_variable_subscription_downloads_ids'][ $index ] ) ? wc_clean( wp_unslash( $_POST['_variable_subscription_downloads_ids'][ $index ] ) ) : array(); if ( version_compare( WC_VERSION, '3.0.0', '<' ) ) { $subscriptions = explode( ',', $subscriptions ); } $subscriptions = array_filter( $subscriptions ); // nosemgrep: audit.php.lang.misc.array-filter-no-callback -- $subscriptions are already passed through wc_clean() and wp_unslash(). $this->update_subscription_downloads( $variation_id, $subscriptions ); } /** * Save subscriptions information when duplicating a product. * * @param int|WC_Product $id_or_product Duplicated product ID * @param WP_Post|WC_Product $post Product being duplicated */ public function save_subscriptions_when_duplicating_product( $id_or_product, $post ) { $post_id = is_a( $post, 'WC_Product' ) ? $post->get_parent_id() : $post->ID; $new_id = is_a( $id_or_product, 'WC_Product' ) ? $id_or_product->get_id() : $id_or_product; $subscriptions = WC_Subscription_Downloads::get_subscriptions( $post_id ); if ( ! empty( $subscriptions ) ) { $this->update_subscription_downloads( $new_id, $subscriptions ); } $children_products = get_children( 'post_parent=' . $post_id . '&post_type=product_variation' ); if ( empty( $children_products ) ) { return; } // Create assoc array where keys are flatten variation attributes and values // are original product variations. $children_ids_by_variation_attributes = array(); foreach ( $children_products as $child ) { $str_attributes = $this->get_str_variation_attributes( $child ); if ( ! empty( $str_attributes ) ) { $children_ids_by_variation_attributes[ $str_attributes ] = $child; } } // Copy variations' subscriptions. $exclude = apply_filters( 'woocommerce_duplicate_product_exclude_children', false ); $new_children_products = get_children( 'post_parent=' . $new_id . '&post_type=product_variation' ); if ( ! $exclude && ! empty( $new_children_products ) ) { foreach ( $new_children_products as $child ) { $str_attributes = $this->get_str_variation_attributes( $child ); if ( ! empty( $children_ids_by_variation_attributes[ $str_attributes ] ) ) { $this->save_subscriptions_when_duplicating_product( $child->ID, $children_ids_by_variation_attributes[ $str_attributes ] ); } } } } /** * Get string representation of variation attributes from a given product variation. * * @param mixed $product_variation Product variation * * @return string Variation attributes */ protected function get_str_variation_attributes( $product_variation ) { $product_variation = wc_get_product( $product_variation ); if ( ! is_callable( array( $product_variation, 'get_formatted_variation_attributes' ) ) ) { return false; } return (string) wc_get_formatted_variation( $product_variation, true ); } }