/**
* Physics Forum Theme - functions.php
*/
if ( ! defined( 'ABSPATH' ) ) exit;
/* ─── Theme Setup ─────────────────────────────── */
function pf_setup() {
add_theme_support( 'automatic-feed-links' );
add_theme_support( 'title-tag' );
add_theme_support( 'post-thumbnails' );
add_theme_support( 'html5', [ 'search-form','comment-form','comment-list','gallery','caption','style','script' ] );
add_theme_support( 'custom-logo', [
'height' => 80,
'width' => 260,
'flex-height' => true,
'flex-width' => true,
]);
add_theme_support( 'customize-selective-refresh-widgets' );
register_nav_menus([
'primary' => __( 'Primary Navigation', 'physics-forum' ),
'footer_1' => __( 'Footer Navigation 1', 'physics-forum' ),
'footer_2' => __( 'Footer Navigation 2', 'physics-forum' ),
'footer_3' => __( 'Footer Navigation 3', 'physics-forum' ),
]);
add_image_size( 'pf-featured', 900, 500, true );
add_image_size( 'pf-thumbnail', 480, 300, true );
add_image_size( 'pf-square', 300, 300, true );
load_theme_textdomain( 'physics-forum', get_template_directory() . '/languages' );
}
add_action( 'after_setup_theme', 'pf_setup' );
/* ─── Content Width ───────────────────────────── */
function pf_content_width() {
$GLOBALS['content_width'] = 900;
}
add_action( 'after_setup_theme', 'pf_content_width', 0 );
/* ─── Enqueue Scripts & Styles ────────────────── */
function pf_scripts() {
// Google Fonts
wp_enqueue_style(
'pf-google-fonts',
'https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;700;800;900&family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&family=Space+Grotesk:wght@400;500;600;700&display=swap',
[],
null
);
// Font Awesome
wp_enqueue_style(
'pf-fontawesome',
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css',
[],
'6.5.0'
);
// Main stylesheet
wp_enqueue_style( 'physics-forum-style', get_stylesheet_uri(), [ 'pf-google-fonts' ], wp_get_theme()->get('Version') );
// Custom CSS overrides
wp_enqueue_style( 'pf-custom', get_template_directory_uri() . '/assets/css/custom.css', [ 'physics-forum-style' ], wp_get_theme()->get('Version') );
// Main JS
wp_enqueue_script( 'pf-main', get_template_directory_uri() . '/assets/js/main.js', [], wp_get_theme()->get('Version'), true );
// Particles JS
wp_enqueue_script( 'pf-particles', get_template_directory_uri() . '/assets/js/particles.js', [], wp_get_theme()->get('Version'), true );
// Collider JS (only on collider page)
if ( is_page_template('page-collider.php') || is_front_page() ) {
wp_enqueue_script( 'pf-collider', get_template_directory_uri() . '/assets/js/collider.js', ['pf-main'], wp_get_theme()->get('Version'), true );
}
if ( is_singular() && comments_open() && get_option('thread_comments') ) {
wp_enqueue_script( 'comment-reply' );
}
// Localize
wp_localize_script( 'pf-main', 'pfData', [
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('pf-nonce'),
'themeUrl' => get_template_directory_uri(),
'siteUrl' => home_url(),
]);
}
add_action( 'wp_enqueue_scripts', 'pf_scripts' );
/* ─── Widgets ─────────────────────────────────── */
function pf_widgets_init() {
$defaults = [
'before_widget' => '
',
'after_widget' => '
',
'before_title' => '',
];
register_sidebar( array_merge($defaults, [
'name' => __('Sidebar', 'physics-forum'),
'id' => 'sidebar-1',
'description' => __('Main sidebar widgets.', 'physics-forum'),
]));
register_sidebar( array_merge($defaults, [
'name' => __('Footer Column 1', 'physics-forum'),
'id' => 'footer-1',
'description' => __('Footer column 1 widgets.', 'physics-forum'),
]));
}
add_action( 'widgets_init', 'pf_widgets_init' );
/* ─── Custom Post Types ───────────────────────── */
function pf_register_post_types() {
// Thought Experiments
register_post_type('thought_experiment', [
'labels' => [
'name' => __('Thought Experiments', 'physics-forum'),
'singular_name' => __('Thought Experiment', 'physics-forum'),
'add_new_item' => __('Add New Thought Experiment', 'physics-forum'),
],
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-lightbulb',
'supports' => ['title','editor','author','thumbnail','excerpt','comments'],
'rewrite' => ['slug' => 'thought-experiments'],
'show_in_rest' => true,
]);
// Discoveries
register_post_type('discovery', [
'labels' => [
'name' => __('Discoveries', 'physics-forum'),
'singular_name' => __('Discovery', 'physics-forum'),
'add_new_item' => __('Add New Discovery', 'physics-forum'),
],
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-star-filled',
'supports' => ['title','editor','author','thumbnail','excerpt'],
'rewrite' => ['slug' => 'discoveries'],
'show_in_rest' => true,
]);
// Mysteries / Bounties
register_post_type('mystery', [
'labels' => [
'name' => __('Unsolved Mysteries', 'physics-forum'),
'singular_name' => __('Mystery', 'physics-forum'),
'add_new_item' => __('Add New Mystery', 'physics-forum'),
],
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-search',
'supports' => ['title','editor','author','thumbnail','excerpt'],
'rewrite' => ['slug' => 'mysteries'],
'show_in_rest' => true,
]);
}
add_action( 'init', 'pf_register_post_types' );
/* ─── Custom Taxonomies ───────────────────────── */
function pf_register_taxonomies() {
register_taxonomy('physics_field', ['post','thought_experiment','discovery','mystery'], [
'labels' => [
'name' => __('Physics Fields', 'physics-forum'),
'singular_name' => __('Physics Field', 'physics-forum'),
],
'hierarchical' => true,
'public' => true,
'rewrite' => ['slug' => 'field'],
'show_in_rest' => true,
]);
}
add_action( 'init', 'pf_register_taxonomies' );
/* ─── Custom Meta Boxes ───────────────────────── */
function pf_add_meta_boxes() {
add_meta_box('pf-mystery-bounty', __('Bounty & Details','physics-forum'), 'pf_mystery_meta_box', 'mystery', 'side');
add_meta_box('pf-discovery-source', __('Source Details','physics-forum'), 'pf_discovery_meta_box', 'discovery', 'side');
add_meta_box('pf-experiment-difficulty', __('Experiment Details','physics-forum'), 'pf_experiment_meta_box', 'thought_experiment', 'side');
}
add_action('add_meta_boxes', 'pf_add_meta_boxes');
function pf_mystery_meta_box($post) {
$bounty = get_post_meta($post->ID, '_pf_bounty', true);
$attempts = get_post_meta($post->ID, '_pf_attempts', true);
$status = get_post_meta($post->ID, '_pf_status', true);
wp_nonce_field('pf_mystery_meta', 'pf_mystery_nonce');
echo '';
echo '';
echo '';
}
function pf_discovery_meta_box($post) {
$source = get_post_meta($post->ID, '_pf_source', true);
$journal = get_post_meta($post->ID, '_pf_journal', true);
wp_nonce_field('pf_discovery_meta', 'pf_discovery_nonce');
echo '';
echo '';
}
function pf_experiment_meta_box($post) {
$difficulty = get_post_meta($post->ID, '_pf_difficulty', true);
$field_branch = get_post_meta($post->ID, '_pf_field_branch', true);
wp_nonce_field('pf_experiment_meta', 'pf_experiment_nonce');
echo '';
echo '';
}
/* ─── Save Meta Boxes ─────────────────────────── */
function pf_save_meta($post_id) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (!current_user_can('edit_post', $post_id)) return;
if (isset($_POST['pf_mystery_nonce']) && wp_verify_nonce($_POST['pf_mystery_nonce'], 'pf_mystery_meta')) {
if (isset($_POST['pf_bounty'])) update_post_meta($post_id, '_pf_bounty', sanitize_text_field($_POST['pf_bounty']));
if (isset($_POST['pf_attempts'])) update_post_meta($post_id, '_pf_attempts', sanitize_text_field($_POST['pf_attempts']));
if (isset($_POST['pf_status'])) update_post_meta($post_id, '_pf_status', sanitize_text_field($_POST['pf_status']));
}
if (isset($_POST['pf_discovery_nonce']) && wp_verify_nonce($_POST['pf_discovery_nonce'], 'pf_discovery_meta')) {
if (isset($_POST['pf_source'])) update_post_meta($post_id, '_pf_source', esc_url_raw($_POST['pf_source']));
if (isset($_POST['pf_journal'])) update_post_meta($post_id, '_pf_journal', sanitize_text_field($_POST['pf_journal']));
}
if (isset($_POST['pf_experiment_nonce']) && wp_verify_nonce($_POST['pf_experiment_nonce'], 'pf_experiment_meta')) {
if (isset($_POST['pf_difficulty'])) update_post_meta($post_id, '_pf_difficulty', sanitize_text_field($_POST['pf_difficulty']));
if (isset($_POST['pf_field_branch'])) update_post_meta($post_id, '_pf_field_branch', sanitize_text_field($_POST['pf_field_branch']));
}
}
add_action('save_post', 'pf_save_meta');
/* ─── Helper: Get Initials Avatar ─────────────── */
function pf_get_avatar($name, $size='md', $color_index=0) {
$colors = [
['bg'=>'rgba(56,189,248,0.25)','text'=>'#38bdf8'],
['bg'=>'rgba(168,85,247,0.25)','text'=>'#a855f7'],
['bg'=>'rgba(16,185,129,0.25)','text'=>'#10b981'],
['bg'=>'rgba(249,115,22,0.25)','text'=>'#f97316'],
['bg'=>'rgba(236,72,153,0.25)','text'=>'#ec4899'],
];
$c = $colors[$color_index % count($colors)];
$parts = explode(' ', $name);
$initials = strtoupper(substr($parts[0],0,1) . (isset($parts[1]) ? substr($parts[1],0,1) : ''));
$sz_class = $size === 'lg' ? 'avatar-lg' : '';
return '' . esc_html($initials) . '
';
}
/* ─── Helper: Difficulty Badge ────────────────── */
function pf_difficulty_badge($difficulty) {
$map = [
'beginner' => ['class'=>'badge-green', 'icon'=>'fa-seedling'],
'intermediate' => ['class'=>'badge-blue', 'icon'=>'fa-atom'],
'advanced' => ['class'=>'badge-purple', 'icon'=>'fa-flask'],
'expert' => ['class'=>'badge-pink', 'icon'=>'fa-brain'],
];
$d = $map[$difficulty] ?? $map['intermediate'];
return ' ' . ucfirst($difficulty) . '';
}
/* ─── Excerpt Length ──────────────────────────── */
function pf_excerpt_length($length) { return 25; }
add_filter('excerpt_length', 'pf_excerpt_length');
function pf_excerpt_more($more) { return '...'; }
add_filter('excerpt_more', 'pf_excerpt_more');
/* ─── Body Classes ────────────────────────────── */
function pf_body_classes($classes) {
if (is_front_page()) $classes[] = 'is-front-page';
if (is_page_template('page-collider.php')) $classes[] = 'is-collider';
return $classes;
}
add_filter('body_class', 'pf_body_classes');
/* ─── Customizer ──────────────────────────────── */
function pf_customize_register($wp_customize) {
$wp_customize->add_section('pf_general', [
'title' => __('Physics Forum Settings','physics-forum'),
'priority' => 25,
]);
$settings = [
'pf_hero_title' => ['label'=>'Hero Title', 'default'=>'Where Physics Meets Curiosity'],
'pf_hero_subtitle' => ['label'=>'Hero Subtitle', 'default'=>'A community where physicists, researchers, and curious minds converge to explore the fundamental laws of the universe.'],
'pf_footer_text' => ['label'=>'Footer Text', 'default'=>'A community where physicists, researchers, and curious minds converge.'],
];
foreach ($settings as $id => $args) {
$wp_customize->add_setting($id, ['default'=>$args['default'], 'sanitize_callback'=>'sanitize_text_field', 'transport'=>'refresh']);
$wp_customize->add_control($id, ['label'=>$args['label'], 'section'=>'pf_general', 'type'=>'text']);
}
}
add_action('customize_register', 'pf_customize_register');
/* ─── AJAX: Load More Posts ───────────────────── */
function pf_load_more_posts() {
check_ajax_referer('pf-nonce','nonce');
$type = sanitize_text_field($_POST['post_type'] ?? 'post');
$page = intval($_POST['page'] ?? 1);
$count = intval($_POST['count'] ?? 6);
$q = new WP_Query(['post_type'=>$type,'posts_per_page'=>$count,'paged'=>$page]);
$data = [];
if ($q->have_posts()) {
while ($q->have_posts()) {
$q->the_post();
$data[] = [
'id' => get_the_ID(),
'title' => get_the_title(),
'excerpt' => get_the_excerpt(),
'link' => get_permalink(),
'date' => get_the_date('M j'),
'author' => get_the_author(),
];
}
wp_reset_postdata();
}
wp_send_json_success(['posts'=>$data,'has_more'=>$q->max_num_pages > $page]);
}
add_action('wp_ajax_pf_load_more', 'pf_load_more_posts');
add_action('wp_ajax_nopriv_pf_load_more', 'pf_load_more_posts');
/* ─── Custom Nav Walker ───────────────────────── */
class PF_Nav_Walker extends Walker_Nav_Menu {
function start_el(&$output, $item, $depth=0, $args=null, $id=0) {
$classes = empty($item->classes) ? [] : (array) $item->classes;
$class_str = join(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item, $args));
$atts = [];
$atts['href'] = !empty($item->url) ? $item->url : '#';
$atts['target'] = !empty($item->target) ? $item->target : '';
$atts['rel'] = !empty($item->xfn) ? $item->xfn : '';
$atts['class'] = in_array('current-menu-item', $classes) ? 'current-menu-item' : '';
$atts['aria-current'] = $item->current ? 'page' : '';
$atts_str = '';
foreach ($atts as $attr => $value) {
if (!empty($value)) $atts_str .= ' ' . $attr . '="' . esc_attr($value) . '"';
}
$title = apply_filters('the_title', $item->title, $item->ID);
$output .= '';
$output .= '' . esc_html($title) . '';
}
}
Log In ‹ Physics Forum — WordPress
Log In