Van csv bestand via PHP post_types aanmaken en ACF velden vullen
PHP Code
php
if (get_current_user_id() === 1) :
/**
* Import EQA Opleidingen from CSV into CPT 'eqa-opleiding'
* Usage: put this in a one-off mu-plugin, a WP-CLI command, or run in a secure admin context.
*/
if ( ! defined('ABSPATH') ) { exit; }
// === CONFIG ===
$fileloc = dirname(__DIR__, 1);
$csvFile = $fileloc . '/pe-opleidingen.csv'; // adjust path
$post_type = 'pe-opleiding';
$taxonomy = 'pe-type'; // ACF taxonomy attached to this post_type
// Map logical field names to ACF field KEYS (recommended).
// TODO: replace field_XXXXXXXX with your actual ACF field keys.
$acf_keys = [
'systeemid' => 'systeemid', // number
'opleidingskenmerk' => 'opleidingskenmerk', // text
'link' => 'link', // link
'toegekend' => 'pe_of_eqa_toegekend_op', // date
'geldig' => 'pe_of_eqa_geldig_tot', // date
'opleidingsvorm' => 'opleidingsvorm', // wysiwyg
'opl_omschrijving' => 'opl_omschrijving', // wysiwyg
'peuren' => 'pe_uren', // number
'duurdagen' => 'duur_dagen', // number
'kosten' => 'kosten', // number
'startdata' => 'startdata', // wysiwyg
// taxonomy is handled via wp_set_object_terms()
];
// === HELPERS ===
/**
* Try to detect delimiter based on header line.
*/
function detect_delimiter($line) {
$candidates = [",", ";", "\t", "|"];
$counts = [];
foreach ($candidates as $d) {
$counts[$d] = substr_count($line, $d);
}
arsort($counts);
return key($counts);
}
/**
* Normalize header labels to canonical keys.
*/
function normalize_header($label) {
$label = trim(mb_strtolower($label));
// allow small variations/spaces
$label = preg_replace('/\s+/', '', $label);
return $label;
}
/**
* Parse a date string into ACF Date Picker format 'Ymd'.
* Returns null if cannot parse or empty.
*/
function to_acf_date($value) {
$value = trim((string)$value);
if ($value === '') return null;
// Try common formats
$formats = ['Y-m-d', 'd-m-Y', 'd/m/Y', 'Y/m/d', 'd.m.Y', 'Ymd'];
foreach ($formats as $fmt) {
$dt = DateTimeImmutable::createFromFormat($fmt, $value);
if ($dt instanceof DateTimeImmutable) {
return $dt->format('Ymd');
}
}
// Last resort: strtotime
$ts = strtotime($value);
if ($ts !== false) {
return date('Ymd', $ts);
}
return null;
}
/**
* Read the first line safely (handling BOM).
*/
function fopen_no_bom($path) {
$h = fopen($path, 'r');
if (! $h) return false;
// Remove UTF-8 BOM if present
$bom = fread($h, 3);
if ($bom !== "\xEF\xBB\xBF") {
// Not a BOM; rewind to start
rewind($h);
}
return $h;
}
/**
* Find existing post by unique meta 'systeemid'.
*/
function find_post_by_systeemid($systeemid, $post_type) {
$q = new WP_Query([
'post_type' => $post_type,
'posts_per_page' => 1,
'post_status' => 'any',
'meta_query' => [
[
'key' => 'systeemid',
'value' => $systeemid,
],
],
'fields' => 'ids',
'no_found_rows' => true,
]);
return $q->have_posts() ? (int)$q->posts[0] : 0;
}
// === RUN ===
if (! file_exists($csvFile)) {
wp_die('CSV not found at: ' . esc_html($csvFile));
}
$handle = fopen_no_bom($csvFile);
if ($handle === false) {
wp_die('Unable to open CSV.');
}
// Peek first line to detect delimiter
$firstLine = fgets($handle);
if ($firstLine === false) {
fclose($handle);
wp_die('CSV is empty.');
}
$delimiter = detect_delimiter($firstLine);
// Build header from first line
$headerRaw = str_getcsv($firstLine, $delimiter);
$headerMap = [];
foreach ($headerRaw as $i => $label) {
$count++;
$norm = normalize_header($label);
$headerMap[$i] = $norm;
}
// Expected canonical keys (normalized):
$required = ['systeemid','naam','opleidingskenmerk','link','toegekend','geldig','petype', 'opleidingsvorm', 'opl_omschrijving', 'peuren', 'duurdagen', 'kosten', 'startdata'];
$missing = array_diff($required, $headerMap);
if ($missing) {
// Try to be forgiving if your header used small differences like "systeemidnaam" earlier:
// If you for some reason have combined headers, adjust here or ensure the CSV header matches the list above.
// For now, enforce correctness:
fclose($handle);
wp_die('CSV header missing columns: ' . implode(', ', $missing));
}
$created = 0;
$updated = 0;
// Iterate rows
while (($row = fgetcsv($handle, 0, $delimiter)) !== false) {
if (count($row) === 1 && trim($row[0]) === '') {
continue; // skip empty lines
}
$item = [];
foreach ($row as $i => $value) {
$key = $headerMap[$i] ?? 'col_'.$i;
$item[$key] = is_string($value) ? trim($value) : $value;
}
// Basic validation
if (($item['naam'] ?? '') === '') {
continue; // skip rows without a title
}
$systeemid = $item['systeemid'] ?? '';
$existing_id = $systeemid !== '' ? find_post_by_systeemid($systeemid, $post_type) : 0;
$postarr = [
'post_type' => $post_type,
'post_title' => $item['naam'],
'post_status' => 'publish',
];
if ($existing_id) {
$postarr['ID'] = $existing_id;
$post_id = wp_update_post($postarr, true);
} else {
$post_id = wp_insert_post($postarr, true);
}
if (is_wp_error($post_id)) {
error_log('Failed to save post for systeemid '.$systeemid.': '.$post_id->get_error_message());
continue;
}
// === ACF fields ===
// Number: systeemid
// === ACF fields — TEXT ===
if (isset($item['opleidingsvorm'])) {
update_field($acf_keys['opleidingsvorm'], sanitize_text_field($item['opleidingsvorm']), $post_id);
}
if (isset($item['opleidingskenmerk'])) {
update_field($acf_keys['opleidingskenmerk'], sanitize_text_field($item['opleidingskenmerk']), $post_id);
}
// === ACF fields — WYSIWYG ===
foreach (['opl_omschrijving','startdata'] as $wysiwygKey) {
if (array_key_exists($wysiwygKey, $item)) {
$val = is_string($item[$wysiwygKey]) ? trim($item[$wysiwygKey]) : $item[$wysiwygKey];
if ($val !== '' && $val !== null) {
update_field($acf_keys[$wysiwygKey], $val, $post_id);
}
}
}
// Numbers: peuren, duurdagen, kosten
foreach (['systeemid','peuren','duurdagen','kosten'] as $numKey) {
if (!empty($item[$numKey])) {
update_field($acf_keys[$numKey], (float) $item[$numKey], $post_id);
}
}
// Link: expects array(url, title, target)
if (!empty($item['link'])) {
$linkArr = [
'url' => esc_url_raw($item['link']),
'title' => $item['naam'], // or a static label like "Bekijk"
'target' => '_blank', // adjust if you use same window
];
update_field($acf_keys['link'], $linkArr, $post_id);
}
// Dates: to ACF date format 'Ymd'
foreach (['toegekend','geldig','verlengd'] as $dateKey) {
$val = isset($item[$dateKey]) ? to_acf_date($item[$dateKey]) : null;
if ($val) {
update_field($acf_keys[$dateKey], $val, $post_id);
} else {
// Optional: clear if empty
// update_field($acf_keys[$dateKey], null, $post_id);
}
}
// Taxonomy: niveau (can be multiple; split by comma if present)
if (!empty($item['petype'])) {
$termsRaw = array_map('trim', preg_split('/[,|;]+/', $item['petype']));
$termsRaw = array_filter($termsRaw, fn($t) => $t !== '');
if ($termsRaw) {
// Ensure terms exist; create as needed
$term_ids = [];
foreach ($termsRaw as $termName) {
$existing = term_exists($termName, $taxonomy);
if ($existing === 0 || $existing === null) {
$created_term = wp_insert_term($termName, $taxonomy);
if (!is_wp_error($created_term)) {
$term_ids[] = (int)$created_term['term_id'];
}
} elseif (is_array($existing) && isset($existing['term_id'])) {
$term_ids[] = (int)$existing['term_id'];
}
}
if ($term_ids) {
wp_set_object_terms($post_id, $term_ids, $taxonomy, false);
}
}
}
if ($existing_id) { $updated++; } else { $created++; }
}
fclose($handle);
printf(
"Done. Created: %d, Updated: %d\n",
$created,
$updated
);
endif;