<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title><![CDATA[Phpost - Terminados]]></title>
		<link>https://phpost.es/</link>
		<description><![CDATA[Phpost - https://phpost.es]]></description>
		<pubDate>Thu, 28 May 2026 18:10:59 +0000</pubDate>
		<generator>MyBB</generator>
		<item>
			<title><![CDATA[Ranking de Usuarios v1.0]]></title>
			<link>https://phpost.es/thread-995.html</link>
			<pubDate>Thu, 28 May 2026 18:46:10 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-995.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Ranking de Usuarios v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Página <span style="font-weight: bold;" class="mycode_b">/ranking/</span> con los 20 usuarios más activos en 4 categorías. Top 3 con medallas de oro, plata y bronce. Fomenta la participación y la competitividad sana entre usuarios.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🏆 Categorías</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">⚡ <span style="font-weight: bold;" class="mycode_b">Puntos</span> — usuarios con más puntos acumulados</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">📝 <span style="font-weight: bold;" class="mycode_b">Posts</span> — usuarios que más posts han publicado</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">💬 <span style="font-weight: bold;" class="mycode_b">Comentarios</span> — usuarios que más han comentado</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">👥 <span style="font-weight: bold;" class="mycode_b">Seguidores</span> — usuarios con más seguidores</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">⚡ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Top 3 con medallas <span style="font-weight: bold;" class="mycode_b">🥇🥈🥉</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Avatar, rango y nombre de cada usuario</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Clic en el usuario lleva a su perfil</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Sin base de datos ni instalador</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo 3 archivos a subir</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.ranking.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ranking.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/<br />
themes/default/templates/t.ranking.tpl&nbsp;&nbsp; →&nbsp;&nbsp;themes/default/templates/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — En head_menu.tpl ponen esto donde quieran:</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;li&gt;&lt;a href="{&#36;tsConfig.url}/ranking/"&gt;&lt;i class="fa-solid fa-trophy"&gt;&lt;/i&gt; Ranking&lt;/a&gt;&lt;/li&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — Borrar la caché</span></span><br />
<br />
Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.<br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Elimina los 3 archivos subidos. No hay tablas que borrar.</span><br />
<hr class="mycode_hr" />
 <br />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
<br />
</div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Ranking de Usuarios v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Página <span style="font-weight: bold;" class="mycode_b">/ranking/</span> con los 20 usuarios más activos en 4 categorías. Top 3 con medallas de oro, plata y bronce. Fomenta la participación y la competitividad sana entre usuarios.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🏆 Categorías</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">⚡ <span style="font-weight: bold;" class="mycode_b">Puntos</span> — usuarios con más puntos acumulados</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">📝 <span style="font-weight: bold;" class="mycode_b">Posts</span> — usuarios que más posts han publicado</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">💬 <span style="font-weight: bold;" class="mycode_b">Comentarios</span> — usuarios que más han comentado</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">👥 <span style="font-weight: bold;" class="mycode_b">Seguidores</span> — usuarios con más seguidores</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">⚡ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Top 3 con medallas <span style="font-weight: bold;" class="mycode_b">🥇🥈🥉</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Avatar, rango y nombre de cada usuario</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Clic en el usuario lleva a su perfil</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Sin base de datos ni instalador</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo 3 archivos a subir</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.ranking.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ranking.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/<br />
themes/default/templates/t.ranking.tpl&nbsp;&nbsp; →&nbsp;&nbsp;themes/default/templates/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — En head_menu.tpl ponen esto donde quieran:</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;li&gt;&lt;a href="{&#36;tsConfig.url}/ranking/"&gt;&lt;i class="fa-solid fa-trophy"&gt;&lt;/i&gt; Ranking&lt;/a&gt;&lt;/li&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — Borrar la caché</span></span><br />
<br />
Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.<br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Elimina los 3 archivos subidos. No hay tablas que borrar.</span><br />
<hr class="mycode_hr" />
 <br />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
<br />
</div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Captcha en Login v1.0]]></title>
			<link>https://phpost.es/thread-994.html</link>
			<pubDate>Thu, 28 May 2026 16:11:44 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-994.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Captcha en Login v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Mejora de seguridad para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Añade el captcha de Cloudflare Turnstile al formulario de login, el mismo que ya tiene el registro. Evita ataques de fuerza bruta automatizados y bots que intenten acceder a cuentas.</span><br />
<hr class="mycode_hr" />
<br />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛡️ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Usa el mismo Cloudflare Turnstile ya configurado en el registro</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Sin instalador ni base de datos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo 2 cambios en 2 archivos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Si no hay clave configurada el captcha se omite — no rompe nada</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Compatible con el mod de Protección de Login y 2FA</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Cloudflare Turnstile configurado (clave pública y secreta en los ajustes del admin)</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Añadir el widget en head_menu.tpl</span><br />
<br />
Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/sections/head_menu.tpl</span> y busca:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;input type="submit" title="Entrar" value="Entrar" style="width:198px; margin-top:5px;" class="mBtn btnOk"&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Cámbialo por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;div class="cf-turnstile" data-sitekey="{&#36;tsConfig.pkey}" data-size="compact" style="margin:8px 0;"&gt;&lt;/div&gt;<br />
&lt;input type="submit" title="Entrar" value="Entrar" style="width:198px; margin-top:5px;" class="mBtn btnOk"&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Añadir el script de Turnstile en main_header.tpl</span><br />
<br />
Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/sections/main_header.tpl</span> y añade antes de <span style="font-weight: bold;" class="mycode_b">&lt;/head&gt;</span>:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;script src="Registrate o inicia tu sesión para ver este contenido" async defer&gt;&lt;/script&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — Verificar el captcha en ajax.login.php</span><br />
<br />
Abre <span style="font-weight: bold;" class="mycode_b">inc/php/ajax/ajax.login.php</span> y busca:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>if(empty(&#36;user) or empty(&#36;pass)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Faltan datos';<br />
} else {</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Cámbialo por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>if(empty(&#36;user) or empty(&#36;pass)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Faltan datos';<br />
} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ── Verificar Turnstile ──<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;captcha = &#36;_POST['cf-turnstile-response'] ?? '';<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (!empty(&#36;tsCore-&gt;settings['pkey']) &amp;&amp; !empty(&#36;tsCore-&gt;settings['skey'])) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;opts = ['http' =&gt; ['method' =&gt; 'POST', 'header' =&gt; 'Content-type: application/x-www-form-urlencoded', 'content' =&gt; http_build_query(['secret' =&gt; &#36;tsCore-&gt;settings['skey'], 'response' =&gt; &#36;captcha, 'remoteip' =&gt; &#36;tsCore-&gt;getIP()])]];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;res&nbsp;&nbsp;= json_decode(@file_get_contents('Registrate o inicia tu sesión para ver este contenido false, stream_context_create(&#36;opts)), true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (empty(&#36;res['success'])) { echo '0: Verifica que no eres un robot.'; break; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ────────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Restaura las líneas originales en <span style="font-weight: bold;" class="mycode_b">head_menu.tpl</span> y <span style="font-weight: bold;" class="mycode_b">ajax.login.php</span>.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
<br />
<br />
<br />
</div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Captcha en Login v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Mejora de seguridad para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Añade el captcha de Cloudflare Turnstile al formulario de login, el mismo que ya tiene el registro. Evita ataques de fuerza bruta automatizados y bots que intenten acceder a cuentas.</span><br />
<hr class="mycode_hr" />
<br />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛡️ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Usa el mismo Cloudflare Turnstile ya configurado en el registro</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Sin instalador ni base de datos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo 2 cambios en 2 archivos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Si no hay clave configurada el captcha se omite — no rompe nada</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Compatible con el mod de Protección de Login y 2FA</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Cloudflare Turnstile configurado (clave pública y secreta en los ajustes del admin)</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Añadir el widget en head_menu.tpl</span><br />
<br />
Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/sections/head_menu.tpl</span> y busca:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;input type="submit" title="Entrar" value="Entrar" style="width:198px; margin-top:5px;" class="mBtn btnOk"&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Cámbialo por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;div class="cf-turnstile" data-sitekey="{&#36;tsConfig.pkey}" data-size="compact" style="margin:8px 0;"&gt;&lt;/div&gt;<br />
&lt;input type="submit" title="Entrar" value="Entrar" style="width:198px; margin-top:5px;" class="mBtn btnOk"&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Añadir el script de Turnstile en main_header.tpl</span><br />
<br />
Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/sections/main_header.tpl</span> y añade antes de <span style="font-weight: bold;" class="mycode_b">&lt;/head&gt;</span>:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;script src="Registrate o inicia tu sesión para ver este contenido" async defer&gt;&lt;/script&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — Verificar el captcha en ajax.login.php</span><br />
<br />
Abre <span style="font-weight: bold;" class="mycode_b">inc/php/ajax/ajax.login.php</span> y busca:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>if(empty(&#36;user) or empty(&#36;pass)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Faltan datos';<br />
} else {</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Cámbialo por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>if(empty(&#36;user) or empty(&#36;pass)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Faltan datos';<br />
} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ── Verificar Turnstile ──<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;captcha = &#36;_POST['cf-turnstile-response'] ?? '';<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (!empty(&#36;tsCore-&gt;settings['pkey']) &amp;&amp; !empty(&#36;tsCore-&gt;settings['skey'])) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;opts = ['http' =&gt; ['method' =&gt; 'POST', 'header' =&gt; 'Content-type: application/x-www-form-urlencoded', 'content' =&gt; http_build_query(['secret' =&gt; &#36;tsCore-&gt;settings['skey'], 'response' =&gt; &#36;captcha, 'remoteip' =&gt; &#36;tsCore-&gt;getIP()])]];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;res&nbsp;&nbsp;= json_decode(@file_get_contents('Registrate o inicia tu sesión para ver este contenido false, stream_context_create(&#36;opts)), true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (empty(&#36;res['success'])) { echo '0: Verifica que no eres un robot.'; break; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ────────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Restaura las líneas originales en <span style="font-weight: bold;" class="mycode_b">head_menu.tpl</span> y <span style="font-weight: bold;" class="mycode_b">ajax.login.php</span>.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
<br />
<br />
<br />
</div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Doble Factor de Autenticación (2FA) v1.0]]></title>
			<link>https://phpost.es/thread-993.html</link>
			<pubDate>Thu, 28 May 2026 14:20:02 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-993.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Doble Factor de Autenticación (2FA) v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size">Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Cada usuario puede activar el 2FA desde su cuenta. Al iniciar sesión, si las credenciales son correctas, se le pide un código de 6 dígitos enviado a su email antes de entrar.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛡️ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Código de <span style="font-weight: bold;" class="mycode_b">6 dígitos criptográficamente seguro</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Expira en <span style="font-weight: bold;" class="mycode_b">5 minutos</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo se puede usar <span style="font-weight: bold;" class="mycode_b">una vez</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Máximo <span style="font-weight: bold;" class="mycode_b">3 intentos fallidos</span> antes de invalidar</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Reenvío con límite de 60 segundos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Cada usuario activa/desactiva desde su cuenta</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Email con diseño moderno</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Compatible con el mod de Protección de Login</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Correo <span style="font-weight: bold;" class="mycode_b">mail()</span> configurado en el servidor</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span><br />
<br />
Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: x-large;" class="mycode_size">⚠️ Elimina la carpeta install/ cuando termine.</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.2fa.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/2fa.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/<br />
inc/php/ajax/ajax.2fa.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; →&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/templates/t.2fa.tpl&nbsp;&nbsp;&nbsp;&nbsp; →&nbsp;&nbsp;themes/default/templates/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En ajax.login.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Dentro del <span style="font-weight: bold;" class="mycode_b">case 'login-user'</span>, donde se llama a <span style="font-weight: bold;" class="mycode_b">loginUser</span>, buscar:</span><br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">if(empty(</span><span style="color: #0000BB">&#36;user</span><span style="color: #007700">)&nbsp;or&nbsp;empty(</span><span style="color: #0000BB">&#36;pass</span><span style="color: #007700">))&nbsp;echo&nbsp;</span><span style="color: #DD0000">'0:&nbsp;Faltan&nbsp;datos'</span><span style="color: #007700">;<br />else&nbsp;echo&nbsp;</span><span style="color: #0000BB">&#36;tsUser</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">loginUser</span><span style="color: #007700">(</span><span style="color: #0000BB">&#36;user</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">&#36;pass</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">&#36;reme</span><span style="color: #007700">);&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Reemplazar por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>if(empty(&#36;user) or empty(&#36;pass)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Faltan datos';<br />
} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;resultado = &#36;tsUser-&gt;loginUser(&#36;user, &#36;pass, &#36;reme);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;resultado === TRUE || is_numeric(&#36;resultado)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ── 2FA ──<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.2fa.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;ts2FA = new ts2FA();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;ts2FA-&gt;tieneActivo(&#36;tsUser-&gt;uid)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsUser-&gt;logoutUser(&#36;tsUser-&gt;uid, null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;_SESSION['ts_2fa_pending']&nbsp;&nbsp;= &#36;tsUser-&gt;uid;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;_SESSION['ts_2fa_remember'] = &#36;reme;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;ts2FA-&gt;enviarCodigo(&#36;tsUser-&gt;uid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo '3: ' . &#36;tsCore-&gt;settings['url'] . '/2fa/';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ────────<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &#36;resultado;<br />
&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &#36;resultado;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — En m.cuenta_cuenta.tpl</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Buscar:</span><br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">&lt;</span><span style="color: #0000BB">div&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"buttons"</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">input&nbsp;type</span><span style="color: #007700">=</span><span style="color: #DD0000">"button"&nbsp;</span><span style="color: #0000BB">value</span><span style="color: #007700">=</span><span style="color: #DD0000">"Guardar"&nbsp;</span><span style="color: #0000BB">onclick</span><span style="color: #007700">=</span><span style="color: #DD0000">"cuenta.save(1)"&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"mBtn&nbsp;btnOk"</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">input&nbsp;type</span><span style="color: #007700">=</span><span style="color: #DD0000">"button"&nbsp;</span><span style="color: #0000BB">value</span><span style="color: #007700">=</span><span style="color: #DD0000">"Siguiente"&nbsp;</span><span style="color: #0000BB">onclick</span><span style="color: #007700">=</span><span style="color: #DD0000">"cuenta.save(1,&nbsp;true)"&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"mBtn&nbsp;btnOk"</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">div</span><span style="color: #007700">&gt;&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Arriba agregar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;div class="field"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;label&gt;Verificación en dos pasos (2FA):&lt;/label&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;div style="padding:10px; background:#f8f9fa; border-radius:6px; border:1px solid #eee;"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;label style="display:flex; align-items:center; gap:10px; cursor:pointer;"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input type="checkbox" name="2fa"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {if &#36;tsUser-&gt;info.user_2fa}checked{/if}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; onchange="cuenta.toggle2FA(this.checked)"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;strong&gt;Activar 2FA&lt;/strong&gt;&lt;br&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;small style="color:#888; font-weight:400;"&gt;Al iniciar sesión se te pedirá un código enviado a tu email.&lt;/small&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/span&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/label&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt;<br />
&lt;/div&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Y en cuenta.js buscar:</span><br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">}<br /><br />}<br /><br />var&nbsp;</span><span style="color: #0000BB">avatar&nbsp;</span><span style="color: #007700">=&nbsp;{&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Reemplazar por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>},<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;toggle2FA: function(activo) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;.ajax({<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type: 'POST',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url: global_data.url + '/2fa-toggle.php',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data: { activo: activo ? 1 : 0 },<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dataType: 'json',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;success: function(r) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (r.ok) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cuenta.alert(1, activo ? '2FA activado' : '2FA desactivado', activo ? 'Ahora se pedirá un código al iniciar sesión.' : 'La verificación en dos pasos ha sido desactivada.');<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
}<br />
<br />
var avatar = {</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>ALTER TABLE u_miembros DROP COLUMN user_2fa;<br />
DROP TABLE IF EXISTS w_2fa_tokens;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos y quita el hook de <span style="font-weight: bold;" class="mycode_b">ajax.login.php</span>.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
<br />
</div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Doble Factor de Autenticación (2FA) v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size">Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Cada usuario puede activar el 2FA desde su cuenta. Al iniciar sesión, si las credenciales son correctas, se le pide un código de 6 dígitos enviado a su email antes de entrar.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛡️ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Código de <span style="font-weight: bold;" class="mycode_b">6 dígitos criptográficamente seguro</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Expira en <span style="font-weight: bold;" class="mycode_b">5 minutos</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo se puede usar <span style="font-weight: bold;" class="mycode_b">una vez</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Máximo <span style="font-weight: bold;" class="mycode_b">3 intentos fallidos</span> antes de invalidar</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Reenvío con límite de 60 segundos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Cada usuario activa/desactiva desde su cuenta</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Email con diseño moderno</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Compatible con el mod de Protección de Login</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Correo <span style="font-weight: bold;" class="mycode_b">mail()</span> configurado en el servidor</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span><br />
<br />
Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: x-large;" class="mycode_size">⚠️ Elimina la carpeta install/ cuando termine.</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.2fa.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/2fa.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/<br />
inc/php/ajax/ajax.2fa.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; →&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/templates/t.2fa.tpl&nbsp;&nbsp;&nbsp;&nbsp; →&nbsp;&nbsp;themes/default/templates/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En ajax.login.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Dentro del <span style="font-weight: bold;" class="mycode_b">case 'login-user'</span>, donde se llama a <span style="font-weight: bold;" class="mycode_b">loginUser</span>, buscar:</span><br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">if(empty(</span><span style="color: #0000BB">&#36;user</span><span style="color: #007700">)&nbsp;or&nbsp;empty(</span><span style="color: #0000BB">&#36;pass</span><span style="color: #007700">))&nbsp;echo&nbsp;</span><span style="color: #DD0000">'0:&nbsp;Faltan&nbsp;datos'</span><span style="color: #007700">;<br />else&nbsp;echo&nbsp;</span><span style="color: #0000BB">&#36;tsUser</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">loginUser</span><span style="color: #007700">(</span><span style="color: #0000BB">&#36;user</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">&#36;pass</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">&#36;reme</span><span style="color: #007700">);&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Reemplazar por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>if(empty(&#36;user) or empty(&#36;pass)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Faltan datos';<br />
} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;resultado = &#36;tsUser-&gt;loginUser(&#36;user, &#36;pass, &#36;reme);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;resultado === TRUE || is_numeric(&#36;resultado)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ── 2FA ──<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.2fa.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;ts2FA = new ts2FA();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;ts2FA-&gt;tieneActivo(&#36;tsUser-&gt;uid)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsUser-&gt;logoutUser(&#36;tsUser-&gt;uid, null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;_SESSION['ts_2fa_pending']&nbsp;&nbsp;= &#36;tsUser-&gt;uid;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;_SESSION['ts_2fa_remember'] = &#36;reme;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;ts2FA-&gt;enviarCodigo(&#36;tsUser-&gt;uid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo '3: ' . &#36;tsCore-&gt;settings['url'] . '/2fa/';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ────────<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &#36;resultado;<br />
&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &#36;resultado;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — En m.cuenta_cuenta.tpl</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Buscar:</span><br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">&lt;</span><span style="color: #0000BB">div&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"buttons"</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">input&nbsp;type</span><span style="color: #007700">=</span><span style="color: #DD0000">"button"&nbsp;</span><span style="color: #0000BB">value</span><span style="color: #007700">=</span><span style="color: #DD0000">"Guardar"&nbsp;</span><span style="color: #0000BB">onclick</span><span style="color: #007700">=</span><span style="color: #DD0000">"cuenta.save(1)"&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"mBtn&nbsp;btnOk"</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">input&nbsp;type</span><span style="color: #007700">=</span><span style="color: #DD0000">"button"&nbsp;</span><span style="color: #0000BB">value</span><span style="color: #007700">=</span><span style="color: #DD0000">"Siguiente"&nbsp;</span><span style="color: #0000BB">onclick</span><span style="color: #007700">=</span><span style="color: #DD0000">"cuenta.save(1,&nbsp;true)"&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"mBtn&nbsp;btnOk"</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">div</span><span style="color: #007700">&gt;&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Arriba agregar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;div class="field"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;label&gt;Verificación en dos pasos (2FA):&lt;/label&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;div style="padding:10px; background:#f8f9fa; border-radius:6px; border:1px solid #eee;"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;label style="display:flex; align-items:center; gap:10px; cursor:pointer;"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;input type="checkbox" name="2fa"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {if &#36;tsUser-&gt;info.user_2fa}checked{/if}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; onchange="cuenta.toggle2FA(this.checked)"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;strong&gt;Activar 2FA&lt;/strong&gt;&lt;br&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;small style="color:#888; font-weight:400;"&gt;Al iniciar sesión se te pedirá un código enviado a tu email.&lt;/small&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/span&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/label&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt;<br />
&lt;/div&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Y en cuenta.js buscar:</span><br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">}<br /><br />}<br /><br />var&nbsp;</span><span style="color: #0000BB">avatar&nbsp;</span><span style="color: #007700">=&nbsp;{&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Reemplazar por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>},<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;toggle2FA: function(activo) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;.ajax({<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;type: 'POST',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url: global_data.url + '/2fa-toggle.php',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data: { activo: activo ? 1 : 0 },<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dataType: 'json',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;success: function(r) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (r.ok) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cuenta.alert(1, activo ? '2FA activado' : '2FA desactivado', activo ? 'Ahora se pedirá un código al iniciar sesión.' : 'La verificación en dos pasos ha sido desactivada.');<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
}<br />
<br />
var avatar = {</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>ALTER TABLE u_miembros DROP COLUMN user_2fa;<br />
DROP TABLE IF EXISTS w_2fa_tokens;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos y quita el hook de <span style="font-weight: bold;" class="mycode_b">ajax.login.php</span>.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
<br />
</div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Historial de Búsquedas v1.0]]></title>
			<link>https://phpost.es/thread-992.html</link>
			<pubDate>Thu, 28 May 2026 13:16:44 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-992.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Historial de Búsquedas v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Guarda las últimas 10 búsquedas del usuario en la sesión y las muestra debajo del campo de búsqueda como píldoras clicables para repetirlas con un clic.</span><br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">🔍 Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Sin base de datos ni instalador</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo 2 archivos a sustituir</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Guarda hasta <span style="font-weight: bold;" class="mycode_b">10 búsquedas</span> por sesión</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">No guarda duplicados — si buscas lo mismo lo mueve al principio</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Clic en una búsqueda anterior la repite directamente</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Botón para <span style="font-weight: bold;" class="mycode_b">borrar el historial</span> con un clic</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo visible cuando hay historial guardado</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Solo hay que sustituir 2 archivos:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/php/buscador.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/<br />
themes/default/templates/t.buscador.tpl&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Borra la caché después de subir.</span><br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">🗑️ Desinstalar</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Restaura los archivos originales de <span style="font-weight: bold;" class="mycode_b">buscador.php</span> y <span style="font-weight: bold;" class="mycode_b">t.buscador.tpl</span>. No hay tablas que borrar.</span><br />
<hr class="mycode_hr" />
 <br />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
<br />
<br />
<br />
</div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Historial de Búsquedas v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Guarda las últimas 10 búsquedas del usuario en la sesión y las muestra debajo del campo de búsqueda como píldoras clicables para repetirlas con un clic.</span><br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">🔍 Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Sin base de datos ni instalador</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo 2 archivos a sustituir</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Guarda hasta <span style="font-weight: bold;" class="mycode_b">10 búsquedas</span> por sesión</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">No guarda duplicados — si buscas lo mismo lo mueve al principio</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Clic en una búsqueda anterior la repite directamente</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Botón para <span style="font-weight: bold;" class="mycode_b">borrar el historial</span> con un clic</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo visible cuando hay historial guardado</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Solo hay que sustituir 2 archivos:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/php/buscador.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/<br />
themes/default/templates/t.buscador.tpl&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Borra la caché después de subir.</span><br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">🗑️ Desinstalar</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Restaura los archivos originales de <span style="font-weight: bold;" class="mycode_b">buscador.php</span> y <span style="font-weight: bold;" class="mycode_b">t.buscador.tpl</span>. No hay tablas que borrar.</span><br />
<hr class="mycode_hr" />
 <br />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
<br />
<br />
<br />
</div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Chat en Tiempo Real v1.0]]></title>
			<link>https://phpost.es/thread-991.html</link>
			<pubDate>Thu, 28 May 2026 12:45:42 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-991.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Chat en Tiempo Real v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Sala de chat global en <span style="font-weight: bold;" class="mycode_b">/chat/</span> con actualización automática cada 3 segundos. Solo usuarios registrados. Muestra los últimos 100 mensajes y la lista de usuarios conectados en tiempo real.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">💬 Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Polling cada <span style="font-weight: bold;" class="mycode_b">3 segundos</span> — funciona en cualquier hosting compartido</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo usuarios registrados pueden chatear</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Anti-flood</span> — máximo 1 mensaje cada 2 segundos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Mensajes guardados <span style="font-weight: bold;" class="mycode_b">24 horas</span> y luego borrados automáticamente</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Lista de <span style="font-weight: bold;" class="mycode_b">usuarios conectados</span> en tiempo real</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Admins pueden borrar mensajes con un clic</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Máximo 500 caracteres por mensaje</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Compatible con el sistema de palabras prohibidas del script</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">MySQL 5.7+ / MariaDB 10.4+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span><br />
<br />
Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: x-large;" class="mycode_size">⚠️ Elimina la carpeta install/ cuando termine.</span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/php/chat.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/<br />
inc/class/c.chat.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ajax/ajax.chat.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/templates/t.chat.tpl&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En head_menu.tpl </span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Pon esto donde quieras:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;li class="tabbed {if &#36;tsPage == 'chat'}here{/if}" id="tabbedchat"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;a href="{&#36;tsConfig.url}/chat/"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;i class="fa-solid fa-comments"&gt;&lt;/i&gt; Chat<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/a&gt;<br />
&lt;/li&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS w_chat;<br />
DROP TABLE IF EXISTS w_chat_presencia;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos y quita la ruta del .htaccess.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
</div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Chat en Tiempo Real v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Sala de chat global en <span style="font-weight: bold;" class="mycode_b">/chat/</span> con actualización automática cada 3 segundos. Solo usuarios registrados. Muestra los últimos 100 mensajes y la lista de usuarios conectados en tiempo real.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">💬 Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Polling cada <span style="font-weight: bold;" class="mycode_b">3 segundos</span> — funciona en cualquier hosting compartido</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo usuarios registrados pueden chatear</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Anti-flood</span> — máximo 1 mensaje cada 2 segundos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Mensajes guardados <span style="font-weight: bold;" class="mycode_b">24 horas</span> y luego borrados automáticamente</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Lista de <span style="font-weight: bold;" class="mycode_b">usuarios conectados</span> en tiempo real</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Admins pueden borrar mensajes con un clic</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Máximo 500 caracteres por mensaje</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Compatible con el sistema de palabras prohibidas del script</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">MySQL 5.7+ / MariaDB 10.4+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span><br />
<br />
Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: x-large;" class="mycode_size">⚠️ Elimina la carpeta install/ cuando termine.</span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/php/chat.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/<br />
inc/class/c.chat.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ajax/ajax.chat.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/templates/t.chat.tpl&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En head_menu.tpl </span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Pon esto donde quieras:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;li class="tabbed {if &#36;tsPage == 'chat'}here{/if}" id="tabbedchat"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;a href="{&#36;tsConfig.url}/chat/"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;i class="fa-solid fa-comments"&gt;&lt;/i&gt; Chat<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/a&gt;<br />
&lt;/li&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS w_chat;<br />
DROP TABLE IF EXISTS w_chat_presencia;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos y quita la ruta del .htaccess.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
</div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Tiempo de Lectura v1.0]]></title>
			<link>https://phpost.es/thread-990.html</link>
			<pubDate>Thu, 28 May 2026 12:05:18 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-990.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Tiempo de Lectura v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size">Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Muestra el tiempo estimado de lectura en la cabecera de cada post, justo debajo del título. Basado en una velocidad media de 200 palabras por minuto, igual que Medium o Dev.to.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⏱️ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Sin base de datos ni instalador</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo 2 cambios en 2 archivos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Calcula el tiempo en PHP — sin JavaScript</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Muestra mínimo 1 minuto</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Ignora el HTML del cuerpo — cuenta solo el texto</span><br />
</li>
</ul>
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Ejemplos:</span></span></span><ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Post de 400 palabras → <span style="font-weight: bold;" class="mycode_b">2 min de lectura</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Post de 50 palabras → <span style="font-weight: bold;" class="mycode_b">1 min de lectura</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Post de 1000 palabras → <span style="font-weight: bold;" class="mycode_b">5 min de lectura</span></span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — En posts.php</span><br />
<br />
Buscar en <span style="font-weight: bold;" class="mycode_b">inc/php/posts.php</span>:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&#36;smarty-&gt;assign("tsPost",&#36;tsPost);</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Agregar debajo:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Tiempo de lectura ──<br />
&#36;texto_plano = strip_tags(html_entity_decode(&#36;tsPost['post_body'], ENT_QUOTES, 'UTF-8'));<br />
&#36;palabras&nbsp;&nbsp;&nbsp;&nbsp;= str_word_count(&#36;texto_plano);<br />
&#36;minutos&nbsp;&nbsp;&nbsp;&nbsp; = max(1, (int)ceil(&#36;palabras / 200));<br />
&#36;smarty-&gt;assign('tsTiempoLectura', &#36;minutos);<br />
// ───────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Añadir en m.posts_content.tpl</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Buscar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;h1&gt;{&#36;tsPost.post_title}&lt;/h1&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Añade justo después:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{if &#36;tsTiempoLectura}<br />
&lt;div style="font-size:12px; color:#999; margin-top:4px; font-weight:400;"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;i class="fa-regular fa-clock"&gt;&lt;/i&gt; {&#36;tsTiempoLectura} min de lectura<br />
&lt;/div&gt;<br />
{/if}</code></div></div><br />
<span style="font-size: large;" class="mycode_size">O sube directamente el <span style="font-weight: bold;" class="mycode_b">m.posts_content.tpl</span> que dejo adjunto que ya incluye el cambio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Quita las líneas añadidas en <span style="font-weight: bold;" class="mycode_b">posts.php</span> y el bloque del título en <span style="font-weight: bold;" class="mycode_b">m.posts_content.tpl</span>.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
</div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Tiempo de Lectura v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size">Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Muestra el tiempo estimado de lectura en la cabecera de cada post, justo debajo del título. Basado en una velocidad media de 200 palabras por minuto, igual que Medium o Dev.to.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⏱️ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Sin base de datos ni instalador</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo 2 cambios en 2 archivos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Calcula el tiempo en PHP — sin JavaScript</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Muestra mínimo 1 minuto</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Ignora el HTML del cuerpo — cuenta solo el texto</span><br />
</li>
</ul>
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Ejemplos:</span></span></span><ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Post de 400 palabras → <span style="font-weight: bold;" class="mycode_b">2 min de lectura</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Post de 50 palabras → <span style="font-weight: bold;" class="mycode_b">1 min de lectura</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Post de 1000 palabras → <span style="font-weight: bold;" class="mycode_b">5 min de lectura</span></span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — En posts.php</span><br />
<br />
Buscar en <span style="font-weight: bold;" class="mycode_b">inc/php/posts.php</span>:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&#36;smarty-&gt;assign("tsPost",&#36;tsPost);</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Agregar debajo:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Tiempo de lectura ──<br />
&#36;texto_plano = strip_tags(html_entity_decode(&#36;tsPost['post_body'], ENT_QUOTES, 'UTF-8'));<br />
&#36;palabras&nbsp;&nbsp;&nbsp;&nbsp;= str_word_count(&#36;texto_plano);<br />
&#36;minutos&nbsp;&nbsp;&nbsp;&nbsp; = max(1, (int)ceil(&#36;palabras / 200));<br />
&#36;smarty-&gt;assign('tsTiempoLectura', &#36;minutos);<br />
// ───────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Añadir en m.posts_content.tpl</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Buscar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;h1&gt;{&#36;tsPost.post_title}&lt;/h1&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Añade justo después:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{if &#36;tsTiempoLectura}<br />
&lt;div style="font-size:12px; color:#999; margin-top:4px; font-weight:400;"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;i class="fa-regular fa-clock"&gt;&lt;/i&gt; {&#36;tsTiempoLectura} min de lectura<br />
&lt;/div&gt;<br />
{/if}</code></div></div><br />
<span style="font-size: large;" class="mycode_size">O sube directamente el <span style="font-weight: bold;" class="mycode_b">m.posts_content.tpl</span> que dejo adjunto que ya incluye el cambio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Quita las líneas añadidas en <span style="font-weight: bold;" class="mycode_b">posts.php</span> y el bloque del título en <span style="font-weight: bold;" class="mycode_b">m.posts_content.tpl</span>.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
</div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Sistema de Referidos v1.0]]></title>
			<link>https://phpost.es/thread-989.html</link>
			<pubDate>Thu, 28 May 2026 11:38:59 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-989.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Sistema de Referidos v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Cada usuario tiene un enlace de invitación único. Cuando alguien se registra con ese enlace y activa su cuenta, el que invitó gana 10 puntos automáticamente y recibe una notificación.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🤝 Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Enlace de referido único por usuario: <span style="font-weight: bold;" class="mycode_b">tudominio.com/registro?ref=NICK</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Puntos solo al activar la cuenta</span> — evita cuentas falsas</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Un usuario solo puede tener un referidor</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Nadie puede referirse a sí mismo</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Notificación automática al ganar los puntos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Widget en el perfil con enlace, estadísticas y lista de invitados</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Botón copiar enlace con un clic</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">El ref se guarda en sesión — no se pierde si el usuario navega antes de registrarse</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">MySQL 5.7+ / MariaDB 10.4+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span><br />
<br />
Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: x-large;" class="mycode_size">⚠️ Elimina la carpeta install/ cuando termine.</span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.referidos.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
themes/default/templates/modules/m.perfil_referidos.tpl →&nbsp;&nbsp;themes/default/templates/modules/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En c.registro.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Buscar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&#36;tsData['user_id'] = db_exec('insert_id');</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Añade justo después:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Referidos ──<br />
require_once TS_CLASS . 'c.referidos.php';<br />
&#36;ref_nick = isset(&#36;_SESSION['ref_nick']) ? &#36;_SESSION['ref_nick'] : (&#36;tsCore-&gt;setSecure(&#36;_GET['ref'] ?? '') ?: &#36;tsCore-&gt;setSecure(&#36;_POST['ref'] ?? ''));<br />
if (!empty(&#36;ref_nick)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsRef = new tsReferidos();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsRef-&gt;guardarReferido(&#36;tsData['user_id'], &#36;ref_nick);<br />
}<br />
// ────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — En c.user.php — userActivate()</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">inc/class/c.user.php</span> y busca dentro de <span style="font-weight: bold;" class="mycode_b">userActivate()</span> esta línea:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>if(db_exec(array(__FILE__, __LINE__), 'query', 'UPDATE u_miembros SET user_activo = 1 WHERE user_id = &#92;''.&#36;tsUserID.'&#92;'' )) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;return &#36;tsData;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Cambiar por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>if(db_exec(array(__FILE__, __LINE__), 'query', 'UPDATE u_miembros SET user_activo = 1 WHERE user_id = &#92;''.&#36;tsUserID.'&#92;'' )) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.referidos.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsRef = new tsReferidos();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsRef-&gt;procesarActivacion((int)&#36;tsUserID);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return &#36;tsData;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Esto cubre tanto la activación por email como la activación directa sin email.</span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Guardar ref en sesión (header.php)</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Al final de <span style="font-weight: bold;" class="mycode_b">header.php</span> añade:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Guardar ref en sesión ──<br />
if (!empty(&#36;_GET['ref'])) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;_SESSION['ref_nick'] = &#36;tsCore-&gt;setSecure(&#36;_GET['ref']);<br />
}<br />
// ───────────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 6 — Widget en el perfil</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">En <span style="font-weight: bold;" class="mycode_b">perfil.php</span> buscar:</span><br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #0000BB">&#36;smarty</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">assign</span><span style="color: #007700">(</span><span style="color: #DD0000">"tsGeneral"</span><span style="color: #007700">,</span><span style="color: #0000BB">&#36;tsGeneral</span><span style="color: #007700">);&nbsp;<br /></span></code></div></div></div><br />
<span style="font-size: large;" class="mycode_size">Debajo agregar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Referidos ──<br />
require_once TS_CLASS . 'c.referidos.php';<br />
if (&#36;tsUser-&gt;uid == &#36;usuario['user_id']) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsRef = new tsReferidos();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;ref_data = &#36;tsRef-&gt;getReferidos(&#36;tsUser-&gt;uid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;ref_data['url'] = tsReferidos::getUrl(&#36;tsUser-&gt;nick);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;ref_data['puntos_por_referido'] = tsReferidos::PUNTOS_POR_REFERIDO;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;smarty-&gt;assign('tsReferidos', &#36;ref_data);<br />
}<br />
// ────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size">En <span style="font-weight: bold;" class="mycode_b">m.perfil_sidebar.tpl</span> añade donde quieras:</span><br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{include file='modules/m.perfil_referidos.tpl'}</code></div></div> <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚙️ Configurar puntos</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Los puntos por referido se configuran en <span style="font-weight: bold;" class="mycode_b">inc/class/c.referidos.php</span>:</span><br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>const PUNTOS_POR_REFERIDO = 10;</code></div></div> <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS u_referidos;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos y quita los hooks añadidos.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
</div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Sistema de Referidos v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Cada usuario tiene un enlace de invitación único. Cuando alguien se registra con ese enlace y activa su cuenta, el que invitó gana 10 puntos automáticamente y recibe una notificación.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🤝 Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Enlace de referido único por usuario: <span style="font-weight: bold;" class="mycode_b">tudominio.com/registro?ref=NICK</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Puntos solo al activar la cuenta</span> — evita cuentas falsas</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Un usuario solo puede tener un referidor</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Nadie puede referirse a sí mismo</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Notificación automática al ganar los puntos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Widget en el perfil con enlace, estadísticas y lista de invitados</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Botón copiar enlace con un clic</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">El ref se guarda en sesión — no se pierde si el usuario navega antes de registrarse</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">MySQL 5.7+ / MariaDB 10.4+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span><br />
<br />
Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: x-large;" class="mycode_size">⚠️ Elimina la carpeta install/ cuando termine.</span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.referidos.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
themes/default/templates/modules/m.perfil_referidos.tpl →&nbsp;&nbsp;themes/default/templates/modules/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En c.registro.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Buscar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&#36;tsData['user_id'] = db_exec('insert_id');</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Añade justo después:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Referidos ──<br />
require_once TS_CLASS . 'c.referidos.php';<br />
&#36;ref_nick = isset(&#36;_SESSION['ref_nick']) ? &#36;_SESSION['ref_nick'] : (&#36;tsCore-&gt;setSecure(&#36;_GET['ref'] ?? '') ?: &#36;tsCore-&gt;setSecure(&#36;_POST['ref'] ?? ''));<br />
if (!empty(&#36;ref_nick)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsRef = new tsReferidos();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsRef-&gt;guardarReferido(&#36;tsData['user_id'], &#36;ref_nick);<br />
}<br />
// ────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — En c.user.php — userActivate()</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">inc/class/c.user.php</span> y busca dentro de <span style="font-weight: bold;" class="mycode_b">userActivate()</span> esta línea:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>if(db_exec(array(__FILE__, __LINE__), 'query', 'UPDATE u_miembros SET user_activo = 1 WHERE user_id = &#92;''.&#36;tsUserID.'&#92;'' )) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;return &#36;tsData;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Cambiar por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>if(db_exec(array(__FILE__, __LINE__), 'query', 'UPDATE u_miembros SET user_activo = 1 WHERE user_id = &#92;''.&#36;tsUserID.'&#92;'' )) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.referidos.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsRef = new tsReferidos();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsRef-&gt;procesarActivacion((int)&#36;tsUserID);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return &#36;tsData;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Esto cubre tanto la activación por email como la activación directa sin email.</span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Guardar ref en sesión (header.php)</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Al final de <span style="font-weight: bold;" class="mycode_b">header.php</span> añade:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Guardar ref en sesión ──<br />
if (!empty(&#36;_GET['ref'])) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;_SESSION['ref_nick'] = &#36;tsCore-&gt;setSecure(&#36;_GET['ref']);<br />
}<br />
// ───────────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 6 — Widget en el perfil</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">En <span style="font-weight: bold;" class="mycode_b">perfil.php</span> buscar:</span><br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #0000BB">&#36;smarty</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">assign</span><span style="color: #007700">(</span><span style="color: #DD0000">"tsGeneral"</span><span style="color: #007700">,</span><span style="color: #0000BB">&#36;tsGeneral</span><span style="color: #007700">);&nbsp;<br /></span></code></div></div></div><br />
<span style="font-size: large;" class="mycode_size">Debajo agregar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Referidos ──<br />
require_once TS_CLASS . 'c.referidos.php';<br />
if (&#36;tsUser-&gt;uid == &#36;usuario['user_id']) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsRef = new tsReferidos();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;ref_data = &#36;tsRef-&gt;getReferidos(&#36;tsUser-&gt;uid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;ref_data['url'] = tsReferidos::getUrl(&#36;tsUser-&gt;nick);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;ref_data['puntos_por_referido'] = tsReferidos::PUNTOS_POR_REFERIDO;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;smarty-&gt;assign('tsReferidos', &#36;ref_data);<br />
}<br />
// ────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size">En <span style="font-weight: bold;" class="mycode_b">m.perfil_sidebar.tpl</span> añade donde quieras:</span><br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{include file='modules/m.perfil_referidos.tpl'}</code></div></div> <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚙️ Configurar puntos</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Los puntos por referido se configuran en <span style="font-weight: bold;" class="mycode_b">inc/class/c.referidos.php</span>:</span><br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>const PUNTOS_POR_REFERIDO = 10;</code></div></div> <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS u_referidos;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos y quita los hooks añadidos.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
</div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Reacciones en Posts v1.0]]></title>
			<link>https://phpost.es/thread-988.html</link>
			<pubDate>Thu, 28 May 2026 10:45:36 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-988.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Reacciones en Posts v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size">Capturas</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Añade un sistema de reacciones con 6 emojis en cada post. Convive con el sistema de puntos existente — son completamente independientes. Un usuario puede dar puntos Y reaccionar al mismo post.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">😊 Reacciones disponibles</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">👍 <span style="font-weight: bold;" class="mycode_b">Me gusta</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">❤️ <span style="font-weight: bold;" class="mycode_b">Me encanta</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">😂 <span style="font-weight: bold;" class="mycode_b">Divertido</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">😮 <span style="font-weight: bold;" class="mycode_b">Sorprendente</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">😢 <span style="font-weight: bold;" class="mycode_b">Triste</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">😡 <span style="font-weight: bold;" class="mycode_b">Enfadado</span></span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚡ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Un usuario solo puede tener <span style="font-weight: bold;" class="mycode_b">una reacción por post</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Cambiar de reacción reemplaza la anterior automáticamente</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Pulsar la misma reacción la <span style="font-weight: bold;" class="mycode_b">quita</span> (toggle)</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo usuarios registrados pueden reaccionar</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Resumen visual con emojis y total de reacciones</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Actualización instantánea sin recargar la página</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Convive con el sistema de puntos — no lo reemplaza</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">MySQL 5.7+ / MariaDB 10.4+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Pulsa <span style="font-weight: bold;" class="mycode_b">Instalar ahora</span>. Crea la tabla <span style="font-weight: bold;" class="mycode_b">p_reacciones</span>.</span><br />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚠️ Elimina la carpeta install/ cuando termine.</span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.reacciones.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ajax/ajax.reacciones.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/templates/modules/m.reacciones.tpl&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/modules/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En posts.php</span><br />
<br />
Busca en <span style="font-weight: bold;" class="mycode_b">inc/php/posts.php</span> la línea:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&#36;smarty-&gt;assign("tsPost",&#36;tsPost);</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Añade justo después:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Reacciones ──<br />
require_once TS_CLASS . 'c.reacciones.php';<br />
&#36;tsReac = new tsReacciones();<br />
&#36;smarty-&gt;assign('tsReacciones', &#36;tsReac-&gt;getReacciones(&#36;tsPost['post_id']));<br />
// ────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — Añadir en m.posts_metadata.tpl</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Busca el bloque de estadísticas que termina con <span style="font-weight: bold;" class="mycode_b">&lt;/ul&gt;</span>:</span><br />
 <br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">&lt;</span><span style="color: #0000BB">div&nbsp;style</span><span style="color: #007700">=</span><span style="color: #DD0000">"margin-top:&nbsp;5px;"</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">strong&nbsp;style</span><span style="color: #007700">=</span><span style="color: #DD0000">"color:&nbsp;#333;&nbsp;font-size:&nbsp;15px;&nbsp;display:&nbsp;block;&nbsp;line-height:&nbsp;1;"</span><span style="color: #007700">&gt;{</span><span style="color: #0000BB">&#36;tsPost</span><span style="color: #007700">.</span><span style="color: #0000BB">post_seguidores</span><span style="color: #007700">}&lt;/</span><span style="color: #0000BB">strong</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">span&nbsp;style</span><span style="color: #007700">=</span><span style="color: #DD0000">"color:&nbsp;#999;&nbsp;font-size:&nbsp;11px;&nbsp;text-transform:&nbsp;uppercase;"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">Seguidores</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">div</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">ul</span><span style="color: #007700">&gt;&nbsp;<br /></span></code></div></div></div><br />
<span style="font-size: large;" class="mycode_size">Debajo agregar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{include file='modules/m.reacciones.tpl'}</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS p_reacciones;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos subidos y quita los hooks añadidos.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
<br />
</div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Reacciones en Posts v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size">Capturas</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Añade un sistema de reacciones con 6 emojis en cada post. Convive con el sistema de puntos existente — son completamente independientes. Un usuario puede dar puntos Y reaccionar al mismo post.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">😊 Reacciones disponibles</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">👍 <span style="font-weight: bold;" class="mycode_b">Me gusta</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">❤️ <span style="font-weight: bold;" class="mycode_b">Me encanta</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">😂 <span style="font-weight: bold;" class="mycode_b">Divertido</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">😮 <span style="font-weight: bold;" class="mycode_b">Sorprendente</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">😢 <span style="font-weight: bold;" class="mycode_b">Triste</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">😡 <span style="font-weight: bold;" class="mycode_b">Enfadado</span></span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚡ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Un usuario solo puede tener <span style="font-weight: bold;" class="mycode_b">una reacción por post</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Cambiar de reacción reemplaza la anterior automáticamente</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Pulsar la misma reacción la <span style="font-weight: bold;" class="mycode_b">quita</span> (toggle)</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Solo usuarios registrados pueden reaccionar</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Resumen visual con emojis y total de reacciones</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Actualización instantánea sin recargar la página</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Convive con el sistema de puntos — no lo reemplaza</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">MySQL 5.7+ / MariaDB 10.4+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Pulsa <span style="font-weight: bold;" class="mycode_b">Instalar ahora</span>. Crea la tabla <span style="font-weight: bold;" class="mycode_b">p_reacciones</span>.</span><br />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚠️ Elimina la carpeta install/ cuando termine.</span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.reacciones.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ajax/ajax.reacciones.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/templates/modules/m.reacciones.tpl&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/modules/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En posts.php</span><br />
<br />
Busca en <span style="font-weight: bold;" class="mycode_b">inc/php/posts.php</span> la línea:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&#36;smarty-&gt;assign("tsPost",&#36;tsPost);</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Añade justo después:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Reacciones ──<br />
require_once TS_CLASS . 'c.reacciones.php';<br />
&#36;tsReac = new tsReacciones();<br />
&#36;smarty-&gt;assign('tsReacciones', &#36;tsReac-&gt;getReacciones(&#36;tsPost['post_id']));<br />
// ────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — Añadir en m.posts_metadata.tpl</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Busca el bloque de estadísticas que termina con <span style="font-weight: bold;" class="mycode_b">&lt;/ul&gt;</span>:</span><br />
 <br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">&lt;</span><span style="color: #0000BB">div&nbsp;style</span><span style="color: #007700">=</span><span style="color: #DD0000">"margin-top:&nbsp;5px;"</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">strong&nbsp;style</span><span style="color: #007700">=</span><span style="color: #DD0000">"color:&nbsp;#333;&nbsp;font-size:&nbsp;15px;&nbsp;display:&nbsp;block;&nbsp;line-height:&nbsp;1;"</span><span style="color: #007700">&gt;{</span><span style="color: #0000BB">&#36;tsPost</span><span style="color: #007700">.</span><span style="color: #0000BB">post_seguidores</span><span style="color: #007700">}&lt;/</span><span style="color: #0000BB">strong</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">span&nbsp;style</span><span style="color: #007700">=</span><span style="color: #DD0000">"color:&nbsp;#999;&nbsp;font-size:&nbsp;11px;&nbsp;text-transform:&nbsp;uppercase;"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">Seguidores</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">div</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">ul</span><span style="color: #007700">&gt;&nbsp;<br /></span></code></div></div></div><br />
<span style="font-size: large;" class="mycode_size">Debajo agregar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{include file='modules/m.reacciones.tpl'}</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #e67e22;" class="mycode_color">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS p_reacciones;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos subidos y quita los hooks añadidos.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
<br />
<br />
</div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Posts Programados v1.0]]></title>
			<link>https://phpost.es/thread-987.html</link>
			<pubDate>Wed, 27 May 2026 21:48:23 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-987.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Posts Programados v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Permite a administradores y moderadores programar la publicación de posts en una fecha y hora concretas. El post se guarda como "programado" y se publica automáticamente cuando llega la hora, sin que nadie tenga que hacer nada.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🕐 Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Solo admins y moderadores</span> pueden programar posts</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Mínimo 5 minutos en el futuro, máximo 1 año</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Publicación automática al cargar cualquier página</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Panel en el admin para ver todos los posts programados</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Publicar manualmente antes de la hora con un clic</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Cancelar devuelve el post a borradores</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Validación estricta de fechas — no se puede manipular desde el frontend</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">MySQL 5.7+ / MariaDB 10.4+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span><br />
<br />
Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Pulsa <span style="font-weight: bold;" class="mycode_b">Instalar ahora</span>. Añade la columna <span style="font-weight: bold;" class="mycode_b">post_publish_at</span> en la tabla <span style="font-weight: bold;" class="mycode_b">p_posts</span>.</span><br />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚠️ Elimina la carpeta install/ cuando termine.</span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.scheduled.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ajax/ajax.scheduled.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/templates/modules/m.scheduled_form.tpl →&nbsp;&nbsp;themes/default/templates/modules/<br />
themes/default/templates/modules/m.scheduled_admin.tpl →&nbsp;&nbsp;themes/default/templates/admin_mods/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En c.posts.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Busca el <span style="font-weight: bold;" class="mycode_b">return &#36;postID;</span> al final de <span style="font-weight: bold;" class="mycode_b">newPost()</span> y añade justo antes:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Posts programados ──<br />
if (!empty(&#36;_POST['post_publish_at']) &amp;&amp; &#36;tsUser-&gt;is_admod) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.scheduled.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsSched = new tsScheduled();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;ts = tsScheduled::parseFecha(&#36;_POST['post_publish_at']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;ts &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsSched-&gt;programar(&#36;postID, &#36;ts);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
// ────────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — En header.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">header.php</span> de la raíz y añade al final, antes del cierre:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Publicar posts programados ──<br />
require_once TS_CLASS . 'c.scheduled.php';<br />
(new tsScheduled())-&gt;publicarPendientes();<br />
// ────────────────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — En m.agregar.form.tpl</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Buscar:</span><br />
{if (&#36;tsUser-&gt;is_admod &gt; 0 || &#36;tsUser-&gt;permisos.moedpo) &amp;&amp; &#36;tsDraft.b_title &amp;&amp; &#36;tsDraft.b_user != &#36;tsUser-&gt;uid}<br />
<br />
Arriba agregar:<br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{include file='modules/m.scheduled_form.tpl'}</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 6 — Panel en el admin</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">En <span style="font-weight: bold;" class="mycode_b">admin.php</span> añade antes de :</span><br />
 <br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">}&nbsp;elseif(</span><span style="color: #0000BB">&#36;action&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #DD0000">'feed'</span><span style="color: #007700">){&nbsp;<br /></span></code></div></div></div><br />
<span style="font-size: large;" class="mycode_size">Agregar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>} elseif(&#36;action == 'scheduled'){<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.scheduled.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsSched = new tsScheduled();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;smarty-&gt;assign('tsProgramados', &#36;tsSched-&gt;getProgramados());</code></div></div><br />
<span style="font-size: large;" class="mycode_size">En <span style="font-weight: bold;" class="mycode_b">t.admin.tpl</span> añade antes del <span style="font-weight: bold;" class="mycode_b">{/if}</span> final:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{elseif &#36;tsAction == 'scheduled'}<br />
{include file='admin_mods/m.scheduled_admin.tpl'}</code></div></div><br />
<span style="font-size: large;" class="mycode_size">En <span style="font-weight: bold;" class="mycode_b">m.admin_sidemenu.tpl</span> añade donde prefieras:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;li id="a_scheduled"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;a href="{&#36;tsConfig.url}/admin/scheduled"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span class="nav-icon"&gt;🕐&lt;/span&gt; Posts Programados<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/a&gt;<br />
&lt;/li&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 7 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>ALTER TABLE p_posts DROP COLUMN post_publish_at;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos subidos y quita los hooks añadidos.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
</div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Posts Programados v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Permite a administradores y moderadores programar la publicación de posts en una fecha y hora concretas. El post se guarda como "programado" y se publica automáticamente cuando llega la hora, sin que nadie tenga que hacer nada.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🕐 Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Solo admins y moderadores</span> pueden programar posts</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Mínimo 5 minutos en el futuro, máximo 1 año</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Publicación automática al cargar cualquier página</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Panel en el admin para ver todos los posts programados</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Publicar manualmente antes de la hora con un clic</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Cancelar devuelve el post a borradores</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Validación estricta de fechas — no se puede manipular desde el frontend</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">MySQL 5.7+ / MariaDB 10.4+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span><br />
<br />
Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Pulsa <span style="font-weight: bold;" class="mycode_b">Instalar ahora</span>. Añade la columna <span style="font-weight: bold;" class="mycode_b">post_publish_at</span> en la tabla <span style="font-weight: bold;" class="mycode_b">p_posts</span>.</span><br />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚠️ Elimina la carpeta install/ cuando termine.</span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.scheduled.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ajax/ajax.scheduled.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/templates/modules/m.scheduled_form.tpl →&nbsp;&nbsp;themes/default/templates/modules/<br />
themes/default/templates/modules/m.scheduled_admin.tpl →&nbsp;&nbsp;themes/default/templates/admin_mods/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En c.posts.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Busca el <span style="font-weight: bold;" class="mycode_b">return &#36;postID;</span> al final de <span style="font-weight: bold;" class="mycode_b">newPost()</span> y añade justo antes:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Posts programados ──<br />
if (!empty(&#36;_POST['post_publish_at']) &amp;&amp; &#36;tsUser-&gt;is_admod) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.scheduled.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsSched = new tsScheduled();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;ts = tsScheduled::parseFecha(&#36;_POST['post_publish_at']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;ts &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsSched-&gt;programar(&#36;postID, &#36;ts);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
// ────────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — En header.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">header.php</span> de la raíz y añade al final, antes del cierre:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Publicar posts programados ──<br />
require_once TS_CLASS . 'c.scheduled.php';<br />
(new tsScheduled())-&gt;publicarPendientes();<br />
// ────────────────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — En m.agregar.form.tpl</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Buscar:</span><br />
{if (&#36;tsUser-&gt;is_admod &gt; 0 || &#36;tsUser-&gt;permisos.moedpo) &amp;&amp; &#36;tsDraft.b_title &amp;&amp; &#36;tsDraft.b_user != &#36;tsUser-&gt;uid}<br />
<br />
Arriba agregar:<br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{include file='modules/m.scheduled_form.tpl'}</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 6 — Panel en el admin</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">En <span style="font-weight: bold;" class="mycode_b">admin.php</span> añade antes de :</span><br />
 <br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">}&nbsp;elseif(</span><span style="color: #0000BB">&#36;action&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #DD0000">'feed'</span><span style="color: #007700">){&nbsp;<br /></span></code></div></div></div><br />
<span style="font-size: large;" class="mycode_size">Agregar:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>} elseif(&#36;action == 'scheduled'){<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.scheduled.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsSched = new tsScheduled();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;smarty-&gt;assign('tsProgramados', &#36;tsSched-&gt;getProgramados());</code></div></div><br />
<span style="font-size: large;" class="mycode_size">En <span style="font-weight: bold;" class="mycode_b">t.admin.tpl</span> añade antes del <span style="font-weight: bold;" class="mycode_b">{/if}</span> final:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{elseif &#36;tsAction == 'scheduled'}<br />
{include file='admin_mods/m.scheduled_admin.tpl'}</code></div></div><br />
<span style="font-size: large;" class="mycode_size">En <span style="font-weight: bold;" class="mycode_b">m.admin_sidemenu.tpl</span> añade donde prefieras:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;li id="a_scheduled"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;a href="{&#36;tsConfig.url}/admin/scheduled"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;span class="nav-icon"&gt;🕐&lt;/span&gt; Posts Programados<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/a&gt;<br />
&lt;/li&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 7 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>ALTER TABLE p_posts DROP COLUMN post_publish_at;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos subidos y quita los hooks añadidos.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
<br />
<br />
</div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Protección de Login v1.0]]></title>
			<link>https://phpost.es/thread-986.html</link>
			<pubDate>Wed, 27 May 2026 18:41:50 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-986.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Protección de Login v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Protección contra ataques de fuerza bruta en el login. Bloquea automáticamente por IP y por nick tras demasiados intentos fallidos, con bloqueo progresivo y log completo de accesos visible desde el panel de admin.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛡️ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Doble bloqueo</span> — por IP y por nombre de usuario de forma independiente</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Bloqueo progresivo</span> — 1er bloqueo 15 min, 2do 1 hora, 3er bloqueo y siguientes 24 horas</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">5 intentos</span> antes de bloquear (configurable en el código)</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Admin nunca se bloquea</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Login correcto resetea los contadores</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Log completo</span> — fecha, IP, nick y resultado de cada intento (guardado 7 días)</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Panel en el admin</span> — ver intentos y desbloquear manualmente con un clic</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Aviso al usuario</span> — muestra cuántos intentos le quedan antes del bloqueo</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">MySQL 5.7+ / MariaDB 10.4+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz del sitio y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Pulsa <span style="font-weight: bold;" class="mycode_b">Instalar ahora</span>. El instalador creará:</span><ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">w_login_log</span> — registro de todos los intentos de login</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">w_login_bloqueos</span> — bloqueos activos por IP y nick</span><br />
</li>
</ul>
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚠️ Elimina la carpeta install/ del servidor cuando termine.</span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.loginlog.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ajax/ajax.loginlog.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/css/loginlog.css&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/css/<br />
themes/default/templates/modules/<br />
&nbsp;&nbsp;m.loginlog_admin.tpl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/modules/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En ajax.login.php</span><br />
<br />
Abre <span style="font-weight: bold;" class="mycode_b">inc/php/ajax/ajax.login.php</span> y reemplaza el <span style="font-weight: bold;" class="mycode_b">case 'login-user'</span> completo por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>case 'login-user':<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&lt;---<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;user = &#36;tsCore-&gt;setSecure(&#36;_POST['nick']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;pass = &#36;tsCore-&gt;setSecure(&#36;_POST['pass']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;reme = ((&#36;_POST['rem'] ?? '') == 'true') ? true : false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(empty(&#36;user) or empty(&#36;pass)) echo '0: Faltan datos';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else echo &#36;tsUser-&gt;loginUser(&#36;user, &#36;pass, &#36;reme);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//---&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</code></div></div> <br />
<span style="font-size: large;" class="mycode_size">Cambiar por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>case 'login-user':<br />
&nbsp;&nbsp;&nbsp;&nbsp;//&lt;---<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;user = &#36;tsCore-&gt;setSecure(&#36;_POST['nick']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;pass = &#36;tsCore-&gt;setSecure(&#36;_POST['pass']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;reme = ((&#36;_POST['rem'] ?? '') == 'true') ? true : false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;ip&nbsp;&nbsp; = &#36;tsCore-&gt;getIP();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (empty(&#36;user) || empty(&#36;pass)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Faltan datos';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ── Protección login ──<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.loginlog.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsLL = new tsLoginLog();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;bloqueo = &#36;tsLL-&gt;estaBloqueado(&#36;user, &#36;ip);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;bloqueo) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tiempo = &#36;tsLL-&gt;formatearTiempo(&#36;bloqueo['faltan']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Demasiados intentos fallidos. Inténtalo de nuevo en ' . &#36;tiempo . '.';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;resultado = &#36;tsUser-&gt;loginUser(&#36;user, &#36;pass, &#36;reme);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;resultado === TRUE || is_numeric(&#36;resultado)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsLL-&gt;registrar(&#36;user, &#36;ip, true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsLL-&gt;resetear(&#36;user, &#36;ip);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &#36;resultado;<br />
&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsLL-&gt;registrar(&#36;user, &#36;ip, false);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;info = &#36;tsLL-&gt;procesarFallo(&#36;user, &#36;ip);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;restantes = &#36;info['restantes'];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;restantes &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &#36;resultado . ' (' . &#36;restantes . ' intento' . (&#36;restantes != 1 ? 's' : '') . ' restante' . (&#36;restantes != 1 ? 's' : '') . ')';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Cuenta bloqueada temporalmente por seguridad.';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ────────────────────<br />
&nbsp;&nbsp;&nbsp;&nbsp;//---&gt;<br />
break;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — Panel en el admin (opcional)</span><br />
<br />
Para ver el log desde el panel de admin añade en la plantilla <span style="font-weight: bold;" class="mycode_b">t.admin.pl</span> arriba de:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{/if}</code></div></div> <br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{elseif &#36;tsAction == 'loginlog'}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{include file='admin_mods/m.loginlog_admin.tpl'}</code></div></div><br />
<span style="font-size: large;" class="mycode_size">En admin.php buscar:</span><br />
 <br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">}&nbsp;elseif(</span><span style="color: #0000BB">&#36;action&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #DD0000">'feed'</span><span style="color: #007700">){&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Agregar antes:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>} elseif(&#36;action == 'loginlog'){<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.loginlog.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsLL = new tsLoginLog();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;smarty-&gt;assign('tsLoginLog', &#36;tsLL-&gt;getLog());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;smarty-&gt;assign('tsBloqueos', &#36;tsLL-&gt;getBloqueos());</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">En m.admin_sidemenu.tpl buscar:</span><br />
 <br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">&lt;</span><span style="color: #0000BB">h4</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">Usuarios</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">h4</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">ul&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"admin-nav-list"</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">li&nbsp;id</span><span style="color: #007700">=</span><span style="color: #DD0000">"a_users"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">a&nbsp;href</span><span style="color: #007700">=</span><span style="color: #DD0000">"</span><span style="color: #007700">{</span><span style="color: #0000BB">&#36;tsConfig</span><span style="color: #007700">.</span><span style="color: #0000BB">url</span><span style="color: #007700">}</span><span style="color: #DD0000">/admin/users"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">span&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"nav-icon"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">👤</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">Usuarios</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">a</span><span style="color: #007700">&gt;&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">li&nbsp;id</span><span style="color: #007700">=</span><span style="color: #DD0000">"a_sesiones"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">a&nbsp;href</span><span style="color: #007700">=</span><span style="color: #DD0000">"</span><span style="color: #007700">{</span><span style="color: #0000BB">&#36;tsConfig</span><span style="color: #007700">.</span><span style="color: #0000BB">url</span><span style="color: #007700">}</span><span style="color: #DD0000">/admin/sesiones"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">span&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"nav-icon"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">🔑</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">Sesiones</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">a</span><span style="color: #007700">&gt;&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">li&nbsp;id</span><span style="color: #007700">=</span><span style="color: #DD0000">"a_nicks"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">a&nbsp;href</span><span style="color: #007700">=</span><span style="color: #DD0000">"</span><span style="color: #007700">{</span><span style="color: #0000BB">&#36;tsConfig</span><span style="color: #007700">.</span><span style="color: #0000BB">url</span><span style="color: #007700">}</span><span style="color: #DD0000">/admin/nicks"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">span&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"nav-icon"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">🆔</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">Nicks</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">a</span><span style="color: #007700">&gt;&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">li&nbsp;id</span><span style="color: #007700">=</span><span style="color: #DD0000">"a_rangos"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">a&nbsp;href</span><span style="color: #007700">=</span><span style="color: #DD0000">"</span><span style="color: #007700">{</span><span style="color: #0000BB">&#36;tsConfig</span><span style="color: #007700">.</span><span style="color: #0000BB">url</span><span style="color: #007700">}</span><span style="color: #DD0000">/admin/rangos"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">span&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"nav-icon"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">💎</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">Rangos</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">a</span><span style="color: #007700">&gt;&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">ul</span><span style="color: #007700">&gt;&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Debajo agregar:</span><br />
 <br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">&lt;</span><span style="color: #0000BB">h4</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">Seguridad</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">h4</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">ul&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"admin-nav-list"</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">li&nbsp;id</span><span style="color: #007700">=</span><span style="color: #DD0000">"a_loginlog"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">a&nbsp;href</span><span style="color: #007700">=</span><span style="color: #DD0000">"</span><span style="color: #007700">{</span><span style="color: #0000BB">&#36;tsConfig</span><span style="color: #007700">.</span><span style="color: #0000BB">url</span><span style="color: #007700">}</span><span style="color: #DD0000">/admin/loginlog"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">span&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"nav-icon"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">🛡️</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">Protección&nbsp;Login</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">a</span><span style="color: #007700">&gt;&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">ul</span><span style="color: #007700">&gt;&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS w_login_log;<br />
DROP TABLE IF EXISTS w_login_bloqueos;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos subidos y restaura el <span style="font-weight: bold;" class="mycode_b">case 'login-user'</span> original en <span style="font-weight: bold;" class="mycode_b">ajax.login.php</span>.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span></div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Protección de Login v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Protección contra ataques de fuerza bruta en el login. Bloquea automáticamente por IP y por nick tras demasiados intentos fallidos, con bloqueo progresivo y log completo de accesos visible desde el panel de admin.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛡️ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Doble bloqueo</span> — por IP y por nombre de usuario de forma independiente</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Bloqueo progresivo</span> — 1er bloqueo 15 min, 2do 1 hora, 3er bloqueo y siguientes 24 horas</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">5 intentos</span> antes de bloquear (configurable en el código)</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Admin nunca se bloquea</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Login correcto resetea los contadores</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Log completo</span> — fecha, IP, nick y resultado de cada intento (guardado 7 días)</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Panel en el admin</span> — ver intentos y desbloquear manualmente con un clic</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Aviso al usuario</span> — muestra cuántos intentos le quedan antes del bloqueo</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">MySQL 5.7+ / MariaDB 10.4+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz del sitio y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Pulsa <span style="font-weight: bold;" class="mycode_b">Instalar ahora</span>. El instalador creará:</span><ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">w_login_log</span> — registro de todos los intentos de login</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">w_login_bloqueos</span> — bloqueos activos por IP y nick</span><br />
</li>
</ul>
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚠️ Elimina la carpeta install/ del servidor cuando termine.</span></span><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.loginlog.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ajax/ajax.loginlog.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/css/loginlog.css&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/css/<br />
themes/default/templates/modules/<br />
&nbsp;&nbsp;m.loginlog_admin.tpl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/modules/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — En ajax.login.php</span><br />
<br />
Abre <span style="font-weight: bold;" class="mycode_b">inc/php/ajax/ajax.login.php</span> y reemplaza el <span style="font-weight: bold;" class="mycode_b">case 'login-user'</span> completo por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>case 'login-user':<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&lt;---<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;user = &#36;tsCore-&gt;setSecure(&#36;_POST['nick']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;pass = &#36;tsCore-&gt;setSecure(&#36;_POST['pass']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;reme = ((&#36;_POST['rem'] ?? '') == 'true') ? true : false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(empty(&#36;user) or empty(&#36;pass)) echo '0: Faltan datos';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else echo &#36;tsUser-&gt;loginUser(&#36;user, &#36;pass, &#36;reme);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//---&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</code></div></div> <br />
<span style="font-size: large;" class="mycode_size">Cambiar por:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>case 'login-user':<br />
&nbsp;&nbsp;&nbsp;&nbsp;//&lt;---<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;user = &#36;tsCore-&gt;setSecure(&#36;_POST['nick']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;pass = &#36;tsCore-&gt;setSecure(&#36;_POST['pass']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;reme = ((&#36;_POST['rem'] ?? '') == 'true') ? true : false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;ip&nbsp;&nbsp; = &#36;tsCore-&gt;getIP();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (empty(&#36;user) || empty(&#36;pass)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Faltan datos';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ── Protección login ──<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.loginlog.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsLL = new tsLoginLog();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;bloqueo = &#36;tsLL-&gt;estaBloqueado(&#36;user, &#36;ip);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;bloqueo) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tiempo = &#36;tsLL-&gt;formatearTiempo(&#36;bloqueo['faltan']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Demasiados intentos fallidos. Inténtalo de nuevo en ' . &#36;tiempo . '.';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;resultado = &#36;tsUser-&gt;loginUser(&#36;user, &#36;pass, &#36;reme);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;resultado === TRUE || is_numeric(&#36;resultado)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsLL-&gt;registrar(&#36;user, &#36;ip, true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsLL-&gt;resetear(&#36;user, &#36;ip);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &#36;resultado;<br />
&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsLL-&gt;registrar(&#36;user, &#36;ip, false);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;info = &#36;tsLL-&gt;procesarFallo(&#36;user, &#36;ip);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;restantes = &#36;info['restantes'];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (&#36;restantes &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &#36;resultado . ' (' . &#36;restantes . ' intento' . (&#36;restantes != 1 ? 's' : '') . ' restante' . (&#36;restantes != 1 ? 's' : '') . ')';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo '0: Cuenta bloqueada temporalmente por seguridad.';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;// ────────────────────<br />
&nbsp;&nbsp;&nbsp;&nbsp;//---&gt;<br />
break;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — Panel en el admin (opcional)</span><br />
<br />
Para ver el log desde el panel de admin añade en la plantilla <span style="font-weight: bold;" class="mycode_b">t.admin.pl</span> arriba de:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{/if}</code></div></div> <br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{elseif &#36;tsAction == 'loginlog'}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{include file='admin_mods/m.loginlog_admin.tpl'}</code></div></div><br />
<span style="font-size: large;" class="mycode_size">En admin.php buscar:</span><br />
 <br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">}&nbsp;elseif(</span><span style="color: #0000BB">&#36;action&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #DD0000">'feed'</span><span style="color: #007700">){&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Agregar antes:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>} elseif(&#36;action == 'loginlog'){<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.loginlog.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsLL = new tsLoginLog();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;smarty-&gt;assign('tsLoginLog', &#36;tsLL-&gt;getLog());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;smarty-&gt;assign('tsBloqueos', &#36;tsLL-&gt;getBloqueos());</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">En m.admin_sidemenu.tpl buscar:</span><br />
 <br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">&lt;</span><span style="color: #0000BB">h4</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">Usuarios</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">h4</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">ul&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"admin-nav-list"</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">li&nbsp;id</span><span style="color: #007700">=</span><span style="color: #DD0000">"a_users"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">a&nbsp;href</span><span style="color: #007700">=</span><span style="color: #DD0000">"</span><span style="color: #007700">{</span><span style="color: #0000BB">&#36;tsConfig</span><span style="color: #007700">.</span><span style="color: #0000BB">url</span><span style="color: #007700">}</span><span style="color: #DD0000">/admin/users"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">span&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"nav-icon"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">👤</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">Usuarios</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">a</span><span style="color: #007700">&gt;&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">li&nbsp;id</span><span style="color: #007700">=</span><span style="color: #DD0000">"a_sesiones"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">a&nbsp;href</span><span style="color: #007700">=</span><span style="color: #DD0000">"</span><span style="color: #007700">{</span><span style="color: #0000BB">&#36;tsConfig</span><span style="color: #007700">.</span><span style="color: #0000BB">url</span><span style="color: #007700">}</span><span style="color: #DD0000">/admin/sesiones"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">span&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"nav-icon"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">🔑</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">Sesiones</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">a</span><span style="color: #007700">&gt;&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">li&nbsp;id</span><span style="color: #007700">=</span><span style="color: #DD0000">"a_nicks"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">a&nbsp;href</span><span style="color: #007700">=</span><span style="color: #DD0000">"</span><span style="color: #007700">{</span><span style="color: #0000BB">&#36;tsConfig</span><span style="color: #007700">.</span><span style="color: #0000BB">url</span><span style="color: #007700">}</span><span style="color: #DD0000">/admin/nicks"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">span&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"nav-icon"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">🆔</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">Nicks</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">a</span><span style="color: #007700">&gt;&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">li&nbsp;id</span><span style="color: #007700">=</span><span style="color: #DD0000">"a_rangos"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">a&nbsp;href</span><span style="color: #007700">=</span><span style="color: #DD0000">"</span><span style="color: #007700">{</span><span style="color: #0000BB">&#36;tsConfig</span><span style="color: #007700">.</span><span style="color: #0000BB">url</span><span style="color: #007700">}</span><span style="color: #DD0000">/admin/rangos"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">span&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"nav-icon"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">💎</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">Rangos</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">a</span><span style="color: #007700">&gt;&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">ul</span><span style="color: #007700">&gt;&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Debajo agregar:</span><br />
 <br />
<div class="codeblock phpcodeblock"><div class="title">Código PHP:</div><div class="body"><div dir="ltr"><code><span style="color: #007700">&lt;</span><span style="color: #0000BB">h4</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">Seguridad</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">h4</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">ul&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"admin-nav-list"</span><span style="color: #007700">&gt;<br />&lt;</span><span style="color: #0000BB">li&nbsp;id</span><span style="color: #007700">=</span><span style="color: #DD0000">"a_loginlog"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">a&nbsp;href</span><span style="color: #007700">=</span><span style="color: #DD0000">"</span><span style="color: #007700">{</span><span style="color: #0000BB">&#36;tsConfig</span><span style="color: #007700">.</span><span style="color: #0000BB">url</span><span style="color: #007700">}</span><span style="color: #DD0000">/admin/loginlog"</span><span style="color: #007700">&gt;&lt;</span><span style="color: #0000BB">span&nbsp;</span><span style="color: #007700">class=</span><span style="color: #DD0000">"nav-icon"</span><span style="color: #007700">&gt;</span><span style="color: #0000BB">🛡️</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">span</span><span style="color: #007700">&gt;&nbsp;</span><span style="color: #0000BB">Protección&nbsp;Login</span><span style="color: #007700">&lt;/</span><span style="color: #0000BB">a</span><span style="color: #007700">&gt;&lt;/</span><span style="color: #0000BB">li</span><span style="color: #007700">&gt;<br />&lt;/</span><span style="color: #0000BB">ul</span><span style="color: #007700">&gt;&nbsp;<br /></span></code></div></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS w_login_log;<br />
DROP TABLE IF EXISTS w_login_bloqueos;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos subidos y restaura el <span style="font-weight: bold;" class="mycode_b">case 'login-user'</span> original en <span style="font-weight: bold;" class="mycode_b">ajax.login.php</span>.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span></div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Vídeos y Medios Embebidos v1.0]]></title>
			<link>https://phpost.es/thread-985.html</link>
			<pubDate>Wed, 27 May 2026 17:08:30 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-985.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Vídeos y Medios Embebidos v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Con este mod basta con pegar una URL en el cuerpo de un post para que se convierta automáticamente en el player embebido correspondiente. Sin etiquetas especiales, sin código — solo la URL en una línea.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-weight: bold;" class="mycode_b"><span style="font-size: x-large;" class="mycode_size">▶ Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">▶ Plataformas soportadas</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">YouTube</span> — youtube.com/watch?v=ID, youtu.be/ID y /shorts/ID</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Vimeo</span> — vimeo.com/ID</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Twitter / X</span> — tweets embebidos con el widget oficial</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Spotify</span> — canciones, álbumes, playlists, podcasts y episodios</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">TikTok</span> — vídeos embebidos con el widget oficial</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">✨ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Sin instalador — no crea tablas ni modifica la base de datos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Detección automática de la plataforma por la URL</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Player responsive adaptado a móvil</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Carga lazy para no ralentizar la página</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">No modifica los datos guardados en BD, solo el renderizado</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Spotify adapta la altura según el tipo (track/podcast = compacto, álbum/playlist = expandido)</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🔒 Seguridad</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Cada URL pasa por una cadena de validaciones antes de generar el embed:</span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">IDs estrictamente validados</span> — YouTube acepta solo exactamente 11 caracteres alfanuméricos. Vimeo solo dígitos. Twitter, TikTok y Spotify tienen sus propios rangos y patrones</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Lista blanca de tipos en Spotify</span> — solo se permiten track, album, playlist, episode y show. Cualquier otro valor se ignora</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Sandbox en iframes</span> — todos los iframes tienen el atributo sandbox con los permisos mínimos necesarios para funcionar</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">youtube-nocookie.com</span> — YouTube se carga desde el dominio de privacidad mejorada para no rastrear a los usuarios</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Vimeo con ?dnt=1</span> — Do Not Track activado</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">URLs reconstruidas</span> — nunca se usa la URL original del usuario directamente en el src del iframe. Se construye una URL nueva y limpia con el ID validado</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Si el ID no pasa la validación</span> — se deja la URL original sin tocar en lugar de romper el post</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.embed.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
themes/default/css/embed.css →&nbsp;&nbsp;themes/default/css/</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — En c.posts.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">inc/class/c.posts.php</span> y busca dentro de <span style="color: #2980b9;" class="mycode_color"><span style="font-weight: bold;" class="mycode_b">getPost()</span></span> este bloque:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&#36;postData['post_body'] = preg_replace(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'/&lt;oembed url="https:&#92;/&#92;/www&#92;.youtube&#92;.com&#92;/watch&#92;?v=([^"]+)"&gt;&lt;&#92;/oembed&gt;/s',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'&lt;iframe width="560" height="315" src="Registrate o inicia tu sesión para ver este contenido" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;postData['post_body']<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Justo después añade:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Embeds automáticos ──<br />
require_once TS_CLASS . 'c.embed.php';<br />
&#36;tsEmbed = new tsEmbed();<br />
&#36;postData['post_body'] = &#36;tsEmbed-&gt;process(&#36;postData['post_body']);<br />
// ────────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📝 Uso</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Al crear un post pega la URL en el cuerpo en una línea aparte:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Mira este vídeo:<br />
Registrate o inicia tu sesión para ver este contenido<br />
<br />
Y esta canción:<br />
Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-size: large;" class="mycode_size">El mod la detecta y la convierte automáticamente en el player al mostrar el post.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Elimina <span style="font-weight: bold;" class="mycode_b">inc/class/c.embed.php</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Elimina <span style="font-weight: bold;" class="mycode_b">themes/default/css/embed.css</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Quita el hook añadido en <span style="font-weight: bold;" class="mycode_b">c.posts.php</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Borra la caché</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Mediafire</span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenidoídeos+y+Medios+Embebidos+v1.0.rar/file" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par...0.rar/file</a><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Google Drive</span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
</div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Vídeos y Medios Embebidos v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Con este mod basta con pegar una URL en el cuerpo de un post para que se convierta automáticamente en el player embebido correspondiente. Sin etiquetas especiales, sin código — solo la URL en una línea.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-weight: bold;" class="mycode_b"><span style="font-size: x-large;" class="mycode_size">▶ Captura</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">▶ Plataformas soportadas</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">YouTube</span> — youtube.com/watch?v=ID, youtu.be/ID y /shorts/ID</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Vimeo</span> — vimeo.com/ID</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Twitter / X</span> — tweets embebidos con el widget oficial</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Spotify</span> — canciones, álbumes, playlists, podcasts y episodios</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">TikTok</span> — vídeos embebidos con el widget oficial</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">✨ Características</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Sin instalador — no crea tablas ni modifica la base de datos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Detección automática de la plataforma por la URL</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Player responsive adaptado a móvil</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Carga lazy para no ralentizar la página</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">No modifica los datos guardados en BD, solo el renderizado</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Spotify adapta la altura según el tipo (track/podcast = compacto, álbum/playlist = expandido)</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🔒 Seguridad</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Cada URL pasa por una cadena de validaciones antes de generar el embed:</span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">IDs estrictamente validados</span> — YouTube acepta solo exactamente 11 caracteres alfanuméricos. Vimeo solo dígitos. Twitter, TikTok y Spotify tienen sus propios rangos y patrones</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Lista blanca de tipos en Spotify</span> — solo se permiten track, album, playlist, episode y show. Cualquier otro valor se ignora</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Sandbox en iframes</span> — todos los iframes tienen el atributo sandbox con los permisos mínimos necesarios para funcionar</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">youtube-nocookie.com</span> — YouTube se carga desde el dominio de privacidad mejorada para no rastrear a los usuarios</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Vimeo con ?dnt=1</span> — Do Not Track activado</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">URLs reconstruidas</span> — nunca se usa la URL original del usuario directamente en el src del iframe. Se construye una URL nueva y limpia con el ID validado</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Si el ID no pasa la validación</span> — se deja la URL original sin tocar en lugar de romper el post</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Risus Nova 2.0 instalado y funcionando</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">PHP 8.0+</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.embed.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
themes/default/css/embed.css →&nbsp;&nbsp;themes/default/css/</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — En c.posts.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">inc/class/c.posts.php</span> y busca dentro de <span style="color: #2980b9;" class="mycode_color"><span style="font-weight: bold;" class="mycode_b">getPost()</span></span> este bloque:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&#36;postData['post_body'] = preg_replace(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'/&lt;oembed url="https:&#92;/&#92;/www&#92;.youtube&#92;.com&#92;/watch&#92;?v=([^"]+)"&gt;&lt;&#92;/oembed&gt;/s',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'&lt;iframe width="560" height="315" src="Registrate o inicia tu sesión para ver este contenido" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;',<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;postData['post_body']<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Justo después añade:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Embeds automáticos ──<br />
require_once TS_CLASS . 'c.embed.php';<br />
&#36;tsEmbed = new tsEmbed();<br />
&#36;postData['post_body'] = &#36;tsEmbed-&gt;process(&#36;postData['post_body']);<br />
// ────────────────────────</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📝 Uso</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Al crear un post pega la URL en el cuerpo en una línea aparte:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Mira este vídeo:<br />
Registrate o inicia tu sesión para ver este contenido<br />
<br />
Y esta canción:<br />
Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-size: large;" class="mycode_size">El mod la detecta y la convierte automáticamente en el player al mostrar el post.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Elimina <span style="font-weight: bold;" class="mycode_b">inc/class/c.embed.php</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Elimina <span style="font-weight: bold;" class="mycode_b">themes/default/css/embed.css</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Quita el hook añadido en <span style="font-weight: bold;" class="mycode_b">c.posts.php</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Borra la caché</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Mediafire</span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenidoídeos+y+Medios+Embebidos+v1.0.rar/file" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par...0.rar/file</a><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Google Drive</span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="font-size: large;" class="mycode_size">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span><br />
</div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Sistema de Encuestas en Posts v1.0]]></title>
			<link>https://phpost.es/thread-984.html</link>
			<pubDate>Wed, 27 May 2026 14:53:31 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-984.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Sistema de Encuestas en Posts v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Sistema de Encuestas en <span style="font-weight: bold;" class="mycode_b">Posts v1.0</span> para <span style="font-weight: bold;" class="mycode_b">Risus Nova 2.0</span>: el <span style="font-weight: bold;" class="mycode_b">Sistema de Encuestas en Posts</span>. Al crear un post puedes añadir una encuesta opcional con hasta 8 opciones. Los usuarios votan directamente desde el post y los resultados se actualizan en tiempo real sin recargar la página.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📊 ¿Qué incluye?</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Encuesta opcional al crear cualquier post</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Hasta 8 opciones por encuesta</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Duración configurable — se puede poner fecha de cierre o sin límite</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Resultados en tiempo real con barras de progreso animadas</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Anti-doble voto por usuario y por IP</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Los usuarios no registrados ven los resultados pero no pueden votar</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Encuestas cerradas siguen mostrando resultados</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Al votar el formulario se transforma en resultados sin recargar</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span><br />
<br />
Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz del sitio y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Pulsa <span style="font-weight: bold;" class="mycode_b">Instalar ahora</span>. El instalador creará 3 tablas:</span><ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">p_encuestas</span> — encuestas ligadas a posts</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">p_encuestas_opciones</span> — opciones de cada encuesta</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">p_encuestas_votos</span> — registro de votos por usuario e IP</span><br />
</li>
</ul>
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚠️ Elimina la carpeta install/ del servidor cuando termine.</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.encuestas.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ajax/ajax.encuesta.php&nbsp;&nbsp;&nbsp;&nbsp; →&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/css/encuesta.css&nbsp;&nbsp; →&nbsp;&nbsp;themes/default/css/<br />
themes/default/templates/modules/m.encuesta.tpl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/modules/<br />
themes/default/templates/modules/m.encuesta_form.tpl →&nbsp;&nbsp;themes/default/templates/modules/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — c.posts.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">inc/class/c.posts.php</span> y busca el <span style="font-weight: bold;" class="mycode_b">return &#36;postID;</span> al final de la función <span style="font-weight: bold;" class="mycode_b">newPost()</span>. Añade justo antes:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Encuesta ──<br />
if (!empty(&#36;_POST['enc_pregunta']) &amp;&amp; !empty(&#36;_POST['enc_opciones'])) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.encuestas.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsEncObj = new tsEncuestas();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsEncObj-&gt;crearEncuesta(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;postID,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;_POST['enc_pregunta'],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;_POST['enc_opciones'],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(int)(&#36;_POST['enc_expira_dias'] ?? 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
}<br />
// ────────────<br />
return &#36;postID;</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — posts.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">inc/php/posts.php</span> y busca:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// PAGINAS<br />
&#36;total = &#36;tsPost['post_comments'];</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Añade justo antes:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Encuesta ──<br />
require_once TS_CLASS . 'c.encuestas.php';<br />
&#36;tsEncObj&nbsp;&nbsp; = new tsEncuestas();<br />
&#36;tsEncuesta = &#36;tsEncObj-&gt;getEncuesta(&#36;tsPost['post_id']);<br />
if (&#36;tsEncuesta &amp;&amp; !empty(&#36;tsEncuesta['opciones'])) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;foreach (&#36;tsEncuesta['opciones'] as &amp;&#36;op) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;op['pct'] = &#36;tsEncuesta['total_votos'] &gt; 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;? round(&#36;op['votos'] / &#36;tsEncuesta['total_votos'] * 100, 1)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;unset(&#36;op);<br />
}<br />
&#36;ip&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = &#36;tsCore-&gt;getIP();<br />
&#36;tsYaVoto&nbsp;&nbsp; = &#36;tsEncuesta ? &#36;tsEncObj-&gt;yaVoto(&#36;tsEncuesta['enc_id'], &#36;tsUser-&gt;uid, &#36;ip) : false;<br />
&#36;tsMiOpcion = &#36;tsEncuesta ? &#36;tsEncObj-&gt;opcionVotada(&#36;tsEncuesta['enc_id'], &#36;tsUser-&gt;uid, &#36;ip) : 0;<br />
&#36;smarty-&gt;assign('tsEncuesta',&nbsp;&nbsp;&#36;tsEncuesta);<br />
&#36;smarty-&gt;assign('tsYaVoto',&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsYaVoto);<br />
&#36;smarty-&gt;assign('tsMiOpcion',&nbsp;&nbsp;&#36;tsMiOpcion);<br />
// ────────────</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Mostrar la encuesta en el post</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/modules/m.posts_content.tpl</span> y busca:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;div class="compartir-risus-banner"&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Añade justo antes:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{include file='modules/m.encuesta.tpl'}</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 6 — Formulario al crear un post</span><br />
<br />
Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/modules/m.agregar.form.tpl</span> y busca el bloque de opciones de publicación (donde está el checkbox de "Solo usuarios registrados"). Añade después del cierre de ese bloque:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{include file='modules/m.encuesta_form.tpl'}</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 7 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS p_encuestas;<br />
DROP TABLE IF EXISTS p_encuestas_opciones;<br />
DROP TABLE IF EXISTS p_encuestas_votos;</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos subidos y quita los hooks añadidos en los pasos 3, 4, 5 y 6.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido://www.mediafire.com/file/o3ucnr12tki963x/Sistema+de+Encuestas+en+Posts+v1.0.rar/file" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par...0.rar/file</a><br />
<br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span></span></span><br />
<br />
</div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Sistema de Encuestas en Posts v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Sistema de Encuestas en <span style="font-weight: bold;" class="mycode_b">Posts v1.0</span> para <span style="font-weight: bold;" class="mycode_b">Risus Nova 2.0</span>: el <span style="font-weight: bold;" class="mycode_b">Sistema de Encuestas en Posts</span>. Al crear un post puedes añadir una encuesta opcional con hasta 8 opciones. Los usuarios votan directamente desde el post y los resultados se actualizan en tiempo real sin recargar la página.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
 <br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📊 ¿Qué incluye?</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Encuesta opcional al crear cualquier post</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Hasta 8 opciones por encuesta</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Duración configurable — se puede poner fecha de cierre o sin límite</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Resultados en tiempo real con barras de progreso animadas</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Anti-doble voto por usuario y por IP</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Los usuarios no registrados ven los resultados pero no pueden votar</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Encuestas cerradas siguen mostrando resultados</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Al votar el formulario se transforma en resultados sin recargar</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span><br />
<br />
Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> a la raíz del sitio y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Pulsa <span style="font-weight: bold;" class="mycode_b">Instalar ahora</span>. El instalador creará 3 tablas:</span><ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">p_encuestas</span> — encuestas ligadas a posts</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">p_encuestas_opciones</span> — opciones de cada encuesta</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">p_encuestas_votos</span> — registro de votos por usuario e IP</span><br />
</li>
</ul>
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚠️ Elimina la carpeta install/ del servidor cuando termine.</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.encuestas.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;inc/class/<br />
inc/php/ajax/ajax.encuesta.php&nbsp;&nbsp;&nbsp;&nbsp; →&nbsp;&nbsp;inc/php/ajax/<br />
themes/default/css/encuesta.css&nbsp;&nbsp; →&nbsp;&nbsp;themes/default/css/<br />
themes/default/templates/modules/m.encuesta.tpl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/modules/<br />
themes/default/templates/modules/m.encuesta_form.tpl →&nbsp;&nbsp;themes/default/templates/modules/</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — c.posts.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">inc/class/c.posts.php</span> y busca el <span style="font-weight: bold;" class="mycode_b">return &#36;postID;</span> al final de la función <span style="font-weight: bold;" class="mycode_b">newPost()</span>. Añade justo antes:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Encuesta ──<br />
if (!empty(&#36;_POST['enc_pregunta']) &amp;&amp; !empty(&#36;_POST['enc_opciones'])) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;require_once TS_CLASS . 'c.encuestas.php';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsEncObj = new tsEncuestas();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsEncObj-&gt;crearEncuesta(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;postID,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;_POST['enc_pregunta'],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;_POST['enc_opciones'],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(int)(&#36;_POST['enc_expira_dias'] ?? 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;);<br />
}<br />
// ────────────<br />
return &#36;postID;</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — posts.php</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">inc/php/posts.php</span> y busca:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// PAGINAS<br />
&#36;total = &#36;tsPost['post_comments'];</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Añade justo antes:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>// ── Encuesta ──<br />
require_once TS_CLASS . 'c.encuestas.php';<br />
&#36;tsEncObj&nbsp;&nbsp; = new tsEncuestas();<br />
&#36;tsEncuesta = &#36;tsEncObj-&gt;getEncuesta(&#36;tsPost['post_id']);<br />
if (&#36;tsEncuesta &amp;&amp; !empty(&#36;tsEncuesta['opciones'])) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;foreach (&#36;tsEncuesta['opciones'] as &amp;&#36;op) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#36;op['pct'] = &#36;tsEncuesta['total_votos'] &gt; 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;? round(&#36;op['votos'] / &#36;tsEncuesta['total_votos'] * 100, 1)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;unset(&#36;op);<br />
}<br />
&#36;ip&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = &#36;tsCore-&gt;getIP();<br />
&#36;tsYaVoto&nbsp;&nbsp; = &#36;tsEncuesta ? &#36;tsEncObj-&gt;yaVoto(&#36;tsEncuesta['enc_id'], &#36;tsUser-&gt;uid, &#36;ip) : false;<br />
&#36;tsMiOpcion = &#36;tsEncuesta ? &#36;tsEncObj-&gt;opcionVotada(&#36;tsEncuesta['enc_id'], &#36;tsUser-&gt;uid, &#36;ip) : 0;<br />
&#36;smarty-&gt;assign('tsEncuesta',&nbsp;&nbsp;&#36;tsEncuesta);<br />
&#36;smarty-&gt;assign('tsYaVoto',&nbsp;&nbsp;&nbsp;&nbsp;&#36;tsYaVoto);<br />
&#36;smarty-&gt;assign('tsMiOpcion',&nbsp;&nbsp;&#36;tsMiOpcion);<br />
// ────────────</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Mostrar la encuesta en el post</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/modules/m.posts_content.tpl</span> y busca:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;div class="compartir-risus-banner"&gt;</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Añade justo antes:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{include file='modules/m.encuesta.tpl'}</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 6 — Formulario al crear un post</span><br />
<br />
Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/modules/m.agregar.form.tpl</span> y busca el bloque de opciones de publicación (donde está el checkbox de "Solo usuarios registrados"). Añade después del cierre de ese bloque:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>{include file='modules/m.encuesta_form.tpl'}</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 7 — Borrar la caché</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> del sitio.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS p_encuestas;<br />
DROP TABLE IF EXISTS p_encuestas_opciones;<br />
DROP TABLE IF EXISTS p_encuestas_votos;</code></div></div><br />
<br />
<span style="font-size: large;" class="mycode_size">Elimina los archivos subidos y quita los hooks añadidos en los pasos 3, 4, 5 y 6.</span><br />
<hr class="mycode_hr" />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido://www.mediafire.com/file/o3ucnr12tki963x/Sistema+de+Encuestas+en+Posts+v1.0.rar/file" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par...0.rar/file</a><br />
<br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<br />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span></span></span><br />
<br />
</div>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Tienda de Puntos v1.0]]></title>
			<link>https://phpost.es/thread-983.html</link>
			<pubDate>Tue, 26 May 2026 21:25:03 +0200</pubDate>
			<dc:creator><![CDATA[<a href="https://phpost.es/member.php?action=profile&uid=1">Tronlar</a>]]></dc:creator>
			<guid isPermaLink="false">https://phpost.es/thread-983.html</guid>
			<description><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Tienda de Puntos v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Primer complemento oficial para <span style="font-weight: bold;" class="mycode_b">Risus Nova 2.0</span>: la <span style="font-weight: bold;" class="mycode_b">Tienda de Puntos</span>. Permite a los usuarios gastar sus puntos acumulados en mejoras para su perfil y sus posts.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛒 ¿Qué incluye?</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Cambio de nick</span> — Los usuarios pueden cambiar su nombre una vez cada 30 días.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Título personalizado</span> — Un texto exclusivo que aparece bajo el nick en comentarios y perfil.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Color de nombre</span> — Personaliza el color del nick con cualquier color hexadecimal.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Marco de avatar</span> — Añade un marco especial alrededor del avatar.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Destacar post 24h</span> — El post aparece destacado en la portada durante 24 horas.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Post fijado 48h</span> — El post queda fijado en su categoría durante 48 horas.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Subir de rango</span> — Sube al siguiente rango sin necesidad de acumular más puntos.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Medallas</span> — Obtén medallas exclusivas para el perfil.</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Risus Nova 2.0</span> instalado y funcionando</span><br />
</li>
<li><span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">PHP 8.0+</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">MySQL 5.7+</span> / <span style="font-weight: bold;" class="mycode_b">MariaDB 10.4+</span></span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #2196f3;" class="mycode_color">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> del ZIP a la raíz de tu sitio y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Pulsa <span style="font-weight: bold;" class="mycode_b">Instalar ahora</span>. El instalador creará automáticamente:</span><ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Tabla <span style="font-weight: bold;" class="mycode_b">w_tienda</span> — catálogo de artículos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Tabla <span style="font-weight: bold;" class="mycode_b">w_tienda_compras</span> — historial de compras</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Columnas nuevas en <span style="font-weight: bold;" class="mycode_b">u_miembros</span>: user_title, user_name_color, user_avatar_frame</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Columnas nuevas en <span style="font-weight: bold;" class="mycode_b">p_posts</span>: post_featured, post_sticky_until</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">8 artículos de ejemplo con precios predefinidos</span><br />
</li>
</ul>
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚠️ Elimina la carpeta install/ del servidor cuando termine.</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.tienda.php&nbsp;&nbsp;&nbsp;&nbsp; →&nbsp;&nbsp;inc/class/<br />
inc/php/tienda.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; →&nbsp;&nbsp;inc/php/<br />
themes/default/css/tienda.css&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/css/<br />
themes/default/t.tienda.tpl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/<br />
themes/default/t.tienda.historial.tpl&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/<br />
themes/default/t.tienda.admin.tpl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/<br />
themes/default/t.tienda.admin.form.tpl →&nbsp;&nbsp;themes/default/templates/</code></div></div><br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — Añadir el CSS en el header</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/sections/main_header.tpl</span> y añade esta línea junto al resto de CSS:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;link href="{&#36;tsConfig.css}/tienda.css" rel="stylesheet" type="text/css"&gt;</code></div></div><br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — Añadir el enlace en el menú</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/sections/head_menu.tpl</span> y añade este elemento en el menú principal:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;li class="tabbed {if &#36;tsPage == 'tienda'}here{/if}" id="tabbedtienda"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;a title="Ir a la Tienda" onclick="menu('tienda', this.href); return false;" href="{&#36;tsConfig.url}/tienda/"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;i class="fa-solid fa-store"&gt;&lt;/i&gt; Tienda<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/a&gt;<br />
&lt;/li&gt;</code></div></div><br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Borrar la caché</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> desde el panel de administración o desde el gestor de archivos del hosting.</span><br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #2196f3;" class="mycode_color">⚙️ Gestionar los artículos</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Accede como administrador a <span style="font-weight: bold;" class="mycode_b">tudominio.com/tienda/?action=admin</span> para:</span><ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Crear nuevos artículos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Editar precios y descripciones</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Activar o desactivar artículos</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #e74c3c;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Si quieres eliminar el complemento, ejecuta esto en <span style="font-weight: bold;" class="mycode_b">phpMyAdmin</span>:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS w_tienda;<br />
DROP TABLE IF EXISTS w_tienda_compras;<br />
ALTER TABLE u_miembros DROP COLUMN user_title;<br />
ALTER TABLE u_miembros DROP COLUMN user_name_color;<br />
ALTER TABLE u_miembros DROP COLUMN user_avatar_frame;<br />
ALTER TABLE p_posts DROP COLUMN post_featured;<br />
ALTER TABLE p_posts DROP COLUMN post_sticky_until;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Y elimina los archivos subidos en el paso 2.</span></span><br />
<hr class="mycode_hr" />
 <br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]<br />
<br />
[img]Registrate o inicia tu sesión para ver este contenido[/img]<br />
<br />
[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<br />
<br />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #e74c3c;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span></span></span></div>]]></description>
			<content:encoded><![CDATA[<div style="text-align: center;" class="mycode_align"><span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Tienda de Puntos v1.0</span></span></span><br />
<span style="font-size: large;" class="mycode_size">Nuevo módulo para Risus Nova 2.0 — PHPost</span></div>
<hr class="mycode_hr" />
<br />
<span style="font-size: large;" class="mycode_size">Primer complemento oficial para <span style="font-weight: bold;" class="mycode_b">Risus Nova 2.0</span>: la <span style="font-weight: bold;" class="mycode_b">Tienda de Puntos</span>. Permite a los usuarios gastar sus puntos acumulados en mejoras para su perfil y sus posts.</span><br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🛒 ¿Qué incluye?</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Cambio de nick</span> — Los usuarios pueden cambiar su nombre una vez cada 30 días.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Título personalizado</span> — Un texto exclusivo que aparece bajo el nick en comentarios y perfil.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Color de nombre</span> — Personaliza el color del nick con cualquier color hexadecimal.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Marco de avatar</span> — Añade un marco especial alrededor del avatar.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Destacar post 24h</span> — El post aparece destacado en la portada durante 24 horas.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Post fijado 48h</span> — El post queda fijado en su categoría durante 48 horas.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Subir de rango</span> — Sube al siguiente rango sin necesidad de acumular más puntos.</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Medallas</span> — Obtén medallas exclusivas para el perfil.</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">📋 Requisitos</span></span></span><br />
 <ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Risus Nova 2.0</span> instalado y funcionando</span><br />
</li>
<li><span style="font-weight: bold;" class="mycode_b"><span style="font-size: large;" class="mycode_size">PHP 8.0+</span></span><br />
</li>
<li><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">MySQL 5.7+</span> / <span style="font-weight: bold;" class="mycode_b">MariaDB 10.4+</span></span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #2196f3;" class="mycode_color">🛠️ Instalación</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 1 — Ejecutar el instalador</span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Sube la carpeta <span style="font-weight: bold;" class="mycode_b">install/</span> del ZIP a la raíz de tu sitio y accede a:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>Registrate o inicia tu sesión para ver este contenido</code></div></div><br />
<span style="font-size: large;" class="mycode_size">Pulsa <span style="font-weight: bold;" class="mycode_b">Instalar ahora</span>. El instalador creará automáticamente:</span><ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Tabla <span style="font-weight: bold;" class="mycode_b">w_tienda</span> — catálogo de artículos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Tabla <span style="font-weight: bold;" class="mycode_b">w_tienda_compras</span> — historial de compras</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Columnas nuevas en <span style="font-weight: bold;" class="mycode_b">u_miembros</span>: user_title, user_name_color, user_avatar_frame</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Columnas nuevas en <span style="font-weight: bold;" class="mycode_b">p_posts</span>: post_featured, post_sticky_until</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">8 artículos de ejemplo con precios predefinidos</span><br />
</li>
</ul>
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">⚠️ Elimina la carpeta install/ del servidor cuando termine.</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 2 — Subir los archivos</span></span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>inc/class/c.tienda.php&nbsp;&nbsp;&nbsp;&nbsp; →&nbsp;&nbsp;inc/class/<br />
inc/php/tienda.php&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; →&nbsp;&nbsp;inc/php/<br />
themes/default/css/tienda.css&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/css/<br />
themes/default/t.tienda.tpl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/<br />
themes/default/t.tienda.historial.tpl&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/<br />
themes/default/t.tienda.admin.tpl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;→&nbsp;&nbsp;themes/default/templates/<br />
themes/default/t.tienda.admin.form.tpl →&nbsp;&nbsp;themes/default/templates/</code></div></div><br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 3 — Añadir el CSS en el header</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/sections/main_header.tpl</span> y añade esta línea junto al resto de CSS:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;link href="{&#36;tsConfig.css}/tienda.css" rel="stylesheet" type="text/css"&gt;</code></div></div><br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 4 — Añadir el enlace en el menú</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Abre <span style="font-weight: bold;" class="mycode_b">themes/default/templates/sections/head_menu.tpl</span> y añade este elemento en el menú principal:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>&lt;li class="tabbed {if &#36;tsPage == 'tienda'}here{/if}" id="tabbedtienda"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;a title="Ir a la Tienda" onclick="menu('tienda', this.href); return false;" href="{&#36;tsConfig.url}/tienda/"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;i class="fa-solid fa-store"&gt;&lt;/i&gt; Tienda<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/a&gt;<br />
&lt;/li&gt;</code></div></div><br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Paso 5 — Borrar la caché</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Borra el contenido de la carpeta <span style="font-weight: bold;" class="mycode_b">/cache/</span> desde el panel de administración o desde el gestor de archivos del hosting.</span><br />
<hr class="mycode_hr" />
<br />
<span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b"><span style="color: #2196f3;" class="mycode_color">⚙️ Gestionar los artículos</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Accede como administrador a <span style="font-weight: bold;" class="mycode_b">tudominio.com/tienda/?action=admin</span> para:</span><ul class="mycode_list"><li><span style="font-size: large;" class="mycode_size">Crear nuevos artículos</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Editar precios y descripciones</span><br />
</li>
<li><span style="font-size: large;" class="mycode_size">Activar o desactivar artículos</span><br />
</li>
</ul>
 <br />
<hr class="mycode_hr" />
<br />
<span style="color: #e74c3c;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">🗑️ Desinstalar</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size">Si quieres eliminar el complemento, ejecuta esto en <span style="font-weight: bold;" class="mycode_b">phpMyAdmin</span>:</span><br />
 <br />
<div class="codeblock"><div class="title">Código:</div><div class="body" dir="ltr"><code>DROP TABLE IF EXISTS w_tienda;<br />
DROP TABLE IF EXISTS w_tienda_compras;<br />
ALTER TABLE u_miembros DROP COLUMN user_title;<br />
ALTER TABLE u_miembros DROP COLUMN user_name_color;<br />
ALTER TABLE u_miembros DROP COLUMN user_avatar_frame;<br />
ALTER TABLE p_posts DROP COLUMN post_featured;<br />
ALTER TABLE p_posts DROP COLUMN post_sticky_until;</code></div></div><br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Y elimina los archivos subidos en el paso 2.</span></span><br />
<hr class="mycode_hr" />
 <br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Capturas</span></span></span><br />
<div style="text-align: center;" class="mycode_align">[img]Registrate o inicia tu sesión para ver este contenido[/img]<br />
<br />
[img]Registrate o inicia tu sesión para ver este contenido[/img]<br />
<br />
[img]Registrate o inicia tu sesión para ver este contenido[/img]</div>
<br />
<br />
 <br />
<div style="text-align: center;" class="mycode_align"><span style="color: #e74c3c;" class="mycode_color"><span style="font-size: x-large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Descarga</span></span></span><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Mediafire</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">Google Drive</span></span><br />
<a href="http://Registrate%20o%20inicia%20tu%20sesión%20para%20ver%20este%20contenido" target="_blank" rel="noopener" class="mycode_url">http://Registrate o inicia tu sesión par... contenido</a><br />
<br />
<br />
<span style="color: #2980b9;" class="mycode_color"><span style="font-size: large;" class="mycode_size"><span style="font-weight: bold;" class="mycode_b">¿Tienes dudas o encuentras algún problema? Déjalo en los comentarios.</span></span></span></div>]]></content:encoded>
		</item>
	</channel>
</rss>