{"id":3634,"date":"2026-08-22T17:49:55","date_gmt":"2026-08-22T17:49:55","guid":{"rendered":"https:\/\/maroczain.com\/?p=3634"},"modified":"2026-08-22T17:49:55","modified_gmt":"2026-08-22T17:49:55","slug":"3634","status":"publish","type":"post","link":"https:\/\/maroczain.com\/en\/2026\/08\/22\/3634\/","title":{"rendered":""},"content":{"rendered":"\n<!doctype html>\n<html lang=\"fr\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Annuaire des agences de voyages au Maroc<\/title>\n<style>\n:root{\n  --navy:#082b45; --blue:#0c78b9; --sky:#eaf6fd; --gold:#d9aa35;\n  --ink:#173042; --muted:#6a7d8b; --white:#fff; --line:#dfe8ee; --bg:#f6f9fb;\n  --ok:#12805c; --danger:#b54a4a;\n}\n*{box-sizing:border-box}\nbody{margin:0;font-family:Inter,system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;background:var(--bg);color:var(--ink)}\na{color:inherit}\n.hero{\n  background:linear-gradient(135deg,#06263c 0%,#0a527b 58%,#0c78b9 100%);\n  color:white;padding:44px 20px 30px;position:relative;overflow:hidden\n}\n.hero:after{content:\"\u2708\";position:absolute;right:4%;top:-20px;font-size:150px;opacity:.08;transform:rotate(-12deg)}\n.wrap{max-width:1220px;margin:auto}\n.badge{display:inline-flex;gap:8px;align-items:center;padding:8px 12px;border:1px solid rgba(255,255,255,.25);border-radius:999px;background:rgba(255,255,255,.08);font-size:13px}\nh1{font-size:clamp(28px,4vw,50px);line-height:1.05;margin:16px 0 10px}\n.subtitle{max-width:760px;opacity:.9;font-size:17px}\n.toolbar{margin-top:26px;display:grid;grid-template-columns:2fr 1fr 1fr 1fr;gap:10px}\ninput,select,button{\n  width:100%;min-height:46px;border-radius:12px;border:1px solid var(--line);\n  padding:0 13px;font-size:14px;background:white;color:var(--ink)\n}\nbutton{cursor:pointer;font-weight:700}\n.primary{background:var(--gold);border-color:var(--gold);color:#173042}\n.secondary{background:white}\n.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin:18px auto 0}\n.stat{background:white;border:1px solid var(--line);border-radius:16px;padding:18px;box-shadow:0 8px 25px rgba(0,0,0,.04)}\n.stat strong{display:block;font-size:27px;color:var(--navy)}\n.stat span{font-size:13px;color:var(--muted)}\nmain{padding:20px}\n.panel{background:white;border:1px solid var(--line);border-radius:18px;padding:16px;margin-bottom:16px}\n.panel-head{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}\n.actions{display:flex;gap:8px;flex-wrap:wrap}\n.actions button,.actions label{width:auto;min-height:40px;padding:10px 14px;border-radius:10px;border:1px solid var(--line);background:white;font-weight:700;cursor:pointer}\n.actions .primary{background:var(--gold);border-color:var(--gold)}\n#file{display:none}\n.notice{background:var(--sky);border:1px solid #cde8f8;padding:12px 14px;border-radius:12px;font-size:13px;color:#285f7f;margin-top:12px}\n.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}\n.card{background:white;border:1px solid var(--line);border-radius:18px;padding:17px;box-shadow:0 6px 18px rgba(8,43,69,.04);display:flex;flex-direction:column;gap:10px}\n.card h3{margin:0;font-size:18px;color:var(--navy)}\n.meta{display:flex;gap:7px;flex-wrap:wrap}\n.tag{font-size:11px;border-radius:999px;padding:5px 8px;background:#eef4f7;color:#526b7b}\n.tag.odv{background:#e8f7f1;color:#0f7854}.tag.dv{background:#fff4dc;color:#875d08}\n.info{font-size:13px;color:#526b7b;line-height:1.55}\n.card .buttons{margin-top:auto;display:flex;gap:8px}\n.card .buttons a{flex:1;text-align:center;text-decoration:none;padding:9px 10px;border-radius:9px;border:1px solid var(--line);font-size:12px;font-weight:700}\n.empty{text-align:center;padding:55px 20px;color:var(--muted)}\n.table-wrap{overflow:auto}\ntable{width:100%;border-collapse:collapse;font-size:13px}\nth,td{text-align:left;padding:11px;border-bottom:1px solid var(--line);white-space:nowrap}\nth{background:#f6f9fb;color:#4e6878;position:sticky;top:0}\nfooter{padding:28px 20px;color:#6b7d88;font-size:12px;text-align:center}\n@media(max-width:900px){.toolbar{grid-template-columns:1fr 1fr}.grid{grid-template-columns:1fr 1fr}.stats{grid-template-columns:1fr 1fr}}\n@media(max-width:620px){.toolbar,.grid{grid-template-columns:1fr}.stats{grid-template-columns:1fr 1fr}}\n<\/style>\n<\/head>\n<body>\n<header class=\"hero\">\n  <div class=\"wrap\">\n    <span class=\"badge\">\ud83c\uddf2\ud83c\udde6 Maroc \u2022 Annuaire professionnel<\/span>\n    <h1>Annuaire des agences de voyages au Maroc<\/h1>\n    <div class=\"subtitle\">Recherchez par raison sociale, ville, r\u00e9gion ou type d\u2019agr\u00e9ment. Importez le fichier CSV officiel pour alimenter l\u2019annuaire en quelques secondes.<\/div>\n    <div class=\"toolbar\">\n      <input id=\"q\" placeholder=\"\ud83d\udd0e Rechercher une agence, ville, adresse\u2026\">\n      <select id=\"region\"><option value=\"\">Toutes les r\u00e9gions<\/option><\/select>\n      <select id=\"ville\"><option value=\"\">Toutes les villes<\/option><\/select>\n      <select id=\"type\"><option value=\"\">ODV + DV<\/option><option>ODV<\/option><option>DV<\/option><\/select>\n    <\/div>\n  <\/div>\n<\/header>\n\n<div class=\"wrap\" style=\"padding:0 20px\">\n  <section class=\"stats\">\n    <div class=\"stat\"><strong id=\"countAll\">0<\/strong><span>agences charg\u00e9es<\/span><\/div>\n    <div class=\"stat\"><strong id=\"countODV\">0<\/strong><span>ODV<\/span><\/div>\n    <div class=\"stat\"><strong id=\"countDV\">0<\/strong><span>DV<\/span><\/div>\n    <div class=\"stat\"><strong id=\"countCities\">0<\/strong><span>villes repr\u00e9sent\u00e9es<\/span><\/div>\n  <\/section>\n<\/div>\n\n<main class=\"wrap\">\n  <section class=\"panel\">\n    <div class=\"panel-head\">\n      <div>\n        <strong>Base de donn\u00e9es<\/strong>\n        <div style=\"font-size:12px;color:var(--muted);margin-top:4px\">Compatible CSV avec s\u00e9parateur virgule ou point-virgule.<\/div>\n      <\/div>\n      <div class=\"actions\">\n        <label for=\"file\" class=\"primary\">\u2b06 Importer CSV<\/label>\n        <input id=\"file\" type=\"file\" accept=\".csv,text\/csv\">\n        <button id=\"download\">\u2b07 Exporter CSV<\/button>\n        <button id=\"sample\">\uff0b Charger d\u00e9monstration<\/button>\n        <button id=\"clear\">\ud83d\uddd1 Vider<\/button>\n      <\/div>\n    <\/div>\n    <div class=\"notice\">\n      Colonnes reconnues automatiquement : <b>raison sociale \/ agence \/ nom<\/b>, <b>adresse<\/b>, <b>ville<\/b>, <b>r\u00e9gion<\/b>, <b>t\u00e9l\u00e9phone<\/b>, <b>email<\/b>, <b>site<\/b>, <b>type \/ cat\u00e9gorie<\/b>. Les donn\u00e9es import\u00e9es restent dans ce navigateur gr\u00e2ce au stockage local.\n    <\/div>\n  <\/section>\n\n  <section class=\"panel\">\n    <div class=\"panel-head\">\n      <strong id=\"resultLabel\">R\u00e9sultats<\/strong>\n      <div class=\"actions\">\n        <button id=\"cardsBtn\">\u25a6 Fiches<\/button>\n        <button id=\"tableBtn\">\u2637 Tableau<\/button>\n      <\/div>\n    <\/div>\n  <\/section>\n\n  <section id=\"cards\" class=\"grid\"><\/section>\n  <section id=\"table\" class=\"panel table-wrap\" style=\"display:none\"><\/section>\n<\/main>\n\n<footer>\n  Annuaire professionnel \u2014 Donn\u00e9es \u00e0 v\u00e9rifier aupr\u00e8s du Minist\u00e8re du Tourisme et de la source officielle avant publication commerciale.\n<\/footer>\n\n<script>\nconst REGIONS=[\n\"Rabat-Sal\u00e9-K\u00e9nitra\",\"Casablanca-Settat\",\"Marrakech-Safi\",\"F\u00e8s-Mekn\u00e8s\",\n\"Tanger-T\u00e9touan-Al Hoce\u00efma\",\"Souss-Massa\",\"L\u2019Oriental\",\"B\u00e9ni Mellal-Kh\u00e9nifra\",\n\"Dr\u00e2a-Tafilalet\",\"Guelmim-Oued Noun\",\"La\u00e2youne-Sakia El Hamra\",\"Dakhla-Oued Ed-Dahab\"\n];\n\nlet agencies = JSON.parse(localStorage.getItem(\"mz_annuaire_agences\")||\"[]\");\nlet mode=\"cards\";\n\nconst $=id=>document.getElementById(id);\nREGIONS.forEach(r=>$(\"region\").insertAdjacentHTML(\"beforeend\",`<option>${r}<\/option>`));\n\nfunction norm(s){return (s||\"\").toString().trim()}\nfunction esc(s){return norm(s).replace(\/[&<>\"']\/g,m=>({\"&\":\"&amp;\",\"<\":\"&lt;\",\">\":\"&gt;\",'\"':\"&quot;\",\"'\":\"&#39;\"}[m]))}\nfunction telLink(s){return norm(s).replace(\/[^\\d+]\/g,\"\")}\nfunction safeUrl(s){\n  s=norm(s); if(!s)return \"\";\n  if(\/^https?:\\\/\\\/\/i.test(s)) return s;\n  return \"https:\/\/\"+s.replace(\/^\\\/+\/,\"\");\n}\nfunction save(){localStorage.setItem(\"mz_annuaire_agences\",JSON.stringify(agencies))}\nfunction valueOf(row, keys){\n  const entries=Object.entries(row);\n  for(const k of keys){\n    const hit=entries.find(([key])=>key.toLowerCase().normalize(\"NFD\").replace(\/[\\u0300-\\u036f]\/g,\"\").includes(k));\n    if(hit && norm(hit[1])) return norm(hit[1]);\n  }\n  return \"\";\n}\nfunction canonical(row){\n  return {\n    name:valueOf(row,[\"raison sociale\",\"raison_sociale\",\"agence\",\"nom\"]),\n    address:valueOf(row,[\"adresse\",\"address\"]),\n    city:valueOf(row,[\"ville\",\"city\",\"localite\"]),\n    region:valueOf(row,[\"region\"]),\n    phone:valueOf(row,[\"telephone\",\"tel\",\"phone\",\"gsm\"]),\n    email:valueOf(row,[\"email\",\"mail\",\"courriel\"]),\n    website:valueOf(row,[\"site web\",\"website\",\"site\"]),\n    type:(valueOf(row,[\"type\",\"categorie\",\"category\",\"licence\"])||\"\").toUpperCase()\n  }\n}\nfunction parseCSV(text){\n  const lines=text.replace(\/^\\uFEFF\/,\"\").split(\/\\r?\\n\/).filter(x=>x.trim());\n  if(!lines.length)return [];\n  const first=lines[0];\n  const sep=(first.split(\";\").length>first.split(\",\").length)?\";\":\",\";\n  function parseLine(line){\n    const out=[];let cur=\"\",quoted=false;\n    for(let i=0;i<line.length;i++){\n      const c=line[i];\n      if(c=='\"'){\n        if(quoted &#038;&#038; line[i+1]=='\"'){cur+='\"';i++} else quoted=!quoted;\n      }else if(c===sep &#038;&#038; !quoted){out.push(cur);cur=\"\"}\n      else cur+=c;\n    } out.push(cur); return out;\n  }\n  const headers=parseLine(lines[0]).map(x=>x.trim());\n  return lines.slice(1).map(line=>{\n    const vals=parseLine(line), row={};\n    headers.forEach((h,i)=>row[h]=vals[i]||\"\");\n    return canonical(row);\n  }).filter(x=>x.name||x.city||x.address);\n}\nfunction refreshCities(){\n  const current=$(\"ville\").value;\n  const cities=[...new Set(agencies.map(x=>x.city).filter(Boolean))].sort((a,b)=>a.localeCompare(b,\"fr\"));\n  $(\"ville\").innerHTML='<option value=\"\">Toutes les villes<\/option>'+cities.map(c=>`<option>${esc(c)}<\/option>`).join(\"\");\n  if(cities.includes(current)) $(\"ville\").value=current;\n}\nfunction filtered(){\n  const q=$(\"q\").value.toLowerCase(), r=$(\"region\").value, v=$(\"ville\").value, t=$(\"type\").value;\n  return agencies.filter(a=>{\n    const hay=Object.values(a).join(\" \").toLowerCase();\n    return (!q||hay.includes(q)) && (!r||a.region===r) && (!v||a.city===v) && (!t||a.type.includes(t));\n  });\n}\nfunction render(){\n  refreshCities();\n  const list=filtered();\n  $(\"countAll\").textContent=agencies.length;\n  $(\"countODV\").textContent=agencies.filter(a=>a.type.includes(\"ODV\")).length;\n  $(\"countDV\").textContent=agencies.filter(a=>a.type===\"DV\"||(\/\\bDV\\b\/.test(a.type)&&!a.type.includes(\"ODV\"))).length;\n  $(\"countCities\").textContent=new Set(agencies.map(a=>a.city).filter(Boolean)).size;\n  $(\"resultLabel\").textContent=`${list.length} r\u00e9sultat${list.length>1?\"s\":\"\"}`;\n\n  if(!list.length){\n    $(\"cards\").innerHTML='<div class=\"panel empty\" style=\"grid-column:1\/-1\"><div style=\"font-size:38px\">\ud83e\udded<\/div><h3>Aucune agence affich\u00e9e<\/h3><p>Importez le CSV officiel ou chargez la d\u00e9monstration pour tester l\u2019interface.<\/p><\/div>';\n  } else {\n    $(\"cards\").innerHTML=list.map(a=>`\n      <article class=\"card\">\n        <div class=\"meta\">\n          ${a.type?`<span class=\"tag ${a.type.includes(\"ODV\")?\"odv\":\"dv\"}\">${esc(a.type)}<\/span>`:\"\"}\n          ${a.region?`<span class=\"tag\">${esc(a.region)}<\/span>`:\"\"}\n        <\/div>\n        <h3>${esc(a.name||\"Agence de voyages\")}<\/h3>\n        <div class=\"info\">\n          ${a.city?`\ud83d\udccd <b>${esc(a.city)}<\/b><br>`:\"\"}\n          ${a.address?`${esc(a.address)}<br>`:\"\"}\n          ${a.phone?`\u260e ${esc(a.phone)}<br>`:\"\"}\n          ${a.email?`\u2709 ${esc(a.email)}`:\"\"}\n        <\/div>\n        <div class=\"buttons\">\n          ${a.phone?`<a href=\"tel:${telLink(a.phone)}\">Appeler<\/a>`:\"\"}\n          ${a.email?`<a href=\"mailto:${esc(a.email)}\">E-mail<\/a>`:\"\"}\n          ${a.website?`<a target=\"_blank\" rel=\"noopener\" href=\"${esc(safeUrl(a.website))}\">Site<\/a>`:\"\"}\n        <\/div>\n      <\/article>`).join(\"\");\n  }\n\n  $(\"table\").innerHTML = list.length ? `<table>\n  <thead><tr><th>Agence<\/th><th>Type<\/th><th>Ville<\/th><th>R\u00e9gion<\/th><th>Adresse<\/th><th>T\u00e9l\u00e9phone<\/th><th>E-mail<\/th><th>Site<\/th><\/tr><\/thead>\n  <tbody>${list.map(a=>`<tr><td><b>${esc(a.name)}<\/b><\/td><td>${esc(a.type)}<\/td><td>${esc(a.city)}<\/td><td>${esc(a.region)}<\/td><td>${esc(a.address)}<\/td><td>${esc(a.phone)}<\/td><td>${esc(a.email)}<\/td><td>${esc(a.website)}<\/td><\/tr>`).join(\"\")}<\/tbody><\/table>` : '<div class=\"empty\">Aucune donn\u00e9e<\/div>';\n\n  $(\"cards\").style.display=mode===\"cards\"?\"grid\":\"none\";\n  $(\"table\").style.display=mode===\"table\"?\"block\":\"none\";\n}\n[\"q\",\"region\",\"ville\",\"type\"].forEach(id=>$(id).addEventListener(id===\"q\"?\"input\":\"change\",render));\n$(\"cardsBtn\").onclick=()=>{mode=\"cards\";render()};\n$(\"tableBtn\").onclick=()=>{mode=\"table\";render()};\n$(\"file\").addEventListener(\"change\",e=>{\n  const f=e.target.files[0]; if(!f)return;\n  const reader=new FileReader();\n  reader.onload=()=>{\n    const parsed=parseCSV(reader.result);\n    agencies=parsed; save(); render();\n    alert(parsed.length+\" agence(s) import\u00e9e(s).\");\n  };\n  reader.readAsText(f,\"utf-8\");\n});\n$(\"clear\").onclick=()=>{\n  if(confirm(\"Vider la base locale de cet annuaire ?\")){agencies=[];save();render()}\n};\n$(\"download\").onclick=()=>{\n  const rows=[[\"Raison Sociale\",\"Type\",\"Ville\",\"R\u00e9gion\",\"Adresse\",\"T\u00e9l\u00e9phone\",\"Email\",\"Site web\"],...filtered().map(a=>[a.name,a.type,a.city,a.region,a.address,a.phone,a.email,a.website])];\n  const csv=rows.map(r=>r.map(v=>`\"${norm(v).replace(\/\"\/g,'\"\"')}\"`).join(\";\")).join(\"\\n\");\n  const blob=new Blob([\"\\uFEFF\"+csv],{type:\"text\/csv;charset=utf-8\"});\n  const url=URL.createObjectURL(blob), a=document.createElement(\"a\");\n  a.href=url;a.download=\"annuaire-agences-voyages-maroc.csv\";a.click();URL.revokeObjectURL(url);\n};\n$(\"sample\").onclick=()=>{\n agencies=[\n  {name:\"Agence D\u00e9monstration Casablanca\",type:\"ODV\",city:\"Casablanca\",region:\"Casablanca-Settat\",address:\"Adresse exemple\",phone:\"\",email:\"\",website:\"\"},\n  {name:\"Agence D\u00e9monstration Marrakech\",type:\"DV\",city:\"Marrakech\",region:\"Marrakech-Safi\",address:\"Adresse exemple\",phone:\"\",email:\"\",website:\"\"},\n  {name:\"Agence D\u00e9monstration Rabat\",type:\"ODV\",city:\"Rabat\",region:\"Rabat-Sal\u00e9-K\u00e9nitra\",address:\"Adresse exemple\",phone:\"\",email:\"\",website:\"\"},\n  {name:\"Agence D\u00e9monstration F\u00e8s\",type:\"DV\",city:\"F\u00e8s\",region:\"F\u00e8s-Mekn\u00e8s\",address:\"Adresse exemple\",phone:\"\",email:\"\",website:\"\"}\n ];\n save();render();\n};\nrender();\n<\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>Annuaire des agences de voyages au Maroc \ud83c\uddf2\ud83c\udde6 Maroc \u2022 Annuaire professionnel Annuaire des agences de voyages au Maroc Recherchez par raison sociale, ville, r\u00e9gion ou type d\u2019agr\u00e9ment. Importez le fichier CSV officiel pour alimenter l\u2019annuaire en quelques secondes. Toutes les r\u00e9gions Toutes les villes ODV + DVODVDV 0agences charg\u00e9es 0ODV 0DV 0villes repr\u00e9sent\u00e9es Base [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1],"tags":[],"class_list":["post-3634","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/maroczain.com\/en\/wp-json\/wp\/v2\/posts\/3634","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/maroczain.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/maroczain.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/maroczain.com\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/maroczain.com\/en\/wp-json\/wp\/v2\/comments?post=3634"}],"version-history":[{"count":1,"href":"https:\/\/maroczain.com\/en\/wp-json\/wp\/v2\/posts\/3634\/revisions"}],"predecessor-version":[{"id":3635,"href":"https:\/\/maroczain.com\/en\/wp-json\/wp\/v2\/posts\/3634\/revisions\/3635"}],"wp:attachment":[{"href":"https:\/\/maroczain.com\/en\/wp-json\/wp\/v2\/media?parent=3634"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/maroczain.com\/en\/wp-json\/wp\/v2\/categories?post=3634"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/maroczain.com\/en\/wp-json\/wp\/v2\/tags?post=3634"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}