Files
OTSSigns-Website/theme/inc/font-manager.php

261 lines
8.4 KiB
PHP
Raw Normal View History

2026-02-20 21:28:00 -05:00
<?php
/**
* Font Manager - Bridges the WordPress Font Library with theme settings.
2026-02-20 21:28:00 -05:00
*
* Uses the built-in Font Library (WP 6.5+) for registration, discovery,
* and @font-face generation. The admin settings page uses the helpers
* in this file to populate font-family dropdowns.
*
* @package OTS_Theme
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Register a curated set of Google Fonts with WordPress's Font Library
* so they appear immediately in the admin settings page dropdown.
*
* Admins can add more fonts via Appearance Editor Fonts at any time.
*/
add_action( 'after_setup_theme', function () {
/*
* WordPress 6.5+ ships wp_register_font_family() / wp_register_font_face()
* via the Fonts API (WP_Fonts or WP_Webfonts depending on merge iteration).
* We wrap the calls so the theme degrades gracefully on older installs.
*/
if ( ! function_exists( 'wp_register_webfont_provider' ) && ! class_exists( 'WP_Fonts' ) ) {
// Font Library is available in WP 6.5+; on older versions the
// Google Fonts CDN link in enqueue.php serves as the fallback.
return;
}
} );
/**
* Return every font family available to this WordPress installation.
*
* Sources (merged, de-duped by slug):
* 1. theme.json settings.typography.fontFamilies
* 2. Font Library any fonts the user installed via Site Editor
* 3. Bundled list a small curated set of popular Google Fonts
*
* @return array<int,array{slug:string,name:string,fontFamily:string}>
*/
function oribi_get_available_fonts() {
$fonts = [];
/* ── 1. theme.json registered families ─────────────────── */
$theme_json = WP_Theme_JSON_Resolver::get_merged_data()->get_data();
if ( ! empty( $theme_json['settings']['typography']['fontFamilies']['theme'] ) ) {
foreach ( $theme_json['settings']['typography']['fontFamilies']['theme'] as $f ) {
$fonts[ $f['slug'] ] = [
'slug' => $f['slug'],
'name' => $f['name'] ?? $f['slug'],
'fontFamily' => $f['fontFamily'],
];
}
}
/* ── 2. Font Library (user-installed via Site Editor) ───── */
$font_families = oribi_query_font_library();
foreach ( $font_families as $f ) {
$slug = sanitize_title( $f['slug'] ?? $f['name'] );
if ( ! isset( $fonts[ $slug ] ) ) {
$fonts[ $slug ] = [
'slug' => $slug,
'name' => $f['name'],
'fontFamily' => $f['fontFamily'] ?? "'{$f['name']}', sans-serif",
];
}
}
/* ── 3. Bundled Google Fonts (always shown as available) ── */
$bundled = oribi_get_bundled_google_fonts();
foreach ( $bundled as $slug => $data ) {
if ( ! isset( $fonts[ $slug ] ) ) {
$fonts[ $slug ] = $data;
}
}
// Sort alphabetically by display name.
uasort( $fonts, function ( $a, $b ) {
return strcasecmp( $a['name'], $b['name'] );
} );
return array_values( $fonts );
}
/**
* Query the WP Font Library (wp_font_family post type) for installed fonts.
*
* @return array<int,array{slug:string,name:string,fontFamily:string}>
*/
function oribi_query_font_library() {
$results = [];
// Font Library stores each font family as a wp_font_family post (WP 6.5+).
$query = new WP_Query( [
'post_type' => 'wp_font_family',
'posts_per_page' => 100,
'post_status' => 'publish',
'no_found_rows' => true,
] );
if ( $query->have_posts() ) {
foreach ( $query->posts as $post ) {
$content = json_decode( $post->post_content, true );
if ( $content ) {
$results[] = [
'slug' => $content['slug'] ?? sanitize_title( $post->post_title ),
'name' => $post->post_title,
'fontFamily' => $content['fontFamily'] ?? "'{$post->post_title}', sans-serif",
];
}
}
}
wp_reset_postdata();
return $results;
}
/**
* Return a curated set of popular Google Fonts bundled with the theme.
*
* These are always shown in the font selector even if the user hasn't
* explicitly installed them via the Font Library. WordPress will load
* them from Google Fonts CDN when selected.
*
* @return array<string,array{slug:string,name:string,fontFamily:string,googleUrl:string}>
*/
function oribi_get_bundled_google_fonts() {
return [
'inter' => [
'slug' => 'inter',
'name' => 'Inter',
'fontFamily' => "'Inter', system-ui, -apple-system, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap',
],
'roboto' => [
'slug' => 'roboto',
'name' => 'Roboto',
'fontFamily' => "'Roboto', system-ui, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&display=swap',
],
'open-sans' => [
'slug' => 'open-sans',
'name' => 'Open Sans',
'fontFamily' => "'Open Sans', system-ui, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700;800&display=swap',
],
'poppins' => [
'slug' => 'poppins',
'name' => 'Poppins',
'fontFamily' => "'Poppins', system-ui, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800;900&display=swap',
],
'lato' => [
'slug' => 'lato',
'name' => 'Lato',
'fontFamily' => "'Lato', system-ui, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700;900&display=swap',
],
'montserrat' => [
'slug' => 'montserrat',
'name' => 'Montserrat',
'fontFamily' => "'Montserrat', system-ui, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700;800;900&display=swap',
],
'source-sans-3' => [
'slug' => 'source-sans-3',
'name' => 'Source Sans 3',
'fontFamily' => "'Source Sans 3', system-ui, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=Source+Sans+3:wght@300;400;500;600;700;800;900&display=swap',
],
'nunito' => [
'slug' => 'nunito',
'name' => 'Nunito',
'fontFamily' => "'Nunito', system-ui, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;500;600;700;800;900&display=swap',
],
'raleway' => [
'slug' => 'raleway',
'name' => 'Raleway',
'fontFamily' => "'Raleway', system-ui, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=Raleway:wght@300;400;500;600;700;800;900&display=swap',
],
'dm-sans' => [
'slug' => 'dm-sans',
'name' => 'DM Sans',
'fontFamily' => "'DM Sans', system-ui, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&display=swap',
],
'work-sans' => [
'slug' => 'work-sans',
'name' => 'Work Sans',
'fontFamily' => "'Work Sans', system-ui, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=Work+Sans:wght@300;400;500;600;700;800;900&display=swap',
],
'plus-jakarta-sans' => [
'slug' => 'plus-jakarta-sans',
'name' => 'Plus Jakarta Sans',
'fontFamily' => "'Plus Jakarta Sans', system-ui, sans-serif",
'googleUrl' => 'https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap',
],
'system-ui' => [
'slug' => 'system-ui',
'name' => 'System UI (no download)',
'fontFamily' => "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif",
'googleUrl' => '',
],
];
}
/**
* Resolve a font slug to its CSS font-family value.
*
* Checks (in order): bundled list Font Library theme.json.
*
* @param string $slug Font slug (e.g. 'inter', 'roboto').
* @return string CSS font-family value.
*/
function oribi_get_font_family_css( $slug ) {
if ( empty( $slug ) ) {
$slug = 'inter';
}
// Bundled fonts (includes Google Fonts URL for enqueue).
$bundled = oribi_get_bundled_google_fonts();
if ( isset( $bundled[ $slug ] ) ) {
return $bundled[ $slug ]['fontFamily'];
}
// Search all available fonts.
$fonts = oribi_get_available_fonts();
foreach ( $fonts as $f ) {
if ( $f['slug'] === $slug ) {
return $f['fontFamily'];
}
}
// Ultimate fallback.
return "'Inter', system-ui, -apple-system, sans-serif";
}
/**
* Return the Google Fonts stylesheet URL for a given font slug,
* or empty string if not a bundled Google Font.
*
* @param string $slug Font slug.
* @return string URL or ''.
*/
function oribi_get_google_font_url( $slug ) {
$bundled = oribi_get_bundled_google_fonts();
return isset( $bundled[ $slug ] ) ? $bundled[ $slug ]['googleUrl'] : '';
}