fix: harden WordPress content rendering

This commit is contained in:
bisco
2026-06-26 15:54:57 +02:00
parent 482928a296
commit 0762b98fc6
8 changed files with 43 additions and 18 deletions
+3 -2
View File
@@ -8,8 +8,9 @@ nor MariaDB publishes a host port; automated security checks guard this assumpti
The custom `azionelab` classic theme renders the public single page. Theme modifications
store the hero, manifesto, laboratory, teacher, lesson, and contact fields. The
`azionelab-content` must-use plugin registers Shows and Gallery custom post types so
structured editorial content survives a theme change. Images use WordPress featured
images with local SVG fallbacks.
structured editorial content survives a theme change. These custom post types are
editorial data sources for the homepage, not standalone public routes or REST
collections. Images use WordPress featured images with local SVG fallbacks.
WP-CLI is an opt-in tools-profile service. Its idempotent bootstrap installs WordPress,
activates the theme, configures the site, and creates realistic demo content. Certbot is
+3
View File
@@ -6,6 +6,9 @@
ignored and real secrets must come from the deployment secret manager.
- WordPress uses its normal capability, nonce, authentication, cookie, and password
controls. Theme settings sanitize input and templates escape output.
- Structured Shows and Gallery content is editable in WordPress admin but is consumed
by the homepage only; it is not exposed as standalone public routes or REST
collections.
- File editing is always disabled. Production also disables web-based core, theme, and
plugin changes; patched images are rebuilt and redeployed instead.
- XML-RPC and comments are disabled. NGINX blocks PHP execution below uploads, dotfiles,
+4 -3
View File
@@ -54,15 +54,15 @@ test("provides usable contact actions", async ({ page }) => {
await expect(page.locator(".social-link-youtube")).toHaveCount(1);
await expect(page.getByRole("link", { name: "Instagram" })).toHaveAttribute(
"href",
"https://instagram.com/",
"https://instagram.com/azionelab",
);
await expect(page.getByRole("link", { name: "Facebook" })).toHaveAttribute(
"href",
"https://facebook.com/",
"https://facebook.com/azionelab",
);
await expect(page.getByRole("link", { name: "YouTube" })).toHaveAttribute(
"href",
"https://youtube.com/",
"https://youtube.com/@azionelab",
);
await expect(page.locator(".social-links .social-icon")).toHaveCount(3);
await expect(page.locator(".contact-actions .contact-icon")).toHaveCount(3);
@@ -123,6 +123,7 @@ test("protects the edge and exposes the WordPress admin", async ({ page, request
expect((await request.get("/wp-config.php")).status()).toBe(404);
expect((await request.get("/wp-content/uploads/probe.php")).status()).toBe(403);
expect((await request.get("/wp-json/wp/v2/users")).status()).toBe(404);
expect((await request.get("/?post_type=azl_show&name=le-cose-che-restano")).status()).toBe(404);
await page.goto("/wp-admin/");
await expect(page).toHaveURL(/\/wp-login\.php/);
+5
View File
@@ -26,3 +26,8 @@ grep -q 'wp-content/(uploads|files)' /workspace/wordpress/apache-hardening.conf
echo "Apache hardening must block PHP execution below uploads/files." >&2
exit 1
}
grep -q "'publicly_queryable'[[:space:]]*=>[[:space:]]*false" /workspace/wordpress/mu-plugins/azionelab-content.php || {
echo "Structured show content must not be exposed as standalone public routes." >&2
exit 1
}
+4 -1
View File
@@ -19,7 +19,10 @@ function azionelab_register_content_types(): void {
'add_new_item' => 'Aggiungi spettacolo',
'edit_item' => 'Modifica spettacolo',
),
'public' => true,
'public' => false,
'show_ui' => true,
'publicly_queryable' => false,
'exclude_from_search'=> true,
'show_in_rest' => false,
'menu_icon' => 'dashicons-tickets-alt',
'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'page-attributes' ),
+15 -4
View File
@@ -21,6 +21,11 @@ $social_links = array_values(
static fn ( array $link ): bool => '' !== $link['url']
)
);
$contact_email = sanitize_email( azionelab_mod( 'contact_email' ) );
$contact_phone = trim( azionelab_mod( 'contact_phone' ) );
$contact_phone_href = azionelab_phone_href( $contact_phone );
$contact_whatsapp = trim( azionelab_mod( 'contact_whatsapp' ) );
$contact_whatsapp_href = azionelab_whatsapp_href( $contact_whatsapp );
?>
<main id="contenuto">
<section class="hero section" id="inizio" aria-labelledby="hero-title">
@@ -135,7 +140,7 @@ $social_links = array_values(
?>
<article class="show-card">
<img src="<?php echo esc_url( $image ); ?>" alt="Locandina di <?php the_title_attribute(); ?>" width="700" height="880" loading="lazy">
<div class="show-copy"><?php if ( $show_meta ) : ?><p class="show-meta"><?php echo esc_html( $show_meta ); ?></p><?php endif; ?><h3><?php the_title(); ?></h3><div><?php the_excerpt(); ?></div></div>
<div class="show-copy"><?php if ( $show_meta ) : ?><p class="show-meta"><?php echo esc_html( $show_meta ); ?></p><?php endif; ?><h3><?php echo esc_html( get_the_title() ); ?></h3><div><?php echo wp_kses_post( wpautop( get_the_excerpt() ) ); ?></div></div>
</article>
<?php
++$show_index;
@@ -207,9 +212,15 @@ $social_links = array_values(
<?php endif; ?>
</div>
<div class="contact-actions">
<a class="contact-action" href="mailto:<?php echo esc_attr( sanitize_email( azionelab_mod( 'contact_email' ) ) ); ?>"><?php echo azionelab_contact_icon( 'email' ); ?><span>Scrivi una mail</span><strong><?php echo esc_html( azionelab_mod( 'contact_email' ) ); ?></strong></a>
<a class="contact-action" href="tel:<?php echo esc_attr( azionelab_phone_href( azionelab_mod( 'contact_phone' ) ) ); ?>"><?php echo azionelab_contact_icon( 'phone' ); ?><span>Chiama</span><strong><?php echo esc_html( azionelab_mod( 'contact_phone' ) ); ?></strong></a>
<a class="contact-action" href="https://wa.me/<?php echo esc_attr( azionelab_whatsapp_href( azionelab_mod( 'contact_whatsapp' ) ) ); ?>" rel="noopener noreferrer"><?php echo azionelab_contact_icon( 'whatsapp' ); ?><span>WhatsApp</span><strong><?php echo esc_html( azionelab_mod( 'contact_whatsapp' ) ); ?></strong></a>
<?php if ( $contact_email ) : ?>
<a class="contact-action" href="mailto:<?php echo esc_attr( $contact_email ); ?>"><?php echo azionelab_contact_icon( 'email' ); ?><span>Scrivi una mail</span><strong><?php echo esc_html( $contact_email ); ?></strong></a>
<?php endif; ?>
<?php if ( $contact_phone && $contact_phone_href ) : ?>
<a class="contact-action" href="tel:<?php echo esc_attr( $contact_phone_href ); ?>"><?php echo azionelab_contact_icon( 'phone' ); ?><span>Chiama</span><strong><?php echo esc_html( $contact_phone ); ?></strong></a>
<?php endif; ?>
<?php if ( $contact_whatsapp && $contact_whatsapp_href ) : ?>
<a class="contact-action" href="https://wa.me/<?php echo esc_attr( $contact_whatsapp_href ); ?>" rel="noopener noreferrer"><?php echo azionelab_contact_icon( 'whatsapp' ); ?><span>WhatsApp</span><strong><?php echo esc_html( $contact_whatsapp ); ?></strong></a>
<?php endif; ?>
</div>
</div>
</section>
+3 -3
View File
@@ -29,9 +29,9 @@ function azionelab_defaults(): array {
'contact_email' => 'ciao@azionelab.org',
'contact_phone' => '+39 333 123 4567',
'contact_whatsapp' => '+39 333 123 4567',
'contact_instagram' => 'https://instagram.com/',
'contact_facebook' => 'https://facebook.com/',
'contact_youtube' => 'https://youtube.com/',
'contact_instagram' => '',
'contact_facebook' => '',
'contact_youtube' => '',
'contact_address' => "Via dell'Epomeo 9999, Napoli",
'footer_text' => 'Uno spazio aperto a chi desidera incontrare il teatro, insieme.',
);
+1
View File
@@ -46,6 +46,7 @@ wp option update permalink_structure '/%postname%/'
if ! wp theme is-active azionelab; then
wp theme activate azionelab
fi
wp eval 'set_theme_mod( "contact_instagram", "https://instagram.com/azionelab" ); set_theme_mod( "contact_facebook", "https://facebook.com/azionelab" ); set_theme_mod( "contact_youtube", "https://youtube.com/@azionelab" );'
for sample_id in 1 2; do
if ! wp post get "$sample_id" --field=ID >/dev/null 2>&1; then