generated from bisco/codex-bootstrap
fix: harden WordPress content rendering
This commit is contained in:
@@ -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
|
The custom `azionelab` classic theme renders the public single page. Theme modifications
|
||||||
store the hero, manifesto, laboratory, teacher, lesson, and contact fields. The
|
store the hero, manifesto, laboratory, teacher, lesson, and contact fields. The
|
||||||
`azionelab-content` must-use plugin registers Shows and Gallery custom post types so
|
`azionelab-content` must-use plugin registers Shows and Gallery custom post types so
|
||||||
structured editorial content survives a theme change. Images use WordPress featured
|
structured editorial content survives a theme change. These custom post types are
|
||||||
images with local SVG fallbacks.
|
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,
|
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
|
activates the theme, configures the site, and creates realistic demo content. Certbot is
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
ignored and real secrets must come from the deployment secret manager.
|
ignored and real secrets must come from the deployment secret manager.
|
||||||
- WordPress uses its normal capability, nonce, authentication, cookie, and password
|
- WordPress uses its normal capability, nonce, authentication, cookie, and password
|
||||||
controls. Theme settings sanitize input and templates escape output.
|
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
|
- File editing is always disabled. Production also disables web-based core, theme, and
|
||||||
plugin changes; patched images are rebuilt and redeployed instead.
|
plugin changes; patched images are rebuilt and redeployed instead.
|
||||||
- XML-RPC and comments are disabled. NGINX blocks PHP execution below uploads, dotfiles,
|
- XML-RPC and comments are disabled. NGINX blocks PHP execution below uploads, dotfiles,
|
||||||
|
|||||||
@@ -54,15 +54,15 @@ test("provides usable contact actions", async ({ page }) => {
|
|||||||
await expect(page.locator(".social-link-youtube")).toHaveCount(1);
|
await expect(page.locator(".social-link-youtube")).toHaveCount(1);
|
||||||
await expect(page.getByRole("link", { name: "Instagram" })).toHaveAttribute(
|
await expect(page.getByRole("link", { name: "Instagram" })).toHaveAttribute(
|
||||||
"href",
|
"href",
|
||||||
"https://instagram.com/",
|
"https://instagram.com/azionelab",
|
||||||
);
|
);
|
||||||
await expect(page.getByRole("link", { name: "Facebook" })).toHaveAttribute(
|
await expect(page.getByRole("link", { name: "Facebook" })).toHaveAttribute(
|
||||||
"href",
|
"href",
|
||||||
"https://facebook.com/",
|
"https://facebook.com/azionelab",
|
||||||
);
|
);
|
||||||
await expect(page.getByRole("link", { name: "YouTube" })).toHaveAttribute(
|
await expect(page.getByRole("link", { name: "YouTube" })).toHaveAttribute(
|
||||||
"href",
|
"href",
|
||||||
"https://youtube.com/",
|
"https://youtube.com/@azionelab",
|
||||||
);
|
);
|
||||||
await expect(page.locator(".social-links .social-icon")).toHaveCount(3);
|
await expect(page.locator(".social-links .social-icon")).toHaveCount(3);
|
||||||
await expect(page.locator(".contact-actions .contact-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-config.php")).status()).toBe(404);
|
||||||
expect((await request.get("/wp-content/uploads/probe.php")).status()).toBe(403);
|
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("/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 page.goto("/wp-admin/");
|
||||||
await expect(page).toHaveURL(/\/wp-login\.php/);
|
await expect(page).toHaveURL(/\/wp-login\.php/);
|
||||||
|
|||||||
@@ -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
|
echo "Apache hardening must block PHP execution below uploads/files." >&2
|
||||||
exit 1
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,12 +19,15 @@ function azionelab_register_content_types(): void {
|
|||||||
'add_new_item' => 'Aggiungi spettacolo',
|
'add_new_item' => 'Aggiungi spettacolo',
|
||||||
'edit_item' => 'Modifica spettacolo',
|
'edit_item' => 'Modifica spettacolo',
|
||||||
),
|
),
|
||||||
'public' => true,
|
'public' => false,
|
||||||
'show_in_rest' => false,
|
'show_ui' => true,
|
||||||
'menu_icon' => 'dashicons-tickets-alt',
|
'publicly_queryable' => false,
|
||||||
'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'page-attributes' ),
|
'exclude_from_search'=> true,
|
||||||
'has_archive' => false,
|
'show_in_rest' => false,
|
||||||
'rewrite' => false,
|
'menu_icon' => 'dashicons-tickets-alt',
|
||||||
|
'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'page-attributes' ),
|
||||||
|
'has_archive' => false,
|
||||||
|
'rewrite' => false,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ $social_links = array_values(
|
|||||||
static fn ( array $link ): bool => '' !== $link['url']
|
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">
|
<main id="contenuto">
|
||||||
<section class="hero section" id="inizio" aria-labelledby="hero-title">
|
<section class="hero section" id="inizio" aria-labelledby="hero-title">
|
||||||
@@ -135,7 +140,7 @@ $social_links = array_values(
|
|||||||
?>
|
?>
|
||||||
<article class="show-card">
|
<article class="show-card">
|
||||||
<img src="<?php echo esc_url( $image ); ?>" alt="Locandina di <?php the_title_attribute(); ?>" width="700" height="880" loading="lazy">
|
<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>
|
</article>
|
||||||
<?php
|
<?php
|
||||||
++$show_index;
|
++$show_index;
|
||||||
@@ -207,9 +212,15 @@ $social_links = array_values(
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="contact-actions">
|
<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>
|
<?php if ( $contact_email ) : ?>
|
||||||
<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="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>
|
||||||
<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 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>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ function azionelab_defaults(): array {
|
|||||||
'contact_email' => 'ciao@azionelab.org',
|
'contact_email' => 'ciao@azionelab.org',
|
||||||
'contact_phone' => '+39 333 123 4567',
|
'contact_phone' => '+39 333 123 4567',
|
||||||
'contact_whatsapp' => '+39 333 123 4567',
|
'contact_whatsapp' => '+39 333 123 4567',
|
||||||
'contact_instagram' => 'https://instagram.com/',
|
'contact_instagram' => '',
|
||||||
'contact_facebook' => 'https://facebook.com/',
|
'contact_facebook' => '',
|
||||||
'contact_youtube' => 'https://youtube.com/',
|
'contact_youtube' => '',
|
||||||
'contact_address' => "Via dell'Epomeo 9999, Napoli",
|
'contact_address' => "Via dell'Epomeo 9999, Napoli",
|
||||||
'footer_text' => 'Uno spazio aperto a chi desidera incontrare il teatro, insieme.',
|
'footer_text' => 'Uno spazio aperto a chi desidera incontrare il teatro, insieme.',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ wp option update permalink_structure '/%postname%/'
|
|||||||
if ! wp theme is-active azionelab; then
|
if ! wp theme is-active azionelab; then
|
||||||
wp theme activate azionelab
|
wp theme activate azionelab
|
||||||
fi
|
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
|
for sample_id in 1 2; do
|
||||||
if ! wp post get "$sample_id" --field=ID >/dev/null 2>&1; then
|
if ! wp post get "$sample_id" --field=ID >/dev/null 2>&1; then
|
||||||
|
|||||||
Reference in New Issue
Block a user