Skip to content

Instantly share code, notes, and snippets.

@vladutilie
Last active August 19, 2024 09:56
Show Gist options
  • Save vladutilie/67e133747f5aa73219cc887506a92bbe to your computer and use it in GitHub Desktop.
Save vladutilie/67e133747f5aa73219cc887506a92bbe to your computer and use it in GitHub Desktop.
Sync WooCommerce products from an external CSV file

Sync WooCommerce products from an external CSV file

This PHP class provides a mechanism to sync WooCommerce products with an external CSV file via a REST API endpoint in WordPress. The class is designed to update the stock status, regular price, and sale price of products based on the CSV data.

Features

  • REST API Integration: Exposes an API route (/theme-name/v1/sync) to trigger the product synchronization.
  • CSV Processing: Downloads a CSV file from a specified URL, parses it, and updates WooCommerce products accordingly.
  • Stock Status Update: Automatically updates the stock status of products based on the CSV data.
  • Price Update: Updates both regular and sale prices of products as per the CSV file.
  • Execution Time Logging: Returns the execution time of the synchronization process in the API response.

Installation

  1. Copy the class into your WordPress theme or plugin.
  2. Replace the placeholder values with your own:
  • NAMESPACE: Set this to a unique identifier for your API namespace.
  • secret_key: Define a secure key to authenticate API requests.
  • external_feed_url: Set the URL to the external CSV file containing product data.
  1. Ensure that WooCommerce is installed and active in your WordPress setup.

Usage

Once the class is integrated into your theme or plugin, the REST API route /wp-json/theme-name/v1/sync will be available. You can trigger the synchronization by making a GET request to this endpoint with the following parameter:

  • secret_key: The secret key to authenticate the request.

Example Request

curl -X GET 'https://your-site.com/wp-json/theme-name/v1/sync?secret_key=my_secret_key'

CSV File Structure

The CSV file should have the following columns in order:

  • SKU: The product's SKU (Stock Keeping Unit).
  • Regular Price: The product's regular price.
  • Sale Price: The product's sale price (optional).
  • Stock Status: 1 for in stock, 0 for out of stock.

Example CSV

sku,regular_price,sale_price,status
12345,19.99,14.99,1
67890,29.99,,0

API Response

The API returns a JSON response containing the number of updated products and the time taken to complete the process:

{
    "new_in_stock": 2,
    "new_out_of_stock": 0,
    "regular_price": 2,
    "sale_price": 1,
    "execution_time_seconds": 1.2345
}

Notes

Ensure that the WP_Filesystem API has the necessary permissions to download and manipulate files on your server. The class handles downloading, reading, and deleting the CSV file during the process.

License

This project is open-source and available under the MIT License.

<?php
/**
* Sync Products
*/
/**
* Sync Products class.
*/
class Sync_Products {
/**
* The namespace of the API
*
* @var string
*/
const NAMESPACE = 'theme-name/v1';
/**
* The secret key to authenticate the request.
*
* @var string
*/
protected string $secret_key = 'my_secret_key';
/**
* The external feed URL.
*
* @var string
*/
protected string $external_feed_url = 'https://url-to-csv-file';
/**
* Constructor function.
*/
public function __construct() {
add_action( 'rest_api_init', array( $this, 'register_api_routes' ) );
}
/**
* Register the API routes.
*/
public function register_api_routes(): void {
register_rest_route(
self::NAMESPACE,
'/sync',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'sync' ),
'permission_callback' => function( $args ) {
return $args['secret_key'] === $this->secret_key;
},
'args' => array(
'secret_key' => array(
'type' => 'string',
'required' => true,
'description' => 'The secret key to authenticate the request.',
),
),
)
);
}
/**
* Sync products.
*
* It stores the CSV file in a temporary file, reads it, deletes it (after the content is stored in a variable)
* and updates the products in the database.
*/
public function sync(): WP_REST_Response {
$start_time = microtime( true );
global $wp_filesystem;
require_once ABSPATH . '/wp-admin/includes/file.php';
WP_Filesystem();
$temporary_path = ABSPATH . '/wp-content/uploads/products.csv';
$content = $wp_filesystem->get_contents( $this->external_feed_url );
$temporary_download = $wp_filesystem->put_contents( $temporary_path, $content, 0644 );
if ( ! $temporary_download ) {
return new WP_REST_Response( array( 'message' => 'Error downloading the file.' ), 500 );
}
$products = array_map( 'str_getcsv', file( $temporary_path ) );
$wp_filesystem->delete( $temporary_path );
array_shift( $products ); // Remove the header of the CSV.
$updates = array(
'new_in_stock' => 0,
'new_out_of_stock' => 0,
'regular_price' => 0,
'sale_price' => 0,
);
foreach ( $products as $key => $line ) {
list( $sku,,,,, $regular_price, $sale_price, $status ) = $line;
$product_id = wc_get_product_id_by_sku( $sku );
if ( $product_id ) {
$needs_save = false;
$product = wc_get_product( $product_id );
if ( '0' === $status ) {
$product->set_stock_status( 'outofstock' );
$updates['new_out_of_stock']++;
$needs_save = true;
} elseif ( '1' === $status ) {
$product->set_stock_status( 'instock' );
$updates['new_in_stock']++;
$needs_save = true;
}
if ( ! empty( $regular_price ) ) {
$product->set_regular_price( $regular_price );
$updates['regular_price']++;
$needs_save = true;
}
if ( ! empty( $sale_price ) ) {
$product->set_sale_price( $sale_price );
$updates['sale_price']++;
$needs_save = true;
}
if ( $needs_save ) {
$product->save();
}
}
}
$end_time = microtime( true );
$execution_time = $end_time - $start_time;
return new WP_REST_Response(
array_merge(
$updates,
array( 'execution_time_seconds' => $execution_time )
),
200
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment