/* ========================== Admin Page Wrapper ========================== */
function rj360_admin_wrapper(){
$nonce = wp_create_nonce('rj360');
$opt = get_option(RJ360_OPT, rj360_defaults());
$cats = get_terms(['taxonomy' => 'category', 'hide_empty' => false, 'number' => 200]);
rj360_output_ui($nonce, $opt, $cats); // Llama al UI puro con datos pre-fetchados
}
/* ========================== Enqueue CSS solo en nuestra pantalla ========================== */
add_action('admin_enqueue_scripts', function($hook){
if ($hook !== 'toplevel_page_rj360-admin') return;
if (!wp_style_is('rj360-admin-style','registered')){
wp_register_style('rj360-admin-style', false, [], RJ360_VER);
}
wp_enqueue_style('rj360-admin-style');
$inline = '/* ===== Admin CSS (inline) ===== */
:root{
--gap:12px; --radius:12px; --border:#e3e6ea; --bg:#f6f7f9; --card:#fff;
--primary:#0366d6; --primary-ink:#fff; --muted:#6b7280; --ok:#16a34a; --warn:#b45309; --danger:#dc2626;
}
#rj360{max-width:1400px}
#rj360 h1{margin-bottom:14px}
#rj360 .rj-grid{
display:grid;
grid-template-columns: 1.1fr 1.8fr 1.1fr;
gap: var(--gap);
align-items:start;
}
#rj360 .card{background:var(--card); border:1px solid var(--border); border-radius:var(--radius); overflow:hidden}
#rj360 .card .inner{padding:14px 14px 18px}
#rj360 .row{display:flex; gap:10px; align-items:center; margin-bottom:10px}
#rj360 .row.cols-2>*, #rj360 .row.cols-3>*{flex:1}
#rj360 .row.cols-3>*{min-width:0}
#rj360 input[type="text"], #rj360 input[type="number"], #rj360 input[type="datetime-local"], #rj360 textarea, #rj360 select{
width:100%; padding:10px 12px; border:1px solid var(--border); border-radius:10px; background:#fff; outline:none
}
#rj360 textarea{font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace}
#rj360 .button{padding:8px 12px; border:1px solid var(--border); background:#fff; border-radius:10px; cursor:pointer}
#rj360 .button:hover{background:#f3f4f6}
#rj360 .button.button-primary{border-color:var(--primary); background:var(--primary); color:var(--primary-ink)}
#rj360 .chips{display:flex; flex-wrap:wrap; gap:8px}
#rj360 .chip{display:inline-flex; align-items:center; gap:6px; padding:6px 10px; border:1px solid var(--border); border-radius:20px; background:#fff}
#rj360 .panel{display:none}
#rj360 .panel.active{display:block}
#rj360 .list{display:flex; flex-direction:column; gap:8px; max-height:520px; overflow:auto; border:1px dashed #e5e7eb; padding:8px; border-radius:10px}
#rj360 .item a{text-decoration:none}
#rj360 .preview{margin-top:12px; border:1px solid var(--border); border-radius:12px; overflow:hidden}
#rj360 .preview #preview-frame{width:100%; height:540px; border:0}
#rj360 .days{display:flex; gap:8px; flex-wrap:wrap}
#rj360 .days-row{align-items:flex-start}
@media (max-width:1280px){
#rj360 .rj-grid{ grid-template-columns: 1fr }
#rj360 .preview #preview-frame{height:480px}
}
@media (min-width:1281px) and (max-width:1600px){
#rj360 .rj-grid{ grid-template-columns: 1fr 1.4fr 1fr }
}';
if (function_exists('wp_add_inline_style')) wp_add_inline_style('rj360-admin-style', $inline);
wp_enqueue_style('theme-style', get_stylesheet_uri(), [], null, 'all');
});
/* ========================== Defaults & Setup ========================== */
function rj360_defaults(){ return [
'feeds'=>[
['url'=>'https://prensa.jujuy.gob.ar/feed/','active'=>true],
['url'=>'https://www.argentina.gob.ar/noticias/todas-las-noticias/rss.xml','active'=>true],
],
'days'=>['mon','tue','wed','thu','fri','sat','sun'],
'safe_image_domains'=>".gob.ar\nargentina.gob.ar\njujuy.gob.ar\nwikipedia.org\nwikimedia.org\nprensa.jujuy.gob.ar"
];}
function rj360_norm_feeds($fs){
$o=[]; foreach((array)$fs as $f){
if(is_array($f)&&isset($f['url'])) $o[]=['url'=>trim($f['url']),'active'=>!empty($f['active'])];
elseif(is_string($f)&&$f) $o[]=['url'=>trim($f),'active'=>true];
} return $o;
}
add_action('admin_init',function(){
$opt=get_option(RJ360_OPT);
if(!$opt) $opt=rj360_defaults();
$opt=array_merge(rj360_defaults(),$opt);
$opt['feeds']=rj360_norm_feeds($opt['feeds']);
update_option(RJ360_OPT,$opt);
});
/* ========================== Admin Menu ========================== */
add_action('admin_menu',function(){
add_menu_page('Reportero 360','Reportero 360','edit_posts','rj360-admin','rj360_admin_wrapper','dashicons-media-document',3);
});
/* ========================== AJAX ========================== */
add_action('wp_ajax_rj360_api', function(){
if(!current_user_can('edit_posts')) wp_send_json_error('forbidden');
check_ajax_referer('rj360');
$sub = sanitize_key($_POST['sub']??'');
$payload = json_decode(stripslashes($_POST['payload']??'{}'), true) ?: [];
try{
switch($sub){
case 'fetch_rss': $out = rj360_ajax_fetch_rss($payload); break;
case 'fetch_url': $out = rj360_ajax_fetch_url($payload); break;
case 'search_posts': $out = rj360_ajax_search_posts($payload); break;
case 'read_post': $out = rj360_ajax_read_post($payload); break;
case 'clean_html': $out = ['html'=>rj360_clean_html($payload['html']??'')]; break;
case 'publish': $out = ['id'=>rj360_publish($payload)]; break;
case 'save_opt': update_option(RJ360_OPT, rj360_merge_options($payload['opt']??[])); $out=['ok'=>true]; break;
default: throw new Exception('acción no soportada');
}
wp_send_json_success($out);
}catch(Throwable $e){
wp_send_json_error($e->getMessage());
}
});
/* ========================== Helpers ========================== */
function rj360_merge_options($in){
$base = get_option(RJ360_OPT, rj360_defaults());
$in['feeds'] = rj360_norm_feeds($in['feeds']??[]);
$out = array_merge($base, $in);
return $out;
}
function rj360_host_allows($url){
$opt = get_option(RJ360_OPT, rj360_defaults());
$list = array_filter(array_map('trim', explode("\n", (string)($opt['safe_image_domains']??''))));
if(!$list) return true;
$host = parse_url($url, PHP_URL_HOST);
if(!$host) return false;
foreach($list as $rule){
$rule = ltrim($rule);
if($rule && (str_ends_with($host,$rule) || $host===$rule || (strpos($rule,'.')===0 && str_ends_with($host,$rule)))){
return true;
}
}
return false;
}
function rj360_clean_html($html){
$allowed = [
'a'=>['href'=>true,'title'=>true,'target'=>true,'rel'=>true],
'p'=>['class'=>true],'br'=>[], 'strong'=>[], 'em'=>[], 'b'=>[], 'i'=>[],
'ul'=>[],'ol'=>[],'li'=>[], 'h1'=>[],'h2'=>[],'h3'=>[],'h4'=>[],'h5'=>[],'h6'=>[],
'img'=>['src'=>true,'alt'=>true,'title'=>true,'width'=>true,'height'=>true,'loading'=>true],
'figure'=>[],'figcaption'=>[], 'blockquote'=>['cite'=>true], 'code'=>[], 'pre'=>[]
];
$html = wp_kses((string)$html, $allowed);
// Quitar atributos peligrosos
$html = preg_replace('/\son\w+="[^"]*"/i','',$html);
// Remover iframes/embeds
$html = preg_replace('#<(iframe|embed|script)[\s\S]*?\1>#i','',$html);
return $html;
}
/* ========================== RSS ========================== */
function rj360_ajax_fetch_rss($p){
$url = esc_url_raw($p['url']??'');
$limit = max(1, min( (int)($p['limit']??12), 50 ));
if(!$url) throw new Exception('feed vacío');
require_once ABSPATH.'wp-includes/feed.php';
$rss = fetch_feed($url);
if(is_wp_error($rss)) throw new Exception('RSS inválido');
$max = $rss->get_item_quantity($limit);
$items = [];
for($i=0; $i<$max; $i++){
$it = $rss->get_item($i);
$items[] = [
'title' => (string)$it->get_title(),
'link' => (string)$it->get_link(),
'date' => (string)$it->get_date('c'),
];
}
return ['items'=>$items];
}
/* ========================== URL Fetch (simple) ========================== */
function rj360_ajax_fetch_url($p){
$url = esc_url_raw($p['url']??'');
if(!$url) throw new Exception('URL vacía');
$res = wp_remote_get($url, ['timeout'=>12,'redirection'=>5,'user-agent'=>'RJ360/3.0']);
if(is_wp_error($res)) throw new Exception('No se pudo descargar');
$html = wp_remote_retrieve_body($res);
if(!$html) throw new Exception('Sin contenido');
// Title
$title=''; if(preg_match('~
(.*?) ~is',$html,$m)) $title=wp_strip_all_tags($m[1]);
// Main image (og:image)
$image=''; if(preg_match('~ ]*>([\s\S]+?)~i',$html,$m)) $content = $m[1];
if(!$content && preg_match('~]*>([\s\S]+?)~i',$html,$m)) $content = $m[1];
$content = rj360_clean_html($content);
return ['title'=>$title,'image'=>$image,'content'=>$content];
}
/* ========================== Posts ========================== */
function rj360_ajax_search_posts($p){
$q = sanitize_text_field($p['q']??'');
$args = ['post_type'=>'post','posts_per_page'=>20,'s'=>$q,'post_status'=>'any','orderby'=>'date','order'=>'DESC'];
$posts = get_posts($args);
return ['items'=>array_map(function($po){
return ['ID'=>$po->ID,'post_title'=>$po->post_title];
}, $posts)];
}
function rj360_ajax_read_post($p){
$id = (int)($p['id']??0);
if($id<1) throw new Exception('ID inválido');
$po = get_post($id);
if(!$po) throw new Exception('No existe');
$img = get_the_post_thumbnail_url($po,'full') ?: '';
$tags = wp_get_post_tags($id, ['fields'=>'names']);
$cats = wp_get_post_categories($id);
return ['title'=>$po->post_title,'content'=>$po->post_content,'image'=>$img,'tags'=>$tags,'cats'=>$cats];
}
/* ========================== Publicar ========================== */
function rj360_publish($p){
$title = sanitize_text_field($p['title']??'');
$subtitle = sanitize_text_field($p['subtitle']??'');
$content = rj360_clean_html($p['content']??'');
$image = esc_url_raw($p['image']??'');
$author = max(1,(int)($p['author']??1));
$status = in_array(($p['status']??'draft'), ['draft','publish','future','pending'], true) ? $p['status'] : 'draft';
$slug = sanitize_title($p['slug']??'');
$excerpt = sanitize_text_field($p['excerpt']??'');
$date = sanitize_text_field($p['date']??'');
$cats = array_filter(array_map('intval', (array)($p['cats']??[])));
$tags = array_filter(array_map('trim', explode(',', (string)($p['tags']??''))));
$postarr = [
'post_title' => $title,
'post_content' => ($subtitle ? ''.esc_html($subtitle).'
' : '').$content,
'post_status' => $status,
'post_author' => $author,
'post_type' => 'post',
];
if($slug) $postarr['post_name'] = $slug;
if($excerpt)$postarr['post_excerpt'] = $excerpt;
if($date) $postarr['post_date'] = date('Y-m-d H:i:s', strtotime($date));
$id = wp_insert_post($postarr, true);
if(is_wp_error($id)) throw new Exception($id->get_error_message());
if($cats) wp_set_post_categories($id, $cats, false);
if($tags) wp_set_post_tags($id, $tags, false);
// Meta JSON
$meta = (array)($p['meta']??[]);
foreach($meta as $k=>$v){
if(is_scalar($v) || is_null($v)) update_post_meta($id, sanitize_key($k), maybe_serialize($v));
}
// Imagen
if($image){
if(!rj360_host_allows($image)) throw new Exception('Dominio de imagen no permitido');
require_once ABSPATH.'wp-admin/includes/media.php';
require_once ABSPATH.'wp-admin/includes/file.php';
require_once ABSPATH.'wp-admin/includes/image.php';
$att_id = media_sideload_image($image, $id, $title, 'id');
if(!is_wp_error($att_id)) set_post_thumbnail($id, $att_id);
}
return $id;
}
/* ========================== Media helpers (fallback) ========================== */
if(!function_exists('rj360_media_sideload')){
function rj360_media_sideload($url,$post=0,$desc=''){
if(!$url) return 0;
require_once ABSPATH.'wp-admin/includes/file.php';
require_once ABSPATH.'wp-admin/includes/media.php';
require_once ABSPATH.'wp-admin/includes/image.php';
$tmp=download_url($url); if(is_wp_error($tmp)) return 0;
$mime=function_exists('mime_content_type')?mime_content_type($tmp):(wp_check_filetype($url)['type']??'image/jpeg');
$name=basename(parse_url($url,PHP_URL_PATH))?:'media.jpg';
$file=['name'=>$name,'type'=>$mime,'tmp_name'=>$tmp,'size'=>@filesize($tmp),'error'=>0];
$id=media_handle_sideload($file,$post,$desc);
if(is_wp_error($id)){ @unlink($tmp); return 0; }
@unlink($tmp);
$path=get_attached_file($id);
if($path&&file_exists($path)){
$meta=wp_generate_attachment_metadata($id,$path);
if($meta) wp_update_attachment_metadata($id,$meta);
}
return $id;
}
}
No se encontró la página | Jujuy 360