Add custom page templates for Home, Contact, and Services
- Created a new Contact Page template with a contact form and information section. - Developed a Home Page template featuring a hero section, core capabilities, and pricing details. - Introduced a Services Page template outlining core services and industry solutions. - Added a default page template for standard pages without a custom template. - Implemented a single post template for displaying individual blog posts. - Created a style.css file for theme metadata and styling.
This commit is contained in:
336
wp-content/themes/ots-signs/functions.php
Normal file
336
wp-content/themes/ots-signs/functions.php
Normal file
@@ -0,0 +1,336 @@
|
||||
<?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;
|
||||
}
|
||||
Reference in New Issue
Block a user