Appearance
Component Guidelines
This guide provides comprehensive guidelines for creating and maintaining components in LamaPress. Follow these guidelines to ensure consistency and quality.
Table of Contents
- Component Structure
- PHP Template Guidelines
- JavaScript Guidelines
- ACF Field Guidelines
- Styling Guidelines
- Best Practices
Component Structure
Required Files
Sections:
index.php- Required: Main templateacf.php- Required: ACF field definitions
Blocks and Parts:
index.php- Required: Main templateacf.php- Optional: Only if fields are reusable
Optional Files
index.js- Optional: JavaScript for interactivitystyle.scss- Optional: Component-specific stylesfunctions.php- Optional: Component-specific functions (sections only)
File Organization
components/
├── sections/
│ └── hero_basic/
│ ├── index.php # Required
│ ├── acf.php # Required
│ ├── index.js # Optional
│ ├── style.scss # Optional
│ └── functions.php # Optional
└── blocks/
└── accordion/
├── index.php # Required
├── acf.php # Optional
├── index.js # Optional
└── style.scss # OptionalPHP Template Guidelines
File Header
All component PHP files:
php
<?php
/**
* Component description here.
*
* This component does X, Y, and Z.
*/
defined('ABSPATH') || exit;Sections only:
php
<?php
/**
* Section description here.
*/
defined('ABSPATH') || exit;
$section ??= false;
$key ??= false;Section Templates
Use llSectionHeader() and llSectionFooter():
php
<?php
llSectionHeader(
name: 'hero_basic',
sectionClasses: 'll-section--dark',
containerClasses: 'll-container--wide',
constructorName: 'hero_basic'
);
// Section content
llSectionFooter();
?>Grid Layouts:
php
<?php
llSectionHeader(
name: 'content_grid',
containerClasses: 'll-grid'
);
// Use grid column utilities
<div class="col-start-1 col-span-12 md:col-span-6">
<!-- Content -->
</div>
llSectionFooter();
?>Block and Part Templates
Property Handling:
php
<?php
$classes = $classes ?? '';
$fields = $fields ?? [];
$title = $fields['title'] ?? false;
?>
<?php if ($title): ?>
<div class="ll-block--my-component <?= $classes ?>">
<h2><?= esc_html($title) ?></h2>
</div>
<?php endif; ?>Always Check for Data:
php
<?php
// ✅ Good - Check before using
$title = $fields['title'] ?? false;
if ($title) {
echo esc_html($title);
}
// ❌ Bad - No check
echo esc_html($fields['title']);
?>Field Access
Use llField() with all arguments:
php
<?php
// ✅ Good - Always pass 3 arguments
$title = llField('title', $key, $section);
// ❌ Bad - Missing arguments
$title = llField('title');
?>Wrap in Conditionals:
php
<?php
// ✅ Good - Wrapped in if statement
$title = llField('title', $key, $section);
if ($title) {
echo '<h1>' . esc_html($title) . '</h1>';
}
// ❌ Bad - No check
echo '<h1>' . esc_html(llField('title', $key, $section)) . '</h1>';
?>HTML Structure
Semantic HTML:
php
<?php
// ✅ Good - Semantic HTML
<section class="ll-section">
<header>
<h1><?= esc_html($title) ?></h1>
</header>
<main>
<?= wp_kses_post($content) ?>
</main>
</section>
// ❌ Bad - Non-semantic
<div class="ll-section">
<div class="title"><?= esc_html($title) ?></div>
<div class="content"><?= wp_kses_post($content) ?></div>
</div>
?>Spacing:
- Add empty line between sibling HTML elements
- Add content within HTML element on new line
php
<?php
// ✅ Good
<div class="container">
<h1><?= esc_html($title) ?></h1>
<p><?= wp_kses_post($content) ?></p>
</div>
// ❌ Bad
<div class="container"><h1><?= esc_html($title) ?></h1><p><?= wp_kses_post($content) ?></p></div>
?>JavaScript Guidelines
Component Class Structure
Standard Structure:
javascript
import { gsap } from 'gsap/all'
import { app } from '@src/js/core/app'
import { killTimeline } from '@src/js/core/utils/helpers'
export default class MyComponent {
constructor(element) {
this.element = element
this.timeline = null
this.init()
}
init = () => {
this.bindEvents()
this.createAnimation()
}
bindEvents = () => {
// Event listeners
}
createAnimation = () => {
// Animation setup
}
enter = () => {
// Reveal animation
}
destroy = () => {
killTimeline(this.timeline)
// Cleanup
}
}Event Handling
Use bindEvents() Method:
javascript
// ✅ Good
bindEvents = () => {
this.element.addEventListener('click', this.handleClick)
this.button.addEventListener('mouseenter', this.handleMouseEnter)
}
// ❌ Bad - Events in init()
init = () => {
this.element.addEventListener('click', this.handleClick)
}Clean Up in destroy():
javascript
destroy = () => {
this.element.removeEventListener('click', this.handleClick)
this.button.removeEventListener('mouseenter', this.handleMouseEnter)
}Animation Guidelines
Bind Timelines to Instance:
javascript
// ✅ Good
this.timeline = gsap.timeline()
// ❌ Bad
const timeline = gsap.timeline()Use killTimeline() Helper:
javascript
import { killTimeline } from '@src/js/core/utils/helpers'
destroy = () => {
killTimeline(this.timeline)
}Reveal Animations:
javascript
createRevealAnimation = () => {
this.timeline = gsap.timeline({
scrollTrigger: {
trigger: this.element,
start: 'top 80%',
}
})
this.timeline.from(this.element, {
opacity: 0,
y: 20,
duration: 0.6
})
}
enter = () => {
// Additional enter logic if needed
}ACF Field Guidelines
Section Fields
Required Variables:
php
<?php
$title = 'Hero Basic'; // Display name
$name = 'hero_basic'; // Identifier (snake_case)
$category = 'common'; // Category for grouping
$key = 'a1b2c3d4e5f6'; // Unique 12-character key (a-z, 0-9)
$groupFields = [ // Field definitions
// ...
];
?>Key Requirements:
- Must be exactly 12 characters
- Only use a-z and 0-9
- Must be unique across all ACF files
- Must be hard-coded (never change)
Field Instructions:
php
<?php
$groupFields = [
[
'key' => $name . '_01',
'label' => 'Title',
'name' => 'title',
'type' => 'text',
'instructions' => 'Enter a compelling title for this section',
],
];
?>Block and Part Fields
Only Return Fields Array:
php
<?php
// ✅ Good - Only return fields
$groupFields = [
[
'key' => 'title',
'label' => 'Title',
'name' => 'title',
'type' => 'text',
],
];Don't Define Variables:
php
<?php
// ❌ Bad - Don't define $key, $name, $title
$key = 'block_key';
$name = 'block_name';
$title = 'Block Title';
$groupFields = [/* ... */];
?>Styling Guidelines
Tailwind First
Use Tailwind Classes:
php
<?php
// ✅ Good - Tailwind classes
<div class="flex items-center justify-between p-4 bg-white rounded-lg">
// ❌ Bad - Custom CSS
<div class="custom-wrapper">Custom Classes
Prefix with ll-:
php
<?php
// ✅ Good
<div class="ll-block--accordion">
// ❌ Bad
<div class="accordion">Only When Necessary:
- Only create custom classes if Tailwind doesn't have what you need
- Use
@applyin SCSS for common Tailwind patterns
scss
// ✅ Good - Using Tailwind
.ll-block--accordion {
@apply flex items-center;
}
// ❌ Bad - Recreating Tailwind
.ll-block--accordion {
display: flex;
align-items: center;
}Component Styles
Minimal Custom SCSS:
scss
// ✅ Good - Only what's necessary
.ll-block--accordion {
// Specific styling not possible with Tailwind
}
// ❌ Bad - Recreating Tailwind
.ll-block--accordion {
display: flex;
padding: 1rem;
background: white;
// Use Tailwind classes instead
}Best Practices
1. Single Responsibility
Each component should do one thing well:
php
<?php
// ✅ Good - Focused component
// components/blocks/title/index.php
<h1><?= esc_html($title) ?></h1>
// ❌ Bad - Too many responsibilities
// components/blocks/content/index.php
<h1><?= esc_html($title) ?></h1>
<p><?= wp_kses_post($content) ?></p>
<img src="<?= $image ?>">
<button><?= $cta ?></button>2. Reusability
Create reusable components:
php
<?php
// ✅ Good - Reusable button component
llPart('buttons/default', [
'text' => 'Click Me',
'url' => '/contact'
]);
// ❌ Bad - Inline button
<a href="/contact" class="btn">Click Me</a>3. Data Validation
Always validate data:
php
<?php
// ✅ Good - Check before use
$items = $fields['items'] ?? [];
if ($items) {
foreach ($items as $item) {
// Process item
}
}
// ❌ Bad - No validation
foreach ($fields['items'] as $item) {
// May error if items doesn't exist
}4. Security
Always escape output:
php
<?php
// ✅ Good - Escaped output
echo esc_html($text);
echo wp_kses_post($html);
echo esc_url($url);
echo esc_attr($attribute);
// ❌ Bad - Unescaped output
echo $text;
echo $html;5. Performance
Optimize for performance:
- Use efficient queries
- Minimize database calls
- Cache expensive operations
- Lazy load images
Related Documentation
- Coding Standards - General coding standards
- Component System - Component architecture
- ACF Integration - ACF field patterns
Next Steps:
- Review Coding Standards for general standards
- Check Component System for architecture
- See Common Patterns for examples