Files
prautoblogger/includes/frontend/class-article-typography.php
peptiderepo a37fb843a3 Add Display settings: article font, font size, table borders
New "Display" admin section with three settings:
- Article Font (7 choices + theme default, Google Fonts loaded on demand)
- Article Font Size (px, 0 = theme default)
- Table Borders (toggle, on by default — adds borders, padding, striping)

Inline CSS injected via wp_head only on singular posts with
_prautoblogger_generated meta — zero impact on other pages.

Extracted Image_Model_Registry to keep settings-fields-extended under
300 lines.

Bump 0.6.3 → 0.7.0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 12:48:57 +07:00

197 lines
6.1 KiB
PHP

<?php
declare(strict_types=1);
/**
* Injects frontend typography and table styles for PRAutoBlogger-generated posts.
*
* What: Outputs inline CSS on single post pages that have the
* _prautoblogger_generated meta flag, applying user-configured
* font family, font size, and table border styles.
* Who calls it: PRAutoBlogger::register_frontend_hooks() hooks this
* into wp_head.
* Dependencies: Reads wp_options for typography settings.
*
* @see class-prautoblogger.php — Registers the wp_head hook.
* @see class-settings-fields.php — Defines the Display settings section.
* @see admin/class-admin-page.php — Renders the settings form.
*/
class PRAutoBlogger_Article_Typography {
/** Option key for article font family. */
private const OPT_FONT_FAMILY = 'prautoblogger_article_font_family';
/** Option key for article body font size in pixels. */
private const OPT_FONT_SIZE = 'prautoblogger_article_font_size';
/** Option key for table border toggle. */
private const OPT_TABLE_BORDERS = 'prautoblogger_table_borders';
/**
* Output inline CSS in <head> for PRAutoBlogger posts.
*
* Only outputs on singular post pages generated by PRAutoBlogger.
* The CSS targets .post-content (PR Theme's article body class)
* and overrides the theme's CSS custom properties so the cascade
* works naturally with headings and sub-elements.
*
* Side effects: echoes a <style> block.
*
* @return void
*/
public function on_wp_head(): void {
if ( ! is_singular( 'post' ) ) {
return;
}
$post_id = get_queried_object_id();
if ( '1' !== get_post_meta( $post_id, '_prautoblogger_generated', true ) ) {
return;
}
$css = $this->build_css();
if ( '' === $css ) {
return;
}
printf(
"\n<style id=\"prautoblogger-typography\">\n%s\n</style>\n",
$css // Already escaped — contains only sanitized option values.
);
}
/**
* Build the CSS string from current settings.
*
* Reads each setting at call time (never cached) so changes
* take effect immediately without cache invalidation.
*
* @return string CSS rules, or empty string if all defaults.
*/
private function build_css(): string {
$rules = [];
$font_family = $this->get_font_family_stack();
if ( '' !== $font_family ) {
$rules[] = sprintf(
".post-content,\n.post-content p,\n.post-content li {\n\tfont-family: %s;\n}",
$font_family
);
}
$font_size = absint( get_option( self::OPT_FONT_SIZE, 0 ) );
if ( $font_size > 0 ) {
$rules[] = sprintf(
".post-content,\n.post-content p,\n.post-content li {\n\tfont-size: %dpx;\n\tline-height: 1.7;\n}",
$font_size
);
}
$table_borders = get_option( self::OPT_TABLE_BORDERS, '1' );
if ( '1' === $table_borders ) {
$rules[] = implode( "\n", [
'.post-content table {',
"\tborder-collapse: collapse;",
"\twidth: 100%;",
"\tmargin: 1.5em 0;",
'}',
'.post-content th,',
'.post-content td {',
"\tborder: 1px solid #d1d5db;",
"\tpadding: 0.6em 1em;",
"\ttext-align: left;",
'}',
'.post-content thead th {',
"\tbackground: #f3f4f6;",
"\tfont-weight: 600;",
'}',
'.post-content tbody tr:nth-child(even) {',
"\tbackground: #f9fafb;",
'}',
] );
}
return implode( "\n\n", $rules );
}
/**
* Map the stored font-family key to a full CSS font stack.
*
* Returns empty string for 'default' (let the theme decide).
*
* @return string CSS font-family value, or empty for theme default.
*/
private function get_font_family_stack(): string {
$key = sanitize_text_field( get_option( self::OPT_FONT_FAMILY, 'default' ) );
$stacks = [
'default' => '',
'inter' => '"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
'georgia' => '"Georgia", "Times New Roman", Times, serif',
'merriweather' => '"Merriweather", Georgia, "Times New Roman", serif',
'lora' => '"Lora", Georgia, "Times New Roman", serif',
'open_sans' => '"Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
'roboto' => '"Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
'system' => '-apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", sans-serif',
];
return $stacks[ $key ] ?? '';
}
/**
* Get available font choices for the settings UI.
*
* @return array<string, string> Map of key => display label.
*/
public static function get_font_choices(): array {
return [
'default' => __( 'Theme Default (Inter)', 'prautoblogger' ),
'inter' => __( 'Inter (Sans-serif)', 'prautoblogger' ),
'georgia' => __( 'Georgia (Serif)', 'prautoblogger' ),
'merriweather' => __( 'Merriweather (Serif)', 'prautoblogger' ),
'lora' => __( 'Lora (Serif)', 'prautoblogger' ),
'open_sans' => __( 'Open Sans (Sans-serif)', 'prautoblogger' ),
'roboto' => __( 'Roboto (Sans-serif)', 'prautoblogger' ),
'system' => __( 'System Default', 'prautoblogger' ),
];
}
/**
* Enqueue Google Fonts stylesheet when a web font is selected.
*
* Only loads on singular PRAutoBlogger posts that use a Google-hosted font.
*
* Side effects: enqueues a remote stylesheet.
*
* @return void
*/
public function on_enqueue_fonts(): void {
if ( ! is_singular( 'post' ) ) {
return;
}
$post_id = get_queried_object_id();
if ( '1' !== get_post_meta( $post_id, '_prautoblogger_generated', true ) ) {
return;
}
$font = sanitize_text_field( get_option( self::OPT_FONT_FAMILY, 'default' ) );
// Map font keys to Google Fonts URLs. Inter is already loaded by the theme.
$google_fonts = [
'merriweather' => 'https://fonts.googleapis.com/css2?family=Merriweather:wght@400;700&display=swap',
'lora' => 'https://fonts.googleapis.com/css2?family=Lora:wght@400;700&display=swap',
'open_sans' => 'https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap',
'roboto' => 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap',
];
if ( isset( $google_fonts[ $font ] ) ) {
wp_enqueue_style(
'prautoblogger-google-font',
$google_fonts[ $font ],
[],
null // No version for external CDN URLs.
);
}
}
}