Compare commits

..

3 Commits

Author SHA1 Message Date
Flatlogic Bot
73204287bd Auto commit: 2026-01-21T17:00:46.423Z 2026-01-21 17:00:46 +00:00
Flatlogic Bot
ffd30c163d Auto commit: 2026-01-21T16:50:02.682Z 2026-01-21 16:50:02 +00:00
Flatlogic Bot
16da92b5f8 Auto commit: 2026-01-21T16:38:53.243Z 2026-01-21 16:38:53 +00:00
19 changed files with 1161 additions and 16 deletions

View File

@ -1,18 +1,11 @@
DirectoryIndex index.php index.html
Options -Indexes
Options -MultiViews
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
# 0) Serve existing files/directories as-is
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# 1) Internal map: /page or /page/ -> /page.php (if such PHP file exists)
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+?)/?$ $1.php [L]
# 2) Optional: strip trailing slash for non-directories (keeps .php links working)
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ $1 [R=301,L]
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

4
admin_credentials.txt Normal file
View File

@ -0,0 +1,4 @@
WordPress Admin Credentials:
URL: http://localhost/wp-admin
Username: admin
Password: J12AcemJKhEQJTi9

BIN
assets/images/beer1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

BIN
assets/images/grill1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

BIN
assets/images/hero.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

View File

@ -0,0 +1,6 @@
{
"hero": "assets\/images\/hero.jpg",
"beer1": "assets\/images\/beer1.jpg",
"party1": "assets\/images\/party1.jpg",
"grill1": "assets\/images\/grill1.jpg"
}

BIN
assets/images/party1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
assets/images/shop-cap.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 KiB

33
fetch_images.php Normal file
View File

@ -0,0 +1,33 @@
<?php
require_once __DIR__ . '/includes/pexels.php';
$queries = [
'hero' => 'party friends beer',
'beer1' => 'beer mug',
'party1' => 'night club party',
'grill1' => 'bbq grill meat'
];
$images = [];
foreach ($queries as $key => $query) {
echo "Fetching image for: $query...\n";
$url = 'https://api.pexels.com/v1/search?query=' . urlencode($query) . '&per_page=1&page=1';
$data = pexels_get($url);
if ($data && !empty($data['photos'])) {
$photo = $data['photos'][0];
$src = $photo['src']['large2x'] ?? $photo['src']['large'];
$dest = __DIR__ . '/assets/images/' . $key . '.jpg';
if (download_to($src, $dest)) {
$images[$key] = 'assets/images/' . $key . '.jpg';
echo "Downloaded to $dest\n";
} else {
echo "Failed to download $src\n";
}
} else {
echo "No photos found for $query\n";
}
}
file_put_contents(__DIR__ . '/assets/images/manifest.json', json_encode($images, JSON_PRETTY_PRINT));

20
generate_content.php Normal file
View File

@ -0,0 +1,20 @@
<?php
require_once __DIR__ . '/ai/LocalAIApi.php';
$prompt = "You are the 'Bro' editor for 'Real Bro Blog'. Generate 3 'Bro Tips of the Week' and 1 'Bro Manifesto' intro for the homepage. Keep it casual, high-energy, and related to beer, parties, and lifestyle. Output in JSON format with keys 'tips' (array of strings) and 'manifesto' (string).";
$resp = LocalAIApi::createResponse(
[
'input' => [
['role' => 'system', 'content' => 'You are a bro-culture content creator.'],
['role' => 'user', 'content' => $prompt],
],
]
);
if (!empty($resp['success'])) {
$text = LocalAIApi::extractText($resp);
echo $text;
} else {
echo "AI Error: " . ($resp['error'] ?? 'unknown');
}

25
includes/pexels.php Normal file
View File

@ -0,0 +1,25 @@
<?php
function pexels_key() {
$k = getenv('PEXELS_KEY');
return $k && strlen($k) > 0 ? $k : 'Vc99rnmOhHhJAbgGQoKLZtsaIVfkeownoQNbTj78VemUjKh08ZYRbf18';
}
function pexels_get($url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [ 'Authorization: '. pexels_key() ],
CURLOPT_TIMEOUT => 15,
]);
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code >= 200 && $code < 300 && $resp) return json_decode($resp, true);
return null;
}
function download_to($srcUrl, $destPath) {
$data = @file_get_contents($srcUrl);
if ($data === false) return false;
if (!is_dir(dirname($destPath))) mkdir(dirname($destPath), 0775, true);
return file_put_contents($destPath, $data) !== false;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,47 @@
<?php
add_action('wp_head', function() {
echo '<style>
:root {
--wp--preset--color--primary: #FFBF00 !important;
--bro-amber: #FFBF00;
--bro-dark: #0A0A0A;
--bro-glass: rgba(255, 191, 0, 0.1);
}
body { background-color: var(--bro-dark) !important; color: #FFFFFF !important; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
.wp-block-post-title a, h1, h2, h3 { color: var(--bro-amber) !important; font-weight: 900 !important; text-transform: uppercase; letter-spacing: -0.02em; }
.wp-block-navigation a { color: #FFFFFF !important; font-weight: bold; text-transform: uppercase; font-size: 0.9rem; transition: color 0.3s ease; }
.wp-block-navigation a:hover { color: var(--bro-amber) !important; }
.wp-block-navigation .wp-block-navigation-item.has-child { position: relative; }
.wp-block-navigation .wp-block-navigation__submenu-container {
background-color: #111 !important;
border: 1px solid var(--bro-amber);
padding: 10px !important;
border-radius: 8px;
}
.wp-block-navigation .wp-block-navigation__submenu-container a {
font-size: 0.8rem !important;
}
.wp-block-button__link { background-color: var(--bro-amber) !important; color: #000 !important; border-radius: 8px !important; font-weight: 800 !important; text-transform: uppercase; border: none !important; transition: transform 0.2s ease, box-shadow 0.2s ease; }
.wp-block-button__link:hover { transform: translateY(-2px); box-shadow: 0 4px 15px rgba(255, 191, 0, 0.4); }
/* Glassmorphism effect for groups */
.has-background.has-black-background-color {
background-color: rgba(20, 20, 20, 0.8) !important;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 191, 0, 0.2);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.8);
}
.wp-block-cover__inner-container h1 {
text-shadow: 0 0 20px rgba(255, 191, 0, 0.5);
}
.wp-block-query .wp-block-post-template {
border-bottom: 1px solid #222;
padding-bottom: 20px;
margin-bottom: 20px;
}
footer { border-top: 1px solid #222; padding-top: 40px; opacity: 0.8; }
</style>';
});

View File

@ -0,0 +1,106 @@
<?php
/**
* Plugin Name: Bro Beer Reviews
* Description: A rating system for the real bro to rate their brews.
* Version: 1.0.0
* Author: Real Bro
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Register Custom Post Type: Beer Review
function bro_register_beer_review_cpt() {
$labels = array(
'name' => 'Beer Reviews',
'singular_name' => 'Beer Review',
'menu_name' => 'Beer Reviews',
'add_new_item' => 'Add New Beer Review',
'edit_item' => 'Edit Beer Review',
'new_item' => 'New Beer Review',
'view_item' => 'View Beer Review',
'search_items' => 'Search Beer Reviews',
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-beer',
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ),
'rewrite' => array( 'slug' => 'beer-review' ),
'show_in_rest' => true, // Enable Gutenberg
);
register_post_type( 'beer_review', $args );
}
add_action( 'init', 'bro_register_beer_review_cpt' );
// Add Meta Box for Rating
function bro_add_beer_rating_meta_box() {
add_meta_box(
'bro_beer_rating_box',
'Bro Rating (1-5 Bottles)',
'bro_render_beer_rating_meta_box',
'beer_review',
'side',
'high'
);
}
add_action( 'add_meta_boxes', 'bro_add_beer_rating_meta_box' );
function bro_render_beer_rating_meta_box( $post ) {
$rating = get_post_meta( $post->ID, '_bro_beer_rating', true );
wp_nonce_field( 'bro_save_beer_rating', 'bro_beer_rating_nonce' );
?>
<select name="bro_beer_rating" style="width: 100%;">
<?php for ( $i = 1; $i <= 5; $i++ ) : ?>
<option value="<?php echo $i; ?>" <?php selected( $rating, $i ); ?>>
<?php echo $i; ?> Bottle<?php echo $i > 1 ? 's' : ''; ?>
</option>
<?php endfor; ?>
</select>
<?php
}
// Save Meta Box Data
function bro_save_beer_rating_data( $post_id ) {
if ( ! isset( $_POST['bro_beer_rating_nonce'] ) || ! wp_verify_nonce( $_POST['bro_beer_rating_nonce'], 'bro_save_beer_rating' ) ) {
return;
}
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
if ( isset( $_POST['bro_beer_rating'] ) ) {
update_post_meta( $post_id, '_bro_beer_rating', sanitize_text_field( $_POST['bro_beer_rating'] ) );
}
}
add_action( 'save_post', 'bro_save_beer_rating_data' );
// Display Rating on Frontend
function bro_display_beer_rating( $content ) {
if ( is_singular( 'beer_review' ) && in_the_loop() && is_main_query() ) {
$rating = get_post_meta( get_the_ID(), '_bro_beer_rating', true );
if ( $rating ) {
$stars = '';
for ( $i = 1; $i <= 5; $i++ ) {
$color = $i <= $rating ? '#FFBF00' : '#444';
$stars .= '<span style="color:' . $color . '; font-size: 24px; margin-right: 5px;">🍺</span>';
}
$rating_html = '<div class="bro-beer-rating" style="margin-bottom: 20px; padding: 10px; background: #1a1a1a; border-radius: 8px; border-left: 4px solid #FFBF00;">';
$rating_html .= '<strong style="color: #FFBF00; text-transform: uppercase; font-family: sans-serif;">Bro Rating:</strong><br>' . $stars;
$rating_html .= '</div>';
$footer_link = '<div style="margin-top: 30px;"><a href="' . get_post_type_archive_link('beer_review') . '" style="color: #FFBF00; font-weight: bold; text-transform: uppercase; text-decoration: none;">← Back to All Reviews</a></div>';
return $rating_html . $content . $footer_link;
}
}
return $content;
}
add_filter( 'the_content', 'bro_display_beer_rating' );

View File

@ -0,0 +1,162 @@
<?php
/**
* Plugin Name: Bro Hangs Map
* Description: Displays a map of legendary bro hangouts.
* Version: 1.0.0
* Author: Real Bro
*/
if (!defined('ABSPATH')) exit;
// Register CPT
add_action('init', 'bro_register_hangout_cpt');
function bro_register_hangout_cpt() {
$labels = array(
'name' => 'Hangouts',
'singular_name' => 'Hangout',
'menu_name' => 'Party Map',
'add_new' => 'Add New Hangout',
'add_new_item' => 'Add New Hangout',
'edit_item' => 'Edit Hangout',
'new_item' => 'New Hangout',
'view_item' => 'View Hangout',
'search_items' => 'Search Hangouts',
'not_found' => 'No hangouts found',
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-location-alt',
'supports' => array('title', 'editor', 'thumbnail'),
'show_in_rest' => true,
);
register_post_type('bro_hangout', $args);
}
// Add Meta Boxes for Latitude and Longitude
add_action('add_meta_boxes', 'bro_add_hangout_meta_boxes');
function bro_add_hangout_meta_boxes() {
add_meta_box('bro_hangout_location', 'Hangout Location', 'bro_hangout_location_callback', 'bro_hangout', 'normal', 'high');
}
function bro_hangout_location_callback($post) {
$lat = get_post_meta($post->ID, '_bro_lat', true);
$lng = get_post_meta($post->ID, '_bro_lng', true);
wp_nonce_field('bro_hangout_save', 'bro_hangout_nonce');
?>
<p>
<label for="bro_lat">Latitude:</label>
<input type="text" id="bro_lat" name="bro_lat" value="<?php echo esc_attr($lat); ?>" class="widefat">
</p>
<p>
<label for="bro_lng">Longitude:</label>
<input type="text" id="bro_lng" name="bro_lng" value="<?php echo esc_attr($lng); ?>" class="widefat">
</p>
<p class="description">Pro tip: Use Google Maps or similar to get coordinates. (e.g. 40.7128, -74.0060)</p>
<?php
}
add_action('save_post', 'bro_save_hangout_meta');
function bro_save_hangout_meta($post_id) {
if (!isset($_POST['bro_hangout_nonce']) || !wp_verify_nonce($_POST['bro_hangout_nonce'], 'bro_hangout_save')) return;
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (!current_user_can('edit_post', $post_id)) return;
if (isset($_POST['bro_lat'])) update_post_meta($post_id, '_bro_lat', sanitize_text_field($_POST['bro_lat']));
if (isset($_POST['bro_lng'])) update_post_meta($post_id, '_bro_lng', sanitize_text_field($_POST['bro_lng']));
}
// Shortcode to display the map
add_shortcode('bro_map', 'bro_display_map');
function bro_display_map() {
wp_enqueue_style('leaflet-css', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css');
wp_enqueue_script('leaflet-js', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js', array(), null, true);
ob_start();
?>
<div id="bro-party-map" style="height: 500px; width: 100%; border-radius: 15px; border: 3px solid #FFBF00; margin: 20px 0;"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
if (typeof L === 'undefined') return;
var map = L.map('bro-party-map').setView([40.7128, -74.0060], 13);
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
// Fetch hangouts via REST API
fetch('/wp-json/wp/v2/bro_hangout?_embed')
.then(response => response.json())
.then(hangouts => {
var bounds = [];
hangouts.forEach(hangout => {
var lat = hangout.meta ? hangout.meta._bro_lat : null;
var lng = hangout.meta ? hangout.meta._bro_lng : null;
// Fallback to searching meta directly if not in REST (REST meta needs registration)
// For now, let's use a custom endpoint or ensure meta is public
if (!lat || !lng) {
// If REST doesn't show meta, we might need a custom endpoint
}
});
});
// Since REST meta registration is a bit verbose, let's inject markers directly for now via PHP localized script or just a simple global
<?php
$hangouts = get_posts(array('post_type' => 'bro_hangout', 'numberposts' => -1));
$markers = array();
foreach ($hangouts as $h) {
$lat = get_post_meta($h->ID, '_bro_lat', true);
$lng = get_post_meta($h->ID, '_bro_lng', true);
if ($lat && $lng) {
$markers[] = array(
'lat' => (float)$lat,
'lng' => (float)$lng,
'title' => $h->post_title,
'content' => wp_trim_words($h->post_content, 20),
'link' => get_permalink($h->ID)
);
}
}
?>
var markers = <?php echo json_encode($markers); ?>;
var group = L.featureGroup();
markers.forEach(function(m) {
var marker = L.marker([m.lat, m.lng]).addTo(map);
marker.bindPopup("<b>" + m.title + "</b><br>" + m.content + "<br><a href='" + m.link + "' style='color:#FFBF00;'>Check it out</a>");
group.addLayer(marker);
});
if (markers.length > 0) {
map.fitBounds(group.getBounds());
}
});
</script>
<style>
.leaflet-popup-content-wrapper {
background: #1a1a1a;
color: #fff;
border: 1px solid #FFBF00;
}
.leaflet-popup-tip {
background: #FFBF00;
}
</style>
<?php
return ob_get_clean();
}
// Display Back to Map link on singular hangout
add_filter('the_content', function($content) {
if (is_singular('bro_hangout') && in_the_loop() && is_main_query()) {
$footer_link = '<div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #333;">';
$footer_link .= '<a href="/party-map/" style="color: #FFBF00; font-weight: bold; text-transform: uppercase; text-decoration: none;">← Back to Party Map</a>';
$footer_link .= '</div>';
return $content . $footer_link;
}
return $content;
});

View File

@ -0,0 +1,128 @@
<?php
/**
* Plugin Name: Bro Quiz
* Description: Find out what kind of Bro you are!
* Version: 1.0.0
* Author: Real Bro
*/
if (!defined('ABSPATH')) exit;
add_shortcode('bro_quiz', 'bro_render_quiz');
function bro_render_quiz() {
ob_start();
?>
<div id="bro-quiz-container" style="background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(10px); border: 2px solid #FFBF00; padding: 30px; border-radius: 20px; color: #fff; max-width: 600px; margin: 20px auto; text-align: center;">
<div id="quiz-intro">
<h2 style="color: #FFBF00; text-transform: uppercase;">The Ultimate Bro Quiz</h2>
<p>Determine your true beer destiny. Are you a Stout Sentinel or a Lager Legend?</p>
<button onclick="startBroQuiz()" style="background: #FFBF00; color: #000; border: none; padding: 15px 30px; border-radius: 50px; font-weight: bold; cursor: pointer; text-transform: uppercase; margin-top: 20px;">Start Quiz</button>
</div>
<div id="quiz-content" style="display: none;">
<h3 id="quiz-question" style="margin-bottom: 20px;"></h3>
<div id="quiz-options" style="display: flex; flex-direction: column; gap: 10px;"></div>
</div>
<div id="quiz-result" style="display: none;">
<h2 style="color: #FFBF00;">Your Result:</h2>
<h1 id="result-title" style="font-size: 3rem; margin: 10px 0;"></h1>
<p id="result-desc"></p>
<div style="display: flex; gap: 10px; justify-content: center; margin-top: 20px;">
<button onclick="location.reload()" style="background: transparent; color: #FFBF00; border: 2px solid #FFBF00; padding: 10px 20px; border-radius: 50px; cursor: pointer;">Take it again</button>
<a href="/" style="background: #FFBF00; color: #000; border: none; padding: 10px 20px; border-radius: 50px; cursor: pointer; text-decoration: none; font-weight: bold; font-size: 14px; line-height: 20px;">Back to Home</a>
</div>
</div>
</div>
<script>
const questions = [
{
q: "It's Friday night, 8 PM. Where are you?",
a: [
{ t: "At the bar with a cold lager.", s: "lager" },
{ t: "Hosting a basement rager.", s: "party" },
{ t: "Sipping an artisanal IPA.", s: "ipa" },
{ t: "In the gym, getting those gains.", s: "protein" }
]
},
{
q: "Favorite pizza topping?",
a: [
{ t: "Double Meat.", s: "protein" },
{ t: "Whatever is left in the box.", s: "party" },
{ t: "Plain Cheese, keep it classic.", s: "lager" },
{ t: "Goat cheese and arugula.", s: "ipa" }
]
},
{
q: "Your go-to music volume?",
a: [
{ t: "11. My neighbors should hear it.", s: "party" },
{ t: "Moderate, enough for conversation.", s: "lager" },
{ t: "I prefer podcasts about hops.", s: "ipa" },
{ t: "Heavy metal for the PRs.", s: "protein" }
]
}
];
let currentQ = 0;
let scores = { lager: 0, party: 0, ipa: 0, protein: 0 };
function startBroQuiz() {
document.getElementById('quiz-intro').style.display = 'none';
document.getElementById('quiz-content').style.display = 'block';
showQuestion();
}
function showQuestion() {
const q = questions[currentQ];
document.getElementById('quiz-question').innerText = q.q;
const optionsDiv = document.getElementById('quiz-options');
optionsDiv.innerHTML = '';
q.a.forEach(opt => {
const btn = document.createElement('button');
btn.innerText = opt.t;
btn.style.cssText = "background: rgba(255,191,0,0.1); color: #fff; border: 1px solid #FFBF00; padding: 12px; border-radius: 10px; cursor: pointer; transition: 0.3s; text-align: left;";
btn.onmouseover = () => btn.style.background = "rgba(255,191,0,0.3)";
btn.onmouseout = () => btn.style.background = "rgba(255,191,0,0.1)";
btn.onclick = () => selectOption(opt.s);
optionsDiv.appendChild(btn);
});
}
function selectOption(s) {
scores[s]++;
currentQ++;
if (currentQ < questions.length) {
showQuestion();
} else {
showResult();
}
}
function showResult() {
document.getElementById('quiz-content').style.display = 'none';
document.getElementById('quiz-result').style.display = 'block';
let maxScore = 0;
let result = 'lager';
for (const [key, value] of Object.entries(scores)) {
if (value > maxScore) {
maxScore = value;
result = key;
}
}
const resultsMap = {
lager: { t: "The Lager Legend", d: "You're a classic bro. Dependable, chill, and always down for a good time without the drama." },
party: { t: "The Party Animal", d: "You don't just go to the party, you ARE the party. Keep those speakers loud and the beer flowing." },
ipa: { t: "The IPA Intellectual", d: "You appreciate the finer notes of hops and life. A bit sophisticated, but still one of the boys." },
protein: { t: "The Iron Bro", d: "Weights before dates. You're dedicated to the grind, but you know how to celebrate a PR properly." }
};
document.getElementById('result-title').innerText = resultsMap[result].t;
document.getElementById('result-desc').innerText = resultsMap[result].d;
}
</script>
<?php
return ob_get_clean();
}