WordPress

xml – Import ponad 50 000 produktów do woocommerce trwa ponad 4 godziny

  • 6 kwietnia, 2023
  • 5 min read
xml – Import ponad 50 000 produktów do woocommerce trwa ponad 4 godziny


Oszaleję, próbując rozwiązać ten problem, pracuję nad tym już od 2 tygodni. Byłbym wdzięczny za wszelką pomoc.

Mam problem z importem ponad 50 000 produktów z pliku xml do woocommerce. Parsowanie xml jest szybkie, działa w mniej niż kilka minut, ale „część importu” do woocommerce jest bardzo powolna.

Próbowałem wordpress/woocommerce rest api i to było wielkie nie, za wolno. Więc teraz używam pliku PHP na serwerze, który analizuje pliki xml i przesyła je.

Otrzymuję plik XML w tym formacie:

 <product>
    <SKU>28760</SKU>
    <Name>...</Name>
    <Description>...</Description>
    <Category>...</Category>
    <Price>...</Price>
    <Shipping>...</Shipping>
    <Currency></Currency>
    <Instock>yes</Instock>
    <ProductUrl>...</ProductUrl>
    <ImageUrl>...</ImageUrl>
    <Brand>...</Brand>
    <OriginalPrice>...</OriginalPrice>
    <Ean>...</Ean>
    <ManufacturerArticleNumber>...</ManufacturerArticleNumber>
  </product>

Następnie podczas analizowania im za pomocą XMLReader w tym celu, wypychając każdy element/wiersz do tablicy tymczasowej, a następnie wywołując funkcję importu z tą tablicą.

Oto jak to działa:

  1. Skrypty Bash uruchamiają php import.php > run.log
  2. Rozpoczyna się import pliku, parsowanie xml jest szybkie, ale import jest powolny i wolniejszy po osiągnięciu około 2000 produktów.

Używam klasy WC_Product_Variable do stworzenia nowego produktu.

Oto moja funkcja „import($p, $coId, $coName)”, gdzie $p to produkt, $coId companyId i $coName nazwa firmy, z której mam plik xml.

    try {
        $product_exists = wc_get_product_id_by_sku($p->SKU . "-MAIN");

        if ($product_exists !== 0) {
            $product = wc_get_product($product_exists);
            $log->info('Product already exists, skipping', ["SKU" => $p->SKU . "-MAIN"]);
        } else {
            $product = new WC_Product_Variable();
            $product->set_name($p->Name);
            $product->set_sku($p->SKU . "-MAIN");
           
            $category = (string)$p->Category;

           
            $categories = explode(" - ", $category);
            $parent_id = 0; 
            foreach ($categories as $cat) {     
                $term = term_exists($cat, 'product_cat', $parent_id); 
                if (!$term) {
                    $term = wp_insert_term(
                        $cat, mn
                        'product_cat', 
                        array(
                            'parent' => $parent_id 
                        )
                    );
                }

                // New category id
                $parent_id = $term['term_id'];
            }

            // Upload image to wordpress
            $image_url = $p->ImageUrl;
            $image_id = media_sideload_image("{$image_url}", 0, null, "id");

            if (is_wp_error($image_id)) {
                echo "Error uploading image \n";
            } else {
                $product->set_image_id($image_id);
            }

            $product->set_category_ids(array($parent_id));

            $attributes = array();

            // one available for variation attribute
            $attribute = new WC_Product_Attribute();
            $attribute->set_name('Company');
            $attribute->set_options(array("{$coName}"));
            $attribute->set_position(0);
            $attribute->set_visible(true);
            $attribute->set_variation(true);
            $attributes[] = $attribute;

            $attribute = new WC_Product_Attribute();
            $attribute->set_name('Brand');
            $attribute->set_options(array($p->Brand));
            $attribute->set_position(0);
            $attribute->set_visible(true);
            $attribute->set_variation(false);
            $attributes[] = $attribute;

            $product->set_short_description((string)$p->Description);
            $product->set_attributes($attributes);
            $product->set_regular_price($p->OriginalPrice);
            $product->set_sale_price($p->Price); 
            $product->set_stock_status("outofstock");
            $product->save();

            $insertTag = wp_set_object_terms($product->get_id(), $p->Brand, "product_tag", true);
            if (is_wp_error($insertTag)) {
                echo "Cant insert tag for product: " . $insertTag->get_error_message() . " \n";
            }
        }
    } catch (Exception $e) {
        $log->error("Can't create main product", ["Error" => $e->getMessage(), "Product SKU" => $p->SKU]);
    }

    try {
        // now we need two variations for Magical and Non-magical Wizard hat
        $variation = new WC_Product_Variation();
        $variation->set_parent_id($product->get_id());
        $variation->set_sku((string)$p->SKU . "-" . $coId);
        $variation->set_attributes(array('company' => $coName));
        $variation->set_regular_price((string)$p->OriginalPrice);
        $variation->set_sale_price((string)$p->Price);
        $variation->set_stock_status(($p->Instock == "no" ? "outofstock" : "instock"));
        $variation->update_meta_data("brand", (string)$p->Brand);
        $variation->update_meta_data("updated", (string)Date("Y-m-d H:i:s"));
        $variation->save();
    } catch (Exception $e) {
        $log->error("Can't create variant product", ["Error" => $e->getMessage(), "Product SKU" => $p->SKU]);
    }

    // Check memory and CPU usage
    $load = sys_getloadavg();
    $memory_usage = memory_get_usage(true);




    if ($load[0] > 1.5 || $memory_usage > 0.9 * $memory_limit) {
        $logger->warning('Current memory and CPU usage - PAUSING 10 SEC', [
            'loadavg' => $load[0],
            'memory' => $memory_usage . " of " . $memory_limit,
        ]);
        sleep(10); // Pause 10 seconds
    }

Jakieś pomysły, jak mogę to przyspieszyć? W tej chwili import 25 000 produktów zajmuje około 4 godzin.

Warto przeczytać!  plugins - Moja witryna jest zepsuta z mnóstwem kodów

Używam VPS z 4 GB ramu, 2 procesory.

Poza tą funkcją jest to zawarte w moim pliku przed funkcją:

set_time_limit(0);
ini_set('memory_limit', '1024M');
ini_set('max_execution_time', 0);


require_once "vendor/autoload.php";

if (!defined('ABSPATH')) {
    define('ABSPATH', '/opt/bitnami/projects/****/public_html/');
}
include_once ABSPATH . 'wp-load.php';
include_once ABSPATH . 'wp-includes/class-wp-error.php';
include_once ABSPATH . 'wp-admin/includes/plugin.php';
include_once ABSPATH . 'wp-admin/includes/file.php';
include_once ABSPATH . 'wp-admin/includes/image.php';
require_once(ABSPATH . 'wp-admin/includes/media.php');



use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$memory_limit = ini_get('memory_limit');
if (preg_match('/^(\d+)(.)$/', $memory_limit, $matches)) {
    if ($matches[2] == 'M') {
        $memory_limit = $matches[1] * 1024 * 1024; // nnnM -> nnn MB
    } else if ($matches[2] == 'K') {
        $memory_limit = $matches[1] * 1024; // nnnK -> nnn KB
    }
}

// Create a logger
$log = new Logger('import');
$log->pushHandler(new StreamHandler('/opt/bitnami/projects/****/logs/import-' . Date("Y-m-d") . '.log', Logger::INFO));
$log->info('Init import', ["Status" => "Starting up"]);


// Log the current memory and CPU usage
$logger = new Monolog\Logger('import-usage');
$logger->pushHandler(new Monolog\Handler\StreamHandler('/opt/bitnami/projects/****/logs/import-' . Date("Y-m-d") . '.log', Monolog\Logger::DEBUG));



echo "Start import job... \n";


Źródło