WooCommerce ESW
Il progetto prevede la creazione di un mini-sito con commerce integrato con Easy Store Web.
Ambiente di lavoro
Container
Abbiamo optato per un docker container così strutturato
docker-compose.yml
version: '3.9'
services:
db:
image: mysql:8.3
ports:
- 3306:3306
environment:
MYSQL_DATABASE: webmobili
MYSQL_USER: webmobili
MYSQL_PASSWORD: w3bm0b1l1
MYSQL_ROOT_PASSWORD: w3bm0b1l1
volumes:
- db:/var/lib/mysql
wordpress:
depends_on:
- db
build:
context: ./
ports:
- 8000:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: webmobili
WORDPRESS_DB_PASSWORD: w3bm0b1l1
WORDPRESS_DB_NAME: webmobili
WORDPRESS_DEBUG: 1
TZ: "Europe/Rome"
volumes:
- wordpress:/var/www/html
volumes:
db:
wordpress:
Punta al seguente Dockerfile che si occupa di configurare xdebug per PHP.
FROM wordpress:6.6.2-apache
RUN apt-get update && \
pecl install xdebug \
&& docker-php-ext-enable xdebug
# Copy xdebug.ini to /usr/local/etc/php/conf.d/
COPY ./*.ini /usr/local/etc/php/conf.d/
# Copy plugin data to to /usr/src/wordpress/wp-content/plugins/
COPY --chown=www-data:www-data ./designbest-esw/ /usr/src/wordpress/wp-content/plugins/designbest-esw/
COPY --chown=www-data:www-data ./designbest-esw-lead/ /usr/src/wordpress/wp-content/plugins/designbest-esw-lead/
Nella root dev'essere presente il file xdebug.ini così configurato:
zend_extension=xdebug.so
[xdebug]
xdebug.mode=develop,debug
xdebug.discover_client_host = true
xdebug.start_with_request=yes
Ecco il devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.238.0/containers/docker-existing-docker-compose
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
{
"name": "Designbest Commerce ESW",
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
"dockerComposeFile": [
"../docker-compose.yml"
],
// The 'service' property is the name of the service for the container that VS Code should
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
"service": "wordpress",
// The optional 'workspaceFolder' property is the path VS Code should open by default when
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
"workspaceFolder": "/var/www/html",
"customizations": {
"vscode": {
"extensions": [
"xdebug.php-pack", "xdebug.php-debug", "bmewburn.vscode-intelephense-client","neilbrayfield.php-docblocker","olback.es6-css-minify"
]
}
},
// Add the IDs of extensions you want installed when the container is created.
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [8000]
}
Visual Studio
- Cliccare sul pulsante Run & Debug e farsi creare in automatico il file .vscode/launch.json per abilitare xdebug per PHP.
- Creare un file .vscode/settings.json per configurare le estensioni col seguente codice
{
"es6-css-minify.minifyOnSave": "exists",
"intelephense.environment.phpVersion": "7.4.3"
}
- Aprire wp-config.php e aggiungere appena sotto a define( 'WP_DEBUG',... la riga
define( 'WP_DEBUG_LOG', true );
Wordpress Admin
Da http://localhost:8000/wp-admin
ho creato credenziali con la mia solita password, utente la mail di lavoro.
- Aggiornare l'aggiornabile
- Installare il plugin WooCommerce
- (opzionale) Installare il tema Astra
- Aspetto => Opzioni Astra => spalla dx => Installa Plugin Importatore
- Da questa pagina installare il template (scegliendo Elementor) Custom Printing con tutti i suoi contenuti
- (opzionale) Installare il plugin Classic Widget
Installare il plugin Checkout Field Editor for WooCommerce.
Entrare nelle impostazioni e aggiungere i campi partita iva e codice fiscale con i nomibilling_cfebilling_piva- (developer) Installare il plugin WP Crontrol per vedere la situazione dei cron jobs e poterli eliminare
- (developer) Installare il plugin WP Hooks Finder (by Muhammad Rehman) per poter vedere tutti gli hook in pagina.
Easy Store - Le specifiche
Ci saranno 3 tipi di utenza
- Clienti con Easy Store
- Clienti con Outlet
- Clienti con Easy Store + Outlet
Il plugin è in grado di distinguere in quale caso ci troviamo in base al file di configurazione
/designbest-esw/config/config.php
Dalla voce
"sorgente-dati" => "designbest", // valori esw o designbest o designbest-esw
Il plugin è basato su 5 interfacce services che cambiano le loro funzioni a seconda del tipo di utenza:
IApiConnectServiceconnessione alle APIIProductsServicesincronizzazione prodottiIOrdersServicegestione degli ordini (fattura ecc)IAdminServicegestione backoffice WPICronJobsServicegestione di cron-job per sincronizzare
Clienti con Easy Store
File config.php correttamente configurato per questa utenza:
return array(
"environment" => "test", // "production"
"sorgente-dati" => "esw", // valori esw o designbest o designbest-esw
"esw_api-domain" => "https://easyapi6.eswportal.it",
"esw_negoziocode" => "Attivo 2",
"esw-x-apikey" => "j9MDojFf4EmbznjJvimErUJ4YWJHWlY4N1VTTWYwM2NRZUZOSmc=",
"esw-dbconnection" => "291_EMMERRE_TEST",
"esw-codicemagazzino" => ["MAG_10","MAG_11","MAG_23"], // magazzini accettati dall'import
"esw-codicevenditore" => "ONL49554",
"esw-incassi-codice_causale" => "05SLD",
"esw-servizi-codice" => "SE",
"esw-mapping-pagamenti" => ["bacs" => "BON","xpay"=> "CC"],
// Gestione clienti che hanno i campi cf, piva e sdi creati con altri plugin
"esw-customer-ordermetadata" => [
"create" => true, // se true crea i campi customCheckoutFields e li mostra in backoffice (false se lo fa già un plugin)
"cf" => "_billing_cf",
"piva" => "_billing_piva",
"sdi" => "_billing_sdi"
]
);
Le API di Easy Store non permettono di caricare articoli sul gestionale, ma solo di leggerli.
Per tenere sincronizzati i prodotti è necessario montare un pooling tramite un cron-job che andrà a leggere i dati del gestionale e li proietterà sul commerce.
Aggiunta funzione per caricare un elenco pre-compilato di categorie in quanto EasyStore non le considera.
Nelle chiamate, tutti i valori booleani vanno passati come stringa utilizzando "true" o "false".
IApiConnectService permette la connessione alle API di Easy Store
IProductsService mette a disposizione
createBrandTaxonomy()che si occupa di aggiungere la tassonomia del manufacturer che stranamente in WooCommerce non è presente.
Oltre a questo inserisce un elenco convenzionato di categories perché Easy Store non ha i dati sulle categorie/tipologie di prodotto.allProductsSync()Legge tutti i prodotti del negozio specificato inconfig.phpche hanno il flag commerce e li sincronizza con WooCommerce.
- Se sono già presenti si limita ad aggiornare solo i campi prezzo e giacenza. Altrimenti inserisce l'intero prodotto.
- I dati sincronizzati non hanno dati sufficienti per una pubblicazione (mancano titolo, descrizione e immagini) e saranno importati come bozze.
insertDefaultCategories()Inserisce gli ambienti default per definire una lista di partenza.
- Il pulsante si trova nell'admin
IOrdersService gestisce l'acquisto sincronizzando tutto col gestionale.
customCheckoutFields()Aggiunge codice fiscale e partita I.V.A. ai campi di checkout del carrello.newOrder()spedisce a Easy Store tutte le informazioni sull'acquisto.
- Si occupa di registrare l'anagrafica e il prodotto venduto tramite i corrispondenti endpoint post
anagraficae postvendite. - In queste chiamate alcuni parametri sono costanti definite durante la progettazione.
codice_venditore = ONL49554tipo_fattura = FTcodice_fornitoreviene passato se è definito, in caso contrario passaECOMMERCEcodice_magazzino = MAGora proviene dalla configurazioneprezzo_forzato = Trueutilizzare i valori string "True" o "False" per i booleani
IAdminService gestisce le pagine di backoffice e le loro logiche lato server.
- Piazza l'elemento nel menu con l'icona adeguata, mette a disposizione una pagina che riassume le caratteristiche del plugin e permette una sincronizzazione manuale premendo un pulsante.
ICronJobsService Attiva (e predispone la disattivazione) di un cron job che chiama la sincronizzazione dei prodotti ( IProductsService::allProductsSync() ) tutti i giorni a partire dalle 8 per 2 volte al giorno.
Clienti con outlet
File config.php correttamente configurato per questa utenza:
return array(
"sorgente-dati" => "designbest",
"environment" => "test", // "production",
"db-api-domain" => "https://apicore.dbdemo47.com",
"db-token_endpoint" => "/token",
"db-token_username" => "designbestrest",
"db-token_password" => "Z3+3MlGwEbz#",
"db-shopnetid" => 318182 // Bensa Arredamenti
);
Il database di Designbest ha dei dati più completi rispetto a ESW per un e-commerce.
Allo stesso modo, il meccanismo di sincronizzazione porterà i dati dal database di Designbest a quello del commerce locale.
IApiConnectService permette la connessione alle API di Designbest
IProductsService mette a disposizione
createBrandTaxonomy()che si occupa di aggiungere la tassonomia del manufacturer che stranamente in WooCommerce non è presente.
- Non si occupa di aggiungere categories al pool di base perché i prodotti Designbest forniscono la precisa tipologia.
allProductsSync()Legge tutti i prodotti del negozio specificato inconfig.phpche hanno il flag e-commerce approved e li sincronizza con WooCommerce.
- Se sono già presenti si limita ad aggiornare solo i campi prezzo e giacenza. Altrimenti inserisce l'intero prodotto.
- I dati sincronizzati saranno importati come bozze.
IOrdersService gestisce l'acquisto sincronizzando tutto col gestionale.
customCheckoutFields()Aggiunge codice fiscale e partita I.V.A. ai campi di checkout del carrello.newOrder()comunica a Designbest la diminuzione della giacenza dell'articolo (non implementato in quanto sovrascritto dalla sincronizzazione programmata).
IAdminService gestisce le pagine di backoffice e le loro logiche lato server.
- Piazza l'elemento nel menu con l'icona adeguata, mette a disposizione una pagina che riassume le caratteristiche del plugin e permette una sincronizzazione manuale premendo un pulsante.
ICronJobsService Attiva (e predispone la disattivazione) di un cron job che chiama la sincronizzazione dei prodotti ( IProductsService::allProductsSync() ) tutti i giorni a partire dalle 8 per 2 volte al giorno.
Clienti con Outlet + Easy Store
File config.php correttamente configurato per questa utenza:
return array(
"sorgente-dati" => "designbest-esw",
"environment" => "test", // "production"
// Configurazione esw
"esw_negoziocode" => "01", // Arredamenti Casabella su Esw
"esw-x-apikey" => "hEckyjWBYUycOIRiUZUgJUJ4YWJHWlY4N1VTTWYwM2NRZUZOSmc=",
"esw-dbconnection" => "173_WMECOMMERCE",
// Configurazione designbest
"db-token_endpoint" => "https://ws.designbest.com/token",
"db-token_username" => "designbestrest",
"db-token_password" => "Z3+3MlGwEbz#",
"db-shop_piva" => "00258570274" // Arredamenti Casabella su Outlet
);
I services dovranno comportarsi in parte come Esw e in parte come Outlet.
Importante che nella configurazione si specifichi la stessa entità con i 2 diversi identificativi (es. Casabella Arredamenti su ESW e lo stesso su Outlet).
Clienti con sviluppi custom non scalabili
Per rispondere alle richieste non scalabili degli utenti sono stati inseriti degli hook nei punti cardine del plugin.
Al momento sono i seguenti:
dbesw_eswinsertanagrafica=>($anag, $order)[filter]dbesw_eswinsertvendita=>($vendita, $order)[filter]
Utilizzo
È necessario creare un nuovo file .php, ad esempio NomeClienteCustomHooks.php, che conterrà le personalizzazioni degli hook nella cartella /config/CustomHooks.
Per utilizzarlo è necessario dichiararlo nel file /config/config.php sotto alla voce 'custom-hooks
<?php
defined( 'ABSPATH' ) || exit;
return array(
// ... altre conf
"custom-hooks" => "NomeClienteCustomHooks.php"
);
e il file, che verra eseguito durante l'inizializzazione del plugin, potrà avere i seguenti contenuti:
<?php
// SVILUPPI CUSTOM per DTime
defined( 'ABSPATH' ) || exit;
add_filter("dbesw_eswinsertanagrafica", function($anag, $order) {
// Manipolazione custom di $anag utilizzando $order per recuperare dati
return $anag;
}, 10, 2);
add_filter("dbesw_eswinsertvendita", function($vendita, $order) {
// Manipolazione custom di $vendita utilizzando $order per recuperare dati
return $vendita;
}, 10, 2);
Attivazione plugin
Qui i passaggi per attivare il plugin sul sito wordpress del cliente.
IMPORTANTE
Nell'ambiente di test, nel file wp-config.php inserire la costante
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', true );
define( 'WP_ENVIRONMENT_TYPE', 'staging' ); // mettere 'local' per sviluppo locale
In produzione rimuovere WP_ENVIRONMENT_TYPE e rimuovere WP_DEBUG e figli.
Innanzitutto bisogna recuperare dal cliente
- Credenziali per accedere a
wp-admin - Credenziali per accedere a
FTP
Poi bisogna farsi dare da Sintesys
api-endpointnegozio_codex-apikeydbconnectioncodice_magazzino
Una volta che si hanno tutti i dati.
- Installare (se non presente) il plugin dipendenza WooCommerce
- Copiare su FTP il folder del plugin nella cartella
/wp-content/plugins - Attivare il plugin tramite l'apposita sezione della dashboard
- (opzionale) installare il plugin WP Crontrol per vedere i cron-job sotto il menu Strumenti
⚠ Stranezze tecniche ⚠
Questa sezione raccoglie tutti i tipi di eccezione che abbiamo incontrato durante lo sviluppo.
WooCommerce incompatibilità di configurazione
Fonte:
https://rudrastyh.com/woocommerce/high-performance-order-storage.html
Esiste una modalità di WooCommerce che si chiama HPOS, si basa sull'utilizzo di tabelle proprie ottimizzate invece di quelle del core WP.
Si attiva da WooCommerce => Impostazioni => Avanzate => Funzioni/Features, non si lascia attivare se qualche plugin non è compatibile.
Ci sono diversi casi da gestire
- Il caso particolare dell'hook
shop_orderche cambia nome inwoocommerce_page_wc-orders. - L'impossibilità di usare
get_post_meta()quando è attivo.
Nel primo caso è possibile scrivere un codice che è compatibile sia che HPOS sia abilitato che non:
public function esw_order_json_data() : void {
add_meta_box(
'esw-order-json-data',
'EASY STORE ORDER DATA',
[$this,'esw_render_meta_box'],
wc_get_page_screen_id( 'shop-order' ), // woocommerce_page_wc-orders (oppure shop_order)is the post type of the admin order page
'normal', // change to 'side' to move box to side column
'low' // priority (where on page to put the box)
);
}
public function esw_render_meta_box($post,$metabox) : void {
//https://rudrastyh.com/woocommerce/high-performance-order-storage.html#screen_id-changes
//Se opzione di Woocommerce HPOS è attiva la variabile $post è di tipo WC_Order e non può accedere direttamente all'ID
$order_id = ( $post instanceof \WP_Post )
? $post->ID
: $post->get_id();
$json_data = $this->eswdb_service->getOrder($order_id);
if($json_data != null){
echo '<pre>'.$json_data. '</pre>';
}else{
echo '<p>Ordine non gestito da Easy Store</p>';
}
// Metabox content
}
Clienti che usano questo plugin
Per il momento sono
WooCommerce Pagamenti
- WooCommerce PayPal Payments
- WooCommerce Stripe Gateway
PayPal Sandbox
Vedere credenziali usate per commerce http://wiki.wmdemo.it/index.php?title=PayPal_Sandbox