'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";