{"id":4313,"date":"2025-08-31T15:33:48","date_gmt":"2025-08-31T14:33:48","guid":{"rendered":"https:\/\/josefranconline.com\/blog\/?page_id=4313"},"modified":"2025-09-10T18:29:22","modified_gmt":"2025-09-10T17:29:22","slug":"affirmations","status":"publish","type":"page","link":"https:\/\/josefranconline.com\/blog\/affirmations\/","title":{"rendered":"Affirmations"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"4313\" class=\"elementor elementor-4313\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c63c639 e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no e-con e-parent\" data-id=\"c63c639\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-12b3e30 elementor-widget elementor-widget-shortcode\" data-id=\"12b3e30\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">    \r\n    <style>\r\n\/* ====== ESTILOS FIJOS (todo a 630px) ====== *\/\r\n\r\n\/* Aviso amarillo *\/\r\n.ap-note-own-yellow{\r\n  display:none;\r\n  margin:8px 0 0;\r\n  padding:10px 12px;\r\n  background:#fff7d6;\r\n  border:1px solid #f1d48a;\r\n  border-radius:8px;\r\n  font-size:.95rem;\r\n  color:#7a5a00;\r\n}\r\n.ap-note-own-yellow strong{ color:#5c4500; }\r\n\r\n\/* Contenedor ra\u00edz: SIEMPRE 630px centrado *\/\r\n.afirmacion-block{\r\n  width:630px !important;\r\n  max-width:630px !important;\r\n  margin:0 auto !important;\r\n  padding:0;\r\n  position:relative;\r\n  box-sizing:border-box;\r\n  text-align:initial;\r\n}\r\n.afirmacion-block, .afirmacion-block *{ box-sizing:border-box; }\r\n\r\n\/* Cabecera, formulario y resultado ocupan el ancho completo *\/\r\n.afirmacion-block .afirmacion-headline,\r\n.afirmacion-block form#afirmacion-ai-form,\r\n.afirmacion-block #afirmacion-ai-respuesta{\r\n  width:100% !important;   \/* = 630px *\/\r\n  max-width:100% !important;\r\n  margin-left:auto;\r\n  margin-right:auto;\r\n  display:block;\r\n}\r\n\r\n\/* Resultado: espacio bajo el bot\u00f3n y altura m\u00ednima *\/\r\n#afirmacion-ai-respuesta{\r\n  margin-top:16px;\r\n  min-height:40px;\r\n  padding:0;\r\n}\r\n\r\n\/* Inputs y select: mismos 630px desde el inicio *\/\r\n.afirmacion-block .ap-fieldset,\r\n.afirmacion-block #sugerencias-temas.ap-select,\r\n.afirmacion-block #tema.ap-input,\r\n.afirmacion-block label[for=\"tema\"],\r\n.afirmacion-block #mensaje-personalizado,\r\n.afirmacion-block .ap-actions-row{\r\n  width:100% !important;   \/* = 630px *\/\r\n  max-width:100% !important;\r\n  margin-left:auto;\r\n  margin-right:auto;\r\n  display:block;\r\n}\r\n\r\n\/* Evitar estiramientos raros en la fila de acciones *\/\r\n.afirmacion-block .ap-actions-row{ display:block; }\r\n\r\n\/* Im\u00e1genes dentro del widget nunca rompen el ancho *\/\r\n.afirmacion-block img{\r\n  max-width:100%;\r\n  height:auto;\r\n  display:block;\r\n  margin:0 auto;\r\n}\r\n\r\n\/* Cabecera (emoji + t\u00edtulo) *\/\r\n.afirmacion-headline{\r\n  display:flex;\r\n  flex-direction:column;\r\n  align-items:center;\r\n}\r\n.afirmacion-headline .afirmacion-emoji{\r\n  display:block !important;\r\n  font-size:32px !important;\r\n  line-height:1 !important;\r\n  margin:0 0 12px 0 !important;\r\n  text-align:center !important;\r\n  width:auto !important;\r\n  height:auto !important;\r\n  font-family:'Apple Color Emoji','Segoe UI Emoji','Noto Color Emoji',sans-serif !important;\r\n}\r\n\r\n\/* Texto de ayuda *\/\r\n.ap-help{ display:block; margin-bottom:14px; }\r\n\r\n\/* Texto generado sin espacio inferior *\/\r\n#afirmacion-ai-respuesta #aia-text-block.aia-field{\r\n  width:584.67px;\r\n  max-width:584.67px;\r\n  margin:22px auto 0 auto;   \/* top:22px, right:auto, bottom:0, left:auto *\/\r\n  display:block;\r\n}\r\n\r\n\/* === Mensaje inicial (\"Aqu\u00ed aparecer\u00e1n los textos y una imagen.\") === *\/\r\n#afirmacion-ai-respuesta #mensaje-inicial.ap-initial{\r\n  width:584.67px;\r\n  max-width:584.67px;\r\n  margin:22px auto;   \/* centrado + 22px arriba y abajo *\/\r\n  display:block;\r\n  text-align:center;  \/* opcional: centrar el texto dentro *\/\r\n}\r\n\r\n    <\/style>\r\n    \r\n<script>\r\n  window.afirmacion_ai_i18n = {\"generating_text\":\"Generating\\u2026\",\"generating_image\":\"Generating image\\u2026\",\"unexpected_error\":\"Unexpected error:\",\"please_enter_topic\":\"Please enter a topic.\",\"copy_nothing\":\"Nothing to copy\",\"copied\":\"Copied\",\"could_not_copy\":\"Could not copy\",\"downloading_uploading\":\"Downloading and uploading\\u2026\",\"screenshot_hint\":\"(Take a screenshot to download the image with the text)\"};\r\n<\/script>\r\n\r\n<script>\r\n(function () {\r\n  \/\/ Fijar tama\u00f1o del emoji incluso si WP lo sustituye despu\u00e9s\r\n  var host = document.querySelector('.afirmacion-headline .afirmacion-emoji');\r\n  if (!host) return;\r\n\r\n  function fixEmoji() {\r\n    var img = host.querySelector('img.emoji');\r\n    if (img) {\r\n      img.style.display = 'block';\r\n      img.style.width   = '20px';\r\n      img.style.height  = '20px';\r\n      img.style.margin  = '0 auto 10px';\r\n    } else {\r\n      \/\/ Caso texto (no sustituido por WP)\r\n      host.style.display    = 'block';\r\n      host.style.width      = '20px';\r\n      host.style.height     = '20px';\r\n      host.style.fontSize   = '20px';\r\n      host.style.lineHeight = '20px';\r\n      host.style.textAlign  = 'center';\r\n      host.style.margin     = '0 auto 10px';\r\n    }\r\n  }\r\n\r\n  \/\/ Intento inicial\r\n  fixEmoji();\r\n\r\n  \/\/ Observar cambios por si WP inserta la <img class=\"emoji\"> despu\u00e9s\r\n  var mo = new MutationObserver(fixEmoji);\r\n  mo.observe(host, { childList: true, subtree: true, attributes: true });\r\n\r\n  \/\/ Fallback temporal\r\n  var tries = 0, t = setInterval(function(){\r\n    fixEmoji();\r\n    if (++tries > 10) clearInterval(t);\r\n  }, 150);\r\n})();\r\n<\/script>\r\n\r\n<div class=\"afirmacion-block\"><!-- wrapper centrado (usa tu CSS) -->\r\n\r\n\r\n<!-- Cabecera -->\r\n<div class=\"afirmacion-headline\">\r\n  <span class=\"afirmacion-emoji\">\ud83c\udf3f<\/span>\r\n  <h2 class=\"afirmacion-title\">\r\n    Affirmations &amp; Practice  <\/h2>\r\n<\/div>\r\n  \r\n  <script>\r\ndocument.addEventListener('DOMContentLoaded', function(){\r\n  var banners = document.querySelectorAll('.aia-toplink');\r\n  banners.forEach(function(el){\r\n    if (el.id !== 'aia-lang-banner') {\r\n      el.parentNode && el.parentNode.removeChild(el);\r\n    }\r\n  });\r\n});\r\n<\/script>\r\n\r\n  <!-- Form card -->\r\n  <form id=\"afirmacion-ai-form\">\r\n    <label id=\"aia-title\" data-i18n=\"title\" for=\"tema\">\r\n      What topic do you want the affirmation about?    <\/label>\r\n\r\n    <div class=\"ap-fieldset\">\r\n      <!-- (2) Option A: Choose a topic -->\r\n      <select\r\n        id=\"sugerencias-temas\"\r\n        class=\"ap-select\"\r\n        name=\"sugerencia\"\r\n        aria-label=\"Choose a topic\">\r\n        <option value=\"\">\r\n          Choose a topic        <\/option>\r\n\r\n        <!-- Topics: value = slug neutro; data-key = clave para i18n JS; data-label = texto visible actual -->\r\n        <option data-key=\"love\"             value=\"love\"             data-label=\"Love\">Love<\/option>\r\n        <option data-key=\"happiness\"        value=\"happiness\"        data-label=\"Happiness\">Happiness<\/option>\r\n        <option data-key=\"self-esteem\"      value=\"self-esteem\"      data-label=\"Self-esteem\">Self-esteem<\/option>\r\n        <option data-key=\"physical-health\"  value=\"physical-health\"  data-label=\"Physical health\">Physical health<\/option>\r\n        <option data-key=\"emotional-health\" value=\"emotional-health\" data-label=\"Emotional health\">Emotional health<\/option>\r\n        <option data-key=\"abundance\"        value=\"abundance\"        data-label=\"Abundance\">Abundance<\/option>\r\n        <option data-key=\"relationships\"    value=\"relationships\"    data-label=\"Relationships\">Relationships<\/option>\r\n        <option data-key=\"inner-peace\"      value=\"inner-peace\"      data-label=\"Inner peace\">Inner peace<\/option>\r\n        <option data-key=\"gratitude\"        value=\"gratitude\"        data-label=\"Gratitude\">Gratitude<\/option>\r\n        <option data-key=\"life-purpose\"     value=\"life-purpose\"     data-label=\"Life purpose\">Life purpose<\/option>\r\n      <\/select>\r\n\r\n      <small id=\"aia-hint\" data-i18n=\"hint\" class=\"ap-help\">\r\n        You can pick from the list or type your own topic in the text field.      <\/small>\r\n\r\n      <!-- Topic field -->\r\n      <input\r\n        type=\"text\"\r\n        id=\"tema\"\r\n        name=\"tema\"\r\n        required\r\n        placeholder=\"E.g. emotional health (you can edit it)\"\r\n        class=\"ap-input\"\r\n        aria-describedby=\"mensaje-personalizado\"\r\n      >\r\n\r\n      <!-- (4) Notice below the field -->\r\n      <div id=\"mensaje-personalizado\"\r\n           class=\"ap-note-own-yellow\"\r\n           role=\"status\"\r\n           aria-live=\"polite\"\r\n           hidden>\r\n        \u270f\ufe0f <strong>You wrote your own topic<\/strong>\r\n      <\/div>\r\n\r\n    <\/div>\r\n\r\n    <div class=\"ap-actions-row\" style=\"margin-top:10px;\">\r\n      <button type=\"submit\">\r\n        Generate affirmation      <\/button>\r\n      <span id=\"ap-status\"><\/span>\r\n    <\/div>\r\n  <\/form>\r\n\r\n  <!-- Resultado -->\r\n  <div id=\"afirmacion-ai-respuesta\">\r\n    <p id=\"mensaje-inicial\" class=\"ap-initial\">\r\n      Texts and an image will appear here.    <\/p>\r\n  <\/div>\r\n\r\n<\/div><!-- \/.afirmacion-block -->\r\n\r\n<script>\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n  const sel = document.getElementById('sugerencias-temas');\r\n  const inp = document.getElementById('tema');\r\n  const msg = document.getElementById('mensaje-personalizado');\r\n\r\n  \/\/ Nace oculto\r\n  if (msg) { msg.hidden = true; msg.style.display = 'none'; }\r\n\r\n  const norm = s => String(s||'')\r\n    .replace(\/[\u201c\u201d]\/g, '\"')\r\n    .replace(\/[\u2018\u2019]\/g, \"'\")\r\n    .replace(\/[\\u200B-\\u200D\\uFEFF]\/g, '')\r\n    .trim();\r\n\r\n  function setFormatted(on) {\r\n    if (!inp) return;\r\n    \/\/ \"sin formateo\" = estilos vac\u00edos (plan B inline)\r\n    inp.style.fontWeight  = on ? '700' : '';\r\n    inp.style.background  = on ? '#fff8c5' : '';\r\n    inp.style.border      = on ? '2px solid #f2cb61' : '';\r\n  }\r\n\r\n  function hideOwnMsg() {\r\n    if (msg) { msg.hidden = true; msg.style.display = 'none'; }\r\n  }\r\n  function showOwnMsg() {\r\n    if (msg) { msg.hidden = false; msg.style.display = 'block'; }\r\n  }\r\n\r\n    function applyPlaceholderExample() {\r\n      const ejemplo = inp.getAttribute('placeholder') || '';\r\n      inp.value = '';                  \/\/ valor vac\u00edo \u2192 cursor al inicio\r\n      inp.placeholder = ejemplo;       \/\/ el ejemplo se muestra como placeholder\r\n      setFormatted(false);             \/\/ sin formateo\r\n      hideOwnMsg();                    \/\/ ocultar aviso\r\n      try { inp.dispatchEvent(new Event('input',  { bubbles: true })); } catch(e) {}\r\n      try { inp.dispatchEvent(new Event('change', { bubbles: true })); } catch(e) {}\r\n    }\r\n\r\n  function handleSelectChange() {\r\n    const o = sel.selectedOptions && sel.selectedOptions[0] ? sel.selectedOptions[0] : null;\r\n\r\n    \/\/ Si est\u00e1 el placeholder (value=\"\")\r\n    if (!o || (o.value || '').trim() === '') {\r\n      applyPlaceholderExample();\r\n      return;\r\n    }\r\n\r\n    \/\/ Opci\u00f3n real \u2192 copiar etiqueta visible (o data-label)\r\n    const label = (o.dataset && o.dataset.label) ? o.dataset.label : (o.textContent || o.innerText || o.value || '');\r\n    const tema  = norm(label);\r\n\r\n    inp.value = tema;\r\n    setFormatted(!!tema);  \/\/ con formateo\r\n    hideOwnMsg();          \/\/ no mostrar aviso en selecci\u00f3n\r\n\r\n    try { inp.dispatchEvent(new Event('input',  { bubbles: true })); } catch(e) {}\r\n    try { inp.dispatchEvent(new Event('change', { bubbles: true })); } catch(e) {}\r\n\r\n    \/\/ Opcional: volver el select a placeholder\r\n    setTimeout(() => { sel.selectedIndex = 0; sel.value = ''; }, 0);\r\n  }\r\n\r\n  if (sel && inp) {\r\n    \/\/ change normal\r\n    sel.addEventListener('change', handleSelectChange);\r\n    \/\/ si vuelves a hacer clic en el placeholder NO hay change \u2192 fuerza comportamiento\r\n    sel.addEventListener('click',  () => { if ((sel.value || '') === '') applyPlaceholderExample(); });\r\n    \/\/ soporte teclado (flechas \/ Home)\r\n    sel.addEventListener('input',  () => { if ((sel.value || '') === '') applyPlaceholderExample(); });\r\n    sel.addEventListener('keyup',  (e) => { if ((sel.value || '') === '' && (e.key === 'Enter' || e.key === 'Home')) applyPlaceholderExample(); });\r\n  }\r\n\r\n  if (inp && msg) {\r\n    \/\/ Tecleo manual \u2192 mostrar aviso y formateo (si hay texto distinto al ejemplo)\r\n    inp.addEventListener('input', function (e) {\r\n      const ejemplo = inp.getAttribute('placeholder') || '';\r\n      const has     = !!(inp.value && inp.value.trim());\r\n      if (e.isTrusted) {\r\n        if (has && inp.value !== ejemplo) showOwnMsg();\r\n        else                              hideOwnMsg();\r\n      }\r\n      setFormatted(has && inp.value !== ejemplo);\r\n    });\r\n  }\r\n});\r\n\r\n  \/\/ --- AUTORRELLENO AL ENVIAR: si #tema est\u00e1 vac\u00edo pero hay un tema elegido en el <select> ---\r\n  const form = document.getElementById('afirmacion-ai-form');\r\n  const sel  = document.getElementById('sugerencias-temas');\r\n  const inp  = document.getElementById('tema');\r\n\r\n  if (form && sel && inp) {\r\n    form.addEventListener('submit', function () {\r\n      const val = (inp.value || '').trim();\r\n      if (!val) {\r\n        const opt = sel.selectedOptions && sel.selectedOptions[0] ? sel.selectedOptions[0] : null;\r\n        if (opt && (opt.value || '').trim() !== '') {\r\n          \/\/ Copiamos la etiqueta visible (o data-label) al input justo antes de enviar\r\n          const etiqueta = (opt.dataset && opt.dataset.label)\r\n            ? opt.dataset.label\r\n            : (opt.textContent || opt.innerText || opt.value || '');\r\n          inp.value = String(etiqueta || '').trim();\r\n\r\n          \/\/ Dispara eventos para que tu l\u00f3gica existente aplique formateo\/oculte aviso\r\n          try { inp.dispatchEvent(new Event('input',  { bubbles: true })); } catch(e) {}\r\n          try { inp.dispatchEvent(new Event('change', { bubbles: true })); } catch(e) {}\r\n        }\r\n        \/\/ Si el select tambi\u00e9n est\u00e1 en placeholder (value=\"\"), dejamos que HTML5 'required' act\u00fae.\r\n      }\r\n    });\r\n  }\r\n\r\n\r\n<\/script>\r\n\r\n\r\n    <script>\r\n    (function(){\r\n      const sel  = document.getElementById('sugerencias-temas');\r\n      const inp  = document.getElementById('tema');\r\n      const note = document.getElementById('mensaje-personalizado');\r\n      if (!sel || !inp) return;\r\n\r\n      const norm = (s)=> (s||'').toString().trim().replace(\/\\s+\/g,' ').toLowerCase();\r\n      const labels = Array.from(sel.options).map(o => (o.textContent||'').trim());\r\n\r\n      \/\/ Al seleccionar: copiar SIEMPRE el TEXTO VISIBLE (ES) al input\r\n      sel.addEventListener('change', function(){\r\n        const opt = this.options[this.selectedIndex];\r\n        if (!opt) return;\r\n        const txt = (opt.textContent || '').trim();\r\n        if (opt.value === '') {\r\n          \/\/ \u201cElije un tema\u201d: no copiar ni mostrar aviso\r\n          inp.value = '';\r\n          if (note) note.style.display = 'none';\r\n          return;\r\n        }\r\n        inp.value = txt; \/\/ \u2190 visible ES\r\n        if (note) note.style.display = 'none';\r\n      });\r\n\r\n      \/\/ Si el usuario escribe algo que no coincide con la lista \u2192 mostrar aviso amarillo\r\n      inp.addEventListener('input', function(){\r\n        const typed = (inp.value||'').trim();\r\n        const inList = labels.some(lbl => norm(lbl) === norm(typed));\r\n        if (typed && !inList) {\r\n          if (note) note.style.display = 'block';\r\n        } else {\r\n          if (note) note.style.display = 'none';\r\n        }\r\n      });\r\n\r\n      \/\/ Al cargar, decide si mostrar aviso seg\u00fan el valor inicial del input\r\n      document.addEventListener('DOMContentLoaded', () => {\r\n        const v = (inp.value||'').trim();\r\n        if (!v) return;\r\n        const inList = labels.some(lbl => norm(lbl) === norm(v));\r\n        if (note) note.style.display = (v && !inList) ? 'block' : 'none';\r\n      });\r\n    })();\r\n    <\/script>\r\n\r\n    <\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2889ff1 e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no e-con e-parent\" data-id=\"2889ff1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-32c9b76 e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-equal-height-no e-con e-child\" data-id=\"32c9b76\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1414593 elementor-widget elementor-widget-text-editor\" data-id=\"1414593\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center; font-size: 16px; line-height: 1.6;\">The <strong>Affirmations Plugin ZIP<\/strong> is ready for download with all files and bonuses included.<\/p><p>\ud83d\udc49 Want the ZIP package with install files and bonuses?<\/p><p><a title=\"Get the Affirmations Plugin ZIP\" href=\"https:\/\/josefranconline.com\/blog\/affirmations-plugin\/\" target=\"_blank\" rel=\"noopener\" aria-label=\"Go to the Affirmations Plugin ZIP sales page\"><br \/>https:\/\/josefranconline.com\/blog\/affirmations-plugin\/<br \/><\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\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>The Affirmations Plugin ZIP is ready for download with all files and bonuses included. \ud83d\udc49 Want the ZIP package with install files and bonuses? https:\/\/josefranconline.com\/blog\/affirmations-plugin\/<\/p>\n","protected":false},"author":7,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"om_disable_all_campaigns":false,"footnotes":""},"class_list":["post-4313","page","type-page","status-publish","hentry"],"aioseo_notices":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/josefranconline.com\/blog\/wp-json\/wp\/v2\/pages\/4313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/josefranconline.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/josefranconline.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/josefranconline.com\/blog\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/josefranconline.com\/blog\/wp-json\/wp\/v2\/comments?post=4313"}],"version-history":[{"count":16,"href":"https:\/\/josefranconline.com\/blog\/wp-json\/wp\/v2\/pages\/4313\/revisions"}],"predecessor-version":[{"id":4619,"href":"https:\/\/josefranconline.com\/blog\/wp-json\/wp\/v2\/pages\/4313\/revisions\/4619"}],"wp:attachment":[{"href":"https:\/\/josefranconline.com\/blog\/wp-json\/wp\/v2\/media?parent=4313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}