Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal

Search the Community

Showing results for tags 'php'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • El núcleo de PHPost
    • Novedades e información
    • Off Topic
    • Presentaciones
  • PHPost Risus
    • Actualizaciones
    • Versión 1.1
    • Versión 1.2
  • La esquina
    • Rincón del PC
    • Rincón del móvil
  • Actualizaciones individuales de PHPost Risus's PHP 7/8
  • Actualizaciones individuales de PHPost Risus's Smarty
  • Actualizaciones individuales de PHPost Risus's EXTRAS
  • Actualizaciones individuales de PHPost Risus's Fixes
  • Actualizaciones individuales de PHPost Risus's Actualizaciones
  • Actualizaciones individuales de PHPost Risus's Complementos

Calendars

There are no results to display.

There are no results to display.


Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Sitio web


ICQ


Yahoo


Jabber


Skype


Localización


Intereses

Found 15 results

  1. Obviamente por el momento tendrá varios errores! Hola a todos, presento "una actualización"(lo estoy haciendo de a poco) que ustedes podrán descargar desde mi repositorio aunque este no será parte del oficial, pero le estoy dando o tratando de dar una 2da oportunidad. Comunidad en discord https://discord.gg/gbg8fce3BF solo info de los últimos cambios!Hasta ahora tiene la última versión de Smarty 4.3.0, la última versión de jQuery 3.6.3 y las librerías de jQuery actualizadasMe gustaría saber que es lo que desean que tenga el "PHPost Risus 1.4x": (los tachados ya están agregados) [ 01 ] Administración & Moderación separados del theme [ 02 ] Chat [ 03 ] Comunidades [ 04 ] Descargar e instalar themes desde la administración [ 05 ] Descargar e plugins básicos desde la administración [ 06 ] Login & Registro separados del theme [ 07 ] Que editor Wysibb (bbcode) o EasyMDE (markdown) [ 08 ] Sección Archivos [ 09 ] Sección Vip [ 10 ] Sitemap.xml & Robots.txt [ 11 ] Algún otro mod/complemento o lo que desees para añadir [ 12 ] Pueden ser diseños nuevos para el default! (en proceso...)Espero sus respuestas. 11.01.2023 NOTA: Instalación arreglada y mejorada Ya tiene en uso password_hash y password_verify, es una mejora completa para las contraseñas. Nicks Reservados (basado en el mod de tutan-kabron), y tiene para añadirles contraseña para usuarios que ustedes deseen que use algunos de esos nicks reservados 12.01.2023 NOTA: Se añadió el último commit realizado en el repositorio (Este se actualizará automáticamente cuando exista un nuevo commit) Así se verá en la administración, arriba de la versión de risus instalada Este es del commit que se hizo en github, lo más probable es que, cuando lo vean ya no será el mismo commit... Ya que lo estaré modificando. 15.01.2023 NOTA:Se esta modificando el theme (semi-responsive pr el momento)Nueva forma de usar el modal, pero mantiene el uso original Mini tutorial de como usar el modal rápido 18.01.2023 NOTA:Home terminada espero XDComunidades añadidasLogin y Registro separados
  2. Bueno como dice el titulo "Mostrar titulo de los posts Anterior y Siguiente v2", ya que este es una actualización mejorada! Topic de la v1 Básicamente se puede realizar tranquilamente desde cero: 1 - Buscan en inc/class/c.posts.php y van hasta la última llave } /* OBTENER LOS TITULOS DE LOS POSTS ANTERIOR/SIGUIENTE */ public function getTitles($from) { global $tsCore; $pid = (int)$_GET["post_id"]; $pid = $from ? $pid - 1 : $pid + 1; $opt = $from ? "<" : ">"; if($pid < 0) return false; // Post $sql = db_exec([__FILE__, __LINE__], "query", "SELECT post_id, post_title, c_seo FROM p_posts LEFT JOIN p_categorias ON post_category = cid WHERE post_id = {$pid}"); // Existe? if(db_exec('num_rows', $sql) === 0) { $sql = db_exec([__FILE__, __LINE__], "query", "SELECT post_id FROM p_posts WHERE post_id {$opt} {$pid} ORDER BY post_id DESC LIMIT 1"); } $data = db_exec('fetch_assoc', $sql); if(!empty($data)) { $data["post_title"] = $tsCore->setSEO($data["post_title"]); $data["post_url"] = "{$tsCore->settings["url"]}/posts/{$data["c_seo"]}/{$data["post_id"]}/{$data["post_title"]}.html"; } return !empty($data) ? $data : false; } 2 - En inc/php/posts.php buscan $tsPages['autor'] = $tsPost['post_user']; y debajo agregan $smarty->assign("tsAnterior", $tsPosts->getTitles(true)); $smarty->assign("tsSiguente", $tsPosts->getTitles(false)); 3 - Luego buscan en tema/templates/modules/m.posts_content.tpl y buscan {if $tsPost.user_firma && $tsConfig.c_allow_firma} y arriba agregan (o donde deseen), obviamente ustedes lo tendrían que adaptar a su theme... Pero si usan bootstrap no tiene que hacer tantos cambios. <div class="post-antsig"> <div class="post-anterior"> <a href="{$tsAnterior.post_url}" class="d-flex justify-content-start align-items-center"> <div class="icon ml-2"> <!-- Acá puede ir un icono o imagen, deciden ustedes --> <i class="icon-angle-left"></i> </div> <div class="titulo"> <small class="text-uppercase">No te piedas</small> <span>{$tsAnterior.post_title|truncate:34}</span> </div> </a> </div> <div class="post-siguiente"> <a href="{$tsSiguente.post_url}" class="d-flex justify-content-end align-items-center t-end"> <div class="titulo"> <small class="text-uppercase">A continuación</small> <span>{$tsSiguente.post_title|truncate:34}</span> </div> <div class="icon mr-2"> <!-- Acá puede ir un icono o imagen, deciden ustedes --> <i class="icon-angle-right"></i> </div> </a> </div> </div> Así quedaría terminado!
  3. Instalador automático de themes! Es completamente básico y no requiere de mucha instalación. 1 - Abren header.php y al final agregan include TS_ROOT . "/inc/InstallAutomaticTheme.php"; 2 - Descargan "InstallAutomaticTheme.php" y lo agregan en inc/ y listo todos los themes que agregues en "themes" y que contengan el archivo "install.php" los va a instalar, primero comprobará si lo tienen instalado en caso que si lo tengan, no lo va a agregar otra vez.
  4. Hola a todos, no se si les interesa, pero les dejó este mod! (No sé si era la idea que tenía) Mod iniciado por: KMario19 Topic: [Desarrollo] BBCode file para archivos No lo he encontrado terminado, así que supongo que para usar este mod, deben tener: [SECCIÓN] Archivos V1.2 [SECCIÓN] Archivos V2 [SECCIÓN] Archivos v2.2 (Actualizado a 1.3) [ZIP] Topic: Sección archivos v2.2 Iniciamos con la instalación 1 - Buscamos en .htaccess y buscamos RewriteRule ^mod-history/([A-Za-z0-9_-]+)/ inc/php/mod-history.php?ver=$1 [QSA,L] debajo agregaremos # Descargar RewriteRule ^download/([0-9_-]+)$ inc/php/download.php?id=$1 [QSA,L] 2 - Luego vamos a inc/class/c.core.php y buscamos public function setMenciones($html) { arriba de la función (también puede ir arriba de la última }) # Extraemos el nombre del archivo public function parseFiles($content) { preg_match_all('/\[file\=(\d+)\]/i', $content, $files); foreach ($files[0] as $id => $file) { $dato = db_exec('fetch_assoc', db_exec([__FILE__, __LINE__], 'query', "SELECT file_id, f_nombre, f_descargas, f_ext FROM a_files WHERE file_id = {$files[1][$id]} LIMIT 1")); if($dato["file_id"] > 0) { $replace = "<a href=\"{$this->settings["url"]}/download/{$dato["file_id"]}\">{$dato["f_nombre"]}.{$dato["f_ext"]} <span style=\"color:#aaa\">{$dato["f_descargas"]} descargas</span>"; } else $replace = "<span style=\"color:#f00\">Archivo eliminado...</span>"; $content = str_replace($file, $replace, $content); } return $content; } 3 - Después buscamos en inc/class/c.posts.php $postData['user_firma'] = $tsCore->parseBadWords($tsCore->parseBBCodeFirma($postData['user_firma']),true); arriba agregamos $postData['post_body'] = $tsCore->parsefiles($postData['post_body']); 4 - Subimos este archivo "download.php" en inc/php 5 - Luego en tema/js/wysibb.js buscan smilebox: "Emoticonos", y debajo pegan file: "Descargar archivo", un poco más abajo buscan modal_link_title: "Insertar enlace", y arriba agregan modal_link_id: "Inserta el ID del archivo", luego buscan strike,sup,sub,| y a lado agregan ,file más abajo buscan img : { y arriba pegan (en buttonHTML lo pueden definir ustedes) file : { title: CURLANG.file, buttonHTML: '<span class="fa-solid fa-paperclip"></span>', // Pueden agregar imagen o lo que deseen modal: { title: CURLANG.modal_link_id, width: "500px", tabs: [ { input: [ {param: "FILE",title:CURLANG.modal_link_id} ] } ] }, transform : { '<a href="{FILE}">{FILE}</a>':"[file={FILE}]" } }, bueno, eso todo... espero no olvidarme de nada!
  5. Este "mod" es dual ya que tiene el login y registro, esta realizado de forma que al ingresar a al sitio tengas que registrarte o loguearte de forma obligatoria...una vista previa de como quedará Bueno comencemos 1 - En header.php buscamos define('TS_TEMA', $tsTema); y debajo agregamos # El tipo de inicio define('INICIO_DUAL', TRUE); 2 - Buscamos en index.php // Checamos... if($tsCore->settings['c_allow_portal'] == 1 && $tsUser->is_member == true && $_GET['do'] == 'portal') { // Portal/mi include('inc/php/portal.php'); } else { // Home include('inc/php/posts.php'); } y la reemplazamos por /** * Dependiendo de la configuración * Solo aplicará el dual si ambos son "TRUE" */ if(INICIO_DUAL AND !$tsUser->is_member) include 'inc/php/dual.php'; else { // Checamos... if(intval($tsCore->settings['c_allow_portal']) == 1 && $tsUser->is_member == true && $_GET['do'] == 'portal') { // Portal/mi include('inc/php/portal.php'); } else { // Home include('inc/php/posts.php'); } } 3 - Descargan los archivos y los ponen en las rutas correspondientes * dual.php en inc/php/ * dual.css en tema/css/ * dual.js en tema/js/ * t.dual.tpl en tema/templates/ 4 - Ir a inc/class/c.registro.php y buscan $tsData = array( 'user_nick' => $tsCore->parseBadWords($_POST['nick']), 'user_password' => $tsCore->parseBadWords($_POST['password']), 'user_email' => $_POST['email'], 'user_dia' => $_POST['dia'], 'user_mes' => $_POST['mes'], 'user_anio' => $_POST['anio'], 'user_sexo' => $_POST['sexo'] == 'f' ? '0' : 1, 'user_pais' => strtoupper($_POST['pais']), 'user_estado' => $_POST['estado'], 'user_terminos' => $_POST['terminos'], 'user_captcha' => $_POST['g-recaptcha-response'], 'user_registro' => time(), ); y la reemplazan por $tsData = array( 'user_nick' => $tsCore->parseBadWords($_POST['nick']), 'user_password' => $tsCore->parseBadWords($_POST['password']), 'user_email' => $_POST['email'], 'user_sexo' => $_POST['sexo'] == 'f' ? '0' : 1, 'user_terminos' => $_POST['terminos'], 'user_captcha' => $_POST['response'], 'user_registro' => time(), ); un poco más abajo buscan /** reCAPTCHA **/ $recaptcha = 'https://www.google.com/recaptcha/api/siteverify?secret=' . $tsCore->settings['skey'] . '&response=' . $tsData['user_captcha'] . '&remoteip=' . $tsCore->getIP(); // Obtener respuesta $response = file_get_contents($recaptcha); // Extraer resultado $ext1 = explode('"success":', $response); $ext2 = explode(',', $ext1[1]); // Comprobar resultado $valid = trim($ext2[0]); // Devolver respuesta si es incorrecta if ($valid == 'false') { return 'recaptcha: No hemos podido validar tu humanidad'; } y la reemplazan por /** * Comprobamos el recaptcha v3 */ $response = $tsCore->reCaptcha($tsData['user_captcha']); if (!$response) return 'recaptcha: No hemos podido validar tu humanidad'; más abajo buscamos // INSERTAMOS EL PERFIL db_exec(array(__FILE__, __LINE__), 'query', 'INSERT INTO `u_perfil` (`user_id`, `user_dia`, `user_mes`, `user_ano`, `user_pais`, `user_estado`, `user_sexo`) VALUES (\''.(int)$tsData['user_id'].'\', \''.(int)$tsData['user_dia'].'\', \''.(int)$tsData['user_mes'].'\', \''.(int)$tsData['user_anio'].'\', \''.$tsCore->setSecure($tsData['user_pais']).'\', \''.$tsCore->setSecure($tsData['user_estado']).'\', \''.(int)$tsData['user_sexo'].'\')'); db_exec(array(__FILE__, __LINE__), 'query', 'INSERT INTO `u_portal` (`user_id`) VALUES (\''.$tsData['user_id'].'\')'); y la reemplazamos por db_exec([__FILE__, __LINE__], "query", "INSERT INTO u_perfil (user_id, p_avatar, user_sexo) VALUES({$tsData['user_id']}, 1, {$tsData['user_sexo']})"); db_exec([__FILE__, __LINE__], "query", "INSERT INTO u_portal (user_id) VALUES({$tsData['user_id']})"); # Generamos automaticamente un avatar $avatar = "https://ui-avatars.com/api/?name=$1&background=random&size=160&font-size=0.60&bold=true&length=2"; $copy = "../../files/avatar/$2_$3.jpg"; $sizes = [50, 120]; foreach ($sizes as $size) { copy( str_replace('$1', $tsData['user_nick'], $avatar), str_replace(['$2', '$3'], [$tsData['user_id'], $size], $copy) ) } 5 - Luego en inc/class/c.core.php buscamos /* getIP */ function getIP(){ y arriba agregamos # Función para comprobar reCaptcha v3 public function reCaptcha(string $publico = '') { $http = http_build_query([ 'secret' => $this->settings["skey"], 'response' => $publico, 'remoteip' => $this->getIP() ]); $init = curl_init(); curl_setopt($init, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify"); curl_setopt($init, CURLOPT_POST, 1); curl_setopt($init, CURLOPT_POSTFIELDS, $http); curl_setopt($init, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($init); curl_close($init); return json_decode($response, true); } Y eso sería todo, espero no olvidarme de nada! Cualquier problema o duda comenten!
  6. Bueno como ya había mencionado, ya esta la "herramienta" para crear copias de seguridad completa o parcial de la base de datos y podrás restaurar dicho copia, el problema será que no tengas acceso a la administración del sitio y allí necesitarás una herramienta externa pero que funcione dentro del sitio. Solo tengo que hacerle algunos cambios a la herramienta que ya tengo creada desde hace 1 año. Capturas: Antes de comenzar, si tienes Ejecutar SQL desde la administración [Arreglado] tendrás que quitarlo o eliminar archivos Bueno comencemos con la integración, los archivos para descargar están al final. 1 - Este archivo "c.database.php" y lo agregan a 2 - En inc/php/admin.php buscamos /** NOTICIAS **/ } elseif($action == 'news'){ arriba agregarán } elseif($action == 'execute' OR $action == 'backup') { # Incluimos el archivo necesario include("../class/c.database.php"); $tsDataBase = new tsDataBase(); # Todas las opciones de la copia de seguridad if($action == 'backup') { if(empty($act)) { $smarty->assign('tsListBackup', $tsDataBase->listBackup()); # Creamos el backup completo } elseif($act === 'new_backup') { if(!empty($_POST["nombre_copia"])) { if($tsDataBase->createBackUp()[0]) $tsCore->redirectTo($tsCore->settings['url'].'/admin/backup?save=true'); else $smarty->assign("tsError", $tsDataBase->createBackUp()[1]); } # Creamos el backup seleccionando tablas } elseif($act === 'new_backup_select') { $smarty->assign('tsTablas', $tsDataBase->show_tables()); if(!empty($_POST["nombre_copia"])) { if($tsDataBase->seletedTables()[0]) $tsCore->redirectTo($tsCore->settings['url'].'/admin/backup?save=true'); else $smarty->assign("tsError", $tsDataBase->seletedTables()[1]); } # Descargamos el fichero } elseif($act === 'download') { if(isset($_GET["code"])) { $smarty->assign('tsDownload', $tsDataBase->downloader()); } } } 3 - Ahora en inc/php/ajax/ajax.php buscan 'admin-badwords-delete' => array('n' => 4, 'p' => ''), debajo agregan 'admin-eliminar-sql' => array('n' => 4, 'p' => ''), 'admin-restaurar-sql' => array('n' => 4, 'p' => ''), 'admin-ejecutar-sql' => array('n' => 4, 'p' => ''), más abajo buscan include("../class/c.admin.php"); $tsAdmin = new tsAdmin(); y agregan if($action === 'admin-eliminar-sql' OR $action === 'admin-restaurar-sql' OR $action === 'admin-ejecutar-sql') { include("../class/c.database.php"); $dbase = new tsDataBase(); } por último buscan default: die('0: Este archivo no existe.'); break; y arriba agregan case 'admin-eliminar-sql': echo $dbase->delete_file_sql(); break; case 'admin-restaurar-sql': echo $dbase->restore_file_sql(); break; case 'admin-ejecutar-sql': echo $dbase->executeSQL(); break; 4 - Ahora en tema/templates/t.admin.tpl buscan {include file='admin_mods/m.admin_rangos.tpl'} y debajo pegan {elseif $tsAction == 'execute' || $tsAction == 'backup'} {include file='admin_mods/m.admin_database.tpl'} 5 - En tema/templates/admin_mods/m.admin_sidemenu.tpl buscan <h4>Configuración de PHPost</h4> y arriba agregan <h4>Seguridad</h4> <ul class="cat-list"> <li id="a_configs"><span class="cat-title"><a href="{$tsConfig.url}/admin/execute">Ejecutar consultas</a></span></li> <li id="a_main"><span class="cat-title"><a href="{$tsConfig.url}/admin/backup">Crear copia</a></span></li> </ul> 6 - Este archivo "m.admin_database.tpl" y lo agregan a tema/templates/admin_mods/ 7 - Por último en tema/ja/admin.js al final del archivo agregan /** * Database * para ejecutar consultas y crear copias */ var database = new function() { this.execute = () => { var SQL = 'sql=' + $("#sql").val(); $.post(global_data.url + '/admin-ejecutar-sql.php', SQL, h => { switch (h.charAt(0)) { case '0': mydialog.alert('Error', h.substring(3), false) break; case '1': mydialog.alert('Bien', h.substring(3), true) break; } }) }, this.delete = (id, file, gew) => { if(!gew) { mydialog.show() mydialog.title('Eliminar') mydialog.body(`Estas seguro que quieres eliminar este archivo: ${file}`) mydialog.buttons(true, true, 'Borrar SQL', `database.delete(${id}, '${file}', true)`, true, false, true, 'Cancelar', 'close', true, true); /*mydialog.buttons([ {mostrar:true,texto:'Borrar SQL',accion:`database.delete(${id}, '${file}', true)`,activo:true}, {mostrar:true,texto:'Cancelar',accion:'cerrar',activo:true} ]); */ mydialog.center() } else { $.post(global_data.url + '/admin-eliminar-sql.php', {id,file}, e => { switch (e.charAt(0)) { case '0': mydialog.alert('Error', e.substring(3)); break; case '1': mydialog.close(); $("#sql" + id).remove(); break; } }) } }, this.restore = (file, gew) => { if(!gew) { mydialog.show() mydialog.title('Restaurar') mydialog.body(`Estas seguro que quieres restaurar esta copia: ${file}`) mydialog.buttons(true, true, 'Restaurar SQL', `database.restore('${file}', true)`, true, false, true, 'Cancelar', 'close', true, true); /*mydialog.buttons([ {mostrar:true,texto:'Restaurar SQL',accion:`database.restore('${file}', true)`,activo:true}, {mostrar:true,texto:'Cancelar',accion:'cerrar',activo:true} ]);*/ mydialog.center() } else { mydialog.procesando_inicio('', "Espere"); mydialog.buttons(false); mydialog.center() $.post(global_data.url + '/admin-restaurar-sql.php', {restore: file}, e => { switch (e.charAt(0)) { case '0': mydialog.procesando_fin(); mydialog.alert('Error', e.substring(3), false); break; case '1': mydialog.procesando_fin(); mydialog.alert('Bien', e.substring(3), false); break; } }) } } } Descargar los archivos "-#- Justo aquí -#-" En caso que tengan problemas al querer crear las copias de seguridad, comprueben que se haya creado la carpeta "database" en files/ y que tenga los permisos 0777 aplicados, en caso contrario deberán crearlo y darle los permisos correspondientes
  7. Bueno lo que trate de hacer es simplificar un poco, quieres agregar una imagen a "rangos", "categorías" o "medallas" y no quieres entrar desde el FTP o CPanel, bueno con esta herramienta deberías poder realizar esta tarea desde la administración de tu sitio. Les mostraré algunas imágenes, pero no esta realizado con el default, si no que es una versión que estoy realizando. Bueno comenzamos... 1 - En inc/class/c.admin.php lo pueden agregar al final o donde quieran. # Obtenemos todas las imagenes de la carpeta public function obtener_paquete($dir) { global $tsCore, $smarty; # Aplicamos los permisos si no los tiene foreach (["cat", "med", "ran"] as $carpeta) chmod($smarty->template_dir["images"] . 'icons/' . $carpeta, 0777); # Creamos un arreglo $data = []; # Buscamos en la carpeta... $carpeta = $smarty->template_dir["images"] . 'icons/' . $dir; $imagenes = opendir( $carpeta ); # Recorremos la carpeta while ($icono = readdir($imagenes)) { if($icono != '.' && $icono != '..'): # Obtenemos información del archivo $inf = getimagesize($carpeta . '/' . $icono); $arr = [ "hash" => substr(md5(explode('.', $icono)[0]), 0, 6), "icon" => explode('.', $icono)[0], "url" => $tsCore->settings["images"] . '/icons/' . $dir . '/' .$icono, "width" => $inf[0], "height" => $inf[1], "type" => $inf["mime"] ]; if(isset($_GET["size"]) or isset($_GET["type"])) { if(intval($_GET["size"]) === $inf[0] or 'image/'.$_GET["type"] === $inf["mime"]) { array_push($data, $arr); } } else array_push($data, $arr); endif; } closedir( $imagenes ); # Retornamos el arreglo return $data; } public function eliminar_icono_paquete() { global $tsCore, $smarty; # Buscamos en la carpeta... $carpeta = $smarty->template_dir["images"] . 'icons/' . $tsCore->setSecure($_POST["path"]); # Eliminamos si son la misma imagen con difente tamaño foreach($this->obtener_paquete($_POST["path"]) as $eliminar) { if($eliminar["hash"] === $_POST["hash"]) { if($_POST["path"] === 'med') { $sizes = [16, 32]; foreach ($sizes as $size) { $nimg = "{$eliminar["icon"]}_{$size}." . substr($eliminar["type"], 6); unlink($carpeta . '/' . $nimg); } return true; } else { $nimg = "{$carpeta}/{$eliminar["icon"]}." . substr($eliminar["type"], 6); return (unlink($nimg)) ? true : false; } } } } public function subir_icono() { global $smarty; # Mover a... $mover = $smarty->template_dir["images"] . 'icons/' . $_POST["path"] . DIRECTORY_SEPARATOR; // if (($_FILES["file"]["type"] == "image/jpg") || ($_FILES["file"]["type"] == "image/png") || ($_FILES["file"]["type"] == "image/gif")) { # Agregamos la imagen, si existe, esta será reemplazada por la nueva return (move_uploaded_file($_FILES["file"]["tmp_name"], $mover . $_FILES['file']['name'])) ? '1: Imagen agregada correctamente...' : '0: No se pudo subir la imagen!'; } else return false; } Este código es para Smarty 4, si no lo tienes actualizado, lo que debes hacer es lo siguiente, buscas esto $smarty->template_dir["images"] . 'icons/' y lo reemplazas por TS_ROOT . '/themes/' . $tsCore->settings["tema"]['t_path'] . '/images/icons/' y borrar el de las funciones, excepto el que lleva $tsCore, allí solo eliminas , $smarty global $smarty; 2 - En inc/php/admin.php buscan } elseif($action == 'creditos'){ y arriba agregan # PACKS } elseif($action == 'packs') { $smarty->assign('tsDir', $_GET["path"]); if($act === 'abrir') { $smarty->assign('tsPack', $tsAdmin->obtener_paquete($_GET["path"])); } 3 - En inc/php/ajax/ajax.admin.php buscan 'admin-badwords-delete' => array('n' => 4, 'p' => ''), y debajo pegan 'admin-eliminar-icono' => array('n' => 4, 'p' => ''), 'admin-subir-icono' => array('n' => 4, 'p' => ''), más abajo default: die('0: Este archivo no existe.'); break; arriba agregan case 'admin-eliminar-icono': echo $tsAdmin->eliminar_icono_paquete(); break; case 'admin-subir-icono': echo $tsAdmin->subir_icono(); break; 4 - En tema/templates/admin_mods/ crean un archivo llamado "m.admin_packs.tpl" y dentro agregan, les recuerdo que lo pueden adaptar a su theme <div class="boxy-title"> <h3>Control de paquetes de imagenes</h3> </div> <div id="res" class="boxy-content"> <p class="alerts ok">Desde aquí podrás ver, agregar, eliminar las imagenes e iconos que estan guardados en "<a href="{$tsConfig.url}/admin/packs?act=abrir&path=ran">ran</a>", "<a href="{$tsConfig.url}/admin/packs?act=abrir&path=med">med</a>", "<a href="{$tsConfig.url}/admin/packs?act=abrir&path=cat">cat</a>".</p> {if $tsSave}<div class="alerts ok">Tus cambios han sido guardados.</div>{/if} <hr class="separator"> {if $tsAct === ''} <div style="display:grid;gap:10px;grid-template-columns: repeat(3, 1fr);"> <a href="{$tsConfig.url}/admin/packs?act=abrir&path=cat" class="block text-center"> <img width="140" height="140" src="{$tsConfig.images}/category.svg" alt="Categorías"> <strong style="margin-top:4px;display: block;">Categorías</strong> </a> <a href="{$tsConfig.url}/admin/packs?act=abrir&path=med" class="block text-center"> <img width="140" height="140" src="{$tsConfig.images}/award.svg" alt="Medallas"> <strong style="margin-top:4px;display: block;">Medallas</strong> </a> <a href="{$tsConfig.url}/admin/packs?act=abrir&path=ran" class="block text-center"> <img width="140" height="140" src="{$tsConfig.images}/ran.svg" alt="Rangos"> <strong style="margin-top:4px;display: block;">Rangos</strong> </a> </div> {elseif $tsAct === 'abrir'} {if $tsDir === 'med' || $tsDir === 'ran'} <span>Filtros:</span> {if $tsDir === 'med'} <a href="{$tsConfig.url}/admin/packs?act=abrir&path=med" style="text-align:center;">Todos</a> - <a href="{$tsConfig.url}/admin/packs?act=abrir&path=med&size=16" style="text-align:center;">16x16</a> - <a href="{$tsConfig.url}/admin/packs?act=abrir&path=med&size=32" style="text-align:center;">32x32</a> {/if} {if $tsDir === 'ran'} <a href="{$tsConfig.url}/admin/packs?act=abrir&path=ran" style="text-align:center;">Todos</a> - <a href="{$tsConfig.url}/admin/packs?act=abrir&path=ran&type=gif" style="text-align:center;">GIF</a> - <a href="{$tsConfig.url}/admin/packs?act=abrir&path=ran&type=png" style="text-align:center;">PNG</a> {/if} {/if} <table class="admin_table"> <thead> <tr> <th>Icono</th> <th>Nombre</th> <th>Dimensiones</th> <th>Tipo</th> <th>Acciones</th> </tr> </thead> {foreach $tsPack item=ic} <tr class="{$ic.hash}"> <td style="text-align:center;"><img src="{$ic.url}" alt="{$ic.icon}"></td> <td style="width: max-content">{$ic.icon}</td> <td>{$ic.width}x{$ic.height}</td> <td>{$ic.type}</td> <td class="admin_actions flex jcsaround aicenter"> <a href="javascript:packs.borrar('{$tsDir}', '{$ic.hash}')" title="Eliminar"><i class="fas fa-trash"></i></a> </td> </tr> {/foreach} </table> <hr class="separator"> <div style="text-align:center;"> <a href="{$tsConfig.url}/admin/packs?act=agregar&path={$tsDir}" class="mBtn">Agregar icono en {$tsDir}</a> </div> {elseif $tsAct === 'agregar'} <form method="post" enctype="multipart/form-data"> <input type="hidden" name="path" id="path" value="{$tsDir}"> <div class="form-line"> <label for="image">Sube una imagen...</label> <input type="file" class="form-control-file" name="image" id="image"> </div> <p><a href="javascript:packs.subir()" class="mBtn btnOk">Agregar</a></p> </form> {/if} </div> 5 - En tema/templates/admin_mods/m.admin_sidemenu.tpl buscan <li id="a_badwords"><span class="cat-title"><a href="{$tsConfig.url}/admin/badwords">Censuras</a></span></li> y debajo agregan <li id="a_main"><span class="cat-title"><a href="{$tsConfig.url}/admin/packs">Control de iconos</a></span></li> 6 - En tema/js/admin.js al final del archivo agregan /** * Control de paquete * para agregar, editar y eliminar iconos */ var packs = new function() { this.reload = path => location.href = global_data.url + '/admin/packs?act=abrir&path=' + path, this.subir = () => { var formData = new FormData(); formData.append('file', $('#image')[0].files[0]); formData.append('path', $('#path').val()); $.ajax({ url: global_data.url + '/admin-subir-icono.php', type: 'post', data: formData, contentType: false, processData: false, success: response => { switch(response.charAt(0)) { case '0': mydialog.alert('Error', response.substring(3), false); mydialog.center(); break; case '1': mydialog.show() mydialog.title('Bien!') mydialog.body(response.substring(3)) mydialog.buttons(true, true, 'Continuar', 'packs.reload(' + carpeta + ')', true, false, false); /*mydialog.buttons({mostrar:true,texto:'Continuar',accion:`packs.reload('${path}')`,activo:true});*/ mydialog.center() break; } } }); return false; }, this.borrar = (carpeta, hash, status) => { if(!status) { mydialog.show() mydialog.title('¿Deseas eliminar ' + (carpeta == 'med' ? 'estos iconos' : 'este icono') + '?') mydialog.body('Esto eliminará el/los iconos de su tema') mydialog.buttons(true, true, 'Continuar', 'packs.borrar(' + carpeta + ', ' + hash + ', true)', true, false, true, 'No', 'close', true, true); /*mydialog.buttons([ {mostrar:true,texto:'Continuar',accion:`packs.borrar('${carpeta}', '${hash}', true)`,activo:true}, {mostrar:true,texto:'No',accion:'cerrar',activo:true} ]);*/ mydialog.center() } else { var params = ['path=' + carpeta, 'hash=' + hash].join('&') $.post(global_data.url + '/admin-eliminar-icono.php', params, del => { mydialog.close(); if(del) { if(carpeta === 'med') { $("tr." + hash).each( (inx, trh) => trh.remove()) } else $("tr." + hash).remove() } }) } } } 7 - Suben estas 3 imágenes a tema/images/ Para la próxima le quiero agregar un paginador, y la subida de múltiples imágenes... NOTA: Para que funciones correctamente, el complemento le asignará a las carpetas ran, cat y med los permisos necesarios para que funcione, en caso que tenga error o no suba las imágenes a dichas carpetas lo que deben hacer es darle permisos 0777 manualmente a las carpetas mencionadas.
  8. En este caso se usará CDN para que sea mejor 1 - En inc/class/c.admin.php buscamos function saveOrden() { ... todo ... } y lo reemplazamos por public function saveOrden() { global $tsCore; # $ordenado = []; # Obtenemos lista con el nuevo orden $nuevo_orden = 1; foreach (explode(',', $_POST["cats"]) as $orden) { db_exec([__FILE__, __LINE__], 'query', "UPDATE p_categorias SET c_orden = ".$nuevo_orden." WHERE cid = ".$orden); array_push($ordenado, $nuevo_orden); $nuevo_orden++; } } 2 - En inc/php/ajax/ajax.admin.php buscan 'admin-badwords-delete' => array('n' => 4, 'p' => ''), y debajo agregan 'admin-ordenar-categorias' => array('n' => 4, 'p' => ''), más abajo buscan case 'admin-badwords-delete': //<--- echo $tsAdmin->deleteBadWord(); //---> break; y debajo agregan case 'admin-ordenar-categorias': //<--- echo $tsAdmin->saveOrden(); //---> break; 3 - Luego en tema/templates/admin_mods/m.admin_cats.tpl y buscamos, puedes eliminar jquery.tablednd.js si quieres <script type="text/javascript" src="{$tsConfig.js}/jquery.tablednd.js"></script> y lo reemplazamos por, se usa la condicional ya que solo es donde se muestra la lista de categorías {if $tsAct == ''} <script src="https://cdn.jsdelivr.net/npm/[email protected]/Sortable.min.js"></script> {/if} abajo de eso buscamos <script type="text/javascript"> // {literal} $(function(){ // {/literal} {if $tsAct == ''} {literal} $('#cats_orden').tableDnD({ onDrop: function(table, row) { $.ajax({ type: 'post', url: global_data.url + '/admin/cats?ajax=true&ordenar=true', cache: false, data: $.tableDnD.serialize() }); } }); // {/literal} {/if} {literal} $('#cats_orden').tableDnD({ onDrop: function(table, row) { $.ajax({ type: 'post', url: global_data.url + '/admin/cats?ajax=true&ordenar=true&t=cat', cache: false, data: $.tableDnD.serialize() }); } }); // $('#cat_img').change(function(){ var cssi = $("#cat_img option:selected").css('background'); $('#c_icon').css({"background" : cssi}); }); // }); //{/literal} </script> y lo reemplazamos por {if $tsAct == '' || $tsAct == 'editar' || $tsAct == 'nueva'} <script> $(() => { /* {if $tsAct == ''} */ new Sortable(document.getElementById('cats_orden'), { animation: 150, dragClass: "arrastrar", // Clase que puedes modificar selectedClass: "seleccionado", // Clase que puedes modificar store: { // Guardar orden set: sortable => $.post(global_data.url + '/admin-ordenar-categorias.php', 'cats=' + sortable.toArray().join(',')) } }); /* {/if} */ $('#cat_img').on('change', () => { $('#c_icon').css({ "background": $("#cat_img option:selected").css('background') }) }); }) </script> {/if} más abajo buscan y le borran id="cats_orden" de <table cellpadding="0" cellspacing="0" border="0" width="500" align="center" class="admin_table" id="cats_orden"> un poco más abajo buscan y le añaden id="cats_orden" a <tbody> abajo buscan <tr id="{$c.cid}"> y lo reemplazan por <tr id="{$c.cid}" data-id="{$c.cid}"> Si quieres puedes añadir estas líneas en tema/css/admin.css .arrastrar { background-color: #EEE; } .seleccionado { background-color: #CCC; } Si quieres obtener más información sobre el complemento "SortableJS", puedes acceder a la página que contiene la documentación para que puedas hacer los cambios que desees!
  9. Esto le va a gustar ya que vamos a simplificar un poco más lo que sería la sección de cuenta, y será bastante largo, y en mi caso le he quitado el porcentaje que se muestra en cuenta y varias opciones que ningún usuario se toma el tiempo en completar, como por ejemplo "Intereses y preferencias" 1 - En .htaccess buscamos RewriteRule ^cuenta.php$ inc/php/cuenta.php [QSA,L] y debajo agregamos RewriteRule ^cuenta/([A-Za-z0-9_-]+)$ inc/php/cuenta.php?accion=$1 [QSA,L] 2 - En tema/templates/t.cuenta.tpl y reemplazamos el contenido por esto {include file='sections/main_header.tpl'} <script src="{$tsConfig.js}/cuenta.js?{$smarty.now}"></script> <script> $(document).ready(() => { avatar.uid = '{$tsUser->uid}'; avatar.current = '{$tsConfig.url}/files/avatar/{if $tsPerfil.p_avatar}{$tsPerfil.user_id}{else}avatar{/if}.jpg'; }); </script> <div class="tabbed-d"> <div class="floatL"> <div id="alerta_guarda"></div> <ul class="menu-tab"> <li{if $tsAccion == ''} class="active"{/if}><a href="{$tsConfig.url}/cuenta/">Cuenta</a></li> <li{if $tsAccion == 'perfil'} class="active"{/if}><a href="{$tsConfig.url}/cuenta/perfil">Perfil</a></li> <li{if $tsAccion == 'block'} class="active"{/if}><a href="{$tsConfig.url}/cuenta/block">Bloqueados</a></li> <li{if $tsAccion == 'clave'} class="active"{/if}><a href="{$tsConfig.url}/cuenta/clave">Cambiar Clave</a></li> <li{if $tsAccion == 'nick'} class="active"{/if}><a href="{$tsConfig.url}/cuenta/nick">Cambiar Nick</a></li> <li{if $tsAccion == 'config'} class="active"{/if}><a href="{$tsConfig.url}/cuenta/config">Privacidad</a></li> </ul> <a name="alert-cuenta"></a> <form class="horizontal" method="post" name="editarcuenta"> <input type="hidden" name="pagina" value="{$tsAccion}"> {include file="modules/m.cuenta_$tsAccion.tpl"} </form> </div> <div class="floatR"> {include file='modules/m.cuenta_sidebar.tpl'} </div> </div> <div style="clear:both"></div> {include file='sections/main_footer.tpl'} 3 - Luego acceden a tema/templates/modules/ y buscan todos los m.cuenta_*.tpl y le quitan (al inicio del archivo) style="display:none" también (7 el numero puede variar, dependiendo de la sección) <div class="alert-cuenta cuenta-7"></div> y luego en los divs con la clase .buttons lo reemplazan por <div class="buttons"> <input type="button" value="Guardar" onclick="cuenta.guardar_datos()" class="mBtn btnOk"> </div> 4 - En inc/php/cuenta.php buscan } elseif($action == 'desactivate'){ if(!empty($_POST['validar'])) echo $tsCuenta->desCuenta(); } y debajo agregan $smarty->assign("tsAccion", $_GET["accion"]); 5 - Luego inc/class/c.cuenta.php en la funcion "savePerfil()" cambian $save = $_POST['save']; por $save = $_POST['pagina']; dentro del switch hacen lo siguiente, cambian el número por el nombre - case 1 -> case '' - case 2 -> case 'perfil' - case 6 -> case 'clave' - case 7 -> case 'config' - case 8 -> case 'nick' luego eliminan estos - case 3: ...todo hasta el break... break; - case 4: ...todo hasta el break... break; - case 5: ...todo hasta el break... break; más abajo buscamos y borramos // COMPROBAR PORCENTAJE $total = array(5,8,9,8,9); // CAMPOS EN CADA CATEGORIA $tid = $save - 1; if($save > 1 && $save < 6){ $total[$tid] = $this->getPorcentTotal($perfilData, $total[$tid]); if($save == 1) $total[$tid] = $total[$tid] - 2; $porcen = db_exec('fetch_assoc', db_exec(array(__FILE__, __LINE__), 'query', 'SELECT p_total FROM u_perfil WHERE user_id = \''.$tsUser->uid.'\' LIMIT 1')); $porcen = unserialize($porcen['p_total']); $porcen[$tid] = $total[$tid]; $porcenNow = $this->getPorcentVal($porcen); $porcen = serialize($porcen); db_exec(array(__FILE__, __LINE__), 'query', 'UPDATE u_perfil SET p_total = \''.$porcen.'\' WHERE user_id = \''.$tsUser->uid.'\''); } justo debajo de eso seleccionan // ACTUALIZAR if($save == 1) { db_exec(array(__FILE__, __LINE__), 'query', 'UPDATE u_miembros SET user_email = \''.$tsCore->setSecure($perfilData['email'], true).'\' WHERE user_id = \''.$tsUser->uid.'\''); array_splice($perfilData, 0, 1); // HACK $updates = $tsCore->getIUP($perfilData, 'user_'); if(!db_exec(array(__FILE__, __LINE__), 'query', 'UPDATE u_perfil SET '.$updates.' WHERE user_id = \''.$tsUser->uid.'\'')) return array('error' => show_error('Error al ejecutar la consulta de la línea '.__LINE__.' de '.__FILE__.'.', 'db')); } else { $updates = $tsCore->getIUP($perfilData, 'p_'); if(!db_exec(array(__FILE__, __LINE__), 'query', 'UPDATE u_perfil SET '.$updates.' WHERE user_id = \''.$tsUser->uid.'\'')) return array('error' => show_error('Error al ejecutar la consulta de la línea '.__LINE__.' de '.__FILE__.'.', 'db')); } // if(is_array($msg_return)) return $msg_return; else return array('porc' => $porcenNow); y lo reemplazan por // ACTUALIZAR if($save == '' or $save == 'perfil' or $save == 'config') { if($save == '') { db_exec([__FILE__, __LINE__], "query", "UPDATE u_miembros SET user_email = '{$perfilData['email']}' WHERE user_id = " . $tsUser->uid); array_splice($perfilData, 0, 1); } $updates = $tsCore->getIUP($perfilData, ($save == '' ? 'user_' : 'p_')); $msg_return = (db_exec([__FILE__, __LINE__], "query", "UPDATE u_perfil SET {$updates} WHERE user_id = " . $tsUser->uid)) ? array("error" => "Los cambios fueron aceptados y serán aplicados.") : die(show_error('Error al ejecutar la consulta de la línea '.__LINE__.' de '.__FILE__.'.', 'Base de datos')); } // return $msg_return; 6 - Crean un archivo llamado ajax.cuenta.php en inc/php/ajax y agregan lo siguiente <?php if ( ! defined('TS_HEADER')) exit('No se permite el acceso directo al script'); /** * Controlador AJAX * * @name ajax.cuenta.php * @author Miguel92 */ $files = [ 'cuenta-guardar' => ['n' => 2, 'p' => ''], ]; // REDEFINIR VARIABLES $tsPage = 'ajax/p.cuenta.'.$files[$action]['p']; $tsLevel = $files[$action]['n']; $tsAjax = empty($files[$action]['p']) ? 1 : 0; // DEPENDE EL NIVEL $tsLevelMsg = $tsCore->setLevel($tsLevel, true); if($tsLevelMsg != 1): echo '0: '.$tsLevelMsg['mensaje']; die(); endif; // CLASE require("../class/c.cuenta.php"); $tsCuenta = new tsCuenta(); // CODIGO switch($action){ case 'cuenta-guardar': echo json_encode($tsCuenta->savePerfil()); break; } 7 - En tema/templates/modules/m.cuenta_cuenta.tpl lo renombran a m.cuenta_.tpl 8 - En tema/templates/modules/m.cuenta_perfil.tpl y reemplazan el contenido por esto, y aplica este Redes sociales en perfil [Mejorado][Simplificado][Sugerencia] <div class="content-tabs perfil"> <fieldset> <div class="field"> <label for="nombrez">Nombre completo</label> <input type="text" value="{$tsPerfil.p_nombre}" maxlength="60" name="nombrez" id="nombrez" class="text cuenta-save-2" style="width:230px"> </div> <div class="field"> <label for="sitio">Mensaje Personal</label> <textarea value="" maxlength="60" name="mensaje" id="mensaje" class="cuenta-save-2">{$tsPerfil.p_mensaje}</textarea> </div> <div class="field"> <label for="sitio">Sitio Web</label> <input type="text" value="{$tsPerfil.p_sitio}" maxlength="60" name="sitio" id="sitio" class="text cuenta-save-2" style="width:230px"> </div> <div class="field"> <label for="red">Redes sociales</label> <div style="display:grid;grid-template-columns: repeat(2, 1fr);gap: 10px;"> {foreach $tsPerfil.redes key=name item=red} <div style="display:flex;justify-content: flex-start;align-items: center;"> <div class="icon"> <img src="{$tsConfig.images}/icons/{$name}.png" width="16" height="16" /> </div> <input type="text" class="text cuenta-save-2" value="{$tsPerfil.p_socials.$name}" placeholder="{$red}" name="red[{$name}]"> </div> {/foreach} </div> </div> <div class="field"> <label>Me gustaría</label> <div class="input-fake"> <ul> {foreach from=$tsPData.gustos key=val item=text} <li><input type="checkbox" name="g_{$val}" class="cuenta-save-2" value="1"{if $tsPerfil.p_gustos.$val == 1} checked{/if}>{$text}</li> {/foreach} </ul> </div> </div> <div class="field"> <label for="estado">Estado Civil</label> <div class="input-fake"> <select class="cuenta-save-2" name="estado" id="estado"> {foreach from=$tsPData.estado key=val item=text} <option value="{$val}"{if $tsPerfil.p_estado == $val} selected{/if}>{$text}</option> {/foreach} </select> </div> </div> <div class="buttons"> <input type="button" value="Guardar" onclick="cuenta.guardar_datos()" class="mBtn btnOk"> </div> </fieldset> <div class="clearfix"></div> </div> 9 - Ahora se viene lo genial, busca en tema/js/cuenta.js , justo antes que empieza var avatar = { var cuenta = {... HASTA ... } y lo reemplazas por var cuenta = { alerta: (alerta) => { $(".alert-cuenta").show(); $("#alerta_guarda").html(`<div style="background:#FFFFCC;text-align:center;margin-bottom: 10px;"><p style="display: block;font-size: 16px;padding: 10px 0;">${alerta}</p></div>`) window.scrollTo(0, 0) // Despues de 5s quitamos el alerta setTimeout(() => $("#alerta_guarda").html(''), 5000) }, chgpais: () => { // Campo pais const pais = $("select[name=pais]").val(); const estado = $("select[name=estado]"); if(empty(pais)) estado.addClass('disabled').attr('disabled', 'disabled').val(''); else { //Obtengo las estados $(estado).html(''); $('#loading').fadeIn(250); $.get(global_data.url + '/registro-geo.php', 'pais_code=' + pais, h => { if(h.charAt(0) === '1') estado.append(h.substring(3)).removeAttr('disabled').val('').focus(); $('#loading').fadeOut(250); }) } }, guardar_datos: () => { $('#loading').slideDown(250); $.ajax({ type: 'post', url: global_data.url + '/cuenta-guardar.php', data: $("form[name=editarcuenta]").serialize(), dataType: 'json', success: response => cuenta.alerta(response.error) }); } } Eso sería todo, espero no olvidarme de ningún paso.
  10. Redes sociales en perfil Mejorado y simplificado Esto es una forma mucho más rápida y sencilla de poder añadir redes sociales a su sitio 1 - En inc/class/c.cuenta.php debajo de class tsCuenta { agregan lo siguiente (solo agregan las redes desde aquí y nada más, ya no tienen que agregar más líneas) # Redes sociales disponibles /** * Si van a agregar más debe ser así 'nombre_minuscula => 'nombre_inicial_mayuscula', */ var $redes = [ 'facebook' => 'Facebook', 'twitter' => 'Twitter', 'instagram' => 'Instagram', 'youtube' => 'Youtube', 'twitch' => 'Twitch', ]; Luego un poco más abajo buscamos private function unData($data) $data['p_socials'] = unserialize($data['p_socials']); $data['p_socials']['f'] = $data['p_socials'][0]; $data['p_socials']['t'] = $data['p_socials'][1]; y la reemplazamos por $data["redes"] = $this->redes; $data['p_socials'] = json_decode($data['p_socials'], true); foreach ($this->redes as $name => $valor) $data['p_socials'][$name]; Luego un poco más abajo buscamos function loadHeadInfo($user_id) $data['p_socials'] = unserialize($data['p_socials']); $data['p_socials']['f'] = $data['p_socials'][0]; $data['p_socials']['t'] = $data['p_socials'][1]; y la reemplazamos por $data['p_socials'] = json_decode($data['p_socials'], true); foreach ($this->redes as $name => $valor) $data['p_socials'][$name]; Más abajo buscan // EXTERNAS $facebook = $tsCore->setSecure($tsCore->parseBadWords($_POST['facebook']), true); $twitter = $tsCore->setSecure($tsCore->parseBadWords($_POST['twitter']), true); y la reemplazan por # Redes sociales $red__social = []; foreach ($_POST["red"] as $llave => $id) $red__social[$llave] = $tsCore->setSecure($tsCore->parseBadWords($id), true); allí mismo buscan 'socials' => serialize(array($facebook,$twitter)), y la reemplazan por 'socials' => json_encode($red__social), 2 - Luego en inc/php/perfil.php buscan $smarty->assign("tsInfo",$tsInfo); y debajo agregan $smarty->assign("tsRedes", $tsCuenta->redes); 3 - Despues en tema/templates/modules/m.cuenta_perfil_me.tpl buscan <div class="field"> <label for="ft">Redes sociales</label> <img src="{$tsConfig.default}/images/icons/facebook.png" width="16" height="16" style="margin:5px; float:left" /> <strong>facebook.com/</strong><input type="text" value="{$tsPerfil.p_socials.f}" maxlength="64" name="facebook" id="ft" class="text cuenta-save-2" style="width:204px"><br /> <img src="{$tsConfig.default}/images/icons/twitter.png" width="16" height="16" style="margin:8px 5px 5px 160px; float:left" /> <strong>twitter.com/</strong><input type="text" value="{$tsPerfil.p_socials.t}" maxlength="64" name="twitter" id="ft2" class="text cuenta-save-2" style="margin-top:3px; width:204px"><br /> </div> y la reemplazan por <div class="field"> <label for="red">Redes sociales</label> <div style="display:grid;grid-template-columns: repeat(2, 1fr);gap: 10px;"> {foreach $tsPerfil.redes key=name item=red} <div style="display:flex;justify-content: flex-start;align-items: center;"> <div class="icon"> <img src="{$tsConfig.images}/icons/{$name}.png" width="16" height="16" /> </div> <input type="text" class="text cuenta-save-2" value="{$tsPerfil.p_socials.$name}" placeholder="{$red}" name="red[{$name}]"> </div> {/foreach} </div> </div> NOTA: En esta parte "{$tsConfig.images}/icons/{$name}.png", deben agregar el icono de la red social que utilicen. Por que "{$name}.png" seria igual a esto "facebook.png", etc. 4 - Por último en tema/templates/modules/m.perfil_sidebar.tpl y arriba de <div style="margin-bottom: 10px"> {$tsConfig.ads_300} </div> agregan esto (En realidad lo pueden poner donde ustedes quieran) {if $tsInfo.p_socials != ''} {foreach $tsRedes key=name item=red} {if $tsInfo.p_socials.$name !== ''} <a class="sitio {$name}" target="_blank" href="https://{$name}.{if $name == 'twitch'}tv{else}com{/if}/{$tsInfo.p_socials.$name}" title="{$red}"><img height="14" width="14" alt="{$name}" src="{$tsConfig.images}/icons/{$name}.png"/></a> {/if} {/foreach} </div> {/if} NOTA: Les debo los iconos de instagram, youtube y twitch Eso sería todo.
  11. Esto es básicamente para el administrador principal con el user_id 1, para evitar que otro administrador meta mano. 1 - En inc/class/c.admin.php buscamos /* saveConfigs() */ function saveConfig() { y arriba agregaremos (Actualizado 25.02.22) # Ejecutamos las consultas! public function executeSQL() { global $tsCore, $tsUser; # Solo administrador principal if($tsUser->is_member AND $tsUser->is_admod === 1 AND intval($tsUser->uid) === 1) { # Cosultas $sqlList = []; $lines = explode("\n", $_POST['sql']); foreach($lines as $sql) { $sql = htmlspecialchars_decode($sql); $sql = str_replace("'", '"', $sql); # Quitamos ; solo si lo tiene if(preg_match("/(.*);/", $sql)) $sql = substr(trim($sql), 0, strlen($sql) - 1); array_push($sqlList, db_exec([__FILE__, __LINE__], 'query', $sql)); } return in_array(true, $sqlList) ? '1: Se ejecut&oacute; correctamente.' : '0: Hubo un error al ejecutar la/s sentencia/s'; } return '0: Solo el administrador principal puede.'; } 2 - En inc/php/ajax/ajax.admin.php buscamos (Actualizado 25.02.22) 'admin-badwords-delete' => array('n' => 4, 'p' => ''), debajo pegamos 'admin-ejecutar-sql' => array('n' => 4, 'p' => ''), más abajo buscamos default: die('0: Este archivo no existe.'); break; y arriba pegamos case 'admin-ejecutar-sql': echo $tsAdmin->executeSQL(); break; 3 - En inc/php/admin.php si tienen agregado esto, bórrenlo, ya no se usará (Actualizado 25.02.22) } elseif($action == 'execute') { if($tsAdmin->executeSQL()) $tsCore->redirectTo($url); else $smarty->assign("tsError", $tsAdmin->executeSQL()); 4 - Luego en tema/templates/t.admin.tpl y buscamos {elseif $tsAction == 'configs'} {include file='admin_mods/m.admin_configs.tpl'} y debajo pegamos {elseif $tsAction == 'execute'} {include file='admin_mods/m.admin_execute.tpl'} 5 - En tema/templates/admin_mods/m.admin_sidemenu.tpl buscamos <h4>Configuración de PHPost</h4> y arriba pegamos <li id="a_execute"><span class="cat-title"><a href="{$tsConfig.url}/admin/execute">Ejecutar consultas </a></span></li> 6 - En tema/templates/admin_mods/ crearemos un archivo llamado m.admin_execute.tpl y agregaremos esto (Actualizado 25.02.22) <div class="boxy-title"> <h3>Administrar Base de datos</h3> </div> <div id="res" class="boxy-content"> {if $tsSave}<div class="alerts ok">Tus cambios han sido guardados.</div>{/if} {if $tsError}<div class="alerts error">Hubo problemas al ejecutar las sentencias.</div>{/if} <h4>Desde aquí tu puedes <u>generar las consultas</u>, antes de hacerlo, comprueba de que este correctamente.</h4> <form method="post" autocomplete="off"> <legend>Consultas</legend> <textarea name="sql" id="sql" cols="30" rows="10" placeholder="EJ: ALTER TABLE w_configuracion ADD privado INT(11) NOT DEFAULT 0;"></textarea> <small style="display:block"><i>Siempre cada consulta debe terminar en ; (punto y coma)</i></small> <input type="button" onclick="database.execute();" value="Enviar consulta" class="mBtn btnOk"/> </form> </div> 7 - En tema/js/admin.js al final del archivo agregan (Actualizado 25.02.22) /** * Database * para ejecutar consultas y crear copias */ var database = new function() { this.execute = () => { $.post(global_data.url + '/admin-ejecutar-sql.php', 'sql=' + $("#sql").val(), h => { switch (h.charAt(0)) { case '0': mydialog.alert('Error', h.substring(3), false) break; case '1': mydialog.alert('Bien', h.substring(3), true) break; } }) } } Eso sería todo, pero úsenlo con mucho cuidado ya que podrían afectar la base de datos, ejemplo quieren eliminar a un usuario y si colocan su id los eliminará a ustedes.. NOTA: Estoy creando algo que incluye esta función, lo cual ustedes van a poder ejecutar consultas, crear copias de seguridad de su base de datos y descargar dicha copia, pero debo averiguar un poco más...
  12. Simplificar la función saveConfig() Como todos sabrán que la función saveConfig() que se encuentra en inc/class/c.admin.php, es un dolor de cabeza para editarlo sin equivocarse... Bueno acá les traigo una solución, pero deben tener en cuenta que los campos en la administración específicamente "Configuración" en el atributo name debe coincidir con la que tienen en la base de datos, ya que si no son iguales, este les devolverá un error. Ejemplo 1: <input type="text" id="ai_titulo" name="titulo" maxlength="24" value="{$tsConfig.titulo}" /> El titulo coincide con w_configuracion.titulo de la base de datos Ejemplo 2: <textarea name="message_welcome" id="ai_met_welcome" style="width: 260px; height: 100px; {if $tsConfig.c_met_welcome == 0} display:none; {/if}">{$tsConfig.c_message_welcome}</textarea> El message_welcome no coincide con w_configuracion.c_message_welcome de la base de datos ya que este comienza con c_ o tal vez comienzan con c_allow_. lo que pueden hacer, es ver database.php del instalador y ver todas las que lleva c_ o c_allow_ y agregarle a los campos que lo requieran, excepto name="chat" y name="xat" ya que sería así name="chat_id" y name="xat_id" Les dejó el archivo m.admin_configs.tpl para los que no quieran buscar, cabe recalcar que si tienen campos agregados lo tendrán que agregar devuelta. (Es de la versión default) Bueno una vez aclarado esto, continuamos, buscamos en el archivo ya mencionado inc/class/c.admin.php... function saveConfig() { global $tsCore; // $c = array( 'titulo' => $tsCore->setSecure($tsCore->parseBadWords($_POST['titulo'])), 'slogan' => $tsCore->setSecure($tsCore->parseBadWords($_POST['slogan'])), 'url' => $tsCore->setSecure($tsCore->parseBadWords($_POST['url'])), 'offline' => empty($_POST['offline']) ? 0 : 1, 'offline_message' => $tsCore->setSecure($tsCore->parseBadWords($_POST['offline_message'])), 'chat' => $tsCore->setSecure($_POST['chat']), 'xat' => $tsCore->setSecure($_POST['xat']), 'edad' => $tsCore->setSecure($_POST['edad']), 'active' => $tsCore->setSecure($_POST['active']), 'sess_ip' => empty($_POST['sess_ip']) ? 0 : 1, 'count_guests' => $tsCore->setSecure($_POST['count_guests']), 'reg_active' => empty($_POST['reg_active']) ? 0 : 1, 'reg_activate' => empty($_POST['reg_activate']) ? 0 : 1, 'met_welcome' => $tsCore->setSecure($_POST['met_welcome']), 'message_welcome' => $tsCore->setSecure($tsCore->parseBadWords($_POST['message_welcome'])), 'fotos_private' => empty($_POST['fotos_private']) ? 0 : 1, 'hits_guest' => empty($_POST['hits_guest']) ? 0 : 1, 'keep_points' => empty($_POST['keep_points']) ? 0 : 1, 'allow_points' => $tsCore->setSecure($_POST['allow_points']), 'see_mod' => empty($_POST['see_mod']) ? 0 : 1, 'stats_cache' => $tsCore->setSecure($_POST['stats_cache']), 'desapprove_post' => empty($_POST['desapprove_post']) ? 0 : 1, 'firma' => empty($_POST['firma']) ? 0 : 1, 'upload' => empty($_POST['upload']) ? 0 : 1, 'portal' => empty($_POST['portal']) ? 0 : 1, 'live' => empty($_POST['live']) ? 0 : 1, 'max_nots' => $tsCore->setSecure($_POST['max_nots']), 'max_acts' => $_POST['max_acts'], 'max_posts' => $tsCore->setSecure($_POST['max_posts']), 'max_com' => $tsCore->setSecure($_POST['max_com']), 'sump' => empty($_POST['sump']) ? 0 : 1, 'newr' => empty($_POST['newr']) ? 0 : 1, 'pkey' => $tsCore->setSecure($_POST['pkey']), 'skey' => $tsCore->setSecure($_POST['skey']), ); // UPDATE if (db_exec(array(__FILE__, __LINE__), 'query', 'UPDATE `w_configuracion` SET `titulo` = \'' . $c['titulo'] . '\', `slogan` = \'' . $c['slogan'] . '\', `url` = \'' . $c['url'] . '\', `chat_id` = \'' . $c['chat'] . '\', `xat_id` = \'' . $c['xat'] . '\',`c_last_active` = \'' . $c['active'] . '\', `c_allow_sess_ip` = \'' . $c['sess_ip'] . '\', `c_count_guests` = \'' . $c['count_guests'] . '\', `c_reg_active` = \'' . $c['reg_active'] . '\', `c_reg_activate` = \'' . $c['reg_activate'] . '\', `c_met_welcome` = \'' . $c['met_welcome'] . '\', `c_message_welcome` = \'' . $c['message_welcome'] . '\', `c_fotos_private` = \'' . $c['fotos_private'] . '\', `c_hits_guest` = \'' . $c['hits_guest'] . '\', `c_keep_points` = \'' . $c['keep_points'] . '\', `c_allow_points` = \'' . $c['allow_points'] . '\', `c_see_mod` = \'' . $c['see_mod'] . '\', `c_stats_cache` = \'' . $c['stats_cache'] . '\',`c_desapprove_post` = \'' . $c['desapprove_post'] . '\', `c_allow_edad` = \'' . $c['edad'] . '\', `c_max_posts` = \'' . $c['max_posts'] . '\', `c_max_com` = \'' . $c['max_com'] . '\', `c_max_nots` = \'' . $c['max_nots'] . '\', `c_max_acts` = \'' . $c['max_acts'] . '\', `c_allow_sump` = \'' . $c['sump'] . '\', `c_newr_type` = \'' . $c['newr'] . '\', `c_allow_firma` = \'' . $c['firma'] . '\', `c_allow_upload` = \'' . $c['upload'] . '\', `c_allow_portal` = \'' . $c['portal'] . '\', `c_allow_live` = \'' . $c['live'] . '\', `offline` = \'' . $c['offline'] . '\', `offline_message` = \'' . $c['offline_message'] . '\', `pkey` = \'' . $c['pkey'] . '\', `skey` = \'' . $c['skey'] . '\' WHERE `tscript_id` = \'1\'')) return true; else exit( show_error('Error al ejecutar la consulta de la l&iacute;nea '.__LINE__.' de '.__FILE__.'.', 'db') ); } y la reemplazamos por public function saveConfig() { global $tsCore; /** * Unimos todos los parametros y * quitamos el $_POST["save"] con array_slice() * @link https://www.php.net/manual/es/function.array-slice.php * con el -1 se quita el $_POST["save"] */ $columnas = $tsCore->getIUP( array_slice($_POST, 0, -1) ); if (db_exec([__FILE__, __LINE__], "query", "UPDATE w_configuracion SET {$columnas} WHERE tscript_id = 1")) return true; else exit( show_error('Error al ejecutar la consulta de la l&iacute;nea '.__LINE__.' de '.__FILE__.'.', 'Base de datos') ); } Ahora en el caso que tengan que incluir por ejemplo el "Proveedor de Email", ya que ese campo se tiene que codificar a JSON...y pensarán, como lo hago es simple.. Se pregunta si existe el parámetro con dicho nombre como por ejemplo isset($_POST['el_nombre']), como el nombre que necesitamos es 'providers' se hace lo siguiente, arriba de $columnas se agrega la condicional. # Consultamos si existe, tenemos que poner el nombre if(isset($_POST["providers"])): # Lo que va a hacer es reemplazar el parametro por este nuevo /** * @link https://www.php.net/manual/es/function.json-encode.php */ $_POST["providers"] = json_encode(explode(', ', $_POST["providers"]), JSON_FORCE_OBJECT); endif; y eso sería básicamente todo, espero haberme explicado bien.
  13. Actualizar a Smarty 4.0 1 - Deben descargar la última versión de smarty del repositorio en github. 2 - Luego van a inc/smarty y eliminan todo el contenido (Aviso, si tienen archivos agregados en plugins les recomiendo hacer una copia) 3 - Abren el archivo descargado "smarty-master.zip", acceden a la carpeta que contiene y luego buscan la carpeta "libs" y extraen el contenido dentro de "inc/smarty" 4 - Ahora vamos a la raíz de nuestro sitio y abrimos "header.php" y sigan los siguientes pasos: A Buscan define('TS_FILES', TS_ROOT.'/files/'); y debajo agregamos define('TS_SMARTY', TS_ROOT.'/inc/smarty/'); B Arriba de "include 'config.inc.php';" agregan # Definimos donde estan los temas define('TS_THEMES', TS_ROOT . '/themes/'); # Definimos donde se estan los plugins adicionales define('TS_PLUGINS', TS_EXTRA . 'plugins/'); # Tiempo de vida del cache antes de ser eliminado [5hs] (3600 equivale 1hs) define('CACHE_LIFE_TIME', 3600 * 5); define('CACHE_CHECKED', TRUE); # Solo usar las carpetas agregadas en $smarty->setTemplateDir() define('SECURITY', TRUE); # Para comprimir el html y que sea más rápido define('COMPRESS_HTML', FALSE); C En inc/ext crean una carpeta llamada plugins y descargar plugins.zip y la descomprimen en "inc/ext" Contenido del comprimido zip: fecha, getUrl, hace, kmg, nl2br, quot, rtrim, seo, strlen, trim y ucfirst D Un poco más abajo buscamos y lo borramos // Smarty include TS_CLASS.'c.smarty.php'; E Más abajo buscamos // Smarty $smarty = new tsSmarty(); y reemplazamos por # Todas las instrucciones de smarty comienzan include TS_ROOT . "/inc/smarty.config.php"; F Al no existir el archivo "smarty.config.php" lo crean dentro de "inc" 5 - Ahora buscamos "/inc/smarty.config.php" y empezaremos la configuración. A - Abrimos la etiqueta de <?php y luego agregan estas instrucciones 6 - Ahora vamos a la raíz de nuestro sitio y abrimos "footer.php": A - Borramos todo el contenido del archivo y la reemplazaremos con esto PD: Se me olvido mencionar que deben ir a inc/php/ajax_files.php y borrar lo siguiente, ya que no lo usaremos $smarty->template_ts = false; // SMARTY SETTINGS NOTA: Como verán en el array $_ACCESO_TPL_PHP_ = [...items...], es el acceso a esas carpetas. ¿Por que incluí esto?, fácil es para simplificar más, antes para incluir un archivo se tenía que agregar de la siguiente manera {include file='sections/main_header.tpl'} pero como en este ejemplo, al estar la ruta de la carpeta "sections" en el array se puede usar así {include file='main_header.tpl'} sin tener que hacer referencia a la carpeta a la que se tenga que acceder, también se puede usar de la forma corta {include 'main_header.tpl'} En la parte que accede al tema, css, js e images es para el funcionamiento de los plugins que había realizado, si desean lo pueden borrar... A no ser que quieran el plugin al que llame phpost, ¿Cuál es su función?: Es agregar todos los css, js sin tener que escribir toda la ruta para acceder a dicho archivo y en caso de que este archivo no exista, no agregará nada(no va a ser una linea vacía) este sería un ejemplo: Agregará la fuente "Roboto" desde google y los estilos que estén mencionados en los parámetros y lo que que sería cache es como esto "archivo.css?{$smarty.now}", así cuando se hace un cambio lo apliquen los cambios {phpost fonts=["Roboto"] css=[ "tema" => ["estilo.css", "css" => ["live.css", "wysibb.css", "$tsPage.css"]], "cache" => true ] ... ETC ... } Al tener la carpeta plugins dentro de inc/ext, puedes agregar más sin problemas
  14. Para esto deben tener los temas en la carpeta "themes" y Smarty 4.0, ya que utilizaremos la configuración hecha en smarty.config.php 1 - Buscan en inc/class/c.admin.php /* getTemas() */ function getTemas() Arriba agregaremos lo siguiente # Buscamos los temas no instalados public function temas_no_instalados() { global $smarty; # Arreglo de temas sin intalar $no_instalado = []; # Esto esta configurado en smarty.config.php # Primero buscamos en la carpeta themes si hay un theme sin instalar $themes = opendir( $smarty->template_dir["themes"] ); # Recorremos toda la carpeta de themes while ($theme = readdir($themes)) { if($theme != '.' && $theme != '..'): # Obtenemos el archivo de instalacion include $smarty->template_dir["themes"] . $theme . "/install.php"; # Ahora comprobamos si esta instalado if(!db_exec('fetch_assoc', db_exec([__FILE__, __LINE__], "query", "SELECT tid FROM w_temas WHERE t_path = '{$theme}' LIMIT 1"))["tid"]) { array_push($no_instalado, [ "nombre" => $tema["nombre"], "path" => $tema["path"], "copy" => $tema["copy"] ]); } endif; } return $no_instalado; } luego un poco más abajo buscamos function newTema() { global $tsCore; // $tema_path = $tsCore->setSecure($_POST['path']); // ARCHIVO DE INSTALACION include ("../../themes/" . $tema_path . '/install.php'); // if (empty($tema)) return 'Revisa que la carpeta del tema sea correcta.'; foreach ($tema as $key => $val) { if (empty($val)) return 'El archivo de instalaci&oacute;n del tema es incorrecto. Recuerda utilizar temas oficiales.'; else $temadb[$key] = $tsCore->setSecure($val); } // NUEVO if (db_exec(array(__FILE__, __LINE__), 'query', 'INSERT INTO `w_temas` (`t_name`, `t_url`, `t_path`, `t_copy`) VALUES (\'' . $tsCore->setSecure($temadb['nombre']) . '\', \'' . $tsCore->setSecure($temadb['url']) . '\', \'' . $tsCore->setSecure($tema_path) . '\', \'' . $tsCore->setSecure($temadb['copy']) . '\')')) return 1; else return 'Ocurri&oacute; un error durante la instalaci&oacute;n. Consulta el foro ofcial de PHPost.'; } y la reemplazaremos por public function newTema() { global $tsCore, $smarty; # ARCHIVO DE INSTALACION $method = (isset($_GET["path"])) ? $_GET["path"] : $_POST["path"]; include $smarty->template_dir["themes"] . $tsCore->setSecure($method) . "/install.php"; # Instalando usando directamente el botón de "instalar tema" $name = $tsCore->setSecure($tema['nombre']); $path = $tsCore->setSecure($tema['path']); $url = $tsCore->settings['url'] . '/themes/' . $path; $copy = $tsCore->setSecure($tema['copy']); # Si hay un problema en la carpeta if(empty($tema)) $data["error"] = 'Revisa que la carpeta del tema sea correcta.'; # Instalamos el tema if(db_exec([__FILE__, __LINE__], "query", "INSERT INTO w_temas (t_name, t_path, t_url, t_copy) VALUES ('{$name}', '{$path}', '{$url}', '{$copy}')")) { return true; } else return $data["error"] = 'Ocurrió un error durante la instalación. Consulta el foro ofcial de PHPost.'; } 2 - Ahora buscamos en inc/php/admin.php } elseif($action == 'temas'){ y debajo pegamos $tni = $tsAdmin->temas_no_instalados(); un poco más abajo buscan $smarty->assign("tsTemas",$tsAdmin->getTemas()); y debajo agregan $smarty->assign("tsNoTemas", count($tni)); más abajo buscan } elseif($act == 'nuevo'){ // GUARDAR if(!empty($_POST['path'])) { $install = $tsAdmin->newTema(); if($install == 1) $tsCore->redirectTo($tsCore->settings['url'].'/admin/temas?save=true'); else $smarty->assign("tsError",$install); } } y debajo agregan } elseif($act == 'nuevo'){ # Primero buscamos si hay temas sin instalar $smarty->assign("tsNoInstall", $tni); # Guardamos if(!empty($_POST['path']) or !empty($_GET['path'])) { if($tsAdmin->newTema()) $tsCore->redirectTo($tsCore->settings['url'].'/admin/temas?save=true'); else $smarty->assign("tsError", $install["error"]); } } 3 - Ahora vamos a nuestro tema templates/admin_mods/m.admin_temas.tpl y buscamos <div class="boxy-title"> <h3>Administrar Temas</h3> </div> y la reemplazamos por <div class="boxy-title" style="display: flex;justify-content: space-between;align-items: center;"> <h3>Administrar Temas</h3> {if $tsNoTemas >= 1} <span>Hay <b>{$tsNoTemas} tema{if $tsNoTemas > 1}s{/if}</b> sin instalar</span> {/if} </div> luego más abajo buscamos {elseif $tsAct == 'nuevo'} {if $tsError}<div style="display: block;" class="mensajes error">{$tsError}</div>{/if} <form action="" method="post" id="admin_form" autocomplete="off"> <label for="ai_path">Nombre de la carpeta donde esta el tema a instalar:<br /><i>{$tsConfig.url}/themes/</i></label> <input type="text" id="ai_path" name="path" size="30" /> <hr /> <label>&nbsp;</label> <input type="submit" value="Instalar tema" class="mBtn btnOk"> </form> {/if} y lo reemplazamos por {elseif $tsAct == 'nuevo'} {if $tsError}<div class="alerts error">{$tsError}</div>{/if} {if !empty($tsNoInstall)} <h4 style="margin: 6px 0;">Temas no instalados</h4> <p class="emptyData">Estos son temas que estan en "<u><i>{$tsConfig.url}/themes/</i></u>", pero no estan instalados en la base</p> <form method="post" autocomplete="off"> <input type="hidden" name="manual" value="0"> {foreach $tsNoInstall key=i item=t} <div style="display: flex;justify-content: space-between;align-items: center;margin-bottom: 10px;"> <div> <span><b>{$t.nombre}</b></span> <span style="display: block;"><b>Carpeta</b>: {$t.path}</span> <span><b>Autor</b>: {$t.copy}</span> </div> <div style="display: flex;justify-content: space-between;align-items: center;"> <a href="{$tsConfig.url}/admin/temas?act=nuevo&path={$t.path}" class="mBtn btnOk">Instalar {$t.nombre}</a> </div> </div> {/foreach} </form> {else} <form action="" method="post" id="admin_form" autocomplete="off"> <input type="hidden" name="manual" value="1"> <label for="ai_path">Nombre de la carpeta donde esta el tema a instalar:<br /><i>{$tsConfig.url}/themes/</i></label> <input type="text" id="ai_path" name="path" size="30" /> <hr class="separator"> <input type="submit" value="Instalar tema" class="mBtn btnOk"> </form> {/if} {/if} Puede ser que el atributo style modifique el css, esto ya es a su gusto. Ahora pueden agregar los themes e instalar desde un botón, sin tener que estar escribiendo el nombre del tema en el input.
  15. Plantilla base, me refiero aun solo archivo al accederemos desde la configuración del footer.php y se pueden crear varios, ejemplo: A - Puede ser para el sitio general B - Puede ser para la administración/moderación C - Puede ser para el perfil. En vez de que se busque la platilla "t.$tsPage.tpl" que esta configurada en la variable $TEMP del archivo ya mencionado, buscará el archivo base que se puede llamar "base_sitio.tpl", es un ejemplo, puede tener cualquier nombre. 1 - Crean un archivo en templates/sections/ con el nombre que deseen, ya que será el archivo base 2 - Colocan dentro todo el main_header.tpl y main_footer.tpl 3 - Ahora en esta parte <div id="cuerpocontainer"> <!--Cuperpo--> <!--end-cuerpo--> </div> luego reemplazan esta parte <!--Cuperpo--> {include "t.{$tsPage}.tpl"} <!--end-cuerpo--> y ya tendrán el archivo base. Ahora se preguntarán como va a funcionar si llama a los templates, bien, ahora buscan en footer.php $TEMP = "t.{$tsPage}.tpl"; y la reemplazarán por lo siguiente $TEMP = (explode('/', $tsPage)[0] === 'php_files') ? "t.{$tsPage}.tpl" : "base.tpl"; y porque esta así y no directamente "base.tpl", la razón es que existen métodos que requiere que se ejecuten archivos que se encuentran dentro de t.php_files o solo ejecutar una función ajax y al tener como valor "base.tpl" este le devolverá un error. Pero en todas las plantillas deberán borrar, ya que estas también se ejecutaran {include file='sections/main_header.tpl'} y {include file='sections/main_footer.tpl'} Y eso sería todo... Si quieren crear vistas separadas para administración/moderación, perfil, etc, úsenlo así $_BASE_ = ($tsPage == 'admin' && $tsPage == 'moderacion') ? '_admin_mods' : ($tsPage == 'perfil' ? '_perfil' : ''); $TEMP = (explode('/', $tsPage)[0] === 'php_files') ? "t.{$tsPage}.tpl" : "base{$_BASE_}.tpl"; por ende deben crear en este caso el archivo "base_admin_mods.tpl" y "base_perfil.tpl", esto en el caso hipotético que quieran hacer algo diferente en estas páginas
×