Files
Josep Piguillem 9a6bcd56e5 Tema: nuevos botones, campos, casillas, tarjetas, selector, interruptor, cabecera y pie
- Botones: borde que se dibuja al pasar el ratón o con el teclado (color según variante) y sombra.
- Campos: subrayados con etiqueta flotante y degradado principal → acento al enfocar; flecha
  propia en los desplegables. Formularios de contacto, cuestionario y finales felices adaptados.
- Casillas: marca «a mano» que se dibuja al marcarlas (ga_checkmark()), accesibles con teclado.
- Tarjetas de animales y finales felices: marco de 2 px con resplandor de acento en la esquina.
- Selector segmentado (.ga-segmented) con píldora deslizante; se usa en las pestañas Perros / Gatos
  y sirve también para grupos de radios.
- Interruptor (.ga-toggle, ga_toggle_ui()) listo para usar.
- Cabecera translúcida con borde al hacer scroll, enlaces en píldora, desplegable animado con
  descripción de cada elemento y fondo oscurecido mientras está abierto.
- Pie: nombre gigante en bajorrelieve que se descubre al final de la página (opción en el
  personalizador, «Bilagun» por defecto).
- Versión del tema 2.3.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:11:17 +02:00

176 lines
8.6 KiB
PHP

<?php
/**
* Finales felices (historias enviadas por las familias, con revisión) y apadrinamiento.
*/
defined( 'ABSPATH' ) || exit;
/* -------------------------------------------------------------------------
* Historias: tipo de contenido
* ---------------------------------------------------------------------- */
add_action( 'init', function () {
register_post_type( 'ga_historia', array(
'labels' => array(
'name' => 'Finales felices',
'singular_name' => 'Final feliz',
'add_new_item' => 'Añadir final feliz',
'edit_item' => 'Revisar final feliz',
'all_items' => 'Finales felices',
'not_found' => 'Aún no hay historias',
'featured_image' => 'Foto',
),
'public' => false,
'show_ui' => true,
'show_in_menu' => 'edit.php?post_type=animal',
'supports' => array( 'title', 'editor', 'thumbnail' ),
'map_meta_cap' => true,
) );
} );
/* Contador de historias pendientes en el menú */
add_action( 'admin_menu', function () {
global $submenu;
$pending = (int) wp_count_posts( 'ga_historia' )->pending;
foreach ( $submenu['edit.php?post_type=animal'] ?? array() as $i => $item ) {
if ( 'edit.php?post_type=ga_historia' === $item[2] && $pending ) {
$submenu['edit.php?post_type=animal'][ $i ][0] .= ' <span class="awaiting-mod">' . $pending . '</span>';
}
}
}, 99 );
/** Historias publicadas en el idioma actual (o en cualquiera si no hay). */
function ga_query_stories( $number = 6 ) {
return new WP_Query( array(
'post_type' => 'ga_historia',
'post_status' => 'publish',
'posts_per_page' => $number,
'no_found_rows' => true,
) );
}
/* -------------------------------------------------------------------------
* [ga_final_feliz] formulario para que las familias envíen su historia
* ---------------------------------------------------------------------- */
add_shortcode( 'ga_final_feliz', function () {
$status = sanitize_key( $_GET['historia'] ?? '' );
$privacy = ga_page_url( 'politica-de-privacidad' );
ob_start();
if ( 'ok' === $status ) {
echo '<div class="ga-notice ga-notice--ok" role="status">' . esc_html( ga__( '¡Gracias por compartirlo! Lo revisaremos antes de publicarlo.', 'Eskerrik asko partekatzeagatik! Argitaratu aurretik berrikusiko dugu.' ) ) . '</div>';
return ob_get_clean();
}
if ( 'error' === $status ) {
echo '<div class="ga-notice ga-notice--error" role="alert">' . esc_html( ga__( 'No hemos podido enviarlo. Revisa los campos y que la foto sea JPG, PNG o WebP de menos de 5 MB.', 'Ezin izan dugu bidali. Egiaztatu eremuak eta argazkia JPG, PNG edo WebP dela eta 5 MB baino gutxiago dituela.' ) ) . '</div>';
}
?>
<form class="ga-form" method="post" enctype="multipart/form-data" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
<input type="hidden" name="action" value="ga_final_feliz">
<input type="hidden" name="redirect" value="<?php echo esc_url( get_permalink() ); ?>">
<input type="hidden" name="idioma" value="<?php echo esc_attr( ga_lang() ); ?>">
<?php wp_nonce_field( 'ga_final_feliz', 'ga_nonce' ); ?>
<div class="ga-hp" aria-hidden="true"><label>No rellenar <input type="text" name="web" tabindex="-1" autocomplete="off"></label></div>
<div class="ga-form__row">
<label class="ga-field"><input type="text" name="animal" required maxlength="80" placeholder=" "><span><?php ga_e( 'Nombre del animal', 'Animaliaren izena' ); ?> *</span></label>
<label class="ga-field"><input type="text" name="familia" required maxlength="80" placeholder=" "><span><?php ga_e( 'Vuestro nombre', 'Zuen izena' ); ?> *</span></label>
</div>
<label class="ga-field"><input type="email" name="email" required placeholder=" "><span><?php ga_e( 'Correo electrónico (no se publica)', 'Posta elektronikoa (ez da argitaratzen)' ); ?> *</span></label>
<label class="ga-field"><textarea name="texto" rows="5" required maxlength="800" placeholder=" "></textarea><span><?php ga_e( '¿Cómo está ahora?', 'Nola dago orain?' ); ?> *</span></label>
<label><?php ga_e( 'Una foto (JPG, PNG o WebP, máx. 5 MB)', 'Argazki bat (JPG, PNG edo WebP, gehienez 5 MB)' ); ?><input type="file" name="foto" accept="image/jpeg,image/png,image/webp"></label>
<label class="ga-form__check"><input type="checkbox" name="publicar" value="1" required><?php echo ga_checkmark(); // SVG estático. ?>
<span><?php ga_e( 'Autorizo a Bilagun a publicar este texto y la foto en su web y redes. *', 'Bilaguni baimena ematen diot testu hau eta argazkia bere webgunean eta sareetan argitaratzeko. *' ); ?></span></label>
<label class="ga-form__check"><input type="checkbox" name="privacidad" value="1" required><?php echo ga_checkmark(); // SVG estático. ?>
<span><?php
printf(
wp_kses( ga__( 'He leído y acepto la <a href="%s" target="_blank">política de privacidad</a>. *', '<a href="%s" target="_blank">Pribatutasun-politika</a> irakurri eta onartzen dut. *' ), array( 'a' => array( 'href' => array(), 'target' => array() ) ) ),
esc_url( $privacy )
);
?></span></label>
<button type="submit" class="ga-btn"><?php ga_e( 'Enviar nuestra historia', 'Gure istorioa bidali' ); ?></button>
</form>
<?php
return ob_get_clean();
} );
add_action( 'admin_post_nopriv_ga_final_feliz', 'ga_handle_story' );
add_action( 'admin_post_ga_final_feliz', 'ga_handle_story' );
function ga_handle_story() {
$redirect = wp_validate_redirect( esc_url_raw( wp_unslash( $_POST['redirect'] ?? '' ) ), home_url( '/' ) );
$go = function ( $status ) use ( $redirect ) {
wp_safe_redirect( add_query_arg( 'historia', $status, $redirect ) . '#historia' );
exit;
};
if ( ! isset( $_POST['ga_nonce'] ) || ! wp_verify_nonce( $_POST['ga_nonce'], 'ga_final_feliz' ) ) {
$go( 'error' );
}
if ( ! empty( $_POST['web'] ) ) {
$go( 'ok' );
}
// Límite sencillo: 3 envíos por hora y dirección IP.
$key = 'ga_story_' . md5( $_SERVER['REMOTE_ADDR'] ?? '' );
$count = (int) get_transient( $key );
if ( $count >= 3 ) {
$go( 'error' );
}
set_transient( $key, $count + 1, HOUR_IN_SECONDS );
$animal = sanitize_text_field( wp_unslash( $_POST['animal'] ?? '' ) );
$familia = sanitize_text_field( wp_unslash( $_POST['familia'] ?? '' ) );
$email = sanitize_email( wp_unslash( $_POST['email'] ?? '' ) );
$texto = mb_substr( sanitize_textarea_field( wp_unslash( $_POST['texto'] ?? '' ) ), 0, 800 );
if ( ! $animal || ! $familia || ! is_email( $email ) || ! $texto || empty( $_POST['publicar'] ) || empty( $_POST['privacidad'] ) ) {
$go( 'error' );
}
$story_id = wp_insert_post( array(
'post_type' => 'ga_historia',
'post_status' => 'pending',
'post_title' => $animal,
'post_content' => $texto,
) );
if ( ! $story_id || is_wp_error( $story_id ) ) {
$go( 'error' );
}
update_post_meta( $story_id, '_ga_familia', $familia );
update_post_meta( $story_id, '_ga_email', $email );
update_post_meta( $story_id, '_ga_idioma', 'eu' === ( $_POST['idioma'] ?? '' ) ? 'eu' : 'es' );
// Foto: solo imágenes reales de hasta 5 MB.
if ( ! empty( $_FILES['foto']['tmp_name'] ) && UPLOAD_ERR_OK === $_FILES['foto']['error'] ) {
$file = $_FILES['foto'];
$check = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'], array( 'jpg|jpeg' => 'image/jpeg', 'png' => 'image/png', 'webp' => 'image/webp' ) );
if ( $file['size'] > 5 * MB_IN_BYTES || ! $check['type'] || ! @getimagesize( $file['tmp_name'] ) ) {
wp_delete_post( $story_id, true );
$go( 'error' );
}
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
$attachment = media_handle_upload( 'foto', $story_id, array(), array( 'test_form' => false, 'mimes' => array( 'jpg|jpeg' => 'image/jpeg', 'png' => 'image/png', 'webp' => 'image/webp' ) ) );
if ( ! is_wp_error( $attachment ) ) {
set_post_thumbnail( $story_id, $attachment );
}
}
wp_mail(
ga_contact_email(),
'[Web] Nuevo final feliz por revisar: ' . $animal,
sprintf( "%s ha enviado la historia de %s.\n\nRevísala y publícala aquí: %s", $familia, $animal, admin_url( 'post.php?action=edit&post=' . $story_id ) )
);
$go( 'ok' );
}
/* En el panel: quién la envió (sin publicar su correo) */
add_action( 'add_meta_boxes_ga_historia', function () {
add_meta_box( 'ga_historia_info', 'Enviada por', function ( $post ) {
printf(
'<p><strong>%s</strong><br>%s<br>Idioma: %s</p><p class="description">Para publicarla pulsa «Publicar». El nombre de la familia se muestra; el correo no.</p>',
esc_html( get_post_meta( $post->ID, '_ga_familia', true ) ?: '—' ),
esc_html( get_post_meta( $post->ID, '_ga_email', true ) ?: '' ),
esc_html( get_post_meta( $post->ID, '_ga_idioma', true ) ?: 'es' )
);
}, 'ga_historia', 'side' );
} );