php - WordPress 查询 19000+ 产品

标签 php mysql wordpress woocommerce

我的 WordPress 查询有问题。

我想做的事情:

我有包含产品数据的 CSV 文件(名称、价格、库存、SKU 等) 我想导入这个文件,但是当我尝试通过 SKU 获取产品 ID 时,我的查询对于我的服务器来说太高了,但我做了一些愚蠢的想法:在 foreach 中我试图获取所有的 Product_id。

可以在不终止我的服务器的情况下拆分我的 wp 查询吗? 我正在尝试 sleep ,但没有结果......

我的代码在这里:

    public function new_import_stock_prices(){
    global $wpdb;
    global $post;

    if ( !function_exists( 'wc_get_product_id_by_sku' ) ) { 
        require_once '/includes/wc-product-functions.php'; 
    } 

    echo '<h1>Import stanów magazynowych i cen z pliku CSV </h1>';
    echo '<h4>Plik pobierany jest z netis/products.csv</h4>';
    $fn = 'https://e-xxxxx.pl/xxx/products.csv';
    $file_array = file($fn);
    echo '<table>';
    echo '<tr>';
    echo '<td>LP</td>';
    echo '<td>Nazwa</td>';
    echo '<td>SKU</td>';
    echo '<td>Stan magazynowy</td>';
    echo '<td>Cena</td>';
    echo '<td>Product ID</td>';
    $i = 1;
    if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {

    foreach ($file_array as $line_number =>&$line)
        {
            if ($line_number > 0 && $line_number % 10 == 0) {

                $row2=explode('|',$line);
                $sku = $row2[1];
                // get the product ID from the SKU
                $product_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_sku' AND meta_value='%s' LIMIT 1", $sku ) );        
                // Get an instance of the WC_Product object
                $product = new WC_Product( $product_id );

                //Get product stock quantity and stock status
                $stock_quantity = $product->get_stock_quantity();
                $stock_status   = $product->get_stock_status();

                echo '<tr>';
                echo '<td>'.$i.'</td>';
                echo '<td>'.$row2[0].'</td>';
                echo '<td>'.$row2[1].'</td>';
                echo '<td>'.$row2[5].'</td>';
                echo '<td>'.$row2[2].'</td>';
                echo '<td>'.$product_id.'</td>';

                echo '</tr>';
                $i = $i +1;
                sleep(10);
            }
        }
    }
    echo '</table>';
}
顺便说一句。我的 wp_postmeta 表有大约 900 000 多条记录:O

最佳答案

And I want to import this file

我没有看到任何用于导入的代码,但我看到了用于显示的代码。假设导入是指显示:

可能发生的事情只是少数事情之一。

  • 内存不足(您应该会收到错误消息)
    • 不要使用file($fn)使用打开文件并逐行读取的文件函数,例如fgetcsv
  • 你的时间不多了
    • 对此您无能为力,除了发送更少的数据
  • 通过发送大量输出来压垮浏览器缓冲区。
    • 同样,您对此无能为力,只能发送更少的数据。

唯一真正的解决方案(假设通过导入,您的意思是显示)是对数据进行分页。

现在,即使在文件中,您也可以对数据进行分页,但我建议使用 SQLFileObject 而不是过程文件函数。也就是说,您可以使用程序样式进行分页,但它是按字节偏移量,而不是页码。

虽然我无法编写整个分页系统的代码,但我可以给您一些提示:

例如

//hard to tell how many lines in the file
$fn = 'https://e-xxxxx.pl/xxx/products.csv';
$f = fopen($fn, 'r');
fseek($f, $_GET['offset']); //seek to a byte offset
$i=0;
while(!feof($f) && ($row=fgetcsv($f)) && null !== $row[0]){

   if($i==10)
       $offset = ftell($f); //get byte offset

   ++$i;
}

ftellfseek 允许您获取或移动文件指针(以字节为单位)。因此,您可以从预定义的偏移量开始读取,您可以在 url 中传递该偏移量...等。

您可以使用 SplFileObject 执行相同的操作,但效果更好一些。

try {
    $fn = 'https://e-xxxxx.pl/xxx/products.csv';
    $csv  = new SplFileObject($fn, 'r');
} catch (RuntimeException $e ) {
    printf("Error openning csv: %s\n", $e->getMessage());
}

$csv->seek($_GET['line']); //seek to a predefined line

while(!$csv->eof() && ($row = $csv->fgetcsv()) && null !== $row[0]) {
    if(($csv->key()-$_GET['line'])==10) 
        $line = $csv->key(); //get line offset
   ++$i;
}

SPL 的主要优点是您可以使用行号,这更容易使用。

您还可以像这样获取文件中的总行数

$csv->seek(PHP_INT_MAX);
$total = $csv->key();
$csv->rewind(); //or $csv->seek($_GET['line'])

基本上,这寻求 PHP 可以处理的最大可能的 INT,但由于文件是固定长度,因此它将指针放在文件末尾,然后使用 key 我们可以得到该行数字。然后我们只需倒退到我们想要阅读的位置即可。

我提到了总行数,因为在分页中能够显示它是很好的。

另一个选项(显示)

此外分页就是不缓冲地输出页面。

 // Turn off output buffering
 ini_set('output_buffering', 'off');
 // Turn off PHP output compression
 ini_set('zlib.output_compression', false);

 //Flush (send) the output buffer and turn off output buffering
 //ob_end_flush();
 while (ob_get_level()) ob_end_flush();

 // Implicitly flush the buffer(s)
 ini_set('implicit_flush', true);
 ob_implicit_flush(true);

将其与我上面展示的方法之一结合起来,一次读取文件 1 行,您最终可能能够读出所有数据。

保存

为了保存数据,您可能需要将其分成批处理,可以在此处完成与分页相同的操作(使用偏移量或行)。这样您一次只能导入几千行。我还建议不要输出数据,因为您可以为浏览器提供更多缓冲区,然后它可以处理并锁定它。但是,如果您对数据进行分页,则可以将其分成足够小的 block ,以便浏览器可以处理它。

您甚至可以使用连续的 AJAX 调用来自动执行此操作。基本上,您会调用后端的代码来保存一定数量的行 (x)。服务器会响应,然后您将再次调用 (x) 更多行,保存并重复。

I want to display all products id, to check if it's correct. Next step is change stock, price and saving products

仅从数据输入的角度来看,在 Excel 之类的工具中完成这项工作会更容易,没有人愿意在网页上编辑数千行,然后导致 session 超时或类似的情况。

希望有帮助。

关于php - WordPress 查询 19000+ 产品,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52921028/

相关文章:

php - 将选择下拉列表添加到 PHP POST 电子邮件表单

php - 在模式而不是新页面中加载查询搜索结果

mysql - 使用附加搜索条件查找每组链接表中字段的总和

php - 仅更改商店页面的 WooCommerce 产品列 CSS

PHP 发送到 Outlook PDF 文件

javascript - 显示多个标记、变量和数组问题

sql - 加权关键字搜索

php - 如何使用动态页面的索引号链接到页面

css - Wordpress - 我想让我网站的访问者在移动响应或桌面样式模式之间进行选择

javascript - 将数组从 HTML 表单传递到 PHP,然后传递到 WordPress