# Facebook Open Graph Protocol Implementation

## Overview

Implementasi lengkap **The Open Graph protocol** dengan Facebook namespace dan App ID untuk optimasi Facebook preview pada shortlink dashboard.

**Implemented Features:**
- ✅ Official OG namespace prefix (`og: https://ogp.me/ns#`)
- ✅ Facebook namespace prefix (`fb: https://ogp.me/ns/fb#`)
- ✅ Facebook App ID integration (`fb:app_id`)
- ✅ Complete OG meta tags (title, description, image, type, locale)
- ✅ Per-shortlink custom App ID support
- ✅ Fallback to default App ID (115190258555800)

## Files Modified/Created

### Database Schema
- **`database-migrations/003_add_fb_app_id_to_shortlinks.sql`** - Adds `fb_app_id` column to shortlinks table

### Backend
- **`src/Repository/ShortlinkRepository.php`** - Updated `create()` and `update()` methods to support `fb_app_id`
- **`src/Service/ShortlinkService.php`** - Added `fb_app_id` validation and sanitization

### AJAX Endpoints
- **`public/ajax/submit-shortlink.php`** - Updated to accept `fb_app_id` field
- **`public/ajax/update-shortlink.php`** - Updated to accept `fb_app_id` field

### Redirect Handler
- **`public/s.php`** -
  - Added HTML prefix: `prefix="og: https://ogp.me/ns# fb: https://ogp.me/ns/fb#"`
  - Added `fb:app_id` meta tag
  - Added additional OG meta tags: `og:locale`, `og:image:type`, `og:image:alt`
  - Dynamic App ID (from database or default)

### Frontend
- **`public/index.php`** - Added Facebook App ID input field to shortlink creation form

---

## Implementation Details

### 1. Database Schema

**New Column: `fb_app_id`**
```sql
ALTER TABLE `shortlinks`
ADD COLUMN `fb_app_id` VARCHAR(50) DEFAULT NULL
COMMENT 'Facebook App ID (optional, for Facebook Insights)'
AFTER `og_type`;
```

**Field Specifications:**
- Type: `VARCHAR(50)`
- Default: `NULL` (uses default App ID if not specified)
- Optional: Can be left empty per shortlink
- Sanitization: Max 50 characters, trimmed

### 2. HTML Structure (s.php)

**HTML Tag with Namespaces:**
```html
<html lang="en" prefix="og: https://ogp.me/ns# fb: https://ogp.me/ns/fb#">
```

**Meta Tags (Complete Implementation):**
```html
<!-- Facebook App ID -->
<meta property="fb:app_id" content="115190258555800">

<!-- Open Graph Protocol -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://yourdomain.com/s/slug">
<meta property="og:title" content="Your Title">
<meta property="og:description" content="Your Description">
<meta property="og:site_name" content="yourdomain.com">
<meta property="og:locale" content="en_US">

<!-- Open Graph Image -->
<meta property="og:image" content="https://example.com/image.jpg">
<meta property="og:image:secure_url" content="https://example.com/image.jpg">
<meta property="og:image:type" content="image/jpeg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Image description">
```

### 3. Dynamic App ID Logic

**PHP Code (s.php):**
```php
// Use shortlink-specific app ID if set, otherwise use default
$fbAppId = !empty($shortlink['fb_app_id'])
    ? $shortlink['fb_app_id']
    : '115190258555800';
```

**Priority:**
1. Database value (`shortlinks.fb_app_id`) - if not NULL
2. Default fallback: `115190258555800`

### 4. Form Integration

**Dashboard Form (Shortlinks Tab):**
```html
<div class="mb-3">
    <label for="shortlink_fb_app_id" class="form-label fw-bold">
        Facebook App ID (optional)
    </label>
    <input type="text"
           class="form-control bw-input"
           id="shortlink_fb_app_id"
           name="fb_app_id"
           placeholder="115190258555800">
    <div class="form-text bw-muted">
        Leave empty to use default (115190258555800)
    </div>
</div>
```

**Field Behavior:**
- Optional field (not required)
- Placeholder shows default App ID
- Empty value → uses default (NULL in database)
- Custom value → stored and used for that shortlink

---

## Deployment Steps

### Step 1: Run Database Migration

```bash
# Via MySQL CLI
mysql -u username -p database_name < database-migrations/003_add_fb_app_id_to_shortlinks.sql

# Or via phpMyAdmin
# 1. Login to phpMyAdmin
# 2. Select your database
# 3. Go to "Import" tab
# 4. Choose file: database-migrations/003_add_fb_app_id_to_shortlinks.sql
# 5. Click "Go"
```

### Step 2: Verify Column Added

```sql
DESCRIBE shortlinks;
-- Should show new column: fb_app_id VARCHAR(50) DEFAULT NULL

SELECT id, slug, fb_app_id FROM shortlinks LIMIT 5;
-- Should return NULL for existing shortlinks (expected behavior)
```

### Step 3: Test Dashboard

1. Navigate to your dashboard: `http://yourdomain.com/`
2. Click **Shortlinks** tab
3. Verify new field: "Facebook App ID (optional)"
4. Create test shortlink:
   - Leave App ID empty → uses default (115190258555800)
   - Fill custom App ID → uses custom value

### Step 4: Test Shortlink with Custom App ID

**Create Shortlink with Custom App ID:**
```
Destination URL: https://facebook.com
Custom Slug: fb-custom-app
OG Title: Test Custom App ID
OG Description: Testing custom Facebook App ID
Facebook App ID: 123456789012345
```

**Test Redirect:**
```bash
curl -s http://yourdomain.com/s/fb-custom-app | grep -i "fb:app_id"
# Expected: <meta property="fb:app_id" content="123456789012345">
```

**Create Shortlink with Default App ID:**
```
Destination URL: https://facebook.com
Custom Slug: fb-default-app
OG Title: Test Default App ID
Facebook App ID: [leave empty]
```

**Test Redirect:**
```bash
curl -s http://yourdomain.com/s/fb-default-app | grep -i "fb:app_id"
# Expected: <meta property="fb:app_id" content="115190258555800">
```

---

## Facebook Debugger Testing

### Test with Facebook Sharing Debugger

**URL:** https://developers.facebook.com/tools/debug/

**Steps:**
1. Enter shortlink URL: `http://yourdomain.com/s/your-slug`
2. Click "Debug"
3. Verify output:

**Expected Results:**
```
✅ og:title         = Your Title
✅ og:description   = Your Description
✅ og:image         = https://example.com/image.jpg (1200x630)
✅ og:type          = website
✅ og:url           = http://yourdomain.com/s/your-slug
✅ og:site_name     = yourdomain.com
✅ og:locale        = en_US
✅ fb:app_id        = 115190258555800 (or custom if set)
```

### Facebook Insights Access

**With fb:app_id configured:**
- Facebook can track sharing metrics
- View insights in Facebook Analytics dashboard
- Track engagement (likes, shares, comments)
- See which pages are sharing your links

**Without fb:app_id:**
- Basic preview works
- No detailed analytics
- Cannot claim domain in Facebook Business Manager

### Verify OG Tags in HTML Source

```bash
# View full HTML with OG tags
curl -s http://yourdomain.com/s/your-slug | grep -i "property=\"og\|property=\"fb"

# Expected output:
# <meta property="fb:app_id" content="115190258555800">
# <meta property="og:type" content="website">
# <meta property="og:url" content="...">
# <meta property="og:title" content="...">
# <meta property="og:description" content="...">
# <meta property="og:site_name" content="...">
# <meta property="og:locale" content="en_US">
# <meta property="og:image" content="...">
# <meta property="og:image:secure_url" content="...">
# <meta property="og:image:type" content="image/jpeg">
# <meta property="og:image:width" content="1200">
# <meta property="og:image:height" content="630">
# <meta property="og:image:alt" content="...">
```

---

## Facebook App ID Benefits

### 1. Facebook Insights & Analytics

**What you get:**
- **Sharing statistics:** How many times your shortlink was shared
- **Engagement metrics:** Likes, comments, reactions on shared posts
- **Demographics:** Age, gender, location of people engaging
- **Referral traffic:** Which Facebook pages/groups share your links

**Access:**
- Facebook Analytics Dashboard
- Facebook Business Manager
- Graph API for programmatic access

### 2. Domain Verification

**With fb:app_id:**
- Claim domain ownership in Facebook Business Manager
- Control how links appear when shared
- Set default image for pages without OG tags
- Moderate/report spam shares

### 3. Enhanced Preview Control

**Benefits:**
- More reliable preview generation
- Faster cache updates (priority crawling)
- Better image selection (respects OG image priority)
- Consistent preview across platforms

### 4. App Integration

**If building Facebook app:**
- Link shortlinks to your Facebook app
- Track app-specific sharing
- Deep linking support
- App Events integration

---

## Per-Shortlink Custom App ID Use Cases

### Use Case 1: Multiple Facebook Apps

**Scenario:** You have multiple Facebook apps for different products/brands.

**Implementation:**
```
Product A Shortlink:
- fb_app_id: 111111111111111
- Tracks shares for Product A app

Product B Shortlink:
- fb_app_id: 222222222222222
- Tracks shares for Product B app

Default Shortlinks:
- fb_app_id: NULL (uses default 115190258555800)
- Tracks shares for main app
```

### Use Case 2: Client Campaign Tracking

**Scenario:** Agency managing multiple client campaigns.

**Implementation:**
```
Client 1 Campaign:
- fb_app_id: <client1_app_id>
- Separate analytics for client 1

Client 2 Campaign:
- fb_app_id: <client2_app_id>
- Separate analytics for client 2

Internal Links:
- fb_app_id: NULL (default)
- Your agency analytics
```

### Use Case 3: A/B Testing

**Scenario:** Test different Facebook apps for better engagement.

**Implementation:**
```
Test Group A:
- fb_app_id: 123456789012345
- Track engagement metrics

Test Group B:
- fb_app_id: 543210987654321
- Track engagement metrics

Compare results in respective Facebook Analytics dashboards
```

---

## Troubleshooting

### Issue: fb:app_id not showing in Facebook Debugger

**Symptoms:** Facebook Debugger shows "Missing fb:app_id"

**Solutions:**
```bash
# 1. Verify HTML source contains tag
curl -s http://yourdomain.com/s/test | grep "fb:app_id"
# Expected: <meta property="fb:app_id" content="...">

# 2. Check database value
mysql -u user -p -e "SELECT slug, fb_app_id FROM database_name.shortlinks WHERE slug='test';"
# If NULL, uses default

# 3. Clear Facebook cache
# Go to: https://developers.facebook.com/tools/debug/
# Enter URL and click "Scrape Again"

# 4. Verify namespace prefix in <html> tag
curl -s http://yourdomain.com/s/test | grep "<html"
# Expected: <html lang="en" prefix="og: https://ogp.me/ns# fb: https://ogp.me/ns/fb#">
```

### Issue: Custom App ID not working

**Symptoms:** Always shows default App ID (115190258555800)

**Solutions:**
```bash
# 1. Check if column exists
mysql -u user -p -e "DESCRIBE database_name.shortlinks;" | grep fb_app_id
# Should show: fb_app_id | varchar(50) | YES | | NULL |

# 2. Check if value saved in database
mysql -u user -p -e "SELECT slug, fb_app_id FROM database_name.shortlinks WHERE slug='test';"
# Should show custom value if set

# 3. Verify form field name
# In index.php, search for: name="fb_app_id"
# Should exist in shortlink form

# 4. Check AJAX endpoint
# In submit-shortlink.php, verify: $data['fb_app_id'] = ...
```

### Issue: Facebook not recognizing namespace

**Symptoms:** OG tags work but Facebook warns about namespace

**Solutions:**
```bash
# Verify <html> tag has correct prefix attribute
curl -s http://yourdomain.com/s/test | grep -o '<html[^>]*>'

# Expected output:
# <html lang="en" prefix="og: https://ogp.me/ns# fb: https://ogp.me/ns/fb#">

# If missing, check s.php line 133:
grep -n 'prefix=' public/s.php
# Should show: <html lang="en" prefix="og: https://ogp.me/ns# fb: https://ogp.me/ns/fb#">
```

---

## Open Graph Protocol Compliance

### Required Properties (✅ Implemented)

- `og:title` - The title of your object
- `og:type` - The type of your object (e.g., "website", "article")
- `og:image` - An image URL representing your object
- `og:url` - The canonical URL of your object

### Recommended Properties (✅ Implemented)

- `og:description` - A one to two sentence description
- `og:site_name` - The name of your website
- `og:locale` - The locale of the content (default: en_US)

### Facebook-Specific (✅ Implemented)

- `fb:app_id` - Facebook App ID for insights and analytics

### Image Properties (✅ Implemented)

- `og:image:secure_url` - HTTPS version of og:image
- `og:image:type` - MIME type of the image
- `og:image:width` - Width in pixels (1200 recommended)
- `og:image:height` - Height in pixels (630 recommended)
- `og:image:alt` - Alt text for the image

---

## Best Practices

### 1. Image Specifications

**Recommended:**
- **Size:** 1200x630 pixels (1.91:1 aspect ratio)
- **Format:** JPG, PNG, or WebP
- **File size:** < 8 MB
- **URL:** HTTPS (secure) for better compatibility

**Why:**
- Facebook uses this size for link preview cards
- Optimal display on desktop and mobile
- Better compression for faster loading

### 2. Title & Description Length

**Title:**
- **Optimal:** 60-90 characters
- **Maximum:** 255 characters (will be truncated)
- **Tip:** Front-load important keywords

**Description:**
- **Optimal:** 150-200 characters
- **Maximum:** No hard limit, but Facebook truncates at ~300 chars
- **Tip:** Make first 150 characters compelling

### 3. App ID Management

**Single App (Simple):**
```
Use default App ID (115190258555800)
Leave fb_app_id field empty for all shortlinks
Track all shares in one Facebook App
```

**Multiple Apps (Advanced):**
```
Set default App ID for general use
Use custom App ID per campaign/client
Track separately in Facebook Analytics
```

### 4. Testing Workflow

**Before Sharing:**
1. Create shortlink with OG tags
2. Test with Facebook Debugger
3. Fix any warnings/errors
4. Click "Scrape Again" to update cache
5. Share on Facebook

**After Deployment:**
1. Monitor Facebook Insights
2. Check sharing metrics weekly
3. A/B test different OG images
4. Optimize title/description based on engagement

---

## API Reference

### Creating Shortlink with Custom App ID

**Endpoint:** `POST /ajax/submit-shortlink.php`

**Request:**
```bash
curl -X POST http://yourdomain.com/ajax/submit-shortlink.php \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "csrf_token=YOUR_CSRF_TOKEN" \
  -d "destination_url=https://example.com" \
  -d "slug=test-fb-app" \
  -d "og_title=Test Facebook App ID" \
  -d "og_description=Testing custom Facebook App ID integration" \
  -d "og_image=https://example.com/image.jpg" \
  -d "fb_app_id=123456789012345"
```

**Response:**
```json
{
  "success": true,
  "message": "Shortlink created successfully",
  "shortlink_id": 42,
  "slug": "test-fb-app",
  "csrf_token": "new_rotated_csrf_token"
}
```

### Updating Shortlink App ID

**Endpoint:** `POST /ajax/update-shortlink.php`

**Request:**
```bash
curl -X POST http://yourdomain.com/ajax/update-shortlink.php \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "csrf_token=YOUR_CSRF_TOKEN" \
  -d "id=42" \
  -d "destination_url=https://example.com" \
  -d "fb_app_id=999888777666555"
```

**Response:**
```json
{
  "success": true,
  "message": "Shortlink updated successfully",
  "csrf_token": "new_rotated_csrf_token"
}
```

---

## Resources

### Official Documentation

- **Open Graph Protocol:** https://ogp.me/
- **Facebook Sharing Debugger:** https://developers.facebook.com/tools/debug/
- **Facebook App Dashboard:** https://developers.facebook.com/apps/
- **Facebook Analytics:** https://analytics.facebook.com/

### Testing Tools

- **Facebook Debugger:** https://developers.facebook.com/tools/debug/
- **LinkedIn Inspector:** https://www.linkedin.com/post-inspector/
- **Twitter Card Validator:** https://cards-dev.twitter.com/validator
- **WhatsApp Validator:** Share link to yourself to test

### Image Resources

- **Placeholder Images:** https://via.placeholder.com/1200x630
- **Free Stock Photos:** https://unsplash.com/ (1200x630 search)
- **OG Image Generator:** https://www.opengraph.xyz/
- **Image Optimizer:** https://tinypng.com/

---

## Changelog

**v1.1.0 (2025-12-26) - Facebook Open Graph Protocol**
- Added Facebook namespace prefix to HTML tag
- Implemented fb:app_id meta tag support
- Added fb_app_id database column
- Per-shortlink custom App ID support
- Default fallback to App ID: 115190258555800
- Enhanced OG meta tags (locale, image:alt, image:type)
- Updated dashboard form with App ID field
- Complete OG protocol compliance

**v1.0.0 (2025-12-26) - Initial Release**
- Basic Open Graph meta tags
- Shortlink management with OG support
- Click tracking and analytics

---

**Version:** 1.1.0
**Last Updated:** 2025-12-26
**Facebook App ID (Default):** 115190258555800
**Maintained By:** Domain Dashboard Team
