I have made a Craft 3 plugin that is manually used in the Craft Admin CP area; click a button and we sync products in Craft with a Shopify API. Now I am trying to automate the process.
I would like to schedule a task that runs the controller that is executed when an admin user manually clicks the Manual Sync button, shown above. Clicking the button runs the actionIndex() method of my plugin's controller, which extends the Craft 3 web controller:
<?php
namespace vendor\shopify\controllers;
use \vendor\shopify\Shopify;
use craft\elements\Entry;
use craft\elements\MatrixBlock;
use DateTime;
class SyncController extends \craft\web\Controller
{
public function actionIndex()
{
$apiKey = \vendor\shopify\Shopify::getInstance()->getSettings()->apiKey;
$password = \vendor\shopify\Shopify::getInstance()->getSettings()->password;
$secret = \vendor\shopify\Shopify::getInstance()->getSettings()->secret;
$hostname = \vendor\shopify\Shopify::getInstance()->getSettings()->hostname;
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://$apiKey:$password@$hostname/admin/products.json",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_POSTFIELDS => "",
CURLOPT_HTTPHEADER => array(
"cache-control: no-cache"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
\Craft::info("(Vendor Shopify plugin) cURL Error #:" . $err, __METHOD__);
}
else {
$section = \Craft::$app->sections->getSectionByHandle('products');
$entryTypes = $section->getEntryTypes();
foreach (json_decode($response)->products as $product) {
$query = Entry::find();
$query->section('products');
$query->shopifyProduct($product->id);
$currentEntries = $query->exists();
if ($currentEntries) {
$existingEntry = $query->all();
$existingEntry = $existingEntry[0];
$blockIds = [];
$field = \Craft::$app->getFields()->getFieldByHandle('productVariants');
$existingMatrixQuery = $existingEntry->getFieldValue('productVariants');
foreach ($existingMatrixQuery->all() as $block) {
$blockIds[] = $block->id;
\Craft::info("(Vendor Shopify plugin) Block Id??: " . json_encode($block->id), __METHOD__);
}
$serializedMatrix = $field->serializeValue($existingMatrixQuery, $existingEntry);
if (count($product->variants) === count($blockIds)) {
foreach ($product->variants as $key => $variant) {
$serializedMatrix[$blockIds[$key]] = [
'type' => 'productVariant',
'enabled' => true,
'fields' => [
'sku' => $variant->sku,
'variantSize' => $variant->title,
'variantPrice' => number_format((float)$variant->price, 2, '.', ''),
'variantCompareAtPrice' => number_format((float)$variant->compare_at_price, 2, '.', ''),
'variantQuantity' => $variant->inventory_quantity,
]
];
}
}
else {
$serializedMatrix = [];
foreach ($product->variants as $key => $variant) {
$serializedMatrix['new' . $key] = [
'type' => 'productVariant',
'enabled' => true,
'fields' => [
'sku' => $variant->sku,
'variantSize' => $variant->title,
'variantPrice' => number_format((float)$variant->price, 2, '.', ''),
'variantCompareAtPrice' => number_format((float)$variant->compare_at_price, 2, '.', ''),
'variantQuantity' => $variant->inventory_quantity,
]
];
}
};
$existingEntry->setFieldValues([
'productDescription' => $product->body_html,
'productVariants' => $serializedMatrix,
]);
$success = \Craft::$app->elements->saveElement($existingEntry);
if (!$success) {
\Craft::info("(Vendor Shopify plugin) Error Saving Product: " . $product->title . " " . $err, __METHOD__);
}
}
}
}
\Craft::$app->getSession()->setNotice('Manual Sync complete.');
return $this->renderTemplate('shopify/done');
}
}
So far, I have explored options discussed in these two StackExchange questions that are somewhat related to my issue (Call Craft controller with cron job and Craft TaskService Overview/Cron Job). Unfortunately my labors haven't been fruitful! I am open to any and all suggestions in regards to how I might accomplish the automation of calling this plugin class's actionIndex method. Thank you, I sincerely appreciate any feedback!