<?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 - Complementos]]></title>
		<link>https://phpost.es/</link>
		<description><![CDATA[Phpost - https://phpost.es]]></description>
		<pubDate>Wed, 27 May 2026 19:02:15 +0000</pubDate>
		<generator>MyBB</generator>
		<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 />
<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 />
<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 />
<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 />
<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 />
<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 />
<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>