Importing and deleting product data in WordPress I am interested in how to handle errors/exceptions/returned data correctly. 

For example, I have a script which creates, updates and deletes products data.

Here is method that receives data from an API, processes and decides what to create/update/delete.

private function importProducts($brand)
{
    $products = $this-&gt;dsApi-&gt;getProductsByBrand($brand);

    //returns ['create' =&gt; [], 'update' =&gt; [], 'delete' =&gt; [] ]
    $preparedProducts = $this-&gt;prepareProducts($products, $brand);

    foreach ($preparedProducts['delete'] as $key =&gt; $product) {
        $this-&gt;deleteProduct($product);
        $this-&gt;log-&gt;info(
            'Brand ' . $brand-&gt;name . '(' . $brand-&gt;id_brand . ')'
            . ' id: ' . $product . ' was deleted'
        );
    }

    foreach ($preparedProducts['create'] as $key =&gt; $product) {

        $this-&gt;importProduct($product, $brand);
        $this-&gt;log-&gt;info(
            'Brand ' . $brand-&gt;name . '(' . $brand-&gt;id_brand . ') sku: ' . $product['sku'] . ' was imported'
        );
    }

    foreach ($preparedProducts['update'] as $key =&gt; $product) {
        $this-&gt;importProduct($product, $brand, $product['idProductWc']);
        $this-&gt;log-&gt;info(
            'Brand ' . $brand-&gt;name . '(' . $brand-&gt;id_brand . ') sku: ' . $product['sku']
            . ' id: ' . $product['idProductWc'] . ' was updated'
        );
    }
}


And for example deleteProduct() method:

private function deleteProduct($product)
{
    wp_delete_post($product, true);

    $args = [
        'order' =&gt; 'ASC',
        'post_mime_type' =&gt; 'image',
        'post_parent' =&gt; (int) $product['idProductWc'],
        'post_status' =&gt; 'inherit',
        'post_type' =&gt; 'attachment',
    ];
    $child = get_children($args);
    foreach ($child as $id =&gt; $item) {
        wp_delete_attachment($id, true);
    }
}


Is the deletion method written correctly? Is it necessary to handle an error in wp_delete_post() method? How to handle it? What to write in logs in this case? Should the method return a response?
Looking at your importProducts() method, firstly ask if this needs to be public, private or protected see PHP visibility

Now the importProducts() method in question, I would separate and have three methods as follows:

/**
 * @param $brand string
 * @param $productsToDelete array
 */
protected function _deletePreparedProducts($brand = null, $productsToDelete = array()) {
    if(empty($brand)) {
        /* Do we need a brand? If not throw an Exception or log to your debug logger */
    }
    /* deletion logic here */
}

/**
 * @param $brand string
 * @param $productsToCreate array
 */
protected function _createPreparedProducts($brand = null, $productsToCreate = array()) { /* create logic here */ }

/**
 * @param $brand string
 * @param $productsToUpdate array
 */
protected function _updatePreparedProducts($brand = null, $productsToUpdate = array()) { /* prepare logic here */ }


I would therefore change the importProducts() method as follows (assuming that you still want this as a private method):

&lt;?php
private function importProducts($brand)
{
    $products = $this-&gt;dsApi-&gt;getProductsByBrand($brand);

    $preparedProducts = $this-&gt;prepareProducts($products, $brand);

    if(!empty($preparedProducts['delete'])) {
        $this-&gt;_deletePreparedProducts($brand, $preparedProducts['delete']);
    }

    if(!empty($preparedProducts['create'])) {
        $this-&gt;_createPreparedProducts($brand, $preparedProducts['create']);
    }

    if(!empty($preparedProducts['update'])) {
        $this-&gt;_updatePreparedProducts($brand, $preparedProducts['update']);
    }
}


Using this approach, if you need to change the logic to update a product, you will only have to worry about your update method, rather than having lots of logic in one method. And in your main method you will be checking if there are any products to delete, update or create first rather than assuming that there is, as is the case in your original script.

If there are no products to import then why was this method called? This is where you could throw an exception, or log to a debug file, like this:

    if(empty($preparedProducts['delete'])
        &amp;&amp; empty($preparedProducts['create'])
        &amp;&amp; empty($preparedProducts['update'])) {
        throw new \Exception("Import products called without any products to import");
    }


I might also consider preparing the data first before calling the importProducts() method, rather than preparing that data within the method - this will depend on your dataflow.

I would finally suggest that as you are updating and deleting products, the method name may be incorrect. manageProducts() or something similar might be a better name for this method.