// Test shortcode Sviluppo plugin WordPress per viaggi condivisi
SUPER-PROGETTO-DUP.docx
DOCX 217.32KB
STRUTTURA (2).xlsx
XLSX 18.33KB
DUP-ORIGINALE-PERFETTO PER MAPPE..php
PHP 60.54KB
sviluppa su un unico file una app per wordprs in un unico file php:
per comuni e mappe ti allego script perfettamente funzionane usalo come base. per i form mi elaboi una soluzione che mi permetta di personalizzarla ti alego un foglio express che ti servira come traccai per creare un sitem di persoalizzazione semplice form
Ecco un plugin WordPress tutto-in-uno che integra la gestione dei comuni, mappe avanzate e un sistema di form completamente personalizzabile basato sul tuo foglio Excel:
php
init();
}
private function init() {
// Activation/Deactivation
register_activation_hook(__FILE__, [$this, ‘create_tables’]);
// Initialize
add_action(‘init’, [$this, ‘load_textdomain’]);
add_action(‘init’, [$this, ‘register_post_types’]);
// Enqueue scripts
add_action(‘wp_enqueue_scripts’, [$this, ‘enqueue_frontend_scripts’]);
add_action(‘admin_enqueue_scripts’, [$this, ‘enqueue_admin_scripts’]);
// Admin menu
add_action(‘admin_menu’, [$this, ‘add_admin_menu’]);
// Shortcodes
$this->register_shortcodes();
// AJAX handlers
$this->register_ajax_handlers();
// Initialize field configuration
$this->load_field_config();
}
public function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// Table for Italian municipalities
$table_comuni = $wpdb->prefix . DMP_TABLE_COMUNI;
$sql_comuni = “CREATE TABLE IF NOT EXISTS $table_comuni (
id mediumint(9) NOT NULL AUTO_INCREMENT,
comune varchar(255) NOT NULL,
provincia varchar(255) NOT NULL,
regione varchar(255) NOT NULL,
lat decimal(10,8),
lng decimal(11,8),
cap varchar(10),
popolazione int,
superficie decimal(10,2),
last_updated datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY unique_comune_provincia (comune, provincia),
INDEX idx_comune (comune),
INDEX idx_provincia (provincia),
INDEX idx_regione (regione)
) $charset_collate;”;
// Table for trips
$table_viaggi = $wpdb->prefix . DMP_TABLE_VIAGGI;
$sql_viaggi = “CREATE TABLE IF NOT EXISTS $table_viaggi (
id mediumint(9) NOT NULL AUTO_INCREMENT,
post_id bigint(20) unsigned NOT NULL,
user_id bigint(20) unsigned NOT NULL,
titolo_viaggio varchar(255) NOT NULL,
ruolo varchar(50) NOT NULL DEFAULT ‘pilota’,
data_partenza datetime NOT NULL,
data_fine_replica date,
ripetibilita varchar(255),
id_comune_partenza mediumint(9) NOT NULL,
id_comune_arrivo mediumint(9) NOT NULL,
lat_partenza decimal(10,8),
lng_partenza decimal(11,8),
lat_arrivo decimal(10,8),
lng_arrivo decimal(11,8),
distanza_lineare decimal(10,2),
distanza_stradale decimal(10,2),
tempo_stimato int,
costo_tipo varchar(50),
costo_fisso decimal(10,2),
rimborso_km decimal(10,2),
ticket_urbano decimal(10,2),
disponibile_tappe tinyint(1) DEFAULT 0,
veicolo varchar(100),
carburante varchar(50),
status varchar(50) DEFAULT ‘attivo’,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_user_id (user_id),
INDEX idx_data_partenza (data_partenza),
INDEX idx_comune_partenza (id_comune_partenza),
INDEX idx_comune_arrivo (id_comune_arrivo),
INDEX idx_status (status),
FOREIGN KEY (post_id) REFERENCES {$wpdb->posts}(ID) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES {$wpdb->users}(ID) ON DELETE CASCADE
) $charset_collate;”;
// Table for user extended data
$table_utenti = $wpdb->prefix . DMP_TABLE_UTENTI_EXTRAS;
$sql_utenti = “CREATE TABLE IF NOT EXISTS $table_utenti (
id mediumint(9) NOT NULL AUTO_INCREMENT,
user_id bigint(20) unsigned NOT NULL UNIQUE,
nickname varchar(100) NOT NULL,
data_nascita date,
ruolo varchar(50),
avatar varchar(500),
sesso varchar(20),
id_comune_residenza mediumint(9),
nazionalita varchar(100),
prefisso_internazionale varchar(10) DEFAULT ‘+39’,
telefono varchar(30),
whatsapp varchar(30),
automezzo varchar(100),
carburante varchar(50),
anno_immatricolazione year,
descrizione text,
foto_gallery text,
tag_foto varchar(255),
rating decimal(3,2) DEFAULT 5.00,
viaggi_completati int DEFAULT 0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_nickname (nickname),
INDEX idx_ruolo (ruolo),
INDEX idx_comune_residenza (id_comune_residenza),
FOREIGN KEY (user_id) REFERENCES {$wpdb->users}(ID) ON DELETE CASCADE
) $charset_collate;”;
// Table for field configuration
$table_fields = $wpdb->prefix . DMP_TABLE_FIELD_CONFIG;
$sql_fields = “CREATE TABLE IF NOT EXISTS $table_fields (
id mediumint(9) NOT NULL AUTO_INCREMENT,
campo_id int NOT NULL,
nome_campo varchar(255) NOT NULL,
tipo_campo varchar(50) NOT NULL,
variabili text,
form_login_rapido int DEFAULT 0,
form_pilota int DEFAULT 0,
form_passeggero int DEFAULT 0,
form_nuovo_utente int DEFAULT 0,
ordine int DEFAULT 0,
attivo tinyint(1) DEFAULT 1,
required tinyint(1) DEFAULT 0,
validation_rules text,
placeholder varchar(255),
default_value varchar(255),
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY unique_campo_id (campo_id),
INDEX idx_tipo_campo (tipo_campo),
INDEX idx_ordine (ordine)
) $charset_collate;”;
// Table for categories/options
$table_cats = $wpdb->prefix . DMP_TABLE_CATEGORIES;
$sql_cats = “CREATE TABLE IF NOT EXISTS $table_cats (
id mediumint(9) NOT NULL AUTO_INCREMENT,
tipo varchar(50) NOT NULL,
valore varchar(255) NOT NULL,
label varchar(255) NOT NULL,
ordine int DEFAULT 0,
attivo tinyint(1) DEFAULT 1,
parent_id mediumint(9) DEFAULT 0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_tipo (tipo),
INDEX idx_parent_id (parent_id),
INDEX idx_ordine (ordine)
) $charset_collate;”;
require_once(ABSPATH . ‘wp-admin/includes/upgrade.php’);
// Execute table creation
dbDelta($sql_comuni);
dbDelta($sql_viaggi);
dbDelta($sql_utenti);
dbDelta($sql_fields);
dbDelta($sql_cats);
// Insert default field configuration from Excel
$this->initialize_field_config();
// Insert default categories
$this->initialize_categories();
}
private function initialize_field_config() {
global $wpdb;
$table = $wpdb->prefix . DMP_TABLE_FIELD_CONFIG;
// Check if already initialized
$count = $wpdb->get_var(“SELECT COUNT(*) FROM $table”);
if ($count > 0) return;
// Default fields from your Excel structure
$default_fields = [
[‘campo_id’ => 0, ‘nome_campo’ => ‘TITOLO MODULO’, ‘tipo_campo’ => ‘text’, ‘form_pilota’ => 1, ‘form_passeggero’ => 1, ‘required’ => 1],
[‘campo_id’ => 1, ‘nome_campo’ => ‘NICKNAME’, ‘tipo_campo’ => ‘text’, ‘form_nuovo_utente’ => 1, ‘required’ => 1],
[‘campo_id’ => 2, ‘nome_campo’ => ‘ETA’, ‘tipo_campo’ => ‘select’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 3, ‘nome_campo’ => ‘RUOLO’, ‘tipo_campo’ => ‘select’, ‘variabili’ => ‘pilota,passeggero’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 4, ‘nome_campo’ => ‘AVATAR’, ‘tipo_campo’ => ‘image’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 6, ‘nome_campo’ => ‘NOME’, ‘tipo_campo’ => ‘text’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 7, ‘nome_campo’ => ‘COGNOME’, ‘tipo_campo’ => ‘text’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 8, ‘nome_campo’ => ‘SESSO’, ‘tipo_campo’ => ‘select’, ‘variabili’ => ‘maschio,femmina,altro’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 9, ‘nome_campo’ => ‘COMUNE RESIDENZA’, ‘tipo_campo’ => ‘cascada’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 11, ‘nome_campo’ => ‘NAZIONALITA’, ‘tipo_campo’ => ‘select’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 12, ‘nome_campo’ => ‘EMAIL’, ‘tipo_campo’ => ‘email’, ‘form_nuovo_utente’ => 1, ‘required’ => 1],
[‘campo_id’ => 13, ‘nome_campo’ => ‘PREFISSO INTERNAZIONALE’, ‘tipo_campo’ => ‘select’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 14, ‘nome_campo’ => ‘GALLERIA FOTOGRAFICA’, ‘tipo_campo’ => ‘gallery’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 15, ‘nome_campo’ => ‘DESCRIZIONE’, ‘tipo_campo’ => ‘textarea’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 17, ‘nome_campo’ => ‘TELEFONO’, ‘tipo_campo’ => ‘tel’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 18, ‘nome_campo’ => ‘WHATSAPP’, ‘tipo_campo’ => ‘tel’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 21, ‘nome_campo’ => ‘AUTOMEZZO’, ‘tipo_campo’ => ‘select’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 22, ‘nome_campo’ => ‘CARBURANTE’, ‘tipo_campo’ => ‘select’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 23, ‘nome_campo’ => ‘ANNO IMMATRICOLAZIONE’, ‘tipo_campo’ => ‘select’, ‘form_nuovo_utente’ => 1],
[‘campo_id’ => 25, ‘nome_campo’ => ‘CATEGORIA VIAGGIO’, ‘tipo_campo’ => ‘select’, ‘form_pilota’ => 1, ‘form_passeggero’ => 1],
[‘campo_id’ => 26, ‘nome_campo’ => ‘DISPONIBILITA TAPPE’, ‘tipo_campo’ => ‘radio’, ‘variabili’ => ‘si,no’, ‘form_pilota’ => 1],
[‘campo_id’ => 27, ‘nome_campo’ => ‘DATA E ORA PARTENZA’, ‘tipo_campo’ => ‘datetime’, ‘form_pilota’ => 1, ‘form_passeggero’ => 1, ‘required’ => 1],
[‘campo_id’ => 28, ‘nome_campo’ => ‘COMUNE PARTENZA’, ‘tipo_campo’ => ‘cascada’, ‘form_pilota’ => 1, ‘form_passeggero’ => 1, ‘required’ => 1],
[‘campo_id’ => 29, ‘nome_campo’ => ‘COMUNE ARRIVO’, ‘tipo_campo’ => ‘cascada’, ‘form_pilota’ => 1, ‘form_passeggero’ => 1, ‘required’ => 1],
[‘campo_id’ => 30, ‘nome_campo’ => ‘MAPPA’, ‘tipo_campo’ => ‘map’, ‘form_pilota’ => 1, ‘form_passeggero’ => 1],
[‘campo_id’ => 35, ‘nome_campo’ => ‘COSTO VIAGGIO’, ‘tipo_campo’ => ‘select’, ‘variabili’ => ‘gratuito,costo_fisso,rimborso_km,ticket_urbano’, ‘form_pilota’ => 1],
[‘campo_id’ => 37, ‘nome_campo’ => ‘COSTO FISSO’, ‘tipo_campo’ => ‘number’, ‘form_pilota’ => 1],
[‘campo_id’ => 38, ‘nome_campo’ => ‘RIMBORSO KM’, ‘tipo_campo’ => ‘select_range’, ‘variabili’ => ‘0.10:3.00:0.10’, ‘form_pilota’ => 1],
[‘campo_id’ => 39, ‘nome_campo’ => ‘TICKET URBANO’, ‘tipo_campo’ => ‘number’, ‘form_pilota’ => 1],
[‘campo_id’ => 42, ‘nome_campo’ => ‘QUANDO PARTO’, ‘tipo_campo’ => ‘select’, ‘form_passeggero’ => 1],
];
foreach ($default_fields as $index => $field) {
$field[‘ordine’] = $index;
$wpdb->insert($table, $field);
}
}
private function initialize_categories() {
global $wpdb;
$table = $wpdb->prefix . DMP_TABLE_CATEGORIES;
$default_cats = [
[‘tipo’ => ‘ruolo’, ‘valore’ => ‘pilota’, ‘label’ => ‘Pilota’],
[‘tipo’ => ‘ruolo’, ‘valore’ => ‘passeggero’, ‘label’ => ‘Passeggero’],
[‘tipo’ => ‘sesso’, ‘valore’ => ‘maschio’, ‘label’ => ‘Maschio’],
[‘tipo’ => ‘sesso’, ‘valore’ => ‘femmina’, ‘label’ => ‘Femmina’],
[‘tipo’ => ‘sesso’, ‘valore’ => ‘altro’, ‘label’ => ‘Altro’],
[‘tipo’ => ‘carburante’, ‘valore’ => ‘benzina’, ‘label’ => ‘Benzina’],
[‘tipo’ => ‘carburante’, ‘valore’ => ‘diesel’, ‘label’ => ‘Diesel’],
[‘tipo’ => ‘carburante’, ‘valore’ => ‘gpl’, ‘label’ => ‘GPL’],
[‘tipo’ => ‘carburante’, ‘valore’ => ‘elettrico’, ‘label’ => ‘Elettrico’],
[‘tipo’ => ‘carburante’, ‘valore’ => ‘ibrido’, ‘label’ => ‘Ibrido’],
[‘tipo’ => ‘costo_tipo’, ‘valore’ => ‘gratuito’, ‘label’ => ‘Gratuito’],
[‘tipo’ => ‘costo_tipo’, ‘valore’ => ‘costo_fisso’, ‘label’ => ‘Costo Fisso’],
[‘tipo’ => ‘costo_tipo’, ‘valore’ => ‘rimborso_km’, ‘label’ => ‘Rimborso al Km’],
[‘tipo’ => ‘costo_tipo’, ‘valore’ => ‘ticket_urbano’, ‘label’ => ‘Ticket Urbano’],
];
foreach ($default_cats as $index => $cat) {
$cat[‘ordine’] = $index;
$wpdb->insert($table, $cat);
}
}
public function load_textdomain() {
load_plugin_textdomain(‘dammiunpassaggio’, false, dirname(plugin_basename(__FILE__)) . ‘/languages’);
}
public function register_post_types() {
// Custom Post Type: Viaggio
register_post_type(‘viaggio’, [
‘labels’ => [
‘name’ => __(‘Viaggi’, ‘dammiunpassaggio’),
‘singular_name’ => __(‘Viaggio’, ‘dammiunpassaggio’),
‘add_new’ => __(‘Aggiungi Viaggio’, ‘dammiunpassaggio’),
‘add_new_item’ => __(‘Aggiungi Nuovo Viaggio’, ‘dammiunpassaggio’),
‘edit_item’ => __(‘Modifica Viaggio’, ‘dammiunpassaggio’),
‘new_item’ => __(‘Nuovo Viaggio’, ‘dammiunpassaggio’),
‘view_item’ => __(‘Visualizza Viaggio’, ‘dammiunpassaggio’),
‘search_items’ => __(‘Cerca Viaggi’, ‘dammiunpassaggio’),
‘not_found’ => __(‘Nessun viaggio trovato’, ‘dammiunpassaggio’),
‘not_found_in_trash’ => __(‘Nessun viaggio nel cestino’, ‘dammiunpassaggio’),
],
‘public’ => true,
‘has_archive’ => true,
‘rewrite’ => [‘slug’ => ‘viaggi’],
‘supports’ => [‘title’, ‘editor’, ‘thumbnail’, ‘author’],
‘menu_icon’ => ‘dashicons-location-alt’,
‘show_in_rest’ => true,
]);
// Custom Post Type: Profilo Utente
register_post_type(‘profilo-utente’, [
‘labels’ => [
‘name’ => __(‘Profili Utente’, ‘dammiunpassaggio’),
‘singular_name’ => __(‘Profilo Utente’, ‘dammiunpassaggio’),
],
‘public’ => false,
‘publicly_queryable’ => false,
‘show_ui’ => true,
‘show_in_menu’ => ‘dammiunpassaggio’,
‘supports’ => [‘title’],
‘capability_type’ => ‘post’,
‘capabilities’ => [
‘create_posts’ => false,
],
‘map_meta_cap’ => true,
]);
}
private function load_field_config() {
global $wpdb;
$table = $wpdb->prefix . DMP_TABLE_FIELD_CONFIG;
$this->field_config = $wpdb->get_results(“SELECT * FROM $table WHERE attivo = 1 ORDER BY ordine”, ARRAY_A);
}
public function enqueue_frontend_scripts() {
// Leaflet for maps
wp_enqueue_style(‘leaflet-css’, ‘https://unpkg.com/leaflet@1.9.4/dist/leaflet.css’);
wp_enqueue_script(‘leaflet-js’, ‘https://unpkg.com/leaflet@1.9.4/dist/leaflet.js’, [], null, true);
// Leaflet Routing Machine
wp_enqueue_style(‘leaflet-routing-machine-css’, ‘https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.css’);
wp_enqueue_script(‘leaflet-routing-machine-js’, ‘https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.js’, [‘leaflet-js’], null, true);
// Dropzone for file uploads
wp_enqueue_style(‘dropzone-css’, ‘https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.css’);
wp_enqueue_script(‘dropzone-js’, ‘https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js’, [], null, true);
// Date/time picker
wp_enqueue_style(‘flatpickr-css’, ‘https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css’);
wp_enqueue_script(‘flatpickr-js’, ‘https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.js’, [], null, true);
wp_enqueue_script(‘flatpickr-it’, ‘https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/it.js’, [‘flatpickr-js’], null, true);
// Plugin styles
wp_enqueue_style(‘dmp-frontend’, DMP_PLUGIN_URL . ‘assets/css/frontend.css’, [], DMP_VERSION);
// Plugin scripts
wp_enqueue_script(‘dmp-frontend’, DMP_PLUGIN_URL . ‘assets/js/frontend.js’,
[‘jquery’, ‘leaflet-js’, ‘leaflet-routing-machine-js’, ‘dropzone-js’, ‘flatpickr-js’],
DMP_VERSION,
true
);
// Localize script
wp_localize_script(‘dmp-frontend’, ‘dmpData’, [
‘ajax_url’ => admin_url(‘admin-ajax.php’),
‘nonce’ => wp_create_nonce(‘dmp_nonce’),
‘default_lat’ => 41.9028,
‘default_lng’ => 12.4964,
‘upload_url’ => admin_url(‘admin-ajax.php?action=dmp_upload_file’),
‘user_id’ => get_current_user_id(),
‘strings’ => [
‘select_region’ => __(‘Seleziona Regione’, ‘dammiunpassaggio’),
‘select_province’ => __(‘Seleziona Provincia’, ‘dammiunpassaggio’),
‘select_municipality’ => __(‘Seleziona Comune’, ‘dammiunpassaggio’),
‘loading’ => __(‘Caricamento…’, ‘dammiunpassaggio’),
]
]);
// Inline styles
$this->enqueue_inline_styles();
}
private function enqueue_inline_styles() {
$css = ‘
‘;
echo $css;
}
public function enqueue_admin_scripts($hook) {
if (strpos($hook, ‘dammiunpassaggio’) === false) {
return;
}
wp_enqueue_style(‘dmp-admin’, DMP_PLUGIN_URL . ‘assets/css/admin.css’, [], DMP_VERSION);
wp_enqueue_script(‘jquery-ui-sortable’);
wp_enqueue_script(‘dmp-admin’, DMP_PLUGIN_URL . ‘assets/js/admin.js’, [‘jquery’, ‘jquery-ui-sortable’], DMP_VERSION, true);
wp_localize_script(‘dmp-admin’, ‘dmpAdminData’, [
‘ajax_url’ => admin_url(‘admin-ajax.php’),
‘nonce’ => wp_create_nonce(‘dmp_admin_nonce’),
‘confirm_delete’ => __(‘Sei sicuro di voler eliminare questo elemento?’, ‘dammiunpassaggio’),
]);
}
public function add_admin_menu() {
add_menu_page(
‘Dammiunpassaggio’,
‘Dammiunpassaggio’,
‘manage_options’,
‘dammiunpassaggio’,
[$this, ‘render_admin_dashboard’],
‘dashicons-car’,
30
);
add_submenu_page(
‘dammiunpassaggio’,
__(‘Configurazione Campi’, ‘dammiunpassaggio’),
__(‘Campi Form’, ‘dammiunpassaggio’),
‘manage_options’,
‘dmp-field-config’,
[$this, ‘render_field_config_page’]
);
add_submenu_page(
‘dammiunpassaggio’,
__(‘Gestione Categorie’, ‘dammiunpassaggio’),
__(‘Categorie’, ‘dammiunpassaggio’),
‘manage_options’,
‘dmp-categories’,
[$this, ‘render_categories_page’]
);
add_submenu_page(
‘dammiunpassaggio’,
__(‘Importa Comuni’, ‘dammiunpassaggio’),
__(‘Importa Comuni’, ‘dammiunpassaggio’),
‘manage_options’,
‘dmp-import-comuni’,
[$this, ‘render_import_comuni_page’]
);
add_submenu_page(
‘dammiunpassaggio’,
__(‘Gestione Audio’, ‘dammiunpassaggio’),
__(‘Audio’, ‘dammiunpassaggio’),
‘manage_options’,
‘dmp-audio’,
[$this, ‘render_audio_page’]
);
add_submenu_page(
‘dammiunpassaggio’,
__(‘Impostazioni’, ‘dammiunpassaggio’),
__(‘Impostazioni’, ‘dammiunpassaggio’),
‘manage_options’,
‘dmp-settings’,
[$this, ‘render_settings_page’]
);
}
private function register_shortcodes() {
// User registration form
add_shortcode(‘dmp_nuovo_utente’, [$this, ‘shortcode_nuovo_utente’]);
// Pilot trip form
add_shortcode(‘dmp_viaggio_pilota’, [$this, ‘shortcode_viaggio_pilota’]);
// Passenger trip form
add_shortcode(‘dmp_viaggio_passeggero’, [$this, ‘shortcode_viaggio_passeggero’]);
// Quick login
add_shortcode(‘dmp_login_rapido’, [$this, ‘shortcode_login_rapido’]);
// Login/Logout
add_shortcode(‘dmp_login’, [$this, ‘shortcode_login’]);
add_shortcode(‘dmp_logout’, [$this, ‘shortcode_logout’]);
// Trip listing
add_shortcode(‘dmp_lista_viaggi’, [$this, ‘shortcode_lista_viaggi’]);
// Trip board
add_shortcode(‘dmp_tabellone_viaggi’, [$this, ‘shortcode_tabellone_viaggi’]);
// Super map
add_shortcode(‘dmp_super_mappa’, [$this, ‘shortcode_super_mappa’]);
// User list
add_shortcode(‘dmp_lista_utenti’, [$this, ‘shortcode_lista_utenti’]);
// Comuni selector (from your existing code)
add_shortcode(‘comuni_selector’, [$this, ‘shortcode_comuni_selector’]);
add_shortcode(‘comuni_supermap’, [$this, ‘shortcode_comuni_supermap’]);
add_shortcode(‘comuni_travel_calc’, [$this, ‘shortcode_comuni_travel_calc’]);
}
private function register_ajax_handlers() {
// Comuni AJAX (from your existing code)
add_action(‘wp_ajax_get_province’, [$this, ‘ajax_get_province’]);
add_action(‘wp_ajax_nopriv_get_province’, [$this, ‘ajax_get_province’]);
add_action(‘wp_ajax_get_comuni’, [$this, ‘ajax_get_comuni’]);
add_action(‘wp_ajax_nopriv_get_comuni’, [$this, ‘ajax_get_comuni’]);
add_action(‘wp_ajax_get_route’, [$this, ‘ajax_get_route’]);
add_action(‘wp_ajax_nopriv_get_route’, [$this, ‘ajax_get_route’]);
add_action(‘wp_ajax_import_csv’, [$this, ‘ajax_import_csv’]);
add_action(‘wp_ajax_geocode_missing’, [$this, ‘ajax_geocode_missing’]);
// DMP specific AJAX
add_action(‘wp_ajax_dmp_save_field_config’, [$this, ‘ajax_save_field_config’]);
add_action(‘wp_ajax_dmp_save_category’, [$this, ‘ajax_save_category’]);
add_action(‘wp_ajax_dmp_delete_category’, [$this, ‘ajax_delete_category’]);
add_action(‘wp_ajax_dmp_reorder_categories’, [$this, ‘ajax_reorder_categories’]);
add_action(‘wp_ajax_dmp_upload_audio’, [$this, ‘ajax_upload_audio’]);
add_action(‘wp_ajax_dmp_submit_form’, [$this, ‘ajax_submit_form’]);
add_action(‘wp_ajax_nopriv_dmp_submit_form’, [$this, ‘ajax_submit_form’]);
add_action(‘wp_ajax_dmp_upload_file’, [$this, ‘ajax_upload_file’]);
add_action(‘wp_ajax_nopriv_dmp_upload_file’, [$this, ‘ajax_upload_file’]);
}
// ============================================
// ADMIN PAGES
// ============================================
public function render_admin_dashboard() {
?>
0
0
0
0
| Shortcode | Descrizione | Utilizzo |
|---|---|---|
|
Form registrazione nuovo utente | |
|
Form inserimento viaggio pilota | |
|
Form inserimento viaggio passeggero | |
|
Lista viaggi con filtri | |
|
Mappa interattiva con tutti i viaggi |
prefix . DMP_TABLE_FIELD_CONFIG;
$fields = $wpdb->get_results(“SELECT * FROM $table ORDER BY ordine”, ARRAY_A);
?>
ID: | Tipo:
prefix . DMP_TABLE_CATEGORIES;
$categories = $wpdb->get_results(“SELECT * FROM $table ORDER BY tipo, ordine”, ARRAY_A);
// Group by type
$grouped_cats = [];
foreach ($categories as $cat) {
$grouped_cats[$cat[‘tipo’]][] = $cat;
}
?>
render_import_page();
}
public function render_audio_page() {
?>
| Nome | Tipo | Dimensione | Data Upload | Azioni |
|---|---|---|---|---|
render_form(‘nuovo_utente’);
}
public function shortcode_viaggio_pilota($atts) {
return $this->render_form(‘pilota’);
}
public function shortcode_viaggio_passeggero($atts) {
return $this->render_form(‘passeggero’);
}
public function shortcode_login_rapido($atts) {
ob_start();
?>
Sei già loggato come ‘ . wp_get_current_user()->display_name . ‘
‘;
}
ob_start();
?>
Non sei loggato
‘;
}
return ‘Logout‘;
}
public function shortcode_lista_viaggi($atts) {
ob_start();
?>
shortcode_lista_viaggi($atts);
}
public function shortcode_super_mappa($atts) {
// Reuse your existing supermap code
return $this->render_supermap($atts);
}
public function shortcode_lista_utenti($atts) {
ob_start();
?>
get_form_title($form_type); ?>
').show(); $('#dmp-form-')[0].reset(); } else { $message.html('
').show();
}
}
});
});
});
prefix . DMP_TABLE_FIELD_CONFIG;
$column_map = [
‘login_rapido’ => ‘form_login_rapido’,
‘pilota’ => ‘form_pilota’,
‘passeggero’ => ‘form_passeggero’,
‘nuovo_utente’ => ‘form_nuovo_utente’
];
$column = $column_map[$form_type] ?? ‘form_nuovo_utente’;
$fields = $wpdb->get_results($wpdb->prepare(
“SELECT * FROM $table WHERE $column = 1 AND attivo = 1 ORDER BY ordine”,
$form_type
), ARRAY_A);
foreach ($fields as $field) {
$this->render_field($field, $form_type);
}
}
private function render_field($field, $form_type) {
$field_id = ‘dmp-field-‘ . $field[‘campo_id’];
$field_name = ‘field_’ . $field[‘campo_id’];
$required = $field[‘required’] ? ‘required’ : ”;
$required_label = $field[‘required’] ? ‘ *‘ : ”;
echo ‘
echo ‘‘;
switch ($field[‘tipo_campo’]) {
case ‘text’:
case ‘email’:
case ‘tel’:
case ‘number’:
echo ‘‘;
break;
case ‘select’:
echo ‘
if ($field[‘variabili’]) {
$options = explode(‘,’, $field[‘variabili’]);
foreach ($options as $option) {
$option = trim($option);
echo ‘‘;
}
} else {
// Load from categories table
global $wpdb;
$cat_table = $wpdb->prefix . DMP_TABLE_CATEGORIES;
$field_name_lower = strtolower(str_replace(‘ ‘, ‘_’, $field[‘nome_campo’]));
$cats = $wpdb->get_results($wpdb->prepare(
“SELECT valore, label FROM $cat_table WHERE tipo = %s AND attivo = 1 ORDER BY ordine”,
$field_name_lower
));
foreach ($cats as $cat) {
echo ‘‘;
echo ‘‘;
echo ‘‘;
break;
case ‘textarea’:
echo ‘‘;
break;
case ‘datetime’:
echo ‘‘;
break;
case ‘image’:
echo ‘
‘;
echo ‘‘;
break;
case ‘gallery’:
echo ‘
‘;
echo ‘‘;
break;
case ‘map’:
echo ‘
‘;
echo ‘‘;
echo ‘‘;
break;
default:
echo ‘‘;
}
echo ‘
‘;
echo ‘
‘;
}
private function get_form_title($form_type) {
$titles = [
‘nuovo_utente’ => ‘Registrazione Nuovo Utente’,
‘pilota’ => ‘Inserisci Viaggio come Pilota’,
‘passeggero’ => ‘Inserisci Viaggio come Passeggero’,
‘login_rapido’ => ‘Accesso Rapido’
];
return $titles[$form_type] ?? ‘Form’;
}
// ============================================
// AJAX HANDLERS
// ============================================
public function ajax_save_field_config() {
check_ajax_referer(‘dmp_admin_nonce’, ‘nonce’);
if (!current_user_can(‘manage_options’)) {
wp_send_json_error(‘Permessi insufficienti’);
}
global $wpdb;
$table = $wpdb->prefix . DMP_TABLE_FIELD_CONFIG;
if (isset($_POST[‘order’])) {
// Save field order
foreach ($_POST[‘order’] as $item) {
$wpdb->update($table,
[‘ordine’ => $item[‘ordine’]],
[‘id’ => $item[‘id’]],
[‘%d’],
[‘%d’]
);
}
wp_send_json_success();
} else {
// Save individual field
$data = [
‘campo_id’ => intval($_POST[‘campo_id’]),
‘nome_campo’ => sanitize_text_field($_POST[‘nome_campo’]),
‘tipo_campo’ => sanitize_text_field($_POST[‘tipo_campo’]),
‘variabili’ => sanitize_textarea_field($_POST[‘variabili’] ?? ”),
‘form_login_rapido’ => isset($_POST[‘form_login_rapido’]) ? 1 : 0,
‘form_pilota’ => isset($_POST[‘form_pilota’]) ? 1 : 0,
‘form_passeggero’ => isset($_POST[‘form_passeggero’]) ? 1 : 0,
‘form_nuovo_utente’ => isset($_POST[‘form_nuovo_utente’]) ? 1 : 0,
‘required’ => isset($_POST[‘required’]) ? 1 : 0,
‘placeholder’ => sanitize_text_field($_POST[‘placeholder’] ?? ”),
‘default_value’ => sanitize_text_field($_POST[‘default_value’] ?? ”),
‘ordine’ => 999 // Will be reordered
];
$wpdb->insert($table, $data);
wp_send_json_success([‘id’ => $wpdb->insert_id]);
}
}
public function ajax_save_category() {
check_ajax_referer(‘dmp_admin_nonce’, ‘nonce’);
if (!current_user_can(‘manage_options’)) {
wp_send_json_error(‘Permessi insufficienti’);
}
global $wpdb;
$table = $wpdb->prefix . DMP_TABLE_CATEGORIES;
$data = [
‘tipo’ => sanitize_text_field($_POST[‘tipo’]),
‘valore’ => sanitize_text_field($_POST[‘valore’]),
‘label’ => sanitize_text_field($_POST[‘label’]),
‘ordine’ => 999
];
$wpdb->insert($table, $data);
wp_send_json_success([‘id’ => $wpdb->insert_id]);
}
public function ajax_delete_category() {
check_ajax_referer(‘dmp_admin_nonce’, ‘nonce’);
if (!current_user_can(‘manage_options’)) {
wp_send_json_error(‘Permessi insufficienti’);
}
global $wpdb;
$table = $wpdb->prefix . DMP_TABLE_CATEGORIES;
$wpdb->delete($table, [‘id’ => intval($_POST[‘id’])]);
wp_send_json_success();
}
public function ajax_reorder_categories() {
check_ajax_referer(‘dmp_admin_nonce’, ‘nonce’);
if (!current_user_can(‘manage_options’)) {
wp_send_json_error(‘Permessi insufficienti’);
}
global $wpdb;
$table = $wpdb->prefix . DMP_TABLE_CATEGORIES;
$order = $_POST[‘order’];
foreach ($order as $index => $cat_id) {
$wpdb->update($table,
[‘ordine’ => $index],
[‘id’ => $cat_id],
[‘%d’],
[‘%d’]
);
}
wp_send_json_success();
}
public function ajax_upload_audio() {
check_ajax_referer(‘dmp_admin_nonce’, ‘nonce’);
if (!current_user_can(‘manage_options’)) {
wp_send_json_error(‘Permessi insufficienti’);
}
if (!function_exists(‘wp_handle_upload’)) {
require_once(ABSPATH . ‘wp-admin/includes/file.php’);
}
$uploadedfile = $_FILES[‘audio_file’];
$upload_overrides = [‘test_form’ => false];
$movefile = wp_handle_upload($uploadedfile, $upload_overrides);
if ($movefile && !isset($movefile[‘error’])) {
// Save to options
$audio_type = sanitize_text_field($_POST[‘audio_type’]);
$audio_name = sanitize_text_field($_POST[‘audio_name’]);
$audios = get_option(‘dmp_audio_files’, []);
$audios[] = [
‘type’ => $audio_type,
‘name’ => $audio_name,
‘url’ => $movefile[‘url’],
‘file’ => $movefile[‘file’],
‘date’ => current_time(‘mysql’)
];
update_option(‘dmp_audio_files’, $audios);
wp_send_json_success([‘url’ => $movefile[‘url’]]);
} else {
wp_send_json_error($movefile[‘error’]);
}
}
public function ajax_submit_form() {
check_ajax_referer(‘dmp_nonce’, ‘nonce’);
$form_type = sanitize_text_field($_POST[‘form_type’]);
// Validate and process form based on type
switch ($form_type) {
case ‘nuovo_utente’:
$this->process_user_registration($_POST);
break;
case ‘pilota’:
$this->process_pilota_trip($_POST);
break;
case ‘passeggero’:
$this->process_passeggero_trip($_POST);
break;
default:
wp_send_json_error(‘Tipo form non valido’);
}
}
private function process_user_registration($data) {
// Validate required fields
$required = [‘field_1’, ‘field_12’]; // NICKNAME, EMAIL
foreach ($required as $field) {
if (empty($data[$field])) {
wp_send_json_error(‘Compila tutti i campi obbligatori’);
}
}
// Create WordPress user
$username = strtoupper(sanitize_user($data[‘field_1’]));
$email = sanitize_email($data[‘field_12’]);
if (username_exists($username) || email_exists($email)) {
wp_send_json_error(‘Username o email già registrati’);
}
$password = wp_generate_password(12, true);
$user_id = wp_create_user($username, $password, $email);
if (is_wp_error($user_id)) {
wp_send_json_error($user_id->get_error_message());
}
// Update user meta
$user_fields = [
‘field_6’ => ‘first_name’, // NOME
‘field_7’ => ‘last_name’, // COGNOME
‘field_17’ => ‘phone’, // TELEFONO
];
foreach ($user_fields as $field => $meta_key) {
if (!empty($data[$field])) {
update_user_meta($user_id, $meta_key, sanitize_text_field($data[$field]));
}
}
// Save to dmp_utenti_extras table
global $wpdb;
$table = $wpdb->prefix . DMP_TABLE_UTENTI_EXTRAS;
$user_data = [
‘user_id’ => $user_id,
‘nickname’ => $username,
‘data_nascita’ => !empty($data[‘field_2’]) ? date(‘Y-m-d’, strtotime($data[‘field_2’] . ‘-01-01’)) : null,
‘ruolo’ => !empty($data[‘field_3’]) ? sanitize_text_field($data[‘field_3’]) : null,
‘sesso’ => !empty($data[‘field_8’]) ? sanitize_text_field($data[‘field_8’]) : null,
‘prefisso_internazionale’ => !empty($data[‘field_13’]) ? sanitize_text_field($data[‘field_13’]) : ‘+39’,
‘telefono’ => !empty($data[‘field_17’]) ? sanitize_text_field($data[‘field_17’]) : null,
‘whatsapp’ => !empty($data[‘field_18’]) ? sanitize_text_field($data[‘field_18’]) : null,
‘automezzo’ => !empty($data[‘field_21’]) ? sanitize_text_field($data[‘field_21’]) : null,
‘carburante’ => !empty($data[‘field_22’]) ? sanitize_text_field($data[‘field_22’]) : null,
‘anno_immatricolazione’ => !empty($data[‘field_23’]) ? intval($data[‘field_23’]) : null,
‘descrizione’ => !empty($data[‘field_15’]) ? sanitize_textarea_field($data[‘field_15’]) : null,
];
// Handle comune residenza (cascading select)
if (!empty($data[‘field_9_comune’])) {
$user_data[‘id_comune_residenza’] = intval($data[‘field_9_comune’]);
}
// Handle avatar
if (!empty($data[‘field_4’])) {
$user_data[‘avatar’] = esc_url_raw($data[‘field_4’]);
}
// Handle gallery
if (!empty($data[‘field_14’])) {
$user_data[‘foto_gallery’] = maybe_serialize(explode(‘,’, $data[‘field_14’]));
}
$wpdb->insert($table, $user_data);
// Send notification email
wp_new_user_notification($user_id, null, ‘both’);
// Auto-login user
wp_set_current_user($user_id);
wp_set_auth_cookie($user_id);
wp_send_json_success([
‘message’ => ‘Registrazione completata con successo! Benvenuto ‘ . $username,
‘redirect’ => home_url(‘/’)
]);
}
private function process_pilota_trip($data) {
if (!is_user_logged_in()) {
wp_send_json_error(‘Devi essere loggato per inserire un viaggio’);
}
$user_id = get_current_user_id();
// Validate required fields
$required = [‘field_0’, ‘field_27’, ‘field_28_comune’, ‘field_29_comune’];
foreach ($required as $field) {
if (empty($data[$field])) {
wp_send_json_error(‘Compila tutti i campi obbligatori’);
}
}
// Get comune data
global $wpdb;
$comuni_table = $wpdb->prefix . DMP_TABLE_COMUNI;
$comune_partenza = $wpdb->get_row($wpdb->prepare(
“SELECT id, lat, lng FROM $comuni_table WHERE id = %d”,
intval($data[‘field_28_comune’])
));
$comune_arrivo = $wpdb->get_row($wpdb->prepare(
“SELECT id, lat, lng FROM $comuni_table WHERE id = %d”,
intval($data[‘field_29_comune’])
));
if (!$comune_partenza || !$comune_arrivo) {
wp_send_json_error(‘Comuni non validi’);
}
// Calculate distances
$linear_distance = $this->calculate_distance(
$comune_partenza->lat, $comune_partenza->lng,
$comune_arrivo->lat, $comune_arrivo->lng
);
// Get road distance from OSRM
$route = $this->get_osrm_route(
$comune_partenza->lat, $comune_partenza->lng,
$comune_arrivo->lat, $comune_arrivo->lng
);
$road_distance = $route ? $route[‘distance’] : $linear_distance * 1.3;
$estimated_time = $route ? $route[‘duration’] : ($road_distance / 80 * 60); // 80 km/h average
// Create post
$post_id = wp_insert_post([
‘post_title’ => strtoupper(sanitize_text_field($data[‘field_0’])),
‘post_type’ => ‘viaggio’,
‘post_status’ => ‘publish’,
‘post_author’ => $user_id,
‘post_content’ => !empty($data[‘field_15’]) ? sanitize_textarea_field($data[‘field_15’]) : ”
]);
if (is_wp_error($post_id)) {
wp_send_json_error($post_id->get_error_message());
}
// Save to dmp_viaggi table
$viaggi_table = $wpdb->prefix . DMP_TABLE_VIAGGI;
$viaggio_data = [
‘post_id’ => $post_id,
‘user_id’ => $user_id,
‘titolo_viaggio’ => strtoupper(sanitize_text_field($data[‘field_0’])),
‘ruolo’ => ‘pilota’,
‘data_partenza’ => date(‘Y-m-d H:i:s’, strtotime($data[‘field_27’])),
‘id_comune_partenza’ => $comune_partenza->id,
‘id_comune_arrivo’ => $comune_arrivo->id,
‘lat_partenza’ => $comune_partenza->lat,
‘lng_partenza’ => $comune_partenza->lng,
‘lat_arrivo’ => $comune_arrivo->lat,
‘lng_arrivo’ => $comune_arrivo->lng,
‘distanza_lineare’ => round($linear_distance, 2),
‘distanza_stradale’ => round($road_distance, 2),
‘tempo_stimato’ => round($estimated_time),
‘disponibile_tappe’ => !empty($data[‘field_26’]) && $data[‘field_26’] === ‘si’ ? 1 : 0,
];
// Handle cost type
if (!empty($data[‘field_35’])) {
$viaggio_data[‘costo_tipo’] = sanitize_text_field($data[‘field_35’]);
switch ($data[‘field_35’]) {
case ‘costo_fisso’:
$viaggio_data[‘costo_fisso’] = !empty($data[‘field_37’]) ? floatval($data[‘field_37’]) : 0;
break;
case ‘rimborso_km’:
$viaggio_data[‘rimborso_km’] = !empty($data[‘field_38’]) ? floatval($data[‘field_38’]) : 0.10;
break;
case ‘ticket_urbano’:
$viaggio_data[‘ticket_urbano’] = !empty($data[‘field_39’]) ? floatval($data[‘field_39’]) : 0;
break;
}
}
// Handle recurring trips
if (!empty($data[‘ripetibilita’]) && !empty($data[‘data_fine_replica’])) {
$viaggio_data[‘ripetibilita’] = sanitize_text_field($data[‘ripetibilita’]);
$viaggio_data[‘data_fine_replica’] = date(‘Y-m-d’, strtotime($data[‘data_fine_replica’]));
// Clone trips for recurring days
$this->clone_recurring_trips($post_id, $viaggio_data);
}
$wpdb->insert($viaggi_table, $viaggio_data);
// Play confirmation sound if audio is configured
$audios = get_option(‘dmp_audio_files’, []);
$confirmation_sound = ”;
foreach ($audios as $audio) {
if ($audio[‘type’] === ‘conferma_form’) {
$confirmation_sound = $audio[‘url’];
break;
}
}
wp_send_json_success([
‘message’ => ‘Viaggio pubblicato con successo!’,
‘sound’ => $confirmation_sound,
‘redirect’ => get_permalink($post_id)
]);
}
private function process_passeggero_trip($data) {
// Similar to pilota but with passeggero role
$this->process_pilota_trip($data);
}
private function clone_recurring_trips($base_post_id, $base_data) {
// Implement recurring trip cloning
// This is a simplified version
global $wpdb;
$days = explode(‘,’, $base_data[‘ripetibilita’]);
$start_date = new DateTime($base_data[‘data_partenza’]);
$end_date = new DateTime($base_data[‘data_fine_replica’]);
while ($start_date <= $end_date) {
if (in_array($start_date->format(‘N’), $days)) {
// Clone the trip for this day
$cloned_data = $base_data;
$cloned_data[‘data_partenza’] = $start_date->format(‘Y-m-d H:i:s’);
$cloned_data[‘post_id’] = 0; // Will be set after post creation
// Create new post
$post = get_post($base_post_id);
$new_post_id = wp_insert_post([
‘post_title’ => $post->post_title . ‘ – ‘ . $start_date->format(‘d/m/Y’),
‘post_type’ => ‘viaggio’,
‘post_status’ => ‘publish’,
‘post_author’ => $post->post_author,
‘post_content’ => $post->post_content
]);
$cloned_data[‘post_id’] = $new_post_id;
unset($cloned_data[‘id’]);
$wpdb->insert($wpdb->prefix . DMP_TABLE_VIAGGI, $cloned_data);
}
$start_date->modify(‘+1 day’);
}
}
public function ajax_upload_file() {
check_ajax_referer(‘dmp_nonce’, ‘nonce’);
if (!function_exists(‘wp_handle_upload’)) {
require_once(ABSPATH . ‘wp-admin/includes/file.php’);
}
$uploadedfile = $_FILES[‘file’];
$upload_overrides = [‘test_form’ => false];
$movefile = wp_handle_upload($uploadedfile, $upload_overrides);
if ($movefile && !isset($movefile[‘error’])) {
wp_send_json_success([‘url’ => $movefile[‘url’]]);
} else {
wp_send_json_error($movefile[‘error’]);
}
}
// ============================================
// REUSED CODE FROM YOUR EXISTING PLUGIN
// ============================================
public function ajax_get_province() {
check_ajax_referer(‘comuni_nonce’, ‘nonce’);
$regione = sanitize_text_field($_POST[‘regione’]);
$province = $this->get_province_by_regione($regione);
wp_send_json_success($province);
}
public function ajax_get_comuni() {
check_ajax_referer(‘comuni_nonce’, ‘nonce’);
$provincia = sanitize_text_field($_POST[‘provincia’]);
$comuni = $this->get_comuni_by_provincia($provincia);
wp_send_json_success($comuni);
}
public function ajax_get_route() {
check_ajax_referer(‘comuni_nonce’, ‘nonce’);
$start_id = intval($_POST[‘start_id’]);
$end_id = intval($_POST[‘end_id’]);
$start = $this->get_comune_data($start_id);
$end = $this->get_comune_data($end_id);
if (!$start || !$end) {
wp_send_json_error([‘message’ => ‘Comune non trovato’]);
}
// Geocode if missing coordinates
if (!$start->lat || !$start->lng) {
$coords = $this->geocode_comune($start->comune, $start->provincia, $start->regione);
if ($coords) {
$this->update_coordinates($start_id, $coords[‘lat’], $coords[‘lng’]);
$start->lat = $coords[‘lat’];
$start->lng = $coords[‘lng’];
}
}
if (!$end->lat || !$end->lng) {
$coords = $this->geocode_comune($end->comune, $end->provincia, $end->regione);
if ($coords) {
$this->update_coordinates($end_id, $coords[‘lat’], $coords[‘lng’]);
$end->lat = $coords[‘lat’];
$end->lng = $coords[‘lng’];
}
}
// Calculate linear distance
$linear_distance = $this->calculate_distance(
$start->lat, $start->lng,
$end->lat, $end->lng
);
// Try to get route from OSRM
$route = $this->get_osrm_route(
$start->lat, $start->lng,
$end->lat, $end->lng
);
// Calculate emissions
$road_distance = $route ? $route[‘distance’] : $linear_distance * 1.3;
$emissions = $this->calculate_emissions($road_distance);
// Estimate travel time
$travel_time = $this->estimate_travel_time($road_distance);
$result = [
‘start’ => $start,
‘end’ => $end,
‘linear_distance’ => round($linear_distance, 2),
‘road_distance’ => round($road_distance, 2),
‘duration’ => $route ? round($route[‘duration’], 0) : $travel_time[‘total_minutes’],
‘route_geometry’ => $route ? $route[‘geometry’] : null,
‘emissions’ => $emissions,
‘travel_time’ => $travel_time
];
wp_send_json_success($result);
}
public function ajax_import_csv() {
check_ajax_referer(‘comuni_import_nonce’, ‘nonce’);
if (!current_user_can(‘manage_options’)) {
wp_send_json_error(‘Permessi insufficienti’);
}
$csv_data = stripslashes($_POST[‘csv_data’]);
$result = $this->import_csv($csv_data);
wp_send_json_success($result);
}
public function ajax_geocode_missing() {
check_ajax_referer(‘comuni_geocode_nonce’, ‘nonce’);
if (!current_user_can(‘manage_options’)) {
wp_send_json_error(‘Permessi insufficienti’);
}
global $wpdb;
$table_name = $wpdb->prefix . DMP_TABLE_COMUNI;
// Get batch of missing coordinates
$missing = $wpdb->get_results(
“SELECT id, comune, provincia, regione FROM $table_name
WHERE (lat IS NULL OR lng IS NULL)
LIMIT 10”
);
$geocoded = 0;
foreach ($missing as $comune) {
$result = $this->geocode_comune(
$comune->comune,
$comune->provincia,
$comune->regione
);
if ($result) {
$this->update_coordinates($comune->id, $result[‘lat’], $result[‘lng’]);
$geocoded++;
// Be nice to Nominatim – wait between requests
sleep(1);
}
}
$total_missing = $wpdb->get_var(“SELECT COUNT(*) FROM $table_name WHERE lat IS NULL OR lng IS NULL”);
wp_send_json_success([
‘geocoded’ => $geocoded,
‘remaining’ => $total_missing,
‘total’ => $wpdb->get_var(“SELECT COUNT(*) FROM $table_name”)
]);
}
private function get_regioni() {
global $wpdb;
$table_name = $wpdb->prefix . DMP_TABLE_COMUNI;
return $wpdb->get_col(“SELECT DISTINCT regione FROM $table_name ORDER BY regione”);
}
private function get_province_by_regione($regione) {
global $wpdb;
$table_name = $wpdb->prefix . DMP_TABLE_COMUNI;
return $wpdb->get_col($wpdb->prepare(
“SELECT DISTINCT provincia FROM $table_name WHERE regione = %s ORDER BY provincia”,
$regione
));
}
private function get_comuni_by_provincia($provincia) {
global $wpdb;
$table_name = $wpdb->prefix . DMP_TABLE_COMUNI;
return $wpdb->get_results($wpdb->prepare(
“SELECT id, comune, lat, lng FROM $table_name WHERE provincia = %s ORDER BY comune”,
$provincia
));
}
private function get_comune_data($comune_id) {
global $wpdb;
$table_name = $wpdb->prefix . DMP_TABLE_COMUNI;
return $wpdb->get_row($wpdb->prepare(
“SELECT * FROM $table_name WHERE id = %d”,
$comune_id
));
}
private function import_csv($csv_data) {
global $wpdb;
$table_name = $wpdb->prefix . DMP_TABLE_COMUNI;
$imported = 0;
$updated = 0;
$errors = [];
$rows = explode(“\n”, $csv_data);
foreach ($rows as $row) {
if (empty(trim($row))) continue;
$data = str_getcsv($row, ‘;’); // Using semicolon as per your format
if (count($data) < 3) continue;
$regione = sanitize_text_field($data[0] ?? '');
$provincia = sanitize_text_field($data[1] ?? '');
$comune = sanitize_text_field($data[2] ?? '');
if (empty($comune) || empty($provincia) || empty($regione)) {
$errors[] = "Riga incompleta: $row";
continue;
}
// Check if exists
$exists = $wpdb->get_var($wpdb->prepare(
“SELECT id FROM $table_name WHERE comune = %s AND provincia = %s”,
$comune, $provincia
));
if ($exists) {
$updated++;
} else {
$wpdb->insert($table_name, [
‘comune’ => $comune,
‘provincia’ => $provincia,
‘regione’ => $regione
]);
$imported++;
}
}
return [
‘imported’ => $imported,
‘updated’ => $updated,
‘errors’ => $errors
];
}
private function update_coordinates($comune_id, $lat, $lng) {
global $wpdb;
$table_name = $wpdb->prefix . DMP_TABLE_COMUNI;
return $wpdb->update($table_name,
[‘lat’ => $lat, ‘lng’ => $lng],
[‘id’ => $comune_id],
[‘%f’, ‘%f’],
[‘%d’]
);
}
private function geocode_comune($comune, $provincia, $regione) {
$nominatim_url = ‘https://nominatim.openstreetmap.org/search’;
// Try different search patterns
$queries = [
“$comune, $provincia, Italia”,
“$comune, $regione, Italia”,
$comune . “, Italia”
];
foreach ($queries as $query) {
$url = add_query_arg([
‘q’ => $query,
‘format’ => ‘json’,
‘limit’ => 1,
‘addressdetails’ => 1,
‘accept-language’ => ‘it’
], $nominatim_url);
$response = wp_remote_get($url, [
‘headers’ => [
‘User-Agent’ => ‘Dammiunpassaggio WordPress Plugin/1.0’,
‘Referer’ => home_url()
],
‘timeout’ => 30
]);
if (is_wp_error($response)) {
continue;
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (!empty($data) && isset($data[0][‘lat’]) && isset($data[0][‘lon’])) {
return [
‘lat’ => (float) $data[0][‘lat’],
‘lng’ => (float) $data[0][‘lon’],
‘display_name’ => $data[0][‘display_name’]
];
}
}
return false;
}
private function calculate_distance($lat1, $lng1, $lat2, $lng2) {
$earth_radius = 6371;
$lat1 = deg2rad($lat1);
$lng1 = deg2rad($lng1);
$lat2 = deg2rad($lat2);
$lng2 = deg2rad($lng2);
$dlat = $lat2 – $lat1;
$dlng = $lng2 – $lng1;
$a = sin($dlat/2) * sin($dlat/2) +
cos($lat1) * cos($lat2) *
sin($dlng/2) * sin($dlng/2);
$c = 2 * atan2(sqrt($a), sqrt(1-$a));
return $earth_radius * $c;
}
private function get_osrm_route($start_lat, $start_lng, $end_lat, $end_lng) {
$osrm_url = ‘https://router.project-osrm.org/route/v1/driving’;
$coordinates = “$start_lng,$start_lat;$end_lng,$end_lat”;
$url = add_query_arg([
‘overview’ => ‘full’,
‘geometries’ => ‘geojson’,
‘steps’ => ‘true’
], $osrm_url . ‘/’ . $coordinates);
$response = wp_remote_get($url, [‘timeout’ => 30]);
if (is_wp_error($response)) {
return false;
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if ($data[‘code’] === ‘Ok’ && !empty($data[‘routes’])) {
$route = $data[‘routes’][0];
return [
‘distance’ => $route[‘distance’] / 1000,
‘duration’ => $route[‘duration’] / 60,
‘geometry’ => $route[‘geometry’]
];
}
return false;
}
private function calculate_emissions($distance_km, $vehicle_type = null) {
if (!$vehicle_type) {
$vehicle_type = get_option(‘dmp_default_vehicle’, ‘car’);
}
$emission_factors = [
‘car’ => 0.12,
‘car_diesel’ => 0.15,
‘car_electric’ => 0.05,
‘motorbike’ => 0.08
];
$factor = $emission_factors[$vehicle_type] ?? $emission_factors[‘car’];
$co2_kg = $distance_km * $factor;
// Equivalent in trees needed to absorb CO2
$trees_needed = $co2_kg / 21;
return [
‘co2_kg’ => round($co2_kg, 2),
‘trees_needed’ => round($trees_needed, 1),
‘vehicle_type’ => $vehicle_type
];
}
private function estimate_travel_time($distance_km, $road_type = ‘mixed’) {
$speeds = [
‘highway’ => 110,
‘urban’ => 50,
‘rural’ => 70,
‘mixed’ => 80
];
$avg_speed = $speeds[$road_type] ?? $speeds[‘mixed’];
$time_hours = $distance_km / $avg_speed;
$time_hours *= 1.1; // Add 10% for traffic
$hours = floor($time_hours);
$minutes = round(($time_hours – $hours) * 60);
return [
‘total_minutes’ => round($time_hours * 60),
‘formatted’ => $hours > 0 ?
sprintf(__(‘%d ore e %d minuti’, ‘dammiunpassaggio’), $hours, $minutes) :
sprintf(__(‘%d minuti’, ‘dammiunpassaggio’), $minutes)
];
}
// ============================================
// EXISTING SHORTCODES FROM YOUR PLUGIN
// ============================================
public function shortcode_comuni_selector($atts) {
$regioni = $this->get_regioni();
ob_start();
?>
‘600px’,
‘filter’ => ‘true’,
‘clusters’ => ‘true’
], $atts);
ob_start();
?>