{"id":473,"date":"2025-11-16T13:09:16","date_gmt":"2025-11-16T13:09:16","guid":{"rendered":"https:\/\/bodafranyjose.com\/?page_id=473"},"modified":"2026-04-13T17:18:20","modified_gmt":"2026-04-13T17:18:20","slug":"lista-invitados","status":"publish","type":"page","link":"https:\/\/bodafranyjose.com\/index.php\/lista-invitados\/","title":{"rendered":"Lista invitados"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"473\" class=\"elementor elementor-473\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-715be97 e-flex e-con-boxed e-con e-parent\" data-id=\"715be97\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-be732c1 elementor-widget elementor-widget-html\" data-id=\"be732c1\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<style>\n  .invitados-container {\n    background: #fff;\n    border-radius: 22px;\n    box-shadow: 0 6px 24px rgba(0,0,0,0.07);\n    padding: 22px 18px;\n    max-width: 950px;\n    margin: 0 auto;\n    font-family: 'Poppins', sans-serif;\n    color: #333;\n  }\n\n  .invitados-head {\n    text-align: center;\n    margin-bottom: 14px;\n  }\n\n  .invitados-title {\n    color: #b67b91;\n    margin: 0 0 5px;\n    font-size: 1.72rem;\n    font-weight: 700;\n    line-height: 1.15;\n  }\n\n  .invitados-subtitle {\n    color: #666;\n    margin: 0;\n    font-size: 0.9rem;\n    font-weight: 600;\n    line-height: 1.28;\n  }\n\n  .resumen-dashboard {\n    display: grid;\n    grid-template-columns: repeat(4, minmax(0, 1fr));\n    gap: 9px;\n    margin-bottom: 12px;\n  }\n\n  .resumen-card {\n    background: #faf6f8;\n    border: 1px solid transparent;\n    border-radius: 13px;\n    text-align: center;\n    padding: 8px 7px;\n    box-shadow: 0 2px 9px rgba(0,0,0,0.04);\n    cursor: pointer;\n    transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease, background 0.2s ease;\n  }\n\n  .resumen-card:hover {\n    transform: translateY(-1px);\n    box-shadow: 0 5px 14px rgba(0,0,0,0.07);\n  }\n\n  .resumen-card.active {\n    background: #fff;\n    border-color: #b67b91;\n    box-shadow: 0 5px 16px rgba(182,123,145,0.16);\n  }\n\n  .resumen-card h3 {\n    font-size: 0.76rem;\n    color: #b67b91;\n    margin: 0 0 4px;\n    font-weight: 700;\n    line-height: 1.1;\n  }\n\n  .resumen-card span {\n    font-size: 1.15rem;\n    font-weight: 800;\n    color: #333;\n    line-height: 1.1;\n  }\n\n  .resumen-card.confirmados { background: #f7eef3; }\n  .resumen-card.acompanantes { background: #eef7f2; }\n  .resumen-card.total { background: #f4f0f8; }\n  .resumen-card.noConfirmados { background: #fcefee; }\n\n  .resumen-card.active.confirmados,\n  .resumen-card.active.acompanantes,\n  .resumen-card.active.total,\n  .resumen-card.active.noConfirmados {\n    background: #fff;\n  }\n\n  .add-invitado-panel {\n    margin-bottom: 10px;\n  }\n\n  .add-toggle-btn {\n    display: block;\n    width: 100%;\n    min-height: 42px;\n    background: #b67b91;\n    color: #fff;\n    border: none;\n    border-radius: 10px;\n    padding: 10px 14px;\n    cursor: pointer;\n    font-family: 'Poppins', sans-serif;\n    font-weight: 800;\n    font-size: 0.92rem;\n    transition: background 0.25s ease;\n  }\n\n  .add-toggle-btn:hover {\n    background: #a56b82;\n  }\n\n  .add-invitado {\n    display: none;\n    grid-template-columns: 1.2fr 1fr auto;\n    gap: 9px;\n    align-items: center;\n    margin-top: 9px;\n    background: #faf6f8;\n    border: 1px solid #f0e6ea;\n    border-radius: 16px;\n    padding: 12px;\n  }\n\n  .add-invitado.active {\n    display: grid;\n  }\n\n  .add-invitado input[type=\"text\"],\n  .add-invitado textarea {\n    width: 100%;\n    min-height: 41px;\n    padding: 9px 10px;\n    border-radius: 10px;\n    border: 1px solid #e2d4da;\n    font-size: 16px;\n    box-sizing: border-box;\n    background: #fff;\n    font-family: 'Poppins', sans-serif;\n  }\n\n  .add-invitado textarea {\n    min-height: 58px;\n    resize: vertical;\n    grid-column: 1 \/ -1;\n  }\n\n  .add-options {\n    display: flex;\n    gap: 12px;\n    justify-content: center;\n    flex-wrap: wrap;\n  }\n\n  .add-check {\n    margin: 0;\n    color: #444;\n    cursor: pointer;\n    font-weight: 700;\n    font-size: 0.86rem;\n    white-space: nowrap;\n  }\n\n  .add-check input {\n    accent-color: #b67b91;\n    margin-right: 5px;\n  }\n\n  .nuevo-acompanante-wrap {\n    display: none;\n    grid-column: 1 \/ -1;\n  }\n\n  .nuevo-acompanante-wrap.active {\n    display: block;\n  }\n\n  .invitados-toolbar {\n    display: grid;\n    grid-template-columns: 1fr auto auto;\n    gap: 9px;\n    align-items: center;\n    margin-bottom: 12px;\n  }\n\n  .buscar-wrap {\n  position: relative;\n}\n\n.buscar-wrap::before,\n.buscar-wrap::after {\n  content: none;\n  display: none;\n}\n\n.buscar-invitado,\n.ordenar-invitado {\n  width: 100%;\n  min-height: 41px;\n  padding: 9px 11px;\n  border-radius: 10px;\n  border: 1px solid #e2d4da;\n  font-size: 16px;\n  box-sizing: border-box;\n  background: #fff;\n  font-family: 'Poppins', sans-serif;\n  font-weight: 400;\n}\n\n.buscar-invitado {\n  padding-left: 11px;\n}\n\n.buscar-invitado::placeholder {\n  color: #888;\n  font-weight: 300;\n}\n\n\n  .buscar-invitado:focus,\n  .ordenar-invitado:focus,\n  .add-invitado input:focus,\n  .add-invitado textarea:focus,\n  .ficha-input:focus,\n  .ficha-textarea:focus {\n    outline: 2px solid #f2e1e8;\n    border-color: #b67b91;\n  }\n\n  .add-btn,\n  .btn-close,\n  .export-btn,\n  .btn-danger {\n    border-radius: 10px;\n    cursor: pointer;\n    font-family: 'Poppins', sans-serif;\n    font-weight: 700;\n    font-size: 0.86rem;\n    transition: 0.25s ease;\n    white-space: nowrap;\n    min-height: 41px;\n  }\n\n  .add-btn,\n  .btn-close {\n    background: #b67b91;\n    color: white;\n    border: none;\n    padding: 9px 13px;\n  }\n\n  .add-btn:hover,\n  .btn-close:hover {\n    background: #a56b82;\n  }\n\n  .export-btn {\n    background: #fff;\n    color: #b67b91;\n    border: 1px solid #e5c9d4;\n    padding: 8px 12px;\n  }\n\n  .export-btn:hover {\n    background: #f9f0f4;\n    border-color: #b67b91;\n  }\n\n  .btn-danger {\n    background: #fff;\n    color: #a5447d;\n    border: 1px solid #f0c8d6;\n    padding: 8px 12px;\n  }\n\n  .btn-danger:hover {\n    background: #fcefee;\n    color: #8f3568;\n  }\n\n  .invitados-lista {\n    display: grid;\n    gap: 7px;\n  }\n\n  .invitado-row {\n    width: 100%;\n    display: grid;\n    grid-template-columns: 28px 1fr auto;\n    gap: 9px;\n    align-items: center;\n    border: 1px solid #f2d6e1;\n    border-radius: 14px;\n    background: #fff;\n    padding: 9px 10px;\n    box-shadow: 0 2px 10px rgba(0,0,0,0.035);\n    font-family: 'Poppins', sans-serif;\n    color: #333;\n    transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;\n  }\n\n  .invitado-row:hover {\n    transform: translateY(-1px);\n    box-shadow: 0 4px 14px rgba(0,0,0,0.055);\n  }\n\n  .invitado-row.confirmado {\n    border-color: #d9efd9;\n    background: linear-gradient(90deg, #f7fcf8, #fff);\n  }\n\n  .row-confirmado-check {\n    transform: scale(1.08);\n    accent-color: #b67b91;\n    cursor: pointer;\n    margin: 0;\n  }\n\n  .invitado-info {\n    min-width: 0;\n    cursor: pointer;\n  }\n\n  .nombre-linea {\n    display: block;\n    font-weight: 800;\n    color: #444;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    line-height: 1.18;\n    font-size: 0.95rem;\n  }\n\n  .acompanante-inline {\n    color: #b67b91;\n    font-weight: 700;\n  }\n\n  .nota-linea {\n    display: block;\n    margin-top: 3px;\n    color: #777;\n    font-size: 0.76rem;\n    font-weight: 600;\n    line-height: 1.15;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n\n  .invitado-side {\n    display: flex;\n    align-items: center;\n    gap: 7px;\n    cursor: pointer;\n  }\n\n  .badge {\n    display: inline-flex;\n    align-items: center;\n    background: #fff;\n    color: #b67b91;\n    border: 1px solid #f0e6ea;\n    border-radius: 999px;\n    padding: 3px 8px;\n    font-size: 0.68rem;\n    font-weight: 800;\n    line-height: 1.1;\n    white-space: nowrap;\n  }\n\n  .badge.ok {\n    color: #3c8d56;\n    border-color: #d9efd9;\n  }\n\n  .badge.warn {\n    color: #a5447d;\n    border-color: #f0c8d6;\n  }\n\n  .row-chevron {\n    color: #b67b91;\n    font-size: 1.1rem;\n    font-weight: 800;\n    line-height: 1;\n  }\n\n  .sin-resultados {\n    text-align: center;\n    color: #b67b91;\n    margin: 14px 0;\n    background: #faf6f8;\n    border-radius: 14px;\n    padding: 16px;\n    font-weight: 700;\n  }\n\n  .invitado-modal {\n    display: none;\n    position: fixed;\n    z-index: 99999;\n    inset: 0;\n    background: rgba(45, 35, 40, 0.38);\n    padding: 18px;\n    box-sizing: border-box;\n    align-items: center;\n    justify-content: center;\n  }\n\n  .invitado-modal.active {\n    display: flex;\n  }\n\n  .invitado-modal-card {\n    width: min(560px, 100%);\n    max-height: calc(100vh - 36px);\n    overflow-y: auto;\n    background: #fff;\n    border-radius: 18px;\n    box-shadow: 0 18px 45px rgba(0,0,0,0.22);\n    border: 1px solid #f0e6ea;\n  }\n\n  .ficha-head {\n    display: grid;\n    grid-template-columns: 1fr 40px;\n    gap: 10px;\n    align-items: center;\n    padding: 14px 14px 12px;\n    background: #faf6f8;\n    border-bottom: 1px solid #f0e6ea;\n    border-radius: 18px 18px 0 0;\n  }\n\n  .ficha-title {\n    margin: 0;\n    color: #b67b91;\n    font-size: 1.08rem;\n    font-weight: 800;\n    line-height: 1.2;\n  }\n\n  .ficha-subtitle {\n    margin: 3px 0 0;\n    color: #666;\n    font-size: 0.8rem;\n    font-weight: 600;\n  }\n\n  .ficha-x {\n    width: 40px;\n    height: 40px;\n    border: 1px solid #f0e6ea;\n    border-radius: 10px;\n    background: #fff;\n    color: #b67b91;\n    cursor: pointer;\n    font-weight: 800;\n    font-size: 1.08rem;\n    line-height: 1;\n    padding: 0;\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    appearance: none;\n  }\n\n  .ficha-body {\n    padding: 14px;\n  }\n\n  .ficha-grid {\n    display: grid;\n    grid-template-columns: 1fr 1fr;\n    gap: 10px;\n  }\n\n  .ficha-field {\n    min-width: 0;\n  }\n\n  .ficha-field.full {\n    grid-column: 1 \/ -1;\n  }\n\n  .ficha-field label,\n  .ficha-check {\n    display: block;\n    color: #b67b91;\n    font-weight: 800;\n    font-size: 0.82rem;\n    margin-bottom: 5px;\n  }\n\n  .ficha-input,\n  .ficha-textarea {\n    width: 100%;\n    min-height: 42px;\n    padding: 9px 10px;\n    border-radius: 10px;\n    border: 1px solid #e2d4da;\n    font-size: 16px;\n    box-sizing: border-box;\n    background: #fff;\n    font-family: 'Poppins', sans-serif;\n  }\n\n  .ficha-textarea {\n    min-height: 88px;\n    resize: vertical;\n  }\n\n  .ficha-check {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    gap: 8px;\n    min-height: 42px;\n    padding: 9px 10px;\n    border: 1px solid #f0e6ea;\n    border-radius: 10px;\n    background: #faf6f8;\n    color: #444;\n    cursor: pointer;\n    box-sizing: border-box;\n    text-align: center;\n  }\n\n  .ficha-check input {\n    accent-color: #b67b91;\n    margin: 0;\n  }\n\n  .ficha-acompanante-wrap {\n    display: none;\n  }\n\n  .ficha-acompanante-wrap.active {\n    display: block;\n  }\n\n  .ficha-actions {\n    display: grid;\n    grid-template-columns: 1fr;\n    gap: 9px;\n    margin-top: 14px;\n  }\n\n  .ficha-danger-zone {\n    margin-top: 13px;\n    padding-top: 13px;\n    border-top: 1px solid #f4e5eb;\n  }\n\n  .ficha-danger-zone .btn-danger {\n    width: 100%;\n  }\n\n  @media (max-width: 768px) {\n    .invitados-container {\n      padding: 16px 12px;\n      border-radius: 18px;\n    }\n\n    .invitados-head {\n      margin-bottom: 10px;\n    }\n\n    .invitados-title {\n      font-size: 1.36rem;\n      margin-bottom: 4px;\n    }\n\n    .invitados-subtitle {\n      font-size: 0.78rem;\n      line-height: 1.25;\n      max-width: 340px;\n      margin: 0 auto;\n    }\n\n    .resumen-dashboard {\n      grid-template-columns: repeat(4, minmax(0, 1fr));\n      gap: 6px;\n      margin-bottom: 10px;\n    }\n\n    .resumen-card {\n      padding: 7px 4px;\n      border-radius: 11px;\n      min-height: 48px;\n    }\n\n    .resumen-card h3 {\n      font-size: 0.56rem;\n      margin-bottom: 3px;\n    }\n\n    .resumen-card span {\n      font-size: 0.88rem;\n    }\n\n    .add-invitado {\n      grid-template-columns: 1fr;\n      gap: 8px;\n      padding: 11px;\n    }\n\n    .add-options {\n      justify-content: flex-start;\n    }\n\n    .invitados-toolbar {\n      grid-template-columns: 1fr 1fr;\n      gap: 8px;\n      margin-bottom: 10px;\n    }\n\n    .buscar-wrap {\n      grid-column: 1 \/ -1;\n    }\n\n    .export-btn {\n      width: 100%;\n    }\n\n    .ordenar-invitado {\n      width: 100%;\n    }\n\n    .add-btn,\n    .add-toggle-btn {\n      width: 100%;\n    }\n\n    .invitados-lista {\n      gap: 6px;\n    }\n\n    .invitado-row {\n      grid-template-columns: 24px 1fr auto;\n      gap: 8px;\n      padding: 8px 9px;\n      border-radius: 13px;\n      min-height: 48px;\n    }\n\n    .row-confirmado-check {\n      transform: scale(1.05);\n    }\n\n    .nombre-linea {\n      font-size: 0.9rem;\n    }\n\n    .nota-linea {\n      font-size: 0.7rem;\n      margin-top: 2px;\n    }\n\n    .badge {\n      font-size: 0.6rem;\n      padding: 3px 6px;\n    }\n\n    .invitado-side {\n      gap: 5px;\n    }\n\n    .row-chevron {\n      font-size: 1rem;\n    }\n\n    .invitado-modal {\n      padding: 10px;\n      align-items: flex-end;\n    }\n\n    .invitado-modal-card {\n      max-height: calc(100vh - 20px);\n      border-radius: 18px;\n    }\n\n    .ficha-head {\n      grid-template-columns: 1fr 40px;\n      padding: 13px 13px 11px;\n    }\n\n    .ficha-title {\n      font-size: 1rem;\n    }\n\n    .ficha-body {\n      padding: 12px;\n    }\n\n    .ficha-grid {\n      grid-template-columns: 1fr 1fr;\n      gap: 9px;\n    }\n\n    .ficha-field.full {\n      grid-column: 1 \/ -1;\n    }\n\n    .ficha-check {\n      min-height: 44px;\n      padding: 9px 8px;\n      font-size: 0.8rem;\n    }\n\n    .ficha-actions {\n      grid-template-columns: 1fr;\n      gap: 8px;\n    }\n\n    .btn-close,\n    .btn-danger {\n      width: 100%;\n    }\n  }\n\n  @media (max-width: 380px) {\n    .resumen-card h3 {\n      font-size: 0.52rem;\n    }\n\n    .resumen-card span {\n      font-size: 0.82rem;\n    }\n\n    .invitados-toolbar {\n      grid-template-columns: 1fr;\n    }\n\n    .badge {\n      display: none;\n    }\n\n    .ficha-check {\n      font-size: 0.74rem;\n    }\n  }\n<\/style>\n\n<div class=\"invitados-container\">\n  <div class=\"invitados-head\">\n    <h2 class=\"invitados-title\">\ud83d\udccb Lista de Invitados<\/h2>\n    <p class=\"invitados-subtitle\">Controla confirmaciones, acompa\u00f1antes y notas importantes.<\/p>\n  <\/div>\n\n  <div class=\"resumen-dashboard\">\n    <div class=\"resumen-card total active\" onclick=\"filtrarInvitados('todos')\">\n      <h3>Total<\/h3><span id=\"total\">0<\/span>\n    <\/div>\n    <div class=\"resumen-card confirmados\" onclick=\"filtrarInvitados('confirmados')\">\n      <h3>Confirm.<\/h3><span id=\"confirmados\">0<\/span>\n    <\/div>\n    <div class=\"resumen-card acompanantes\" onclick=\"filtrarInvitados('acompanantes')\">\n      <h3>Acomp.<\/h3><span id=\"acompanantes\">0<\/span>\n    <\/div>\n    <div class=\"resumen-card noConfirmados\" onclick=\"filtrarInvitados('noConfirmados')\">\n      <h3>Pend.<\/h3><span id=\"noConfirmados\">0<\/span>\n    <\/div>\n  <\/div>\n\n  <div class=\"add-invitado-panel\">\n    <button class=\"add-toggle-btn\" onclick=\"toggleFormularioInvitado()\">\u2795 A\u00f1adir invitado<\/button>\n\n    <div class=\"add-invitado\" id=\"addInvitadoForm\">\n      <input type=\"text\" id=\"nuevoInvitado\" placeholder=\"Nombre del invitado...\">\n\n      <div class=\"add-options\">\n        <label class=\"add-check\">\n          <input type=\"checkbox\" id=\"nuevoConfirmado\"> Confirmado\n        <\/label>\n        <label class=\"add-check\">\n          <input type=\"checkbox\" id=\"nuevoAcompanante\" onchange=\"toggleNuevoAcompanante(this.checked)\"> Acompa\u00f1ante\n        <\/label>\n      <\/div>\n\n      <button class=\"add-btn\" onclick=\"agregarInvitado()\">Guardar invitado<\/button>\n\n      <div class=\"nuevo-acompanante-wrap\" id=\"nuevoAcompananteWrap\">\n        <input type=\"text\" id=\"nuevoAcompananteNombre\" placeholder=\"Nombre del acompa\u00f1ante...\">\n      <\/div>\n\n      <textarea id=\"nuevasNotas\" placeholder=\"Notas, alergias, men\u00fa...\"><\/textarea>\n    <\/div>\n  <\/div>\n\n  <div class=\"invitados-toolbar\">\n    <div class=\"buscar-wrap\">\n      <input type=\"text\" id=\"buscarInvitado\" class=\"buscar-invitado\" placeholder=\"Buscar invitado...\" oninput=\"actualizarBusqueda(this.value)\">\n    <\/div>\n\n    <select id=\"ordenInvitados\" class=\"ordenar-invitado\" onchange=\"actualizarOrden(this.value)\">\n      <option value=\"nombre\">Nombre<\/option>\n      <option value=\"pendientes\">Pendientes primero<\/option>\n      <option value=\"confirmados\">Confirmados primero<\/option>\n      <option value=\"acompanantes\">Con acompa\u00f1ante<\/option>\n    <\/select>\n\n    <button class=\"export-btn\" onclick=\"exportarInvitados()\">\ud83d\udce4 Exportar<\/button>\n  <\/div>\n\n  <div id=\"listaInvitados\" class=\"invitados-lista\"><\/div>\n<\/div>\n\n<div class=\"invitado-modal\" id=\"invitadoModal\" onclick=\"cerrarFichaDesdeFondo(event)\">\n  <div class=\"invitado-modal-card\" role=\"dialog\" aria-modal=\"true\">\n    <div class=\"ficha-head\">\n      <div>\n        <h3 class=\"ficha-title\" id=\"fichaTitulo\">Editar invitado<\/h3>\n        <p class=\"ficha-subtitle\">Los cambios se guardan autom\u00e1ticamente.<\/p>\n      <\/div>\n      <button class=\"ficha-x\" onclick=\"cerrarFicha()\">\u2715<\/button>\n    <\/div>\n\n    <div class=\"ficha-body\">\n      <div class=\"ficha-grid\">\n        <div class=\"ficha-field full\">\n          <label>Nombre<\/label>\n          <input type=\"text\" id=\"fichaNombre\" class=\"ficha-input\" oninput=\"actualizarTextoFicha('nombre', this.value)\">\n        <\/div>\n\n        <div class=\"ficha-field\">\n          <label class=\"ficha-check\">\n            <input type=\"checkbox\" id=\"fichaConfirmado\" onchange=\"actualizarConfirmadoFicha(this.checked)\">\n            Confirmado\n          <\/label>\n        <\/div>\n\n        <div class=\"ficha-field\">\n          <label class=\"ficha-check\">\n            <input type=\"checkbox\" id=\"fichaAcompanante\" onchange=\"actualizarAcompananteFicha(this.checked)\">\n            Acompa\u00f1ante\n          <\/label>\n        <\/div>\n\n        <div class=\"ficha-field full ficha-acompanante-wrap\" id=\"fichaAcompananteWrap\">\n          <label>Nombre del acompa\u00f1ante<\/label>\n          <input type=\"text\" id=\"fichaAcompananteNombre\" class=\"ficha-input\" placeholder=\"Nombre del acompa\u00f1ante...\" oninput=\"actualizarTextoFicha('acompananteNombre', this.value)\">\n        <\/div>\n\n        <div class=\"ficha-field full\">\n          <label>Notas<\/label>\n          <textarea id=\"fichaNotas\" class=\"ficha-textarea\" placeholder=\"Notas, alergias, men\u00fa...\" oninput=\"actualizarTextoFicha('notas', this.value)\"><\/textarea>\n        <\/div>\n      <\/div>\n\n      <div class=\"ficha-actions\">\n        <button class=\"btn-close\" onclick=\"cerrarFicha()\">Cerrar ficha<\/button>\n      <\/div>\n\n      <div class=\"ficha-danger-zone\">\n        <button class=\"btn-danger\" onclick=\"eliminarInvitadoEditando()\">Eliminar invitado<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\nconst JSON_URL = 'https:\/\/bodafranyjose.com\/wp-content\/uploads\/invitados\/invitados.json';\nconst GUARDAR_URL = 'https:\/\/bodafranyjose.com\/wp-content\/uploads\/invitados\/guardar.php?key=bodafest2025KEY';\n\nlet invitados = [];\nlet filtroActivo = 'todos';\nlet busquedaActiva = '';\nlet ordenActivo = 'nombre';\nlet guardadoTimer = null;\nlet invitadoEditando = null;\n\nfunction escaparHTML(valor) {\n  return String(valor || \"\")\n    .replace(\/&\/g, \"&amp;\")\n    .replace(\/<\/g, \"&lt;\")\n    .replace(\/>\/g, \"&gt;\")\n    .replace(\/\"\/g, \"&quot;\")\n    .replace(\/'\/g, \"&#039;\");\n}\n\nfunction normalizarTexto(valor) {\n  return String(valor || \"\")\n    .normalize(\"NFD\")\n    .replace(\/[\\u0300-\\u036f]\/g, \"\")\n    .trim()\n    .toLowerCase();\n}\n\nfunction limpiarCSV(valor) {\n  return String(valor || \"\")\n    .replace(\/\"\/g, '\"\"')\n    .replace(\/\\n\/g, \" \")\n    .replace(\/\\r\/g, \" \");\n}\n\nfunction nombreAcompanante(inv) {\n  if (!inv || !inv.acompanante) return \"\";\n\n  return inv.acompananteNombre && inv.acompananteNombre.trim()\n    ? inv.acompananteNombre.trim()\n    : \"Acompa\u00f1ante de \" + (inv.nombre || \"\");\n}\n\nfunction programarGuardado() {\n  if (guardadoTimer) {\n    clearTimeout(guardadoTimer);\n  }\n\n  guardadoTimer = setTimeout(function () {\n    guardarCambios(true);\n  }, 650);\n}\n\nfunction toggleFormularioInvitado() {\n  const form = document.getElementById(\"addInvitadoForm\");\n\n  if (!form) {\n    return;\n  }\n\n  form.classList.toggle(\"active\");\n\n  if (form.classList.contains(\"active\")) {\n    const input = document.getElementById(\"nuevoInvitado\");\n\n    if (input) {\n      setTimeout(function () {\n        input.focus();\n      }, 100);\n    }\n  }\n}\n\nasync function cargarDatos() {\n  try {\n    const res = await fetch(JSON_URL + '?v=' + Date.now());\n    invitados = await res.json();\n\n    if (!Array.isArray(invitados)) {\n      invitados = [];\n    }\n\n    invitados = invitados.map(function (inv) {\n      return Object.assign({}, inv, {\n        acompananteNombre: inv.acompananteNombre || \"\",\n        notas: inv.notas || \"\"\n      });\n    });\n  } catch (e) {\n    console.error(\"Error cargando invitados:\", e);\n    invitados = [];\n  }\n\n  renderInvitados();\n}\n\nfunction ordenarLista(lista) {\n  return lista.slice().sort(function (a, b) {\n    if (ordenActivo === 'pendientes') {\n      if (Boolean(a.confirmado) !== Boolean(b.confirmado)) {\n        return a.confirmado ? 1 : -1;\n      }\n    }\n\n    if (ordenActivo === 'confirmados') {\n      if (Boolean(a.confirmado) !== Boolean(b.confirmado)) {\n        return a.confirmado ? -1 : 1;\n      }\n    }\n\n    if (ordenActivo === 'acompanantes') {\n      if (Boolean(a.acompanante) !== Boolean(b.acompanante)) {\n        return a.acompanante ? -1 : 1;\n      }\n    }\n\n    return String(a.nombre || \"\").localeCompare(String(b.nombre || \"\"), \"es\");\n  });\n}\n\nfunction renderInvitados() {\n  const contenedor = document.getElementById(\"listaInvitados\");\n  contenedor.innerHTML = \"\";\n\n  const termino = normalizarTexto(busquedaActiva);\n\n  let lista = invitados.map(function (inv, idx) {\n    return Object.assign({}, inv, { index: idx });\n  }).filter(function (inv) {\n    if (filtroActivo === 'confirmados' && !inv.confirmado) return false;\n    if (filtroActivo === 'noConfirmados' && inv.confirmado) return false;\n    if (filtroActivo === 'acompanantes' && !inv.acompanante) return false;\n\n    if (!termino) return true;\n\n    return normalizarTexto(inv.nombre).includes(termino) ||\n      normalizarTexto(inv.notas).includes(termino) ||\n      normalizarTexto(inv.acompananteNombre).includes(termino);\n  });\n\n  lista = ordenarLista(lista);\n  actualizarResumen();\n\n  if (lista.length === 0) {\n    contenedor.innerHTML = '<p class=\"sin-resultados\">Sin invitados en este filtro.<\/p>';\n    return;\n  }\n\n  lista.forEach(function (inv) {\n    const i = inv.index;\n    const nombre = inv.nombre || \"\";\n    const notas = inv.notas || \"\";\n    const tieneNotas = notas.trim().length > 0;\n    const estadoBadge = inv.confirmado ? '<span class=\"badge ok\">OK<\/span>' : '<span class=\"badge warn\">Pend.<\/span>';\n    const acompananteInline = inv.acompanante ? `<span class=\"acompanante-inline\"> \u00b7 ${escaparHTML(nombreAcompanante(inv))}<\/span>` : '';\n    const notaLinea = tieneNotas ? `<span class=\"nota-linea\">${escaparHTML(notas)}<\/span>` : '';\n\n    const item = document.createElement(\"div\");\n    item.className = \"invitado-row \" + (inv.confirmado ? \"confirmado\" : \"pendiente\");\n\n    item.innerHTML = `\n      <input\n        type=\"checkbox\"\n        class=\"row-confirmado-check\"\n        title=\"Confirmado\"\n        ${inv.confirmado ? \"checked\" : \"\"}\n        onclick=\"event.stopPropagation()\"\n        onchange=\"toggleConfirmadoRapido(${i}, this.checked)\"\n      >\n\n      <div class=\"invitado-info\" onclick=\"abrirFicha(${i})\">\n        <span class=\"nombre-linea\">${escaparHTML(nombre)}${acompananteInline}<\/span>\n        ${notaLinea}\n      <\/div>\n\n      <div class=\"invitado-side\" onclick=\"abrirFicha(${i})\">\n        ${estadoBadge}\n        <span class=\"row-chevron\">\u203a<\/span>\n      <\/div>\n    `;\n\n    contenedor.appendChild(item);\n  });\n}\n\nasync function toggleConfirmadoRapido(i, activo) {\n  if (!invitados[i]) {\n    return;\n  }\n\n  invitados[i].confirmado = Boolean(activo);\n  actualizarResumen();\n  await guardarCambios(true);\n  renderInvitados();\n}\n\nfunction abrirFicha(i) {\n  if (!invitados[i]) {\n    return;\n  }\n\n  invitadoEditando = i;\n\n  const inv = invitados[i];\n  const modal = document.getElementById(\"invitadoModal\");\n  const titulo = document.getElementById(\"fichaTitulo\");\n  const nombre = document.getElementById(\"fichaNombre\");\n  const confirmado = document.getElementById(\"fichaConfirmado\");\n  const acompanante = document.getElementById(\"fichaAcompanante\");\n  const acompananteNombre = document.getElementById(\"fichaAcompananteNombre\");\n  const notas = document.getElementById(\"fichaNotas\");\n  const wrap = document.getElementById(\"fichaAcompananteWrap\");\n\n  titulo.textContent = inv.nombre || \"Editar invitado\";\n  nombre.value = inv.nombre || \"\";\n  confirmado.checked = Boolean(inv.confirmado);\n  acompanante.checked = Boolean(inv.acompanante);\n  acompananteNombre.value = inv.acompananteNombre || \"\";\n  notas.value = inv.notas || \"\";\n\n  if (wrap) {\n    wrap.classList.toggle(\"active\", Boolean(inv.acompanante));\n  }\n\n  if (modal) {\n    modal.classList.add(\"active\");\n    document.body.style.overflow = \"hidden\";\n  }\n}\n\nfunction cerrarFicha() {\n  const modal = document.getElementById(\"invitadoModal\");\n\n  if (modal) {\n    modal.classList.remove(\"active\");\n  }\n\n  document.body.style.overflow = \"\";\n  invitadoEditando = null;\n  renderInvitados();\n}\n\nfunction cerrarFichaDesdeFondo(event) {\n  if (event.target && event.target.id === \"invitadoModal\") {\n    cerrarFicha();\n  }\n}\n\nfunction actualizarTextoFicha(campo, valor) {\n  if (invitadoEditando === null || !invitados[invitadoEditando]) {\n    return;\n  }\n\n  invitados[invitadoEditando][campo] = valor;\n\n  if (campo === \"nombre\") {\n    const titulo = document.getElementById(\"fichaTitulo\");\n    if (titulo) {\n      titulo.textContent = valor || \"Editar invitado\";\n    }\n  }\n\n  actualizarResumen();\n  programarGuardado();\n}\n\nfunction actualizarConfirmadoFicha(activo) {\n  if (invitadoEditando === null || !invitados[invitadoEditando]) {\n    return;\n  }\n\n  invitados[invitadoEditando].confirmado = Boolean(activo);\n  actualizarResumen();\n  programarGuardado();\n}\n\nfunction actualizarAcompananteFicha(activo) {\n  if (invitadoEditando === null || !invitados[invitadoEditando]) {\n    return;\n  }\n\n  invitados[invitadoEditando].acompanante = Boolean(activo);\n\n  if (!activo) {\n    invitados[invitadoEditando].acompananteNombre = \"\";\n    const input = document.getElementById(\"fichaAcompananteNombre\");\n    if (input) input.value = \"\";\n  }\n\n  const wrap = document.getElementById(\"fichaAcompananteWrap\");\n  if (wrap) {\n    wrap.classList.toggle(\"active\", Boolean(activo));\n  }\n\n  actualizarResumen();\n  programarGuardado();\n}\n\nasync function eliminarInvitadoEditando() {\n  if (invitadoEditando === null || !invitados[invitadoEditando]) {\n    return;\n  }\n\n  await eliminarInvitado(invitadoEditando);\n  cerrarFicha();\n}\n\nfunction toggleNuevoAcompanante(activo) {\n  const wrap = document.getElementById(\"nuevoAcompananteWrap\");\n\n  if (wrap) {\n    wrap.classList.toggle(\"active\", activo);\n  }\n}\n\nfunction actualizarBusqueda(valor) {\n  busquedaActiva = valor;\n  renderInvitados();\n}\n\nfunction actualizarOrden(valor) {\n  ordenActivo = valor;\n  renderInvitados();\n}\n\nasync function eliminarInvitado(i) {\n  if (!invitados[i]) {\n    return;\n  }\n\n  const nombre = invitados[i].nombre || \"este invitado\";\n\n  if (confirm(`\u00bfSeguro que quieres eliminar a \"${nombre}\"?`)) {\n    invitados.splice(i, 1);\n    renderInvitados();\n    await guardarCambios(true);\n  }\n}\n\nasync function agregarInvitado() {\n  const nombreInput = document.getElementById(\"nuevoInvitado\");\n  const confirmadoInput = document.getElementById(\"nuevoConfirmado\");\n  const acompananteInput = document.getElementById(\"nuevoAcompanante\");\n  const acompNombreInput = document.getElementById(\"nuevoAcompananteNombre\");\n  const notasInput = document.getElementById(\"nuevasNotas\");\n\n  const nombre = nombreInput.value.trim();\n  const confirmado = confirmadoInput.checked;\n  const acompanante = acompananteInput.checked;\n  const acompananteNombre = acompanante ? acompNombreInput.value.trim() : \"\";\n  const notas = notasInput.value.trim();\n\n  if (!nombre) {\n    alert(\"\u26a0\ufe0f Escribe un nombre antes de a\u00f1adir.\");\n    return;\n  }\n\n  invitados.push({\n    nombre,\n    confirmado,\n    acompanante,\n    acompananteNombre,\n    notas\n  });\n\n  nombreInput.value = \"\";\n  confirmadoInput.checked = false;\n  acompananteInput.checked = false;\n  acompNombreInput.value = \"\";\n  notasInput.value = \"\";\n  toggleNuevoAcompanante(false);\n\n  const form = document.getElementById(\"addInvitadoForm\");\n  if (form) {\n    form.classList.remove(\"active\");\n  }\n\n  renderInvitados();\n  await guardarCambios(true);\n}\n\nfunction actualizarResumen() {\n  const confirmados = invitados.filter(i => i.confirmado).length;\n  const acompanantes = invitados.filter(i => i.acompanante).length;\n  const invitadosBase = invitados.length;\n  const totalPersonas = invitadosBase + acompanantes;\n  const noConfirmados = invitadosBase - confirmados;\n\n  document.getElementById(\"confirmados\").textContent = confirmados;\n  document.getElementById(\"acompanantes\").textContent = acompanantes;\n  document.getElementById(\"total\").textContent = totalPersonas;\n  document.getElementById(\"noConfirmados\").textContent = noConfirmados;\n}\n\nfunction filtrarInvitados(tipo) {\n  filtroActivo = tipo;\n\n  document.querySelectorAll('.resumen-card').forEach(card => {\n    card.classList.remove('active');\n  });\n\n  let selector = '.resumen-card.total';\n\n  if (tipo === 'confirmados') {\n    selector = '.resumen-card.confirmados';\n  } else if (tipo === 'acompanantes') {\n    selector = '.resumen-card.acompanantes';\n  } else if (tipo === 'noConfirmados') {\n    selector = '.resumen-card.noConfirmados';\n  }\n\n  const card = document.querySelector(selector);\n\n  if (card) {\n    card.classList.add('active');\n  }\n\n  renderInvitados();\n}\n\nasync function guardarCambios(silencioso = false) {\n  try {\n    const res = await fetch(GUARDAR_URL, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application\/json' },\n      body: JSON.stringify(invitados)\n    });\n\n    if (!res.ok) {\n      throw new Error(\"Error HTTP \" + res.status);\n    }\n\n    actualizarResumen();\n\n    if (!silencioso) {\n      alert(\"\u2705 Cambios guardados correctamente\");\n    }\n  } catch (e) {\n    console.error(\"\u274c Error al guardar invitados:\", e);\n\n    if (!silencioso) {\n      alert(\"\u274c Error al guardar\");\n    }\n  }\n}\n\nfunction exportarInvitados() {\n  const filas = [];\n\n  filas.push([\n    \"Nombre\",\n    \"Tipo\",\n    \"Confirmado\",\n    \"Acompa\u00f1ante\",\n    \"Notas\"\n  ]);\n\n  const listaOrdenada = invitados\n    .slice()\n    .sort((a, b) => String(a.nombre || \"\").localeCompare(String(b.nombre || \"\"), \"es\"));\n\n  listaOrdenada.forEach(inv => {\n    filas.push([\n      inv.nombre || \"\",\n      \"Invitado\",\n      inv.confirmado ? \"S\u00ed\" : \"No\",\n      inv.acompanante ? \"S\u00ed\" : \"No\",\n      inv.notas || \"\"\n    ]);\n\n    if (inv.acompanante) {\n      filas.push([\n        nombreAcompanante(inv),\n        \"Acompa\u00f1ante\",\n        inv.confirmado ? \"S\u00ed\" : \"No\",\n        \"De \" + (inv.nombre || \"\"),\n        inv.notas || \"\"\n      ]);\n    }\n  });\n\n  const csv = filas\n    .map(fila => fila.map(celda => `\"${limpiarCSV(celda)}\"`).join(\";\"))\n    .join(\"\\n\");\n\n  const blob = new Blob([\"\\uFEFF\" + csv], {\n    type: \"text\/csv;charset=utf-8;\"\n  });\n\n  const url = URL.createObjectURL(blob);\n  const enlace = document.createElement(\"a\");\n\n  enlace.href = url;\n  enlace.download = \"invitados-boda-fran-y-jose.csv\";\n  enlace.click();\n\n  URL.revokeObjectURL(url);\n}\n\ncargarDatos();\n\nwindow.guardarCambios = guardarCambios;\n<\/script>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7283356 elementor-widget elementor-widget-html\" data-id=\"7283356\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<style>\n  body {\n    padding-bottom: 90px; \/* evita que la barra tape botones *\/\n  }\n\n  .nav-bottom {\n    position: fixed;\n    bottom: 15px;\n    left: 50%;\n    transform: translateX(-50%);\n    display: flex;\n    justify-content: space-around;\n    align-items: center;\n    width: 90%;\n    max-width: 420px;\n    background: rgba(255, 255, 255, 0.92);\n    backdrop-filter: blur(10px);\n    padding: 10px 18px;\n    border-radius: 50px;\n    box-shadow: 0 6px 20px rgba(0,0,0,0.08);\n    z-index: 1000;\n  }\n\n  .nav-link {\n    flex: 1;\n    text-align: center;\n    text-decoration: none;\n    color: #b67b91;\n    font-family: 'Poppins', sans-serif;\n    font-size: 0.95rem;\n    font-weight: 600;\n    padding: 8px 10px;\n    border-radius: 40px;\n    transition: all 0.3s ease;\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    gap: 3px;\n  }\n\n  .nav-link .icon {\n    font-size: 1.4rem;\n  }\n\n  .nav-link.active {\n    background: #b67b91;\n    color: #fff;\n    box-shadow: 0 3px 10px rgba(182, 123, 145, 0.3);\n  }\n\n  .nav-link:hover {\n    background: #f2e1e8;\n  }\n\n  @media (min-width: 769px) {\n    .nav-bottom {\n      bottom: 25px;\n      max-width: 500px;\n    }\n\n    .nav-link .icon {\n      font-size: 1.3rem;\n    }\n  }\n<\/style>\n\n<!-- \ud83d\ude80 Barra de navegaci\u00f3n inferior -->\n<div class=\"nav-bottom\">\n  <a href=\"https:\/\/bodafranyjose.com\/index.php\/lista-invitados\/\" class=\"nav-link\" id=\"link-invitados\">\n    <span class=\"icon\">\ud83d\udc8d<\/span>\n    <span>Invitados<\/span>\n  <\/a>\n\n  <a href=\"https:\/\/bodafranyjose.com\/index.php\/gastos\/\" class=\"nav-link\" id=\"link-gastos\">\n    <span class=\"icon\">\ud83d\udcb8<\/span>\n    <span>Gastos<\/span>\n  <\/a>\n<\/div>\n\n<script>\n  \/\/ Detecta la p\u00e1gina actual y activa el bot\u00f3n correspondiente\n  const url = window.location.href;\n  const linkInv = document.getElementById('link-invitados');\n  const linkGas = document.getElementById('link-gastos');\n\n  if (url.includes('gastos')) {\n    linkGas.classList.add('active');\n  } else if (url.includes('lista-invitados')) {\n    linkInv.classList.add('active');\n  }\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>\ud83d\udccb Lista de Invitados Controla confirmaciones, acompa\u00f1antes y notas importantes. Total 0 Confirm. 0 Acomp. 0 Pend. 0 \u2795 A\u00f1adir invitado Confirmado Acompa\u00f1ante Guardar invitado NombrePendientes primeroConfirmados primeroCon acompa\u00f1ante \ud83d\udce4 Exportar Editar invitado Los cambios se guardan autom\u00e1ticamente. \u2715 Nombre Confirmado Acompa\u00f1ante Nombre del acompa\u00f1ante Notas Cerrar ficha Eliminar invitado \ud83d\udc8d Invitados \ud83d\udcb8 Gastos<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-473","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Lista invitados -<\/title>\n<meta name=\"robots\" content=\"noindex, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Lista invitados -\" \/>\n<meta property=\"og:description\" content=\"\ud83d\udccb Lista de Invitados Controla confirmaciones, acompa\u00f1antes y notas importantes. Total 0 Confirm. 0 Acomp. 0 Pend. 0 \u2795 A\u00f1adir invitado Confirmado Acompa\u00f1ante Guardar invitado NombrePendientes primeroConfirmados primeroCon acompa\u00f1ante \ud83d\udce4 Exportar Editar invitado Los cambios se guardan autom\u00e1ticamente. \u2715 Nombre Confirmado Acompa\u00f1ante Nombre del acompa\u00f1ante Notas Cerrar ficha Eliminar invitado \ud83d\udc8d Invitados \ud83d\udcb8 Gastos\" \/>\n<meta property=\"og:url\" content=\"https:\/\/bodafranyjose.com\/index.php\/lista-invitados\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-04-13T17:18:20+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data1\" content=\"14 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/bodafranyjose.com\\\/index.php\\\/lista-invitados\\\/\",\"url\":\"https:\\\/\\\/bodafranyjose.com\\\/index.php\\\/lista-invitados\\\/\",\"name\":\"Lista invitados -\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/bodafranyjose.com\\\/#website\"},\"datePublished\":\"2025-11-16T13:09:16+00:00\",\"dateModified\":\"2026-04-13T17:18:20+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/bodafranyjose.com\\\/index.php\\\/lista-invitados\\\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/bodafranyjose.com\\\/index.php\\\/lista-invitados\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/bodafranyjose.com\\\/index.php\\\/lista-invitados\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Portada\",\"item\":\"https:\\\/\\\/bodafranyjose.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Lista invitados\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/bodafranyjose.com\\\/#website\",\"url\":\"https:\\\/\\\/bodafranyjose.com\\\/\",\"name\":\"\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/bodafranyjose.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Lista invitados -","robots":{"index":"noindex","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"og_locale":"es_ES","og_type":"article","og_title":"Lista invitados -","og_description":"\ud83d\udccb Lista de Invitados Controla confirmaciones, acompa\u00f1antes y notas importantes. Total 0 Confirm. 0 Acomp. 0 Pend. 0 \u2795 A\u00f1adir invitado Confirmado Acompa\u00f1ante Guardar invitado NombrePendientes primeroConfirmados primeroCon acompa\u00f1ante \ud83d\udce4 Exportar Editar invitado Los cambios se guardan autom\u00e1ticamente. \u2715 Nombre Confirmado Acompa\u00f1ante Nombre del acompa\u00f1ante Notas Cerrar ficha Eliminar invitado \ud83d\udc8d Invitados \ud83d\udcb8 Gastos","og_url":"https:\/\/bodafranyjose.com\/index.php\/lista-invitados\/","article_modified_time":"2026-04-13T17:18:20+00:00","twitter_card":"summary_large_image","twitter_misc":{"Tiempo de lectura":"14 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/bodafranyjose.com\/index.php\/lista-invitados\/","url":"https:\/\/bodafranyjose.com\/index.php\/lista-invitados\/","name":"Lista invitados -","isPartOf":{"@id":"https:\/\/bodafranyjose.com\/#website"},"datePublished":"2025-11-16T13:09:16+00:00","dateModified":"2026-04-13T17:18:20+00:00","breadcrumb":{"@id":"https:\/\/bodafranyjose.com\/index.php\/lista-invitados\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/bodafranyjose.com\/index.php\/lista-invitados\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/bodafranyjose.com\/index.php\/lista-invitados\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Portada","item":"https:\/\/bodafranyjose.com\/"},{"@type":"ListItem","position":2,"name":"Lista invitados"}]},{"@type":"WebSite","@id":"https:\/\/bodafranyjose.com\/#website","url":"https:\/\/bodafranyjose.com\/","name":"","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/bodafranyjose.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"}]}},"_links":{"self":[{"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/pages\/473","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/comments?post=473"}],"version-history":[{"count":196,"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/pages\/473\/revisions"}],"predecessor-version":[{"id":1004,"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/pages\/473\/revisions\/1004"}],"wp:attachment":[{"href":"https:\/\/bodafranyjose.com\/index.php\/wp-json\/wp\/v2\/media?parent=473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}