Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 84
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
EcommerceSiteTypeService
0.00% covered (danger)
0.00%
0 / 84
0.00% covered (danger)
0.00%
0 / 8
756
0.00% covered (danger)
0.00%
0 / 1
 publish_woo_product
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
56
 set_woo_product_featured_image_from_url
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 import_image_from_url
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 create_or_get_woo_category
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 setup_woo_pages
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 get_woo_shop_page_info
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
20
 get_ecommerce_plugins
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 install_ecommerce_plugins
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2/**
3 * Ecommerce site type service.
4 *
5 * @package NewfoldLabs\WP\Module\Onboarding\Services\SiteTypes
6 */
7
8namespace NewfoldLabs\WP\Module\Onboarding\Services\SiteTypes;
9
10use NewfoldLabs\WP\Module\Installer\Services\PluginInstaller;
11use NewfoldLabs\WP\Module\Installer\TaskManagers\PluginActivationTaskManager;
12use NewfoldLabs\WP\Module\Installer\TaskManagers\PluginInstallTaskManager;
13use NewfoldLabs\WP\Module\Installer\Tasks\PluginActivationTask;
14use NewfoldLabs\WP\Module\Installer\Tasks\PluginInstallTask;
15use NewfoldLabs\WP\Module\Onboarding\Data\Plugins as LegacyPlugins;
16
17/**
18 * Ecommerce site type service.
19 */
20class EcommerceSiteTypeService {
21
22    /**
23     * Publishes a WooCommerce product.
24     *
25     * @param array $product The product.
26     * @return int|WP_Error The product ID.
27     */
28    public static function publish_woo_product( string $name, string $description, mixed $price, string $image_url = '', array $categories = array()) {
29        // Remove hooks that can slow down the operation.
30        remove_all_actions('woocommerce_new_product');
31        remove_all_actions('woocommerce_update_product');
32        remove_all_actions('wp_insert_post');
33        remove_all_actions('save_post');
34
35        $product_data = array(
36            'post_title'   => $name,
37            'post_content' => '',
38            'post_excerpt' => $description,
39            'post_status'  => 'publish',
40            'post_type'    => 'product',
41            'post_author'  => get_current_user_id() ?: 1,
42        );
43        // Insert product.
44        $product_id = wp_insert_post( $product_data );
45        // Validate product was created successfully.
46        if ( is_wp_error( $product_id ) || !$product_id ) {
47            return new \WP_Error( 'error_publishing_woo_product', 'Failed to create product' );
48        }
49        // Product meta.
50        update_post_meta( $product_id, '_regular_price', $price );
51        update_post_meta( $product_id, '_price', $price );
52        update_post_meta( $product_id, '_stock_status', 'instock' );
53        update_post_meta( $product_id, '_manage_stock', 'no' );
54        // Product categories.
55        if ( ! empty( $categories ) ) {
56            $category_ids = array();
57            foreach ( $categories as $category ) {
58                $category_ids[] = self::create_or_get_woo_category( $category );
59            }
60            wp_set_post_terms( $product_id, $category_ids, 'product_cat' );
61        }
62        // Featured image.
63        if ( ! empty( $image_url ) ) {
64            self::set_woo_product_featured_image_from_url( $image_url, $product_id );
65        }
66
67        return $product_id;
68    }
69
70    /**
71     * Sets the featured image for a WooCommerce product.
72     *
73     * @param string $image_url The URL of the image.
74     * @param int $product_id The ID of the product.
75     * @return void
76     */
77    private static function set_woo_product_featured_image_from_url( string $image_url, int $product_id ): void {
78        $image_id = self::import_image_from_url( $image_url, $product_id );
79        if ( $image_id ) {
80            update_post_meta( $product_id, '_thumbnail_id', $image_id );
81        }
82    }
83
84    /**
85     * Imports an image from a URL.
86     *
87     * @param string $image_url The URL of the image.
88     * @param int $product_id The ID of the product.
89     * @return int The ID of the attachment.
90     */
91    private static function import_image_from_url( string $image_url, int $product_id ): int {
92        if ( ! function_exists( 'media_handle_sideload' ) ) {
93            require_once( ABSPATH . 'wp-admin/includes/media.php' );
94            require_once( ABSPATH . 'wp-admin/includes/file.php' );
95            require_once( ABSPATH . 'wp-admin/includes/image.php' );
96        }
97
98        // Add an arbitrary extension to the image URL to trick media_sideload_image to download the image.
99        $image_url     = $image_url . '?ext=.jpeg';
100        $attachment_id = media_sideload_image( $image_url, $product_id, null, 'id' );
101        if ( is_wp_error( $attachment_id ) ) {
102            return 0;
103        }
104
105        return $attachment_id;
106    }
107
108    /**
109     * Creates or gets a WooCommerce category.
110     *
111     * @param string $name The name of the category.
112     * @return int The ID of the category.
113     */
114    public static function create_or_get_woo_category( string $name ): int {
115        $category_slug = sanitize_title( $name );
116        $category      = get_term_by( 'slug', $category_slug, 'product_cat' );
117        if ( $category ) {
118            return $category->term_id;
119        }
120        $category = wp_insert_term( $name, 'product_cat' );
121        if ( is_wp_error( $category ) ) {
122            return 0;
123        }
124        return $category['term_id'];
125    }
126
127    /**
128     * Sets up the WooCommerce pages.
129     *
130     * @return bool
131     */
132    public static function setup_woo_pages(): bool {
133        if ( class_exists( '\WC_Install' ) ) {
134            \WC_Install::create_pages();
135            return true;
136        }
137
138        return false;
139    }
140
141    /**
142     * Gets the WooCommerce shop page info.
143     *
144     * @return array The shop page info or an empty array if the shop page is not found.
145     */
146    public static function get_woo_shop_page_info(): array {
147        if ( ! function_exists( '\wc_get_page_id' ) || ! function_exists( '\wc_get_page_permalink' ) ) {
148            return array();
149        }
150
151        $shop_page_id = \wc_get_page_id( 'shop' );
152        if ( $shop_page_id ) {
153            return array(
154                'id'        => $shop_page_id,
155                'title'     => \get_the_title( $shop_page_id ),
156                'permalink' => \get_permalink( $shop_page_id ),
157            );
158        }
159
160        return array();
161    }
162
163    /**
164     * Gets the ecommerce plugins.
165     *
166     * @return array
167     */
168    public static function get_ecommerce_plugins(): array {
169        return LegacyPlugins::get_ecommerce_plugins();
170    }
171
172    /**
173     * Installs the ecommerce plugins (background task).
174     *
175     * @return void
176     */
177    public static function install_ecommerce_plugins(): void {
178        $ecommerce_plugins = self::get_ecommerce_plugins();
179
180        foreach ( $ecommerce_plugins as $plugin ) {
181            $plugin_type = PluginInstaller::get_plugin_type( $plugin['slug'] );
182            $plugin_path = PluginInstaller::get_plugin_path( $plugin['slug'], $plugin_type );
183            if ( ! $plugin_path ) {
184                continue;
185            }
186
187            // Checks if a plugin with the given slug and activation criteria already installed.
188            if ( PluginInstaller::is_plugin_installed( $plugin_path ) ) {
189                // If the plugin is installed, we'll add it to the activation queue.
190                PluginActivationTaskManager::add_to_queue(
191                    new PluginActivationTask(
192                        $plugin['slug']
193                    )
194                );
195                continue;
196            }
197
198            // If the plugin is not installed, we'll add it to the install/activation queue.
199            PluginInstallTaskManager::add_to_queue(
200                new PluginInstallTask(
201                    $plugin['slug'],
202                    true,
203                    isset( $plugin['priority'] ) ? $plugin['priority'] : 0
204                )
205            );
206        }
207
208        return;
209    }
210}