--- a/greenshift-animation-and-page-builder-blocks/blockrender/element/block.php
+++ b/greenshift-animation-and-page-builder-blocks/blockrender/element/block.php
@@ -134,6 +134,7 @@
$supported_attributes[] = 'poster';
$supported_attributes[] = 'title';
$supported_attributes[] = 'icon';
+ $supported_attributes[] = 'className';
return $supported_attributes;
});
@@ -657,9 +658,9 @@
if(!empty($value['dynamicEnable']) && function_exists('GSPB_make_dynamic_text')){
$dynamicAttributes[$index]['value'] = GSPB_make_dynamic_text($dynamicAttributes[$index]['value'], $block['attrs'], $block, $value);
}else{
- $value = sanitize_text_field($value['value']);
- $dynamicAttributes[$index]['value'] = greenshift_dynamic_placeholders($value);
- if(!empty($value['name']) && strpos($value['name'], 'on') === 0){
+ $sanitized_value = sanitize_text_field($value['value']);
+ $dynamicAttributes[$index]['value'] = greenshift_dynamic_placeholders($sanitized_value);
+ if(!empty($dynamicAttributes[$index]['name']) && strpos($dynamicAttributes[$index]['name'], 'on') === 0){
$dynamicAttributes[$index]['value'] = '';
}
}
@@ -874,7 +875,7 @@
if(!empty($overrides['textContent'])){
$html = str_replace($block['attrs']['textContent'], esc_html($overrides['textContent']), $html);
}
- if(!empty($overrides['src']) || !empty($overrides['alt']) || !empty($overrides['href']) || !empty($overrides['title']) || !empty($overrides['poster'])){
+ if(!empty($overrides['src']) || !empty($overrides['alt']) || !empty($overrides['href']) || !empty($overrides['title']) || !empty($overrides['poster']) || !empty($overrides['className'])){
$p = new WP_HTML_Tag_Processor( $html );
$p->next_tag();
if(!empty($overrides['src'])){
@@ -892,6 +893,10 @@
if(!empty($overrides['poster'])){
$p->set_attribute( 'poster', esc_url($overrides['poster']));
}
+ if(!empty($overrides['className'])){
+ $idClass = !empty($block['attrs']['localId']) ? $block['attrs']['localId'] : '';
+ $p->set_attribute( 'class', esc_attr($overrides['className']).' '.$idClass);
+ }
$html = $p->get_updated_html();
}
// Handle icon override for SVG elements
--- a/greenshift-animation-and-page-builder-blocks/build/gspbLibrary.asset.php
+++ b/greenshift-animation-and-page-builder-blocks/build/gspbLibrary.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-dom', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-rich-text'), 'version' => '79922cb5a397945c3d17');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-dom', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-rich-text'), 'version' => '5d873f5ee2abd7e8e32e');
--- a/greenshift-animation-and-page-builder-blocks/build/gspbSiteEditor.asset.php
+++ b/greenshift-animation-and-page-builder-blocks/build/gspbSiteEditor.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => 'd16d818f9c06cbce4cac');
+<?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => 'c675f65f1f5d2ecefa79');
--- a/greenshift-animation-and-page-builder-blocks/build/gspbStylebook.asset.php
+++ b/greenshift-animation-and-page-builder-blocks/build/gspbStylebook.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => '622f4d7382b6b12cea74');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => 'd901e597bd902734f819');
--- a/greenshift-animation-and-page-builder-blocks/build/index.asset.php
+++ b/greenshift-animation-and-page-builder-blocks/build/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-dom', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives'), 'version' => 'bef74a4b537f97c10e44');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-dom', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives'), 'version' => 'd7cd673c444048345de1');
--- a/greenshift-animation-and-page-builder-blocks/includes/abilities.php
+++ b/greenshift-animation-and-page-builder-blocks/includes/abilities.php
@@ -0,0 +1,596 @@
+<?php
+/**
+ * WordPress Abilities API integration for GreenShift.
+ * Requires WordPress 6.9+.
+ *
+ * @package greenshift-animation-and-page-builder-blocks
+ */
+
+if ( ! defined( 'ABSPATH' ) ) {
+ exit;
+}
+
+// Backward compatibility: skip if Abilities API is not available.
+if ( ! class_exists( 'WP_Ability' ) ) {
+ return;
+}
+
+/**
+ * Register the GreenShift ability category.
+ */
+add_action( 'wp_abilities_api_categories_init', 'gspb_register_ability_category' );
+function gspb_register_ability_category( $registry ) {
+ wp_register_ability_category( 'greenshift', array(
+ 'label' => __( 'GreenShift', 'greenshift-animation-and-page-builder-blocks' ),
+ 'description' => __( 'Design abilities provided by GreenShift – preset colors, element styles, custom colors, classes, and CSS variables.', 'greenshift-animation-and-page-builder-blocks' ),
+ ) );
+}
+
+/**
+ * Register all GreenShift abilities.
+ */
+add_action( 'wp_abilities_api_init', 'gspb_register_abilities' );
+function gspb_register_abilities( $registry ) {
+
+ // ── 1. Preset Colors ────────────────────────────────────────────────
+
+ wp_register_ability( 'greenshift/get-preset-colors', array(
+ 'label' => __( 'Get Preset Colors', 'greenshift-animation-and-page-builder-blocks' ),
+ 'description' => __( 'Retrieves the GreenShift global preset color palette.', 'greenshift-animation-and-page-builder-blocks' ),
+ 'category' => 'greenshift',
+ 'output_schema' => array(
+ 'type' => 'object',
+ 'description' => 'Key-value map of color names to color values (hex/rgb).',
+ ),
+ 'execute_callback' => 'gspb_ability_get_preset_colors',
+ 'permission_callback' => function () {
+ return current_user_can( 'edit_posts' );
+ },
+ 'meta' => array(
+ 'show_in_rest' => true,
+ 'annotations' => array(
+ 'readonly' => true,
+ 'idempotent' => true,
+ ),
+ ),
+ ) );
+
+ wp_register_ability( 'greenshift/update-preset-colors', array(
+ 'label' => __( 'Update Preset Colors', 'greenshift-animation-and-page-builder-blocks' ),
+ 'description' => __( 'Merges new colors into the GreenShift global preset color palette.', 'greenshift-animation-and-page-builder-blocks' ),
+ 'category' => 'greenshift',
+ 'input_schema' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'colors' => array(
+ 'type' => 'object',
+ 'description' => 'Key-value map of color name to color value to set or merge.',
+ ),
+ ),
+ 'required' => array( 'colors' ),
+ ),
+ 'output_schema' => array(
+ 'type' => 'object',
+ 'description' => 'Operation result with success flag and updated colors.',
+ ),
+ 'execute_callback' => 'gspb_ability_update_preset_colors',
+ 'permission_callback' => function () {
+ return current_user_can( 'manage_options' );
+ },
+ 'meta' => array(
+ 'show_in_rest' => true,
+ 'annotations' => array(
+ 'idempotent' => true,
+ ),
+ ),
+ ) );
+
+ // ── 2. Element Styles ───────────────────────────────────────────────
+
+ wp_register_ability( 'greenshift/get-element-styles', array(
+ 'label' => __( 'Get Element Styles', 'greenshift-animation-and-page-builder-blocks' ),
+ 'description' => __( 'Retrieves the GreenShift global element style definitions.', 'greenshift-animation-and-page-builder-blocks' ),
+ 'category' => 'greenshift',
+ 'output_schema' => array(
+ 'type' => 'array',
+ 'description' => 'Array of element style definitions.',
+ ),
+ 'execute_callback' => 'gspb_ability_get_element_styles',
+ 'permission_callback' => function () {
+ return current_user_can( 'edit_posts' );
+ },
+ 'meta' => array(
+ 'show_in_rest' => true,
+ 'annotations' => array(
+ 'readonly' => true,
+ 'idempotent' => true,
+ ),
+ ),
+ ) );
+
+ wp_register_ability( 'greenshift/update-element-styles', array(
+ 'label' => __( 'Update Element Styles', 'greenshift-animation-and-page-builder-blocks' ),
+ 'description' => __( 'Replaces the GreenShift global element style definitions.', 'greenshift-animation-and-page-builder-blocks' ),
+ 'category' => 'greenshift',
+ 'input_schema' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'elements' => array(
+ 'type' => 'array',
+ 'description' => 'Array of element style definitions to save.',
+ ),
+ ),
+ 'required' => array( 'elements' ),
+ ),
+ 'output_schema' => array(
+ 'type' => 'object',
+ 'description' => 'Operation result with success flag.',
+ ),
+ 'execute_callback' => 'gspb_ability_update_element_styles',
+ 'permission_callback' => function () {
+ return current_user_can( 'manage_options' );
+ },
+ 'meta' => array(
+ 'show_in_rest' => true,
+ 'annotations' => array(
+ 'idempotent' => true,
+ ),
+ ),
+ ) );
+
+ // ── 3. Custom Colors (WP Global Theme Palette) ──────────────────────
+
+ wp_register_ability( 'greenshift/get-custom-colors', array(
+ 'label' => __( 'Get Custom Colors', 'greenshift-animation-and-page-builder-blocks' ),
+ 'description' => __( 'Retrieves the WordPress global theme color palette.', 'greenshift-animation-and-page-builder-blocks' ),
+ 'category' => 'greenshift',
+ 'output_schema' => array(
+ 'type' => 'array',
+ 'description' => 'Array of theme color palette entries with name, slug, and color.',
+ ),
+ 'execute_callback' => 'gspb_ability_get_custom_colors',
+ 'permission_callback' => function () {
+ return current_user_can( 'edit_posts' );
+ },
+ 'meta' => array(
+ 'show_in_rest' => true,
+ 'annotations' => array(
+ 'readonly' => true,
+ 'idempotent' => true,
+ ),
+ ),
+ ) );
+
+ wp_register_ability( 'greenshift/add-custom-colors', array(
+ 'label' => __( 'Add Custom Colors', 'greenshift-animation-and-page-builder-blocks' ),
+ 'description' => __( 'Adds or updates colors in the WordPress global theme color palette.', 'greenshift-animation-and-page-builder-blocks' ),
+ 'category' => 'greenshift',
+ 'input_schema' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'colors' => array(
+ 'type' => 'array',
+ 'description' => 'Array of color entries to add.',
+ 'items' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'name' => array(
+ 'type' => 'string',
+ 'description' => 'Human-readable color name.',
+ ),
+ 'slug' => array(
+ 'type' => 'string',
+ 'description' => 'URL-safe slug for the color.',
+ ),
+ 'color' => array(
+ 'type' => 'string',
+ 'description' => 'CSS color value.',
+ ),
+ ),
+ 'required' => array( 'name', 'slug', 'color' ),
+ ),
+ ),
+ ),
+ 'required' => array( 'colors' ),
+ ),
+ 'output_schema' => array(
+ 'type' => 'object',
+ 'description' => 'Operation result with success flag.',
+ ),
+ 'execute_callback' => 'gspb_ability_add_custom_colors',
+ 'permission_callback' => function () {
+ return current_user_can( 'edit_posts' );
+ },
+ 'meta' => array(
+ 'show_in_rest' => true,
+ 'annotations' => array(
+ 'idempotent' => true,
+ ),
+ ),
+ ) );
+
+ // ── 4. Custom Classes ───────────────────────────────────────────────
+
+ wp_register_ability( 'greenshift/get-custom-classes', array(
+ 'label' => __( 'Get Custom Classes', 'greenshift-animation-and-page-builder-blocks' ),
+ 'description' => __( 'Retrieves the GreenShift global custom CSS classes.', 'greenshift-animation-and-page-builder-blocks' ),
+ 'category' => 'greenshift',
+ 'output_schema' => array(
+ 'type' => 'array',
+ 'description' => 'Array of custom class definitions.',
+ ),
+ 'execute_callback' => 'gspb_ability_get_custom_classes',
+ 'permission_callback' => function () {
+ return current_user_can( 'edit_posts' );
+ },
+ 'meta' => array(
+ 'show_in_rest' => true,
+ 'annotations' => array(
+ 'readonly' => true,
+ 'idempotent' => true,
+ ),
+ ),
+ ) );
+
+ wp_register_ability( 'greenshift/add-custom-classes', array(
+ 'label' => __( 'Add Custom Classes', 'greenshift-animation-and-page-builder-blocks' ),
+ 'description' => __( 'Adds or updates GreenShift global custom CSS classes.', 'greenshift-animation-and-page-builder-blocks' ),
+ 'category' => 'greenshift',
+ 'input_schema' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'classes' => array(
+ 'type' => 'array',
+ 'description' => 'Array of class objects. "value" (class name) and "type" are required. Provide "css" with raw CSS rules for the class, "selectors" for sub-selector styles (e.g. hover, child elements), and "attributes" for stored block attributes.',
+ 'items' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'value' => array(
+ 'type' => 'string',
+ 'description' => 'CSS class name (e.g. "my-custom-class").',
+ ),
+ 'type' => array(
+ 'type' => 'string',
+ 'description' => 'Class origin type: "global" (synced across site), "local" (page-scoped), "component" (reusable component), "classic" (plain className), or "custom" (framework class).',
+ ),
+ 'label' => array(
+ 'type' => 'string',
+ 'description' => 'Human-readable label for the class (defaults to value).',
+ ),
+ 'css' => array(
+ 'type' => 'string',
+ 'description' => 'Raw CSS rules for the class selector (e.g. "color: red; font-size: 16px;").',
+ ),
+ 'attributes' => array(
+ 'type' => 'object',
+ 'description' => 'Stored block style attributes object for the class.',
+ ),
+ 'selectors' => array(
+ 'type' => 'array',
+ 'description' => 'Array of sub-selector objects, each with "value" (CSS selector suffix like ":hover", " a", " .child"), "css" (rules for that selector), and optional "attributes".',
+ ),
+ ),
+ 'required' => array( 'value' ),
+ ),
+ ),
+ ),
+ 'required' => array( 'classes' ),
+ ),
+ 'output_schema' => array(
+ 'type' => 'object',
+ 'description' => 'Operation result with success flag.',
+ ),
+ 'execute_callback' => 'gspb_ability_add_custom_classes',
+ 'permission_callback' => function () {
+ return current_user_can( 'manage_options' );
+ },
+ 'meta' => array(
+ 'show_in_rest' => true,
+ 'annotations' => array(
+ 'idempotent' => true,
+ ),
+ ),
+ ) );
+
+ // ── 5. Custom CSS Variables ─────────────────────────────────────────
+
+ wp_register_ability( 'greenshift/get-custom-variables', array(
+ 'label' => __( 'Get Custom CSS Variables', 'greenshift-animation-and-page-builder-blocks' ),
+ 'description' => __( 'Retrieves the GreenShift global custom CSS code (may contain CSS variables).', 'greenshift-animation-and-page-builder-blocks' ),
+ 'category' => 'greenshift',
+ 'output_schema' => array(
+ 'type' => 'object',
+ 'description' => 'Object containing the custom_css string.',
+ ),
+ 'execute_callback' => 'gspb_ability_get_custom_variables',
+ 'permission_callback' => function () {
+ return current_user_can( 'edit_posts' );
+ },
+ 'meta' => array(
+ 'show_in_rest' => true,
+ 'annotations' => array(
+ 'readonly' => true,
+ 'idempotent' => true,
+ ),
+ ),
+ ) );
+
+ wp_register_ability( 'greenshift/update-custom-variables', array(
+ 'label' => __( 'Update Custom CSS Variables', 'greenshift-animation-and-page-builder-blocks' ),
+ 'description' => __( 'Updates the GreenShift global custom CSS code.', 'greenshift-animation-and-page-builder-blocks' ),
+ 'category' => 'greenshift',
+ 'input_schema' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'custom_css' => array(
+ 'type' => 'string',
+ 'description' => 'Full custom CSS string to save.',
+ ),
+ ),
+ 'required' => array( 'custom_css' ),
+ ),
+ 'output_schema' => array(
+ 'type' => 'object',
+ 'description' => 'Operation result with success flag.',
+ ),
+ 'execute_callback' => 'gspb_ability_update_custom_variables',
+ 'permission_callback' => function () {
+ return current_user_can( 'manage_options' );
+ },
+ 'meta' => array(
+ 'show_in_rest' => true,
+ 'annotations' => array(
+ 'idempotent' => true,
+ ),
+ ),
+ ) );
+}
+
+
+// =====================================================================
+// Execute Callbacks
+// =====================================================================
+
+/**
+ * Get preset colors from gspb_global_settings.
+ */
+function gspb_ability_get_preset_colors() {
+ $settings = get_option( 'gspb_global_settings' );
+ $colours = ! empty( $settings['colours'] ) ? $settings['colours'] : '{}';
+
+ if ( is_string( $colours ) ) {
+ $colours = json_decode( $colours, true );
+ }
+
+ return is_array( $colours ) ? $colours : array();
+}
+
+/**
+ * Update preset colors – merges into existing palette.
+ */
+function gspb_ability_update_preset_colors( $input ) {
+ $settings = get_option( 'gspb_global_settings' );
+ if ( ! is_array( $settings ) ) {
+ $settings = array();
+ }
+
+ $existing = ! empty( $settings['colours'] ) ? $settings['colours'] : '{}';
+ if ( is_string( $existing ) ) {
+ $existing = json_decode( $existing, true );
+ }
+ if ( ! is_array( $existing ) ) {
+ $existing = array();
+ }
+
+ foreach ( $input['colors'] as $name => $value ) {
+ $existing[ sanitize_text_field( $name ) ] = sanitize_text_field( $value );
+ }
+
+ $settings['colours'] = wp_json_encode( $existing );
+ update_option( 'gspb_global_settings', $settings );
+
+ return array(
+ 'success' => true,
+ 'colors' => $existing,
+ );
+}
+
+/**
+ * Get element styles from gspb_global_settings.
+ */
+function gspb_ability_get_element_styles() {
+ $settings = get_option( 'gspb_global_settings' );
+ $elements = ! empty( $settings['elements'] ) ? $settings['elements'] : '[]';
+
+ if ( is_string( $elements ) ) {
+ $elements = json_decode( $elements, true );
+ }
+
+ return is_array( $elements ) ? $elements : array();
+}
+
+/**
+ * Update element styles – replaces the full list.
+ */
+function gspb_ability_update_element_styles( $input ) {
+ $settings = get_option( 'gspb_global_settings' );
+ if ( ! is_array( $settings ) ) {
+ $settings = array();
+ }
+
+ $settings['elements'] = wp_json_encode( $input['elements'] );
+ update_option( 'gspb_global_settings', $settings );
+
+ return array( 'success' => true );
+}
+
+/**
+ * Get custom colors from the WP global theme palette.
+ */
+function gspb_ability_get_custom_colors() {
+ $global = wp_get_global_settings();
+ $palette = ! empty( $global['color']['palette']['theme'] ) ? $global['color']['palette']['theme'] : array();
+
+ return $palette;
+}
+
+/**
+ * Add custom colors to the WP global theme palette.
+ * Reuses the same wp_global_styles storage logic as gspb_update_global_wp_settings().
+ */
+function gspb_ability_add_custom_colors( $input ) {
+ $global = wp_get_global_settings();
+ $palette = ! empty( $global['color']['palette']['theme'] ) ? $global['color']['palette']['theme'] : array();
+
+ // Build slug index for dedup.
+ $slug_map = array();
+ foreach ( $palette as $idx => $entry ) {
+ if ( ! empty( $entry['slug'] ) ) {
+ $slug_map[ $entry['slug'] ] = $idx;
+ }
+ }
+
+ foreach ( $input['colors'] as $color ) {
+ $slug = sanitize_title( $color['slug'] );
+ $entry = array(
+ 'name' => sanitize_text_field( $color['name'] ),
+ 'slug' => $slug,
+ 'color' => sanitize_text_field( $color['color'] ),
+ );
+
+ if ( isset( $slug_map[ $slug ] ) ) {
+ $palette[ $slug_map[ $slug ] ] = $entry;
+ } else {
+ $palette[] = $entry;
+ $slug_map[ $slug ] = count( $palette ) - 1;
+ }
+ }
+
+ // Persist to wp_global_styles post (same approach as init.php).
+ $theme = wp_get_theme();
+ if ( $theme->parent_theme ) {
+ $template_dir = basename( get_template_directory() );
+ $theme = wp_get_theme( $template_dir );
+ }
+ $themename = $theme->get( 'TextDomain' );
+
+ $post_type = 'wp_global_styles';
+ $post_name = 'wp-global-styles-' . $themename;
+ $styles_obj = get_page_by_path( $post_name, OBJECT, $post_type );
+ $styles_id = is_object( $styles_obj ) ? $styles_obj->ID : 0;
+
+ if ( $styles_id ) {
+ $content = json_decode( $styles_obj->post_content, true );
+ if ( empty( $content ) ) {
+ $content = array();
+ }
+ $content['settings']['color']['palette']['theme'] = $palette;
+ $content['isGlobalStylesUserThemeJSON'] = true;
+ $content['version'] = 3;
+
+ wp_update_post( array(
+ 'ID' => $styles_id,
+ 'post_name' => $post_name,
+ 'post_status' => 'publish',
+ 'post_title' => $styles_obj->post_title,
+ 'post_content' => wp_slash( wp_json_encode( $content ) ),
+ ) );
+ } else {
+ $content = array(
+ 'settings' => array(
+ 'color' => array(
+ 'palette' => array(
+ 'theme' => $palette,
+ ),
+ ),
+ ),
+ 'isGlobalStylesUserThemeJSON' => true,
+ 'version' => 3,
+ );
+
+ wp_insert_post( array(
+ 'post_content' => wp_slash( wp_json_encode( $content ) ),
+ 'post_status' => 'publish',
+ 'post_type' => $post_type,
+ 'post_name' => $post_name,
+ 'post_title' => 'Custom Styles',
+ ) );
+ }
+
+ return array(
+ 'success' => true,
+ 'palette' => $palette,
+ );
+}
+
+/**
+ * Get custom classes.
+ */
+function gspb_ability_get_custom_classes() {
+ $classes = get_option( 'greenshift_global_classes' );
+
+ return is_array( $classes ) ? $classes : array();
+}
+
+/**
+ * Add / update custom classes – merges by "value" key.
+ */
+function gspb_ability_add_custom_classes( $input ) {
+ $existing = get_option( 'greenshift_global_classes' );
+ if ( ! is_array( $existing ) ) {
+ $existing = array();
+ }
+
+ $value_map = array();
+ foreach ( $existing as $idx => $cls ) {
+ if ( ! empty( $cls['value'] ) ) {
+ $value_map[ $cls['value'] ] = $idx;
+ }
+ }
+
+ foreach ( $input['classes'] as $cls ) {
+ if ( empty( $cls['value'] ) ) {
+ continue;
+ }
+ $cls['value'] = sanitize_text_field( $cls['value'] );
+
+ if ( isset( $value_map[ $cls['value'] ] ) ) {
+ $existing[ $value_map[ $cls['value'] ] ] = $cls;
+ } else {
+ $existing[] = $cls;
+ $value_map[ $cls['value'] ] = count( $existing ) - 1;
+ }
+ }
+
+ update_option( 'greenshift_global_classes', $existing );
+
+ return array(
+ 'success' => true,
+ 'classes' => $existing,
+ );
+}
+
+/**
+ * Get custom CSS variables / code.
+ */
+function gspb_ability_get_custom_variables() {
+ $settings = get_option( 'gspb_global_settings' );
+ $custom_css = ! empty( $settings['custom_css'] ) ? $settings['custom_css'] : '';
+
+ return array( 'custom_css' => $custom_css );
+}
+
+/**
+ * Update custom CSS variables / code.
+ */
+function gspb_ability_update_custom_variables( $input ) {
+ $settings = get_option( 'gspb_global_settings' );
+ if ( ! is_array( $settings ) ) {
+ $settings = array();
+ }
+
+ $settings['custom_css'] = $input['custom_css'];
+ update_option( 'gspb_global_settings', $settings );
+
+ return array( 'success' => true );
+}
--- a/greenshift-animation-and-page-builder-blocks/init.php
+++ b/greenshift-animation-and-page-builder-blocks/init.php
@@ -75,6 +75,10 @@
$gspb_css_content = str_replace('@media (max-width: 991.98px)', '@media (max-width: ' . $get_breakpoints["desktop_down"] . 'px)', $gspb_css_content);
}
+ if (!empty($gspb_css_content)) {
+ $gspb_css_content = wp_strip_all_tags($gspb_css_content);
+ }
+
return apply_filters('gspb_get_final_css', $gspb_css_content);
}
@@ -2830,7 +2834,25 @@
}
$gspb_json_filename = 'settings_backup.json';
- $gspb_backup_data = json_encode( $settings, JSON_PRETTY_PRINT );
+
+ // Exclude API keys from backup
+ $backup_settings = $settings;
+ $keys_to_exclude = [
+ 'googleapi',
+ 'turnstile_site_key',
+ 'turnstile_secret_key',
+ 'openaiapi',
+ 'claudeapi',
+ 'deepseekapi',
+ 'geminiapi'
+ ];
+ foreach ($keys_to_exclude as $key) {
+ if (isset($backup_settings[$key])) {
+ unset($backup_settings[$key]);
+ }
+ }
+
+ $gspb_backup_data = json_encode( $backup_settings, JSON_PRETTY_PRINT );
if (!$wp_filesystem->put_contents($dir . $gspb_json_filename, $gspb_backup_data)) {
throw new Exception(__('JSON is not saved due the permission!!!', 'greenshift-animation-and-page-builder-blocks'));
--- a/greenshift-animation-and-page-builder-blocks/plugin.php
+++ b/greenshift-animation-and-page-builder-blocks/plugin.php
@@ -6,7 +6,7 @@
* Author: Wpsoul
* Author URI: https://greenshiftwp.com
* Plugin URI: https://greenshiftwp.com
- * Version: 12.8.3
+ * Version: 12.8.4
* Text Domain: greenshift-animation-and-page-builder-blocks
* License: GPL2+
* License URI: https://www.gnu.org/licenses/gpl-2.0.txt
@@ -178,6 +178,7 @@
require_once GREENSHIFT_DIR_PATH . 'settings.php';
require_once GREENSHIFT_DIR_PATH . 'includes/jsoptimization.php';
require_once GREENSHIFT_DIR_PATH . 'includes/importer.php';
+require_once GREENSHIFT_DIR_PATH . 'includes/abilities.php';
require_once GREENSHIFT_DIR_PATH . '/edd/edd_start.php';
add_action('plugins_loaded', 'gspb_GreenShift_plugin_init');
--- a/greenshift-animation-and-page-builder-blocks/settings.php
+++ b/greenshift-animation-and-page-builder-blocks/settings.php
@@ -1076,23 +1076,14 @@
</td>
<td>
<select name="openaiapimodel">
- <option value="gpt-5.1" <?php selected($openaiapimodel, 'gpt-5.1'); ?>> gpt-5.1 </option>
- <option value="gpt-4.1-mini" <?php selected($openaiapimodel, 'gpt-4.1-mini'); ?>> gpt-4.1-mini </option>
- <option value="gpt-5" <?php selected($openaiapimodel, 'gpt-5'); ?>> gpt-5 </option>
- <option value="gpt-5-mini" <?php selected($openaiapimodel, 'gpt-5-mini'); ?>> gpt-5-mini </option>
- <option value="gpt-5.2-pro" <?php selected($openaiapimodel, 'gpt-5.2-pro'); ?>> gpt-5.2-pro </option>
<option value="gpt-5.2" <?php selected($openaiapimodel, 'gpt-5.2'); ?>> gpt-5.2 </option>
- <option value="o1" <?php selected($openaiapimodel, 'o1'); ?>> o1 </option>
- <option value="o1-mini" <?php selected($openaiapimodel, 'o1-mini'); ?>> o1-mini </option>
- <option value="o3" <?php selected($openaiapimodel, 'o3'); ?>> o3 </option>
- <option value="o1-pro" <?php selected($openaiapimodel, 'o1-pro'); ?>> o1-pro </option>
- <option value="o4-mini" <?php selected($openaiapimodel, 'o4-mini'); ?>> o4-mini </option>
+ <option value="gpt-5.2-pro" <?php selected($openaiapimodel, 'gpt-5.2-pro'); ?>> gpt-5.2-pro </option>
<option value="gemini-3-flash-preview" <?php selected($openaiapimodel, 'gemini-3-flash-preview'); ?>> gemini-3-flash-preview </option>
<option value="gemini-2.5-flash" <?php selected($openaiapimodel, 'gemini-2.5-flash'); ?>> gemini-2.5-flash </option>
<option value="gemini-3-pro-preview" <?php selected($openaiapimodel, 'gemini-3-pro-preview'); ?>> gemini-3-pro-preview </option>
- <option value="claude-sonnet-4-5" <?php selected($openaiapimodel, 'claude-sonnet-4-5'); ?>> claude-sonnet-4-5 </option>
+ <option value="claude-sonnet-4-6" <?php selected($openaiapimodel, 'claude-sonnet-4-6'); ?>> claude-sonnet-4-6 </option>
<option value="claude-haiku-4-5" <?php selected($openaiapimodel, 'claude-haiku-4-5'); ?>> claude-haiku-4-5 </option>
- <option value="claude-opus-4-5-20251101" <?php selected($openaiapimodel, 'claude-opus-4-5-20251101'); ?>> claude-opus-4-5-20251101 </option>
+ <option value="claude-opus-4-6" <?php selected($openaiapimodel, 'claude-opus-4-6'); ?>> claude-opus-4-6 </option>
<option value="deepseek-chat" <?php selected($openaiapimodel, 'deepseek-chat'); ?>> deepseek-chat </option>
</select>
</td>
@@ -1103,19 +1094,15 @@
</td>
<td>
<select name="aihelpermodel">
- <option value="gpt-5.1" <?php selected($aihelpermodel, 'gpt-5.1'); ?>> gpt-5.1 </option>
- <option value="gpt-4.1-mini" <?php selected($aihelpermodel, 'gpt-4.1-mini'); ?>> gpt-4.1-mini </option>
+ <option value="gpt-5.2" <?php selected($aihelpermodel, 'gpt-5.2'); ?>> gpt-5.2 </option>
<option value="gpt-5" <?php selected($aihelpermodel, 'gpt-5'); ?>> gpt-5 </option>
- <option value="gpt-5-mini" <?php selected($aihelpermodel, 'gpt-5-mini'); ?>> gpt-5-mini </option>
<option value="gpt-5.2-pro" <?php selected($aihelpermodel, 'gpt-5.2-pro'); ?>> gpt-5.2-pro </option>
- <option value="o3" <?php selected($aihelpermodel, 'o3'); ?>> o3 </option>
- <option value="o4-mini" <?php selected($aihelpermodel, 'o4-mini'); ?>> o4-mini </option>
<option value="gemini-3-flash-preview" <?php selected($aihelpermodel, 'gemini-3-flash-preview'); ?>> gemini-3-flash-preview </option>
<option value="gemini-3-pro-preview" <?php selected($aihelpermodel, 'gemini-3-pro-preview'); ?>> gemini-3-pro-preview </option>
<option value="gemini-2.5-flash" <?php selected($aihelpermodel, 'gemini-2.5-flash'); ?>> gemini-2.5-flash </option>
<option value="claude-haiku-4-5" <?php selected($aihelpermodel, 'claude-haiku-4-5'); ?>> claude-haiku-4-5 </option>
- <option value="claude-sonnet-4-5" <?php selected($aihelpermodel, 'claude-sonnet-4-5'); ?>> claude-sonnet-4-5 </option>
- <option value="claude-opus-4-5-20251101" <?php selected($aihelpermodel, 'claude-opus-4-5-20251101'); ?>> claude-opus-4-5-20251101 </option>
+ <option value="claude-sonnet-4-6" <?php selected($aihelpermodel, 'claude-sonnet-4-6'); ?>> claude-sonnet-4-6 </option>
+ <option value="claude-opus-4-6" <?php selected($aihelpermodel, 'claude-opus-4-6'); ?>> claude-opus-4-6 </option>
</select>
</td>
@@ -1128,7 +1115,7 @@
<select name="aiimagemodel">
<option value="gemini-2.5-flash-image-preview" <?php selected($aiimagemodel, 'gemini-2.5-flash-image-preview'); ?>> Google Flash 2.5 </option>
<option value="gemini-3-pro-image-preview" <?php selected($aiimagemodel, 'gemini-3-pro-image-preview'); ?>> Google Pro 3 Preview </option>
- <option value="gpt-image-1" <?php selected($aiimagemodel, 'gpt-image-1'); ?>> GPT Image 1 </option>
+ <option value="gpt-image-1" <?php selected($aiimagemodel, 'gpt-image-1'); ?>> GPT Image 1.5 </option>
<option value="gpt-image-1.5" <?php selected($aiimagemodel, 'gpt-image-1.5'); ?>> GPT Image 1.5 </option>
</select>
@@ -1141,9 +1128,10 @@
<td>
<select name="aidesignmodel">
<option value="claude-haiku-4-5" <?php selected($aidesignmodel, 'claude-haiku-4-5'); ?>> claude-haiku-4-5 </option>
- <option value="claude-sonnet-4-5" <?php selected($aidesignmodel, 'claude-sonnet-4-5'); ?>> claude-sonnet-4-5 </option>
- <option value="claude-opus-4-5-20251101" <?php selected($aidesignmodel, 'claude-opus-4-5-20251101'); ?>> claude-opus-4-5-20251101 </option>
+ <option value="claude-sonnet-4-6" <?php selected($aidesignmodel, 'claude-sonnet-4-6'); ?>> claude-sonnet-4-6 </option>
+ <option value="claude-opus-4-6" <?php selected($aidesignmodel, 'claude-opus-4-6'); ?>> claude-opus-4-6 </option>
<option value="gemini-3-flash-preview" <?php selected($aidesignmodel, 'gemini-3-flash-preview'); ?>> gemini-3-flash-preview </option>
+ <option value="gemini-3-pro-preview" <?php selected($aidesignmodel, 'gemini-3-pro-preview'); ?>> gemini-3-pro-preview </option>
</select>
@@ -1486,7 +1474,25 @@
}
$gspb_json_filename = 'settings_backup.json';
- $gspb_backup_data = json_encode($global_settings, JSON_PRETTY_PRINT);
+
+ // Exclude API keys from backup
+ $backup_settings = $global_settings;
+ $keys_to_exclude = [
+ 'googleapi',
+ 'turnstile_site_key',
+ 'turnstile_secret_key',
+ 'openaiapi',
+ 'claudeapi',
+ 'deepseekapi',
+ 'geminiapi'
+ ];
+ foreach ($keys_to_exclude as $key) {
+ if (isset($backup_settings[$key])) {
+ unset($backup_settings[$key]);
+ }
+ }
+
+ $gspb_backup_data = json_encode($backup_settings, JSON_PRETTY_PRINT);
if (!$wp_filesystem->put_contents($dir . $gspb_json_filename, $gspb_backup_data)) {
throw new Exception(esc_html__('JSON is not saved due the permission!!!', 'greenshift-animation-and-page-builder-blocks'));
@@ -1685,6 +1691,10 @@
if ($content_post->post_status !== 'publish') {
wp_send_json_error('Block not published');
}
+ // Don't serve content if post is password protected
+ if (!empty($content_post->post_password)) {
+ wp_send_json_error('Block is password protected');
+ }
$content = '';
$content = $content_post->post_content;
$content = apply_filters('the_content', $content);