Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/color-picker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## Color Picker (Moose)

Provides a predefined color palette and stores the slug (e.g. white, blue) instead of a hex code. Works with ACF via Extended ACF.

### Add a Color Picker field
```php
use Extended\ACF\Fields\ColorPickerMoose;

ColorPickerMoose::make('Header background color', 'page_header_bg_color')
->colors([
'white' => '#ffffff',
'black' => '#000000',
'blue' => '#0073aa',
])
->defaultValue('white');
```

`->colors()` accepts a slug => hex map. In order to use theme values leave field empty

`->defaultValue()` sets the default slug.
`->helperText()` add helper text to the field.

### Get the saved value (slug)
```php
$color_slug = get_field('page_header_bg_color'); // e.g. "white"
```

Use it directly for class-based styling:

```php
echo '<div class="page-header color--' . esc_attr($color_slug) . '"></div>';
```

Notes

Field type key: `color_picker_tribe`.

Stores slug in DB; front end receives the same slug via get_field().

Ensure your CSS defines classes for slugs, e.g. `.color--white`, `.color--blue`, et
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php declare(strict_types=1);

namespace Tribe\Plugin\Integrations\ACF_Fields\Color_Picker;

use Extended\ACF\Fields\Field;
use Extended\ACF\Fields\Settings\ConditionalLogic;
use Extended\ACF\Fields\Settings\HelperText;
use Extended\ACF\Fields\Settings\Required;
use Extended\ACF\Fields\Settings\Wrapper;

class Color_Picker extends Field {

use ConditionalLogic;
use HelperText;
use Required;
use Wrapper;

protected ?string $type = 'color_picker_tribe';

/**
* @var array{
* default_value: string,
* colors: array<int|string, mixed>
* }
*/
protected array $defaults = [
'default_value' => '',
'colors' => [],
];

public function __construct( string $label, ?string $name = null ) {
parent::__construct( $label, $name );

$this->colors();
}

/**
* Define a fluent setter for colors.
*/
public function colors( array $colors = [] ): static {
// bail of colors set via field
if ( ! empty( $colors ) ) {
$this->settings['colors'] = $colors;

return $this;
}

$settings = wp_get_global_settings();
if ( empty( $settings ) || empty( $settings['color'] ) ) {
$this->settings['color'] = $colors;

return $this;
}

$palette = $settings['color']['palette'] ?? [];

if ( empty( $palette ) ) {
$this->settings['colors'] = $colors;

return $this;
}

$result = [];

foreach ( $palette['theme'] as $key => $item ) {
if ( $key === 'default' ) {
continue;
}

$slug = $item['slug'];
$result[] = [
'name' => $item['name'],
'slug' => $slug,
'color' => $item['color'],
];
}

$this->settings['colors'] = $result;

return $this;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php declare(strict_types=1);

namespace Tribe\Plugin\Integrations\ACF_Fields\Color_Picker;

class Color_Picker_Render {

public function render_color_picker( array $field ): void {
$value = esc_attr( $field['value'] ?? '' );
$name = esc_attr( $field['name'] );
$colors = (array) ( $field['colors'] ?? [] );

$hex = '';

foreach ( $colors as $color ) {
if ( $color['slug'] !== $value ) {
continue;
}
$hex = $color['color'];
}

$props = [
'value' => $hex ?: $value,
'colorsToUse' => $colors,
'colorAttribute' => $name,
'showTransparentOption' => 'false',
];

$props_json = wp_json_encode( $props );
$wrapper_id = 'acf-color-picker-' . uniqid();

echo '<div id="' . esc_attr( $wrapper_id ) . '"
class="acf-color-picker-wrapper"
data-props=\'' . esc_attr( $props_json ) . '\'></div>';

// Hidden input ensures ACF sees the value
echo '<input type="hidden" name="' . $name . '" value="' . $value . '" />';

// Inline mount script (minimal)
echo '<script>
window.MTColorPickerBridge = window.MTColorPickerBridge || [];
window.MTColorPickerBridge.push({
el: document.getElementById("' . esc_js( $wrapper_id ) . '")
});
</script>';
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Tribe\Plugin\Integrations;

use Tribe\Plugin\Core\Abstract_Subscriber;
use Tribe\Plugin\Integrations\ACF_Fields\Color_Picker\Color_Picker_Render;

class Integrations_Subscriber extends Abstract_Subscriber {

Expand All @@ -27,6 +28,10 @@ public function register(): void {

return $this->container->get( RankMath::class )->exclude_post_types( $post_types );
}, 100 );

add_action('acf/render_field/type=color_picker_tribe', function ($field): void {
$this->container->get( Color_Picker_Render::class )->render_color_picker( $field );
}, 10, 1 );
}

}
1 change: 1 addition & 0 deletions wp-content/plugins/core/src/Object_Meta/Meta_Definer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Meta_Definer implements Definer_Interface {
public function define(): array {
return [
self::OBJECT_META => DI\add( [
DI\get( Page_Header_Settings::class ),
] ),
];
}
Expand Down
34 changes: 34 additions & 0 deletions wp-content/plugins/core/src/Object_Meta/Page_Header_Settings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php declare(strict_types=1);

namespace Tribe\Plugin\Object_Meta;

use Extended\ACF\Location;
use Tribe\Plugin\Integrations\ACF_Fields\Color_Picker\Color_Picker;
use Tribe\Plugin\Post_Types\Page\Page;

class Page_Header_Settings extends Meta_Object {

public const string GROUP_SLUG = 'page_header_settings';
public const HEADER_COLOR = 'header_color';

public function get_slug(): string {
return self::GROUP_SLUG;
}

#[\Override] public function get_title(): string {
return esc_html__( 'Header Settings', 'tribe' );
}

#[\Override] public function get_fields(): array {
return [
Color_Picker::make( esc_html__( 'Header Background Color', 'tribe' ), self::HEADER_COLOR ),
];
}

#[\Override] public function get_locations(): array {
return [
Location::where( 'post_type', Page::NAME ),
];
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public function register(): void {
$this->container->get( Comment_Support::class )->remove_admin_bar_comments();
});

add_filter( 'body_class', function ( array $classes ): array {
return $this->container->get( Theme_Customize::class )->add_header_color_body_class( $classes );
}, 10, 1 );

/**
* Disable XML-RPC authentication support.
*
Expand Down
32 changes: 32 additions & 0 deletions wp-content/plugins/core/src/Theme_Config/Theme_Customize.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);

namespace Tribe\Plugin\Theme_Config;

use Tribe\Plugin\Object_Meta\Page_Header_Settings;

class Theme_Customize {

/**
* Add header color class to body on all pages
*
* @param array<string> $classes Array of body classes
*
* @return array<string> Modified body classes
*/
public function add_header_color_body_class( array $classes ): array {
$post_id = get_the_ID();

if ( ! is_page() || ! $post_id ) {
return array_merge( $classes, [ 'is-header--default' ] );
}

$header_color = get_field( Page_Header_Settings::HEADER_COLOR, $post_id );

if ( empty( $header_color ) || ! is_string( $header_color ) ) {
return array_merge( $classes, [ 'is-header--default' ] );
}

return array_merge( $classes, [ esc_attr( $header_color ) ] );
}

}
86 changes: 86 additions & 0 deletions wp-content/themes/core/assets/js/editor/color-picker/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { useEffect, useState, createElement } from '@wordpress/element';
import DynamicColorPicker from 'components/DynamicColorPicker';

const mountColorPicker = ( el ) => {
if ( ! el || el.__mounted ) {
return;
}
el.__mounted = true;

const props = JSON.parse( el.dataset.props || '{}' );
const { colorAttribute, value: initialValue, colorsToUse } = props;

const Bridge = () => {
const [ current, setCurrent ] = useState( initialValue );

useEffect( () => {
const input = document.querySelector(
`input[name = "${ colorAttribute }"]`
);

if ( input ) {
const hex = normalizeValue( current );
input.value = extractSlugByHex( hex );
input.dispatchEvent( new Event( 'change', { bubbles: true } ) );
}
}, [ current ] );

const normalizeValue = ( val ) => {
if ( ! val || typeof val !== 'object' ) {
return val ?? '';
}

if ( val.slug ) {
return val.slug;
}

if ( val.value ) {
return val.value;
}
const first = Object.values( val ).find(
( v ) => typeof v === 'string'
);

return first ?? '';
};

const extractSlugByHex = ( hex ) => {
if ( ! hex ) {
return '';
}
const entry = colorsToUse.find( ( color ) => {
return color.color.toLowerCase() === hex.toLowerCase();
} );

return entry?.slug ?? hex;
};

return createElement( DynamicColorPicker, {
...props,
colorsToUse,
colorValue: normalizeValue( current ),
onChange: setCurrent,
} );
};

if ( wp?.element?.createRoot ) {
const root = wp.element.createRoot( el );
root.render( createElement( Bridge ) );
}
};

const init = () => {
window.MTColorPickerBridge ??= [];
window.MTColorPickerBridge.forEach( ( { el } ) => mountColorPicker( el ) );
window.MTColorPickerBridg = { push: ( { el } ) => mountColorPicker( el ) };

[ 'acf/render_block_preview', 'acf/setup_fields' ].forEach( ( event ) => {
window.addEventListener( event, () => {
document
.querySelectorAll( '.acf-color-picker-wrapper' )
.forEach( ( el ) => mountColorPicker( el ) );
} );
} );
};

export default init;
2 changes: 2 additions & 0 deletions wp-content/themes/core/assets/js/editor/ready.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import blockAnimations from './block-animations';
import colorPicker from './color-picker';

/**
* @function init
Expand All @@ -14,6 +15,7 @@ import blockAnimations from './block-animations';
const init = () => {
// initialize block animation controls in editor
blockAnimations();
colorPicker();

console.info(
'Editor: Initialized all javascript that targeted document ready.'
Expand Down