v2
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined('ABSPATH') ) require_once dirname(__DIR__, 4) . '/wp-load.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/media.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/image.php';
|
||||
do_action('acf/init');
|
||||
|
||||
$data = json_decode(file_get_contents(__DIR__ . '/migration-data.json'), true);
|
||||
if (!$data) { fwrite(STDERR, "migration-data.json invalid\n"); exit(1); }
|
||||
|
||||
$fr_routes = ['home'=>'accueil','municipality'=>'municipalite','mayor'=>'mot-du-maire','council'=>'conseil-municipal','services'=>'services-municipaux-et-publics','documents'=>'documents-importants','community'=>'notre-communaute','communityPhotos'=>'album-photos-communaute','activitiesPhotos'=>'album-photos-activites','developmentPlan'=>'plan-de-developpement','townMap'=>'carte-de-la-ville','businesses'=>'entreprises-locales','events'=>'evenements','publicNotices'=>'avis-publics','minutes'=>'proces-verbaux','newsletters'=>'bulletins'];
|
||||
$en_routes = ['home'=>'en','municipality'=>'en/municipality','mayor'=>'en/word-from-the-mayor','council'=>'en/our-council','services'=>'en/our-services','documents'=>'en/important-documents','community'=>'en/our-community','communityPhotos'=>'en/community-photo-album','activitiesPhotos'=>'en/activities-photo-album','developmentPlan'=>'en/development-plan','townMap'=>'en/town-map','businesses'=>'en/local-businesses','events'=>'en/events','publicNotices'=>'en/public-notices','minutes'=>'en/minutes','newsletters'=>'en/newsletters'];
|
||||
|
||||
function csj_v($value, string $lang, string $fallback=''): string { return is_array($value) ? (string)($value[$lang] ?? $value['fr'] ?? $fallback) : (string)($value ?? $fallback); }
|
||||
function csj_post_by_path(string $path): ?WP_Post { return get_page_by_path($path, OBJECT, 'page') ?: null; }
|
||||
function csj_upsert_page(string $path, string $title, int $parent=0): int {
|
||||
$post = csj_post_by_path($path);
|
||||
$slug = basename($path);
|
||||
$args = ['post_type'=>'page','post_status'=>'publish','post_title'=>$title,'post_name'=>$slug,'post_parent'=>$parent];
|
||||
if ($post) { $args['ID']=$post->ID; wp_update_post($args); return $post->ID; }
|
||||
return (int) wp_insert_post($args);
|
||||
}
|
||||
function csj_ensure_langs(): void {
|
||||
if (!function_exists('pll_languages_list')) return;
|
||||
$existing = pll_languages_list(['fields'=>'slug']);
|
||||
$langs = [
|
||||
'fr' => ['name'=>'Français','slug'=>'fr','locale'=>'fr_CA','rtl'=>0,'term_group'=>0,'flag'=>'ca'],
|
||||
'en' => ['name'=>'English','slug'=>'en','locale'=>'en_CA','rtl'=>0,'term_group'=>1,'flag'=>'ca'],
|
||||
];
|
||||
foreach ($langs as $slug=>$args) if (!in_array($slug,$existing,true)) PLL()->model->add_language($args);
|
||||
$opts = get_option('polylang'); if (is_array($opts)) { $opts['default_lang']='fr'; $opts['force_lang']=1; $opts['hide_default']=1; update_option('polylang',$opts); }
|
||||
}
|
||||
function csj_set_lang(int $id, string $lang): void { if (function_exists('pll_set_post_language')) pll_set_post_language($id,$lang); }
|
||||
function csj_link_translations(array $ids): void { if (function_exists('pll_save_post_translations')) pll_save_post_translations(array_filter($ids)); }
|
||||
function csj_find_asset(string $src): ?string {
|
||||
if (!$src) return null;
|
||||
$base = basename(parse_url($src, PHP_URL_PATH) ?: $src);
|
||||
$candidates = [
|
||||
dirname(__DIR__) . '/assets/dist/assets/' . $base,
|
||||
'/home/websimple/.openclaw/workspace-build/wordpress-clients/cascapedia-st-jules/site-migration/source-repo/dist/assets/' . $base,
|
||||
'/home/websimple/.openclaw/workspace-build/wordpress-clients/cascapedia-st-jules/site-migration/source-repo/dist/pdfs/' . $base,
|
||||
];
|
||||
foreach ($candidates as $p) if (is_file($p)) return $p;
|
||||
$matches = glob(dirname(__DIR__) . '/assets/dist/assets/' . preg_replace('/-[A-Za-z0-9_]+(?=\.[^.]+$)/','-*',$base));
|
||||
return $matches[0] ?? null;
|
||||
}
|
||||
function csj_import_file(string $path, string $title='', string $alt=''): int {
|
||||
if (!is_file($path)) return 0;
|
||||
$hash = md5_file($path);
|
||||
$found = get_posts(['post_type'=>'attachment','post_status'=>'inherit','meta_key'=>'_csj_source_hash','meta_value'=>$hash,'fields'=>'ids','posts_per_page'=>1]);
|
||||
if ($found) return (int)$found[0];
|
||||
$file_array = ['name'=>basename($path), 'tmp_name'=>wp_tempnam(basename($path))];
|
||||
copy($path, $file_array['tmp_name']);
|
||||
$id = media_handle_sideload($file_array, 0, $title ?: pathinfo($path, PATHINFO_FILENAME));
|
||||
if (is_wp_error($id)) { @unlink($file_array['tmp_name']); return 0; }
|
||||
update_post_meta($id, '_csj_source_hash', $hash);
|
||||
if ($alt) update_post_meta($id, '_wp_attachment_image_alt', $alt);
|
||||
return (int)$id;
|
||||
}
|
||||
function csj_import_src(string $src, string $title='', string $alt=''): int { $p=csj_find_asset($src); return $p ? csj_import_file($p,$title,$alt) : 0; }
|
||||
function csj_upsert_typed(string $type, string $title, string $lang, array $args=[]): int {
|
||||
$q = new WP_Query(['post_type'=>$type,'post_status'=>'any','title'=>$title,'posts_per_page'=>1,'fields'=>'ids','lang'=>$lang]);
|
||||
$postarr = array_merge(['post_type'=>$type,'post_status'=>'publish','post_title'=>$title],$args);
|
||||
if (!empty($q->posts[0])) { $postarr['ID']=(int)$q->posts[0]; wp_update_post($postarr); $id=(int)$q->posts[0]; }
|
||||
else $id=(int)wp_insert_post($postarr);
|
||||
csj_set_lang($id,$lang); return $id;
|
||||
}
|
||||
|
||||
function csj_section_row(array $s, string $lang): array {
|
||||
$layout = str_replace('-','_',$s['type'] ?? 'text_intro');
|
||||
$row = ['acf_fc_layout'=>$layout];
|
||||
foreach (['title','body','intro','eyebrow','subtitle'] as $k) if (isset($s[$k])) $row[$k] = csj_v($s[$k],$lang);
|
||||
if (isset($s['align'])) $row['align']=$s['align'];
|
||||
if (isset($s['background'])) $row['background']=$s['background'];
|
||||
if (isset($s['cta'])) { $row['cta_label']=csj_v($s['cta']['label']??'',$lang); $row['cta_url']=$s['cta']['href']??''; $row['cta_external']=!empty($s['cta']['external']); }
|
||||
if ($layout==='hero_carousel') { $row['autoplay_ms']=$s['autoplayMs']??6000; $row['slides']=[]; foreach (($s['slides']??[]) as $slide) { $img=csj_import_src($slide['image']['src']??'', csj_v($slide['title']??'',$lang), csj_v($slide['image']['alt']??'',$lang)); if($img)$row['slides'][]=['image'=>$img,'eyebrow'=>csj_v($slide['eyebrow']??'',$lang),'title'=>csj_v($slide['title']??'',$lang),'subtitle'=>csj_v($slide['subtitle']??'',$lang)]; } }
|
||||
if ($layout==='text_image') { $row['image_position']=$s['imagePosition']??'right'; $row['image']=csj_import_src($s['image']['src']??'', csj_v($s['title']??'',$lang), csj_v($s['image']['alt']??'',$lang)); }
|
||||
if ($layout==='services_list') { $row['services']=[]; foreach(($s['services']??[]) as $it) $row['services'][]=['title'=>csj_v($it['title']??'',$lang),'description'=>csj_v($it['description']??'',$lang),'items'=>implode("\n", array_map(fn($x)=>csj_v($x,$lang), $it['items']??[]))]; }
|
||||
if ($layout==='photo_gallery') { $row['photos']=[]; foreach(($s['photos']??[]) as $p){ $id=csj_import_src($p['src']??'', csj_v($s['title']??'',$lang), csj_v($p['alt']??'',$lang)); if($id)$row['photos'][]=$id; } }
|
||||
if ($layout==='council_grid') { $row['members']=[]; foreach(($s['members']??[]) as $m){ $photo=csj_import_src($m['photo']['src']??'', $m['name']??'', csj_v($m['photo']['alt']??'',$lang)); $row['members'][]=['name'=>$m['name']??'','role'=>csj_v($m['role']??'',$lang),'email'=>$m['email']??'','photo'=>$photo]; } if(isset($s['footnote']))$row['footnote']=csj_v($s['footnote'],$lang); }
|
||||
if ($layout==='pdf_embed') { $href=$s['href']??($s['file']['href']??''); $row['file']=csj_import_src($href, csj_v($s['title']??'',$lang)); $row['height']=$s['height']??800; }
|
||||
return $row;
|
||||
}
|
||||
|
||||
csj_ensure_langs();
|
||||
|
||||
// Import logo into media and localized site options.
|
||||
$logo = csj_import_file(dirname(__DIR__) . '/assets/dist/assets/logo-municipality-CW-yydo5.png', 'Logo Cascapédia-St-Jules', 'Logo Cascapédia-St-Jules');
|
||||
foreach(['fr','en'] as $lang){
|
||||
update_field('municipality_name', csj_v($data['siteSettings']['municipality']['name']??'',$lang), 'option');
|
||||
update_field('municipality_short_name', csj_v($data['siteSettings']['municipality']['shortName']??'',$lang), 'option');
|
||||
update_field('site_logo', $logo, 'option');
|
||||
update_field('phone', $data['siteSettings']['contact']['phone']??'', 'option');
|
||||
update_field('email', $data['siteSettings']['contact']['email']??'', 'option');
|
||||
update_field('address', csj_v($data['siteSettings']['contact']['address']??'',$lang), 'option');
|
||||
update_field('hours', csj_v($data['siteSettings']['contact']['hours']??'',$lang), 'option');
|
||||
update_field('facebook_url', $data['siteSettings']['social']['facebook']??'', 'option');
|
||||
}
|
||||
|
||||
// Pages + ACF sections.
|
||||
$page_pairs=[]; $updated=0;
|
||||
$en_parent = csj_upsert_page('en','English',0); csj_set_lang($en_parent,'en');
|
||||
foreach ($data['pages'] as $key=>$page) {
|
||||
if (!isset($fr_routes[$key],$en_routes[$key])) continue;
|
||||
$fr_id = csj_upsert_page($fr_routes[$key], csj_v($page['seo']['title']??$key,'fr'), 0);
|
||||
$parent = str_starts_with($en_routes[$key],'en/') ? $en_parent : 0;
|
||||
$en_id = csj_upsert_page($en_routes[$key], csj_v($page['seo']['title']??$key,'en'), $parent);
|
||||
foreach(['fr'=>$fr_id,'en'=>$en_id] as $lang=>$id){
|
||||
csj_set_lang($id,$lang);
|
||||
$rows=[]; foreach(($page['sections']??[]) as $s) $rows[]=csj_section_row($s,$lang);
|
||||
update_field('sections',$rows,$id);
|
||||
update_post_meta($id,'_seo_title',csj_v($page['seo']['title']??'',$lang));
|
||||
update_post_meta($id,'_seo_description',csj_v($page['seo']['description']??'',$lang));
|
||||
delete_post_meta($id,'_react_sections_json');
|
||||
$updated++;
|
||||
}
|
||||
csj_link_translations(['fr'=>$fr_id,'en'=>$en_id]);
|
||||
$page_pairs[$key]=['fr'=>$fr_id,'en'=>$en_id];
|
||||
}
|
||||
|
||||
// Documents from documents/minutes/newsletters groups.
|
||||
$doc_pairs=0;
|
||||
foreach (['documents','minutes','newsletters'] as $page_key) foreach(($data['pages'][$page_key]['sections']??[]) as $s) if(($s['type']??'')==='documents-list') foreach(($s['groups']??[]) as $group) foreach(($group['documents']??[]) as $doc){
|
||||
$ids=[]; $file=csj_import_src($doc['href']??'', csj_v($doc['title']??'','fr'));
|
||||
foreach(['fr','en'] as $lang){
|
||||
$id=csj_upsert_typed('document', csj_v($doc['title']??'Document',$lang), $lang, ['post_excerpt'=>csj_v($doc['description']??'',$lang)]);
|
||||
update_field('document_file',$file,$id); update_field('document_group',csj_v($group['label']??'Documents',$lang),$id); update_field('document_date',$doc['date']??'',$id);
|
||||
delete_post_meta($id,'source_pdf_path'); delete_post_meta($id,'_source_json'); $ids[$lang]=$id;
|
||||
}
|
||||
csj_link_translations($ids); $doc_pairs++;
|
||||
}
|
||||
|
||||
// Businesses.
|
||||
$biz_pairs=0; foreach(($data['pages']['businesses']['sections']??[]) as $s) if(($s['type']??'')==='businesses-list') foreach(($s['categories']??[]) as $cat) foreach(($cat['businesses']??[]) as $b){
|
||||
$ids=[]; foreach(['fr','en'] as $lang){ $id=csj_upsert_typed('local_business',$b['name']??'Entreprise',$lang,['post_content'=>csj_v($b['description']??'',$lang)]); foreach(['phone','email','website','address'] as $m) update_field($m,$b[$m]??'',$id); delete_post_meta($id,'_source_json'); $ids[$lang]=$id; } csj_link_translations($ids); $biz_pairs++; }
|
||||
|
||||
// Events from home event list + event detail texts.
|
||||
$event_items=[]; foreach(($data['pages']['home']['sections']??[]) as $s) if(($s['type']??'')==='events-list') foreach(($s['events']??[]) as $e) $event_items[]=$e; foreach(($data['pages']['events']['sections']??[]) as $s) if(($s['type']??'')==='text-intro') $event_items[]=['title'=>$s['title']??'','description'=>$s['body']??'','date'=>''];
|
||||
$event_pairs=0; foreach($event_items as $e){ $ids=[]; foreach(['fr','en'] as $lang){ $id=csj_upsert_typed('event', csj_v($e['title']??'Événement',$lang),$lang,['post_content'=>csj_v($e['description']??'',$lang)]); update_field('event_date',$e['date']??'',$id); update_field('location',csj_v($e['location']??'',$lang),$id); delete_post_meta($id,'_source_json'); $ids[$lang]=$id; } csj_link_translations($ids); $event_pairs++; }
|
||||
|
||||
// Galleries.
|
||||
$gallery_pairs=0; foreach(['communityPhotos'=>'community','activitiesPhotos'=>'activities'] as $page_key=>$gkey) foreach(($data['pages'][$page_key]['sections']??[]) as $s) if(($s['type']??'')==='photo-gallery'){ $photos=[]; foreach(($s['photos']??[]) as $p){$pid=csj_import_src($p['src']??'',csj_v($s['title']??'Galerie','fr'),csj_v($p['alt']??'','fr')); if($pid)$photos[]=$pid;} $ids=[]; foreach(['fr','en'] as $lang){$id=csj_upsert_typed('gallery',csj_v($s['title']??'Galerie',$lang),$lang,['post_content'=>csj_v($s['intro']??'',$lang)]); update_field('gallery_key',$gkey,$id); update_field('gallery_photos',$photos,$id); delete_post_meta($id,'_source_json'); delete_post_meta($id,'_source_photos_json'); $ids[$lang]=$id;} csj_link_translations($ids); $gallery_pairs++; }
|
||||
|
||||
// Clean old JSON-in-WYSIWYG/meta artifacts.
|
||||
global $wpdb;
|
||||
$wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE meta_key = '_react_sections_json' OR meta_key LIKE '_source_%' OR (meta_key LIKE 'sections\\_%\\_content\\_%' AND meta_value LIKE '{%')");
|
||||
|
||||
flush_rewrite_rules();
|
||||
echo "pages_updated=$updated\n";
|
||||
echo "documents_pairs=$doc_pairs\n";
|
||||
echo "business_pairs=$biz_pairs\n";
|
||||
echo "event_pairs=$event_pairs\n";
|
||||
echo "gallery_pairs=$gallery_pairs\n";
|
||||
echo "image_attachments=" . (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type='attachment' AND post_mime_type LIKE 'image/%'") . "\n";
|
||||
echo "pdf_attachments=" . (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type='attachment' AND post_mime_type='application/pdf'") . "\n";
|
||||
Reference in New Issue
Block a user