π Write Fields
π Generated JSON-LD Code
π Google Search Result Preview
const schemaType = document.getElementById('schemaType');
const fieldsContainer = document.getElementById('fieldsContainer');
const generateBtn = document.getElementById('generateBtn');
const copyBtn = document.getElementById('copyBtn');
const previewBtn = document.getElementById('previewBtn');
const schemaOutput = document.getElementById('schemaOutput');
const outputSection = document.getElementById('outputSection');
const previewSection = document.getElementById('previewSection');
const previewContent = document.getElementById('previewContent');
const fieldDefs = {
FAQPage: [
{id: 'question', label: 'Question', type: 'text', placeholder: 'FAQ 1', multi: true},
{id: 'answer', label: 'Answer', type: 'textarea', placeholder: 'Question content', multi: true},
],
Article: [
{id: 'headline', label: 'Title', type: 'text', placeholder: 'Article title'},
{id: 'description', label: 'Description', type: 'textarea', placeholder: 'Article description'},
{id: 'author', label: 'Author', type: 'text', placeholder: 'Author name'},
{id: 'datePublished', label: 'Publish Date', type: 'date'},
{id: 'image', label: 'Image URL', type: 'text', placeholder: 'https://example.com/image.jpg', optional: true},
],
SoftwareApplication: [
{id: 'name', label: 'App Name', type: 'text', placeholder: 'Tool name'},
{id: 'description', label: 'Description', type: 'textarea', placeholder: 'Tool feature description'},
{id: 'operatingSystem', label: 'Operating System', type: 'text', placeholder: 'Web / Windows / macOS / iOS / Android'},
{id: 'applicationCategory', label: 'App Category', type: 'text', placeholder: 'UtilitiesApplication / MultimediaApplication / ...'},
{id: 'price', label: 'Price (0 for Free)', type: 'text', placeholder: '0'},
{id: 'priceCurrency', label: 'Currency', type: 'text', placeholder: 'CNY / USD'},
],
LocalBusiness: [
{id: 'name', label: 'Business Name', type: 'text', placeholder: 'Business name'},
{id: 'description', label: 'Description', type: 'textarea', placeholder: 'Business description'},
{id: 'address', label: 'Address', type: 'text', placeholder: 'Street, City, Country'},
{id: 'telephone', label: 'Phone', type: 'text', placeholder: '+86 1234567890'},
{id: 'openingHours', label: 'Opening Hours', type: 'text', placeholder: 'Mo-Fr 09:00-18:00', optional: true},
{id: 'image', label: 'Image URL', type: 'text', placeholder: 'https://example.com/logo.jpg', optional: true},
],
Product: [
{id: 'name', label: 'Product Name', type: 'text', placeholder: 'Product name'},
{id: 'description', label: 'Description', type: 'textarea', placeholder: 'Product description'},
{id: 'brand', label: 'Brand', type: 'text', placeholder: 'Brand name'},
{id: 'price', label: 'Price', type: 'text', placeholder: '29.99'},
{id: 'priceCurrency', label: 'Currency', type: 'text', placeholder: 'USD / CNY'},
{id: 'availability', label: 'Availability', type: 'select', options: ['InStock', 'OutOfStock', 'PreOrder', 'Discontinued']},
],
BreadcrumbList: [
{id: 'item1_name', label: 'Item 1 Name', type: 'text', placeholder: 'Home'},
{id: 'item1_url', label: 'Item 1 URL', type: 'text', placeholder: 'https://example.com/'},
{id: 'item2_name', label: 'Item 2 Name', type: 'text', placeholder: 'Category'},
{id: 'item2_url', label: 'Item 2 URL', type: 'text', placeholder: 'https://example.com/category/'},
{id: 'item3_name', label: 'Item 3 Name', type: 'text', placeholder: 'Current Page', optional: true},
{id: 'item3_url', label: 'Item 3 URL', type: 'text', placeholder: 'https://example.com/category/page/', optional: true},
],
Event: [
{id: 'name', label: 'Event Name', type: 'text', placeholder: 'Event name'},
{id: 'description', label: 'Description', type: 'textarea', placeholder: 'Event description'},
{id: 'startDate', label: 'Start Date', type: 'date'},
{id: 'endDate', label: 'End Date', type: 'date', optional: true},
{id: 'location', label: 'Location', type: 'text', placeholder: 'Event location'},
{id: 'url', label: 'Event Link', type: 'text', placeholder: 'https://example.com/event', optional: true},
],
Recipe: [
{id: 'name', label: 'Recipe Name', type: 'text', placeholder: 'Recipe name'},
{id: 'description', label: 'Description', type: 'textarea', placeholder: 'Recipe description'},
{id: 'prepTime', label: 'Prep Time', type: 'text', placeholder: 'PT15M (15 minutes)'},
{id: 'cookTime', label: 'Cook Time', type: 'text', placeholder: 'PT30M (30 minutes)'},
{id: 'recipeYield', label: 'Servings', type: 'text', placeholder: '2-3 servings'},
{id: 'image', label: 'Image URL', type: 'text', placeholder: 'https://example.com/food.jpg', optional: true},
],
Person: [
{id: 'name', label: 'Name', type: 'text', placeholder: 'Full name'},
{id: 'jobTitle', label: 'Job Title', type: 'text', placeholder: 'CEO / Developer'},
{id: 'description', label: 'Introduction', type: 'textarea', placeholder: 'Person introduction', optional: true},
{id: 'url', label: 'Personal Website', type: 'text', placeholder: 'https://example.com/', optional: true},
{id: 'image', label: 'Headshot URL', type: 'text', placeholder: 'https://example.com/avatar.jpg', optional: true},
],
Organization: [
{id: 'name', label: 'Organization Name', type: 'text', placeholder: 'Public / Organization name'},
{id: 'description', label: 'Description', type: 'textarea', placeholder: 'Organization description'},
{id: 'url', label: 'Website URL', type: 'text', placeholder: 'https://example.com/', optional: true},
{id: 'logo', label: 'Logo URL', type: 'text', placeholder: 'https://example.com/logo.jpg', optional: true},
{id: 'contactPoint', label: 'Phone', type: 'text', placeholder: '+86 1234567890', optional: true},
]
};
// Add FAQ item management
let faqCount = 3;
function renderFields() {
const type = schemaType.value;
const fields = fieldDefs[type];
if(!fields) return;
let html = '';
for(const field of fields) {
const required = field.optional ? '' : ' \x3Cspan style="color:#f87171">*\x3C/span>';
const optClass = field.optional ? ' style="opacity:0.6"' : '';
if(field.multi && type === 'FAQPage') {
html += '\x3Cdiv id="faqContainer">';
for(let i = 0; i < faqCount; i++) {
html += '\x3Cdiv class="faq-pair" style="background:rgba(15,23,42,.5);border-radius:8px;padding:12px;margin-bottom:10px">';
html += '\x3Cdiv class="form-group">\x3Clabel>Question ' + (i+1) + required + '\x3C/label>' +
'\x3Cinput type="text" id="faq_q_' + i + '" placeholder="FAQ ' + (i+1) + '" style="font-family:inherit">\x3C/div>';
html += '\x3Cdiv class="form-group">\x3Clabel>Answer ' + (i+1) + required + '\x3C/label>' +
'\x3Ctextarea id="faq_a_' + i + '" placeholder="Answer content" style="min-height:60px;font-family:inherit">\x3C/textarea>\x3C/div>';
if(i >= 3) {
html += '\x3Cbutton class="btn btn-danger" onclick="removeFaq(' + i + ')" style="font-size:.8rem;padding:4px 10px">β Delete\x3C/button>';
}
html += '\x3C/div>';
}
html += '\x3Cbutton class="btn btn-secondary" onclick="addFaq()" style="font-size:.8rem">+ Add Question\x3C/button>';
html += '\x3C/div>';
continue;
}
html += '\x3Cdiv class="form-group"' + optClass + '>' +
'\x3Clabel>' + field.label + required + '\x3C/label>';
if(field.type === 'textarea') {
html += '\x3Ctextarea id="field_' + field.id + '" placeholder="' + (field.placeholder || '') + '" style="min-height:60px;font-family:inherit">\x3C/textarea>';
} else if(field.type === 'select') {
html += '\x3Cselect id="field_' + field.id + '">';
for(const opt of (field.options || [])) {
html += '\x3Coption value="' + opt + '">' + opt + '\x3C/option>';
}
html += '\x3C/select>';
} else if(field.type === 'date') {
html += '\x3Cinput type="date" id="field_' + field.id + '">';
} else {
html += '\x3Cinput type="text" id="field_' + field.id + '" placeholder="' + (field.placeholder || '') + '">';
}
html += '\x3C/div>';
}
fieldsContainer.innerHTML = html;
outputSection.style.display = 'none';
previewSection.style.display = 'none';
copyBtn.style.display = 'none';
previewBtn.style.display = 'none';
}
window.addFaq = function() {
faqCount++;
renderFields();
};
window.removeFaq = function(index) {
faqCount--;
renderFields();
};
function generateJSON() {
const type = schemaType.value;
let schema = { '@context': 'https://schema.org', '@type': type };
switch(type) {
case 'FAQPage': {
const entities = [];
for(let i = 0; i < faqCount; i++) {
const q = document.getElementById('faq_q_' + i);
const a = document.getElementById('faq_a_' + i);
if(q && a && q.value.trim() && a.value.trim()) {
entities.push({
'@type': 'Question',
'name': q.value.trim(),
'acceptedAnswer': { '@type': 'Answer', 'text': a.value.trim() }
});
}
}
schema.mainEntity = entities;
break;
}
case 'Article': {
schema.headline = g('headline');
schema.description = g('description');
if(g('author')) schema.author = { '@type': 'Person', 'name': g('author') };
if(g('datePublished')) schema.datePublished = g('datePublished');
if(g('image')) schema.image = g('image');
break;
}
case 'SoftwareApplication': {
schema.name = g('name');
schema.description = g('description');
schema.operatingSystem = g('operatingSystem') || 'Web';
schema.applicationCategory = g('applicationCategory') || 'UtilitiesApplication';
schema.offers = { '@type': 'Offer', 'price': g('price') || '0', 'priceCurrency': g('priceCurrency') || 'USD' };
break;
}
case 'LocalBusiness': {
schema.name = g('name');
schema.description = g('description');
if(g('address')) schema.address = { '@type': 'PostalAddress', 'streetAddress': g('address') };
if(g('telephone')) schema.telephone = g('telephone');
if(g('openingHours')) schema.openingHours = g('openingHours');
if(g('image')) schema.image = g('image');
break;
}
case 'Product': {
schema.name = g('name');
schema.description = g('description');
if(g('brand')) schema.brand = { '@type': 'Brand', 'name': g('brand') };
schema.offers = { '@type': 'Offer', 'price': g('price') || '0', 'priceCurrency': g('priceCurrency') || 'USD', 'availability': 'https://schema.org/' + (document.getElementById('field_availability')?.value || 'InStock') };
break;
}
case 'BreadcrumbList': {
const items = [];
for(let i = 1; i <= 3; i++) {
const name = document.getElementById('field_item' + i + '_name');
const url = document.getElementById('field_item' + i + '_url');
if(name && url && name.value.trim() && url.value.trim()) {
items.push({ '@type': 'ListItem', 'position': i, 'name': name.value.trim(), 'item': url.value.trim() });
}
}
schema.itemListElement = items;
break;
}
case 'Event': {
schema.name = g('name');
schema.description = g('description');
if(g('startDate')) schema.startDate = g('startDate');
if(g('endDate')) schema.endDate = g('endDate');
if(g('location')) schema.location = { '@type': 'Place', 'name': g('location') };
if(g('url')) schema.url = g('url');
break;
}
case 'Recipe': {
schema.name = g('name');
schema.description = g('description');
if(g('prepTime')) schema.prepTime = g('prepTime');
if(g('cookTime')) schema.cookTime = g('cookTime');
if(g('recipeYield')) schema.recipeYield = g('recipeYield');
if(g('image')) schema.image = g('image');
break;
}
case 'Person': {
schema.name = g('name');
if(g('jobTitle')) schema.jobTitle = g('jobTitle');
if(g('description')) schema.description = g('description');
if(g('url')) schema.url = g('url');
if(g('image')) schema.image = g('image');
break;
}
case 'Organization': {
schema.name = g('name');
schema.description = g('description');
if(g('url')) schema.url = g('url');
if(g('logo')) schema.logo = g('logo');
if(g('contactPoint')) schema.contactPoint = { '@type': 'ContactPoint', 'telephone': g('contactPoint'), 'contactType': 'customer service' };
break;
}
}
return JSON.stringify(schema, null, 2);
}
function g(id) {
const el = document.getElementById('field_' + id);
return el ? el.value.trim() : '';
}
generateBtn.addEventListener('click', () => {
const json = generateJSON();
const output = '\x3Cscript type="application/ld+json">' + json + '\\n<\\/script>';
schemaOutput.textContent = output;
outputSection.style.display = 'block';
previewSection.style.display = 'block';
copyBtn.style.display = 'inline-block';
previewBtn.style.display = 'inline-block';
// Preview
const type = schemaType.value;
let previewHtml = '';
switch(type) {
case 'FAQPage':
previewHtml = '\x3Cdiv style="color:#1a0dab;font-size:1rem;margin-bottom:4px">FAQ\x3C/div>\x3Cdiv style="color:#006621;font-size:.85rem">Q&A structured data generated\x3C/div>';
break;
case 'Article':
previewHtml = '\x3Cdiv style="color:#1a0dab;font-size:1.1rem;margin-bottom:4px">' + (g('headline') || 'Article title') + '\x3C/div>' +
'\x3Cdiv style="color:#006621;font-size:.85rem">' + (g('datePublished') || 'Date') + '\x3C/div>' +
'\x3Cdiv style="color:#545454;font-size:.85rem">' + (g('description') || 'Article description') + '\x3C/div>';
break;
case 'SoftwareApplication':
previewHtml = '\x3Cdiv style="color:#1a0dab;font-size:1rem;margin-bottom:4px">' + (g('name') || 'App name') + ' - ' + (g('applicationCategory') || '') + '\x3C/div>' +
'\x3Cdiv style="color:#545454;font-size:.85rem">' + (g('description') || 'Description') + '\x3C/div>' +
'\x3Cdiv style="color:#006621;font-size:.8rem">Free Β· Price: ' + (g('priceCurrency') || '') + (g('price') || 'Free') + '\x3C/div>';
break;
default:
previewHtml = '\x3Cdiv style="color:#1a0dab;font-size:1rem;margin-bottom:4px">' + type + ' Schema\x3C/div>' +
'\x3Cdiv style="color:#545454;font-size:.85rem">Structured data generated, total ' + json.length + ' characters\x3C/div>';
}
previewContent.innerHTML = previewHtml;
});
copyBtn.addEventListener('click', () => {
navigator.clipboard.writeText(schemaOutput.textContent).then(() => {
copyBtn.textContent = 'β
Copied';
setTimeout(() => { copyBtn.textContent = 'π Copy Code'; }, 2000);
}).catch(() => {
const range = document.createRange();
range.selectNode(schemaOutput);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand('copy');
copyBtn.textContent = 'β
Copied';
setTimeout(() => { copyBtn.textContent = 'π Copy Code'; }, 2000);
});
});
previewBtn.addEventListener('click', () => {
previewSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
});
schemaType.addEventListener('change', renderFields);
// Initialize
renderFields();