'; printf( /* Translators: %1$s is the install command, %2$s is the build command, %3$s is the watch command. */ esc_html__( 'WooCommerce Blocks development mode requires files to be built. From the plugin directory, run %1$s to install dependencies, %2$s to build the files or %3$s to build the files and watch for changes.', 'woo-gutenberg-products-block' ), 'npm install', 'npm run build', 'npm start' ); echo '

'; } /** * Adds a WooCommerce category to the block inserter. * * @param array $categories Array of categories. * @return array Array of block categories. */ function wgpb_add_block_category( $categories ) { return array_merge( $categories, array( array( 'slug' => 'woocommerce', 'title' => __( 'WooCommerce', 'woo-gutenberg-products-block' ), 'icon' => 'woocommerce', ), ) ); } /** * Register the Products block and its scripts. */ function wgpb_register_blocks() { include_once dirname( __FILE__ ) . '/includes/blocks/class-wc-block-featured-product.php'; // Legacy block. register_block_type( 'woocommerce/products', array( 'editor_script' => 'woocommerce-products-block-editor', 'editor_style' => 'woocommerce-products-block-editor', ) ); // New blocks. register_block_type( 'woocommerce/handpicked-products', array( 'editor_script' => 'wc-handpicked-products', 'editor_style' => 'wc-handpicked-products-editor', ) ); register_block_type( 'woocommerce/product-best-sellers', array( 'editor_script' => 'wc-product-best-sellers', 'editor_style' => 'wc-product-best-sellers-editor', ) ); register_block_type( 'woocommerce/product-category', array( 'editor_script' => 'wc-product-category', 'editor_style' => 'wc-product-category-editor', ) ); register_block_type( 'woocommerce/product-new', array( 'editor_script' => 'wc-product-new', 'editor_style' => 'wc-product-new-editor', ) ); register_block_type( 'woocommerce/product-on-sale', array( 'editor_script' => 'wc-product-on-sale', 'editor_style' => 'wc-product-on-sale-editor', ) ); register_block_type( 'woocommerce/product-top-rated', array( 'editor_script' => 'wc-product-top-rated', 'editor_style' => 'wc-product-top-rated-editor', ) ); register_block_type( 'woocommerce/featured-product', array( 'render_callback' => array( 'WC_Block_Featured_Product', 'render' ), 'editor_script' => 'wc-featured-product', 'style' => 'wc-featured-product-editor', ) ); } /** * Register extra scripts needed. */ function wgpb_register_scripts() { if ( ! function_exists( 'wc_get_theme_support' ) ) { return; } $block_dependencies = array( 'wp-api-fetch', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-editor', 'wp-i18n', 'wp-url', 'lodash', 'wc-vendors', ); // @todo Remove this dependency (as it adds a separate react instance). wp_register_script( 'react-transition-group', plugins_url( 'assets/js/vendor/react-transition-group.js', __FILE__ ), array(), '2.2.1', true ); wp_register_script( 'wc-vendors', plugins_url( 'build/vendors.js', __FILE__ ), array(), wgpb_get_file_version( '/build/vendors.js' ), true ); wp_register_script( 'wc-handpicked-products', plugins_url( 'build/handpicked-products.js', __FILE__ ), $block_dependencies, wgpb_get_file_version( '/build/handpicked-products.js' ), true ); wp_register_script( 'wc-product-best-sellers', plugins_url( 'build/product-best-sellers.js', __FILE__ ), $block_dependencies, wgpb_get_file_version( '/build/product-best-sellers.js' ), true ); wp_register_script( 'wc-product-category', plugins_url( 'build/product-category.js', __FILE__ ), $block_dependencies, wgpb_get_file_version( '/build/product-category.js' ), true ); wp_register_script( 'wc-product-new', plugins_url( 'build/product-new.js', __FILE__ ), $block_dependencies, wgpb_get_file_version( '/build/product-new.js' ), true ); wp_register_script( 'wc-product-on-sale', plugins_url( 'build/product-on-sale.js', __FILE__ ), $block_dependencies, wgpb_get_file_version( '/build/product-on-sale.js' ), true ); wp_register_script( 'wc-product-top-rated', plugins_url( 'build/product-top-rated.js', __FILE__ ), $block_dependencies, wgpb_get_file_version( '/build/product-top-rated.js' ), true ); wp_register_script( 'wc-featured-product', plugins_url( 'build/featured-product.js', __FILE__ ), $block_dependencies, wgpb_get_file_version( '/build/featured-product.js' ), true ); wp_register_script( 'woocommerce-products-block-editor', plugins_url( 'build/products-block.js', __FILE__ ), array( 'wp-api-fetch', 'wp-element', 'wp-components', 'wp-blocks', 'wp-editor', 'wp-i18n', 'react-transition-group' ), wgpb_get_file_version( '/build/products-block.js' ), true ); if ( function_exists( 'wp_set_script_translations' ) ) { wp_set_script_translations( 'woocommerce-blocks', 'woo-gutenberg-products-block' ); } wp_register_style( 'wc-vendors', plugins_url( 'build/vendors.css', __FILE__ ), array(), wgpb_get_file_version( '/build/vendors.css' ) ); wp_register_style( 'wc-products-grid', plugins_url( 'build/products-grid.css', __FILE__ ), array(), wgpb_get_file_version( '/build/products-grid.css' ) ); wp_register_style( 'wc-handpicked-products-editor', plugins_url( 'build/handpicked-products.css', __FILE__ ), array( 'wc-vendors', 'wp-edit-blocks', 'wc-products-grid' ), wgpb_get_file_version( '/build/handpicked-products.css' ) ); wp_register_style( 'wc-product-best-sellers-editor', plugins_url( 'build/product-best-sellers.css', __FILE__ ), array( 'wc-vendors', 'wp-edit-blocks', 'wc-products-grid' ), wgpb_get_file_version( '/build/product-best-sellers.css' ) ); wp_register_style( 'wc-product-category-editor', plugins_url( 'build/product-category.css', __FILE__ ), array( 'wc-vendors', 'wp-edit-blocks', 'wc-products-grid' ), wgpb_get_file_version( '/build/product-category.css' ) ); wp_register_style( 'wc-product-new-editor', plugins_url( 'build/product-new.css', __FILE__ ), array( 'wc-vendors', 'wp-edit-blocks', 'wc-products-grid' ), wgpb_get_file_version( '/build/product-new.css' ) ); wp_register_style( 'wc-product-on-sale-editor', plugins_url( 'build/product-on-sale.css', __FILE__ ), array( 'wc-vendors', 'wp-edit-blocks', 'wc-products-grid' ), wgpb_get_file_version( '/build/product-on-sale.css' ) ); wp_register_style( 'wc-product-top-rated-editor', plugins_url( 'build/product-top-rated.css', __FILE__ ), array( 'wc-vendors', 'wp-edit-blocks', 'wc-products-grid' ), wgpb_get_file_version( '/build/product-top-rated.css' ) ); wp_register_style( 'woocommerce-products-block-editor', plugins_url( 'build/products-block.css', __FILE__ ), array( 'wc-vendors', 'wp-edit-blocks' ), wgpb_get_file_version( '/build/products-block.css' ) ); wp_register_style( 'wc-featured-product-editor', plugins_url( 'build/featured-product.css', __FILE__ ), array( 'wc-vendors', 'wp-edit-blocks' ), wgpb_get_file_version( '/build/featured-product.css' ) ); add_action( 'admin_print_footer_scripts', 'wgpb_print_script_settings', 1 ); } /** * Get the file modified time as a cache buster if we're in dev mode. * * @param string $file Local path to the file. * @return string The cache buster value to use for the given file. */ function wgpb_get_file_version( $file ) { if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) { $file = trim( $file, '/' ); return filemtime( plugin_dir_path( __FILE__ ) . $file ); } return WGPB_VERSION; } /** * Output the wcSettings global before printing any script tags. */ function wgpb_print_script_settings() { global $wp_locale; $code = get_woocommerce_currency(); // Settings and variables can be passed here for access in the app. // Will need `wcAdminAssetUrl` if the ImageAsset component is used. // Will need `dataEndpoints.countries` if Search component is used with 'country' type. // Will need `orderStatuses` if the OrderStatus component is used. // Deliberately excluding: `embedBreadcrumbs`, `trackingEnabled`. $settings = array( 'adminUrl' => admin_url(), 'wcAssetUrl' => plugins_url( 'assets/', WC_PLUGIN_FILE ), 'siteLocale' => esc_attr( get_bloginfo( 'language' ) ), 'currency' => array( 'code' => $code, 'precision' => wc_get_price_decimals(), 'symbol' => get_woocommerce_currency_symbol( $code ), 'position' => get_option( 'woocommerce_currency_pos' ), ), 'stockStatuses' => wc_get_product_stock_status_options(), 'siteTitle' => get_bloginfo( 'name' ), 'dataEndpoints' => array(), 'l10n' => array( 'userLocale' => get_user_locale(), 'weekdaysShort' => array_values( $wp_locale->weekday_abbrev ), ), ); // Global settings used in each block. $block_settings = array( 'min_columns' => wc_get_theme_support( 'product_grid::min_columns', 1 ), 'max_columns' => wc_get_theme_support( 'product_grid::max_columns', 6 ), 'default_columns' => wc_get_default_products_per_row(), 'min_rows' => wc_get_theme_support( 'product_grid::min_rows', 1 ), 'max_rows' => wc_get_theme_support( 'product_grid::max_rows', 6 ), 'default_rows' => wc_get_default_product_rows_per_page(), ); ?> register_routes(); $categories = new WGPB_Product_Categories_Controller(); $categories->register_routes(); $attributes = new WGPB_Product_Attributes_Controller(); $attributes->register_routes(); $attribute_terms = new WGPB_Product_Attribute_Terms_Controller(); $attribute_terms->register_routes(); } /** * Brings some extra required shortcode features from WC core 3.4+ to this feature plugin. * * @todo Remove this function when merging into core because it won't be necessary. * * @param array $args WP_Query args. * @param array $attributes Shortcode attributes. * @param string $type Type of shortcode currently processing. */ function wgpb_extra_shortcode_features( $args, $attributes, $type ) { if ( 'products' !== $type ) { return $args; } // Enable term ids in the category shortcode. if ( ! empty( $attributes['category'] ) ) { $categories = array_map( 'sanitize_title', explode( ',', $attributes['category'] ) ); $field = 'slug'; if ( empty( $args['tax_query'] ) ) { $args['tax_query'] = array(); // WPCS: slow query ok. } // Unset old category tax query. foreach ( $args['tax_query'] as $index => $tax_query ) { if ( 'product_cat' === $tax_query['taxonomy'] ) { unset( $args['tax_query'][ $index ] ); } } if ( is_numeric( $categories[0] ) ) { $categories = array_map( 'absint', $categories ); $field = 'term_id'; } $args['tax_query'][] = array( 'taxonomy' => 'product_cat', 'terms' => $categories, 'field' => $field, 'operator' => $attributes['cat_operator'], // See https://github.com/woocommerce/woocommerce/pull/20207/files#diff-9982e2749834d5232f1ed411b6c20312. 'include_children' => 'AND' === $attributes['cat_operator'] ? false : true, ); } // Enable term ids in the attributes shortcode and just-attribute queries. if ( ! empty( $attributes['attribute'] ) || ! empty( $attributes['terms'] ) ) { $taxonomy = strstr( $attributes['attribute'], 'pa_' ) ? sanitize_title( $attributes['attribute'] ) : 'pa_' . sanitize_title( $attributes['attribute'] ); $terms = $attributes['terms'] ? array_map( 'sanitize_title', explode( ',', $attributes['terms'] ) ) : array(); $field = 'slug'; if ( empty( $args['tax_query'] ) ) { $args['tax_query'] = array(); // WPCS: slow query ok. } // Unset old attribute tax query. foreach ( $args['tax_query'] as $index => $tax_query ) { if ( $taxonomy === $tax_query['taxonomy'] ) { unset( $args['tax_query'][ $index ] ); } } if ( $terms && is_numeric( $terms[0] ) ) { $terms = array_map( 'absint', $terms ); $field = 'term_id'; } // If no terms were specified get all products that are in the attribute taxonomy. if ( ! $terms ) { $terms = get_terms( array( 'taxonomy' => $taxonomy, 'fields' => 'ids', ) ); $field = 'term_id'; } $args['tax_query'][] = array( 'taxonomy' => $taxonomy, 'terms' => $terms, 'field' => $field, 'operator' => $attributes['terms_operator'], ); } return $args; } add_filter( 'woocommerce_shortcode_products_query', 'wgpb_extra_shortcode_features', 10, 3 );