Last active
May 19, 2022 07:33
-
-
Save andykillen/e68db8f52bf3315e0a971d626509befa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* copyrights andrew killen 2017 | |
* | |
* Attribution-ShareAlike 4.0 International. | |
**/ | |
/** | |
* This will get the contents from the db about the current values, optionally if you have setup | |
* a custom taxonomy you can say "I want from supplier ID n" this helps as SKU's can often be the same | |
* for many suppliers, it will then load/download an XML file and convert it to an Array, | |
* and finally loop through the DB current values, looking for them in the feed array by SKU, if they exist | |
* then it will try to update the meta, logging ths changes made. | |
* | |
**/ | |
class xmlUpdateWooCommerce { | |
// place on the system where CRON downloads the file. this is normally 10 --> 20X faster than php | |
protected $fileSystemFile = '/path/to/cron/downloaded/file.xml'; | |
// fall back to remote url | |
protected $feedUrl = "https://somesite.com/feed.xml"; | |
// where the database current values are held | |
protected $result; | |
// the XML that is loaded | |
protected $xml; | |
/** | |
* How to run the whole thing. | |
* @param $supplier int, optional tax term id that can be used to define all products from one supplier | |
*/ | |
public function init($supplier = 0){ | |
$this->getCurrentDbValues($supplier); | |
$this->openFeedAsXML(); | |
$this->feedLoopAndUpdate() | |
} | |
/** | |
* Use $wpdb and a generated select statement to return an object with all | |
* of the needed produt meta + product ID | |
* | |
* @param $supplier int taxonomy term id | |
* | |
* @return object | |
*/ | |
protected function getCurrentDbValues($supplier = 0){ | |
global $wpdb; | |
// set the post type to search through | |
$post_type = 'product'; | |
// postmeta data that will be joined to the result | |
$metas = ['_sku','_stock', '_regular_price','_price']; | |
// look the metas to add the sql statement to make the joins | |
foreach ($metas as $i => $meta_key) { | |
$meta_fields[] = 'm' . $i . '.meta_value as ' . $meta_key; | |
$meta_joins[] = ' left join ' . $wpdb->postmeta . ' as m' . $i . ' on m' . $i . '.post_id=' . $wpdb->posts . '.ID and m' . $i . '.meta_key="' . $meta_key . '"'; | |
} | |
// begin the SQL statemnt adding in the meta fields to ID | |
$request = "SELECT ID, " . join(',', $meta_fields) . " FROM $wpdb->posts "; | |
// add the joins | |
$request .= join(' ', $meta_joins); | |
// make sure its using the right post status and post type | |
$request .= " WHERE {$wpdb->posts}.post_status='publish' AND {$wpdb->posts}.post_type='{$post_type}'"; | |
/** | |
* Optional, use supplier taxonomy to reduce the total number of records | |
* returned. This is often needed as SKU's can be the same from many suppliers. | |
* | |
* It should really double check to see if the term tax id exists first... | |
**/ | |
if($supplier != 0){ | |
$request .= " AND ID IN( | |
select object_id FROM {$wpdb->prefix}term_relationships where term_taxonomy_id ='{$supplier}' | |
)"; | |
} | |
$this->result = $wpdb->get_results($request); | |
} | |
/** | |
* tries to get CRON downloaded file first | |
* | |
* Idealy this should check the file datetime to see if it out of date | |
* | |
* @return void | |
**/ | |
protected function openFeedAsXML(){ | |
if(file_exists($this->fileSystemFile)){ | |
$this->xml = simplexml_load_file($this->fileSystemFile, NULL, LIBXML_NOCDATA); | |
} else { | |
$content = file_get_contents($this->feedUrl); | |
$this->xml = simplexml_load_string($content, NULL, LIBXML_NOCDATA); | |
} | |
} | |
/** | |
* Loop through the feed XML converting it to an assoicative array | |
* where the sku is the key, and the other values are in an array assoicated | |
* with it. | |
* | |
* this will convert the entire feed, not just the items that are in the db. | |
* becuase of the use late of isset(), it will make it uber fast. | |
* | |
* If I was making this for anyone else I would have spilt this up a bit into separate methods | |
* and not nested loops, but I love doing it this way. nested loops make me happy :) | |
*/ | |
protected function feedLoopAndUpdate(){ | |
// VidaXL use /products/product to hold the stock items. change this as needed | |
$nodes = $this->xml->xpath("/products/product"); | |
$output = []; | |
// This is part of the magic here. make sure the SKU is the key | |
foreach($nodes as $node ){ | |
$output [(int) $node->SKU] = [ | |
'stock' => (int) $node->Stock, | |
'rrp' => (string) $node->RRP, | |
]; | |
} | |
// loop through the result | |
foreach( $this->result as $row ){ | |
$check = [ | |
'_stock' => 'stock', | |
'_price' => 'rrp' , | |
'_regular_price' => 'rrp', | |
]; | |
// check the feed array if the sku exists. if it does work on it | |
if(isset($output[$row->_sku])){ | |
// loop through the fiels/post meta you can to check | |
foreach($check as $meta => $field) { | |
// continue to next meta is this meta does not exist | |
if(empty($row->{$meta})){ | |
continue; | |
} | |
// If the current meta value is different to the one in the feed, update. | |
if($output[$row->_sku][$field] != $row->{$meta}){ | |
/** | |
* some error logging so you can see what happend | |
*/ | |
error_log( "ID: {$row->ID} SKU: {$row->_sku} - changing $meta to be: {$output[$row->_sku][$field]} , $meta was: {$row->{$meta}}" ); | |
if(is_admin()){ | |
echo "ID: {$row->ID} SKU: {$row->_sku} - changing $meta to be: {$output[$row->_sku][$field]} , $meta was: {$row->{$meta}} "; | |
echo "<a href='".get_permalink($row->ID)."'>". get_the_title($row->ID) ."</a> <br/>"; | |
} | |
/* | |
* update the post meta for that value | |
*/ | |
update_post_meta($row->ID, $meta, $output[$row->_sku][$field]); | |
} | |
} | |
} else { | |
$this->whatToDoIfSKUdoesNotExistInFeed($row->ID); | |
} | |
} | |
} | |
protected function whatToDoIfSKUdoesNotExistInFeed($id) { | |
// do something like send an email, or create a report that tells | |
// the system owner that the product is no longer available in the feed | |
// this will stop orphaned products, or products that say they have stock | |
// when the supplier cannot deliver. | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment