Files
OTSSigns-Website/wp-content/themes/ots-signs/functions.php

337 lines
19 KiB
PHP
Raw Normal View History

<?php
/**
* OTS Signs Theme Functions
*/
if ( ! defined( 'ABSPATH' ) ) exit;
define( 'OTS_THEME_VERSION', '1.0.0' );
define( 'OTS_THEME_DIR', get_template_directory() );
define( 'OTS_THEME_URI', get_template_directory_uri() );
// ─── Theme Setup ──────────────────────────────────────────────────────────────
function ots_setup() {
add_theme_support( 'title-tag' );
add_theme_support( 'post-thumbnails' );
add_theme_support( 'html5', [ 'search-form', 'comment-form', 'comment-list', 'gallery', 'caption' ] );
add_theme_support( 'custom-logo', [
'height' => 60,
'width' => 200,
'flex-height' => true,
'flex-width' => true,
] );
register_nav_menus( [
'primary' => __( 'Primary Menu', 'ots-signs' ),
'footer' => __( 'Footer Menu', 'ots-signs' ),
] );
}
add_action( 'after_setup_theme', 'ots_setup' );
// ─── Fallback Menu ────────────────────────────────────────────────────────────
if ( ! function_exists( 'ots_fallback_menu' ) ) {
function ots_fallback_menu() {
echo '<ul class="nav-menu">';
echo '<li><a href="' . esc_url( home_url( '/' ) ) . '">Home</a></li>';
echo '<li><a href="' . esc_url( home_url( '/services' ) ) . '">Services</a></li>';
echo '<li><a href="' . esc_url( home_url( '/about' ) ) . '">About</a></li>';
echo '<li><a href="' . esc_url( home_url( '/contact' ) ) . '">Contact</a></li>';
echo '</ul>';
}
}
// ─── Enqueue Assets ───────────────────────────────────────────────────────────
function ots_enqueue_assets() {
// Google Fonts
wp_enqueue_style(
'ots-fonts',
'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap',
[],
null
);
// Main stylesheet — use filemtime for cache-busting during development
wp_enqueue_style(
'ots-main',
OTS_THEME_URI . '/assets/css/main.css',
[ 'ots-fonts' ],
filemtime( OTS_THEME_DIR . '/assets/css/main.css' )
);
// Main JS — use filemtime for cache-busting during development
wp_enqueue_script(
'ots-main',
OTS_THEME_URI . '/assets/js/main.js',
[],
filemtime( OTS_THEME_DIR . '/assets/js/main.js' ),
true
);
// Pass ajaxurl and nonce to JS
wp_localize_script( 'ots-main', 'otsAjax', [
'url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'ots_contact_nonce' ),
] );
}
add_action( 'wp_enqueue_scripts', 'ots_enqueue_assets' );
// ─── Constrain Custom Logo Output ─────────────────────────────────────────
/**
* Force the custom logo image to have inline size constraints and use a
* smaller image size so the browser never paints the full-resolution upload.
*/
add_filter( 'get_custom_logo', 'ots_constrain_custom_logo' );
function ots_constrain_custom_logo( $html ) {
if ( empty( $html ) ) {
return $html;
}
// Swap the full-size src for the 'medium' version (much smaller file)
$custom_logo_id = get_theme_mod( 'custom_logo' );
if ( $custom_logo_id ) {
$medium = wp_get_attachment_image_url( $custom_logo_id, 'medium' );
$full = wp_get_attachment_image_url( $custom_logo_id, 'full' );
if ( $medium && $full && $medium !== $full ) {
$html = str_replace( esc_url( $full ), esc_url( $medium ), $html );
}
}
// Inject inline max-height directly on the <img> tag
$html = preg_replace(
'/<img\b/',
'<img style="max-height:40px;width:auto;height:auto;max-width:180px;display:block;object-fit:contain;"',
$html,
1
);
// Strip any srcset/sizes that might force a larger source
$html = preg_replace( '/\s*srcset="[^"]*"/', '', $html );
$html = preg_replace( '/\s*sizes="[^"]*"/', '', $html );
return $html;
}
// ─── Contact Form AJAX Handler ─────────────────────────────────────────────
function ots_handle_contact() {
check_ajax_referer( 'ots_contact_nonce', 'nonce' );
$name = sanitize_text_field( $_POST['name'] ?? '' );
$email = sanitize_email( $_POST['email'] ?? '' );
$phone = sanitize_text_field( $_POST['phone'] ?? '' );
$company = sanitize_text_field( $_POST['company'] ?? '' );
$message = sanitize_textarea_field( $_POST['message'] ?? '' );
if ( empty( $name ) || empty( $email ) || empty( $message ) ) {
wp_send_json_error( [ 'message' => 'Please fill in all required fields.' ] );
}
if ( ! is_email( $email ) ) {
wp_send_json_error( [ 'message' => 'Please enter a valid email address.' ] );
}
$to = get_option( 'admin_email' );
$subject = 'New Contact Form Submission from ' . $name;
$body = "Name: {$name}\n";
$body .= "Email: {$email}\n";
if ( $phone ) $body .= "Phone: {$phone}\n";
if ( $company ) $body .= "Company: {$company}\n";
$body .= "\nMessage:\n{$message}";
$headers = [
'Content-Type: text/plain; charset=UTF-8',
'Reply-To: ' . $name . ' <' . $email . '>',
];
$sent = wp_mail( $to, $subject, $body, $headers );
if ( $sent ) {
wp_send_json_success( [ 'message' => 'Thanks! We\'ll be in touch shortly.' ] );
} else {
wp_send_json_error( [ 'message' => 'Sorry, there was a problem sending your message. Please try again.' ] );
}
}
add_action( 'wp_ajax_ots_contact', 'ots_handle_contact' );
add_action( 'wp_ajax_nopriv_ots_contact', 'ots_handle_contact' );
// ─── Custom Page Templates ─────────────────────────────────────────────────
function ots_body_classes( $classes ) {
$classes[] = 'ots-theme';
return $classes;
}
add_filter( 'body_class', 'ots_body_classes' );
// ─── Excerpt length ────────────────────────────────────────────────────────
function ots_excerpt_length( $length ) {
return 25;
}
add_filter( 'excerpt_length', 'ots_excerpt_length' );
// ─── Meta Boxes ────────────────────────────────────────────────────────────
/**
* Each page template gets its own meta box with the key
* marketing copy fields. All fields fall back to sensible
* defaults so the site works without any editing.
*/
add_action( 'add_meta_boxes', 'ots_register_meta_boxes' );
function ots_register_meta_boxes() {
$screens = [ 'page' ];
add_meta_box(
'ots_page_hero',
'Page Hero Content',
'ots_render_hero_meta_box',
$screens,
'normal',
'high'
);
}
function ots_render_hero_meta_box( $post ) {
wp_nonce_field( 'ots_save_meta', 'ots_meta_nonce' );
$template = get_page_template_slug( $post->ID );
$fields = ots_get_meta_fields_for_template( $template );
if ( empty( $fields ) ) {
echo '<p style="color:#888;">No editable fields for this page template.</p>';
return;
}
echo '<style>
.ots-meta-table { width:100%; border-collapse:collapse; }
.ots-meta-table th { text-align:left; padding:10px 8px 4px; font-size:13px; color:#1d2327; width:180px; vertical-align:top; }
.ots-meta-table td { padding:6px 8px 12px; }
.ots-meta-table input[type=text], .ots-meta-table textarea { width:100%; font-size:13px; }
.ots-meta-table textarea { min-height:80px; }
.ots-meta-table .hint { font-size:11px; color:#888; margin-top:4px; }
.ots-meta-section { background:#f6f7f7; border-left:3px solid #2271b1; padding:6px 10px; margin:12px 0 6px; font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; color:#2271b1; }
</style>';
echo '<table class="ots-meta-table">';
foreach ( $fields as $field ) {
if ( $field['type'] === 'section' ) {
echo '<tr><td colspan="2"><div class="ots-meta-section">' . esc_html( $field['label'] ) . '</div></td></tr>';
continue;
}
$value = get_post_meta( $post->ID, $field['key'], true );
if ( $value === '' ) $value = $field['default'] ?? '';
echo '<tr>';
echo '<th><label for="ots_' . esc_attr( $field['key'] ) . '">' . esc_html( $field['label'] ) . '</label></th>';
echo '<td>';
if ( $field['type'] === 'textarea' ) {
echo '<textarea id="ots_' . esc_attr( $field['key'] ) . '" name="ots_meta[' . esc_attr( $field['key'] ) . ']" rows="3">' . esc_textarea( $value ) . '</textarea>';
} else {
echo '<input type="text" id="ots_' . esc_attr( $field['key'] ) . '" name="ots_meta[' . esc_attr( $field['key'] ) . ']" value="' . esc_attr( $value ) . '">';
}
if ( ! empty( $field['hint'] ) ) {
echo '<div class="hint">' . esc_html( $field['hint'] ) . '</div>';
}
echo '</td></tr>';
}
echo '</table>';
echo '<p style="margin-top:12px;padding-top:12px;border-top:1px solid #ddd;font-size:12px;color:#888;">
Fields left blank will use the default content shown above as placeholder text.
</p>';
}
function ots_get_meta_fields_for_template( $template ) {
$templates = [
'page-home.php' => [
[ 'type' => 'section', 'label' => 'Hero Section' ],
[ 'key' => 'hero_title', 'label' => 'Hero Title', 'type' => 'textarea', 'default' => 'Turn any screen into a dynamic communication tool for your business.', 'hint' => 'Wrap a keyword in <span class="highlight">…</span> to colour it teal.' ],
[ 'key' => 'hero_description', 'label' => 'Hero Description', 'type' => 'textarea', 'default' => 'The complete package for engaging digital signage. From eye-catching retail displays to dynamic informational screens, we craft tailored solutions that capture attention and deliver your message.' ],
[ 'key' => 'hero_cta_primary_label', 'label' => 'Primary CTA Label', 'type' => 'text', 'default' => 'Get in Touch' ],
[ 'key' => 'hero_cta_secondary_label', 'label' => 'Secondary CTA Label', 'type' => 'text', 'default' => 'View Demo' ],
[ 'type' => 'section', 'label' => 'Hero Stats' ],
[ 'key' => 'stat_1_value', 'label' => 'Stat 1 Value', 'type' => 'text', 'default' => '500+' ],
[ 'key' => 'stat_1_label', 'label' => 'Stat 1 Label', 'type' => 'text', 'default' => 'Screens Managed' ],
[ 'key' => 'stat_2_value', 'label' => 'Stat 2 Value', 'type' => 'text', 'default' => '6' ],
[ 'key' => 'stat_2_label', 'label' => 'Stat 2 Label', 'type' => 'text', 'default' => 'Industry Verticals' ],
[ 'key' => 'stat_3_value', 'label' => 'Stat 3 Value', 'type' => 'text', 'default' => '99.9%' ],
[ 'key' => 'stat_3_label', 'label' => 'Stat 3 Label', 'type' => 'text', 'default' => 'Uptime SLA' ],
[ 'type' => 'section', 'label' => 'Features Section' ],
[ 'key' => 'features_heading', 'label' => 'Features Heading', 'type' => 'text', 'default' => 'Everything You Need for Engaging Digital Signage' ],
[ 'key' => 'features_subheading', 'label' => 'Features Subheading', 'type' => 'textarea', 'default' => 'We provide a complete, end-to-end digital signage solution — from hardware to content management to live data integrations.' ],
[ 'type' => 'section', 'label' => 'Industries Section' ],
[ 'key' => 'industries_heading', 'label' => 'Industries Heading', 'type' => 'text', 'default' => 'Our Services Empower Your Brand' ],
[ 'key' => 'industries_subheading', 'label' => 'Industries Subheading', 'type' => 'textarea', 'default' => 'Modern businesses need real-time communication. Digital signage helps you connect with your audience where it matters most.' ],
[ 'type' => 'section', 'label' => 'Pricing Section' ],
[ 'key' => 'pricing_heading', 'label' => 'Pricing Heading', 'type' => 'text', 'default' => 'Affordable Solutions, Scalable Options' ],
[ 'key' => 'pricing_subheading', 'label' => 'Pricing Subheading', 'type' => 'textarea', 'default' => 'All plans include content scheduling/day-parting, live data integrations, unlimited user seats, and the ability to publish content to your signs in minutes.' ],
[ 'type' => 'section', 'label' => 'CTA Banner' ],
[ 'key' => 'cta_heading', 'label' => 'CTA Heading', 'type' => 'text', 'default' => 'Ready to Transform Your Screens?' ],
[ 'key' => 'cta_description', 'label' => 'CTA Description', 'type' => 'textarea', 'default' => 'Get in touch today and discover how OTS Signs can revolutionize the way you communicate with your audience.' ],
],
'page-about.php' => [
[ 'type' => 'section', 'label' => 'Page Hero' ],
[ 'key' => 'hero_title', 'label' => 'Page Title', 'type' => 'text', 'default' => 'The Complete Digital Signage Solution' ],
[ 'key' => 'hero_description', 'label' => 'Page Subtitle', 'type' => 'textarea', 'default' => 'We help businesses of all sizes connect with their audiences through powerful, easy-to-manage digital signage.' ],
[ 'type' => 'section', 'label' => 'Who We Are Section' ],
[ 'key' => 'about_heading', 'label' => 'Section Heading', 'type' => 'text', 'default' => 'Bringing Your Message to Life on Every Screen' ],
[ 'key' => 'about_intro', 'label' => 'Intro Paragraph', 'type' => 'textarea', 'default' => 'OTS Signs is a digital signage company dedicated to transforming how businesses communicate with their audiences. We offer a complete, end-to-end solution — from the hardware players to our cloud management platform to custom content creation.' ],
[ 'key' => 'about_body', 'label' => 'Body Paragraph', 'type' => 'textarea', 'default' => 'Digital signage is the modern way to connect with your audience, transforming any screen into a way to communicate and engage. Whether you need an eye-catching retail display, a dynamic menu board, or enterprise-grade live data dashboards, we deliver solutions that capture attention and get results.' ],
[ 'type' => 'section', 'label' => 'CTA Banner' ],
[ 'key' => 'cta_heading', 'label' => 'CTA Heading', 'type' => 'text', 'default' => "Let's Build Something Great Together" ],
[ 'key' => 'cta_description', 'label' => 'CTA Description', 'type' => 'textarea', 'default' => 'Ready to see what OTS Signs can do for your business? Get in touch or explore our demo platform.' ],
],
'page-services.php' => [
[ 'type' => 'section', 'label' => 'Page Hero' ],
[ 'key' => 'hero_title', 'label' => 'Page Title', 'type' => 'text', 'default' => 'Services & Solutions' ],
[ 'key' => 'hero_description', 'label' => 'Page Subtitle', 'type' => 'textarea', 'default' => 'From content creation to cloud management to live data integrations — we deliver everything you need for a complete digital signage deployment.' ],
[ 'type' => 'section', 'label' => 'Core Services Section' ],
[ 'key' => 'services_heading', 'label' => 'Section Heading', 'type' => 'text', 'default' => 'The Complete Package for Engaging Digital Signage' ],
[ 'key' => 'services_subheading', 'label' => 'Section Subheading', 'type' => 'textarea', 'default' => 'Every service we offer is designed to make your digital signage as impactful, reliable, and easy to manage as possible.' ],
[ 'type' => 'section', 'label' => 'Pricing Section' ],
[ 'key' => 'pricing_heading', 'label' => 'Pricing Heading', 'type' => 'text', 'default' => 'Affordable Solutions, Scalable Options' ],
[ 'key' => 'pricing_subheading', 'label' => 'Pricing Subheading', 'type' => 'textarea', 'default' => 'Simple, transparent pricing with no hidden fees. Choose the plan that fits your business size.' ],
[ 'type' => 'section', 'label' => 'CTA Banner' ],
[ 'key' => 'cta_heading', 'label' => 'CTA Heading', 'type' => 'text', 'default' => 'Want to See How Our Platform Works?' ],
[ 'key' => 'cta_description', 'label' => 'CTA Description', 'type' => 'textarea', 'default' => 'Request access to our demo instance and explore the OTS Signs platform hands-on.' ],
],
'page-contact.php' => [
[ 'type' => 'section', 'label' => 'Page Hero' ],
[ 'key' => 'hero_title', 'label' => 'Page Title', 'type' => 'text', 'default' => 'Get in Touch' ],
[ 'key' => 'hero_description', 'label' => 'Page Subtitle', 'type' => 'textarea', 'default' => "Ready to transform your screens? We'd love to hear about your project. Drop us a message and we'll get back to you promptly." ],
[ 'type' => 'section', 'label' => 'Contact Info' ],
[ 'key' => 'contact_heading', 'label' => 'Section Heading', 'type' => 'text', 'default' => "Let's Start the Conversation" ],
[ 'key' => 'contact_subheading', 'label' => 'Section Subheading', 'type' => 'textarea', 'default' => "Whether you're looking for a quote, want to see a demo, or just have questions — we're here to help." ],
[ 'key' => 'contact_email', 'label' => 'Contact Email', 'type' => 'text', 'default' => 'info@ots-signs.com' ],
[ 'type' => 'section', 'label' => 'Demo CTA Section' ],
[ 'key' => 'demo_heading', 'label' => 'Demo Heading', 'type' => 'text', 'default' => 'Explore Our Demo Platform' ],
[ 'key' => 'demo_description', 'label' => 'Demo Description', 'type' => 'textarea', 'default' => 'See the OTS Signs CMS in action. Request access to our live demo instance and experience the platform for yourself before making any commitment.' ],
],
];
return $templates[ $template ] ?? [];
}
// Save meta fields
add_action( 'save_post_page', 'ots_save_meta_fields' );
function ots_save_meta_fields( $post_id ) {
if ( ! isset( $_POST['ots_meta_nonce'] ) ) return;
if ( ! wp_verify_nonce( $_POST['ots_meta_nonce'], 'ots_save_meta' ) ) return;
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( ! current_user_can( 'edit_page', $post_id ) ) return;
if ( ! isset( $_POST['ots_meta'] ) || ! is_array( $_POST['ots_meta'] ) ) return;
foreach ( $_POST['ots_meta'] as $key => $value ) {
$key = sanitize_key( $key );
// Allow basic HTML (spans, br, strong, em) for rich text fields
$allowed = array_merge( wp_kses_allowed_html( 'post' ), [] );
update_post_meta( $post_id, $key, wp_kses_post( $value ) );
}
}
/**
* Helper: get a meta value with a default fallback.
*/
function ots_meta( $post_id, $key, $default = '' ) {
$value = get_post_meta( $post_id, $key, true );
return ( $value !== '' && $value !== false ) ? $value : $default;
}