0

Drupal's FORM API lets you specify Form States. These have a handy visibility state are that let you show/hide parts of a form depending on which fields have been filled in. It's a good way of reducing clutter on a form.

I am building my own custom Panel Style. The style settings has a lot of options, so I want to use the Form Visibility State to hide them.

I have added the code following the tutorials here and here. However, when I select an option on the form, I get this error message:

The form has become outdated. Copy any unsaved work in the form below and then reload this page.

How can I fix this?

This Dr Drupal tutorial suggests I need to use $form['form_build_id'], $form['form_id'], $form['form_token']. However, the tutorial is quite terse, so I'm not sure how to add them to my code.

The code for my panel style is here:

<?php
// $Id$

/**
 * Returns form render array.
 */
function coloroptions($form, $form_state)
{
    $form['color_default'] = array(
        '#type' => 'select',
        '#title' => t('Select a Colour'),
        '#options' => array(
            '000000' => t('Black'),
            'ffffff' => t('White'),
            'custom' => t('Custom')
        ),
        '#default_value' => (isset($form['color_default'])) ? $form['color_default'] : '000000',
        '#description' => t('The Colour you want to use')
    );


    $form['color_custom'] = array(
        '#type' => 'textfield',
        '#title' => t('background color for pane'),
        '#states' => array(
            'visible' => array(
                ':input[name="color_default"]' => array(
                    'value' => 'custom'
                )
            )
        ),
        '#default_value' => (isset($form['color_custom'])) ? $form['color_custom'] : '',
        '#description' => t('The Colour you want to use')
    );

    $form['color_location'] = array(
        '#type' => 'select',
        '#title' => t('Box around'),
        '#options' => array(
            'pane' => t('Each pane'),
            'region' => t('Each region')
        ),
        '#default_value' => (isset($form['color_location'])) ? $form['color_location'] : 'pane',
        '#description' => t('Choose whether to include the box around each pane (piece of content) or region (each column or region)')
    );



    return $form;


}




/**
 * @file
 *   Definition of the 'color' panel style.
 */

/* Place this file in themename/plugins/styles/STYLENAME/
/* In theme.INFO add the following:
/* ;----------// Plugin Panels
plugins[panels][layouts] = plugins/layouts
plugins[panels][styles] = plugins/styles
/* Reset your cahce afterwards.  */


$plugin = array(
    'title' => t('Example: Color text style'),
    'description' => t('Simply changes the text color of a pane, as an example.'),

    // Names the function to render a pane. Only required for pane styles.
    'render pane' => 'panels_colors_style_pane',

    // Names the function to render a region. Only required for pane styles.
    'render region' => 'panels_colors_style_region',

    // Names the function providing settings form for the pane. (optional)
    'pane settings form' => 'panels_colors_style_pane_settings',

    // Names the function providing settings form for the region. (optional)
    'settings form' => 'panels_colors_style_region_settings',

    // Provide a template to be used by Pane and/or Region. (optional)    
    'hook theme' => array(
        'panels_colors_box' => array(
            'variables' => array(
                'content' => NULL
            ),
            'path' => path_to_theme('plugins/styles/colors'),
            'template' => 'panels-colors-box'
        )
    )

);



/**
 * Settings form for the pane.
 *
 * Any form will do here. The settings will come through to the theme
 * function in $pane->style['settings'].
 * Use form API to construct the form: http://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7
 *
 * @param $style_settings
 *   The $style_settings if they've already been set.
 * @return
 *   The form.
 */


function panels_colors_style_pane_settings($style_settings)
{
    return drupal_get_form('coloroptions');

    return $form;
}



/**
 * Settings form for the region.
 *
 * Any form will do here. The settings will come through to the theme
 * function in $pane->style['settings'].
 * Use form API to construct the form: http://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7
 *
 * @param $style_settings
 *   The $style_settings if they've already been set.
 * @return
 *   The form.
 */


function panels_colors_style_region_settings($style_settings)
{
    /*    $form['color'] = array(
    '#type' => 'textfield',
    '#title' => t('background color for pane'),
    '#default_value' => (isset($style_settings['color'])) ? $style_settings['color'] : '#000000',
    '#description' => t('Select the background color for the region.')
    );

    $form['color_location'] = array(
    '#type' => 'select',
    '#title' => t('Box around'),
    '#options' => array(
    'pane' => t('Each pane'),
    'region' => t('Each region')
    ),
    '#default_value' => (isset($style_settings['color_location'])) ? $style_settings['color_location'] : 'pane',
    '#description' => t('Choose whether to include the box around each pane (piece of content) or region (each column or region)')
    );*/


    return drupal_get_form('coloroptions');


    return $form;

    dpm($form);

}



/**
 * Render the pane content.
 *
 * The name of this function is referenced in hook_default_panels_styles(), and
 * it's free-form, but of course be careful to namespace it.
 * But the name is just theme_<render pane> where "<render pane>" is what you
 * put into the array above.
 *
 * This is optional, but shows how a plugin can render a pane.
 *
 * Please remember that you have to rebuild the theme registry after
 * introducing this function or changing its name.
 *
 * @param $content
 *   The content of the block to be rendered. It has a title and a content.
 * @param $pane
 * @param $display
 * @return
 *   rendered content
 */
function theme_panels_colors_style_pane($vars)
{
    kpr($vars);
    $display        = $vars['display'];
    $content        = $vars['content'];
    $pane           = $vars['pane'];
    $style_settings = $pane->style['settings'];
    $color          = $style_settings['color'];
    $output         = "";
    if (!empty($content->title)) {
        $output .= "<h3>$content->title</h3>";
    }

    // For this simple example, wrap the content in a div with style.
    // We could have loaded extra css, etc.
    drupal_add_css(drupal_get_path('theme', 'legendary') . '/plugins/styles/colors/yellow.css', 'theme');
    $output .= "<div style='background-color:";
    $output .= $color;
    $output .= ";'>";

    $output .= theme('panels_pane', array(
        'content' => $content,
        'pane' => $pane,
        'display' => $display
    ));
    //   $output = theme('panels_colors_box', array('content' => $output));
    $output .= "</div>";
    return $output;
}





/**
 * The function which will render the panel or region with this style.
 *
 * This is optional, but shows how the plugin can be used to change the
 * rendering of a panel or region.
 *
 * @param $display
 * @param $panel_id
 * @param $panes
 * @param $settings
 * @return
 *   Rendered output for the panel.
 */
function theme_panels_colors_style_region($vars)
{
    $display   = $vars['display'];
    $region_id = $vars['region_id'];
    $panes     = $vars['panes'];
    $settings  = $vars['settings'];
    $output    = '';

    $color_default = $settings['color_default'];
    $color_custom  = $settings['color_custom'];

    if ($color_default != 'custom') {
        $color = $color_default;
    } else {
        $color = $color_custom;
    }

    $output = "<div style='text-decoration: underline; background-color: #$color;'>";

    $where = empty($settings['color_location']) ? 'pane' : $settings['color_location'];

    foreach ($panes as $pane_id => $pane) {
        if ($where == 'pane') {
            // If you are NOT using a tpl.php file (see top of this document), uncomment the following file:
            //    $output .= $pane;

            //If you ARE using a Tpl.php file (see top of this document), uncomment the following file:        
            $output .= theme('panels_colors_box', array(
                'content' => $pane
            ));

        }

        else {
            //Loop throught to gather each pane and put them into $allpanes          
            $allpanes .= $pane;
            $print_separator = TRUE;
        }


    }

    if ($where == 'region') {
        // If you are NOT using a tpl.php file (see top of this document), uncomment the following file:
        //$output .= $allpanes;

        // If you are using a tpl.php file (see top of this document), uncomment the following file:
        $output .= theme('panels_colors_box', array(
            'content' => $allpanes
        ));
    }

    $output .= "</div>";
    return $output;

}

1 Answer 1

0

I've figured this out!

The form part has to be moved to where return drupal_get_form('coloroptions'); is.

Then, the visibility options for the Form state have to be updated, so they match the Panel Style form options correctly.

I have posted the code below, as it will make more sense to someone having the same problem:

<?php
// $Id$

/**
 * @file
 *   Definition of the 'color' panel style.
 */

/* Place this file in themename/plugins/styles/STYLENAME/
/* In theme.INFO add the following:
/* ;----------// Plugin Panels
plugins[panels][layouts] = plugins/layouts
plugins[panels][styles] = plugins/styles
/* Reset your cahce afterwards.  */


$plugin = array(
    'title' => t('Example: Color text style'),
    'description' => t('Simply changes the text color of a pane, as an example.'),

    // Names the function to render a pane. Only required for pane styles.
    'render pane' => 'panels_colors_style_pane',

    // Names the function to render a region. Only required for pane styles.
    'render region' => 'panels_colors_style_region',

    // Names the function providing settings form for the pane. (optional)
    'pane settings form' => 'panels_colors_style_pane_settings',

    // Names the function providing settings form for the region. (optional)
    'settings form' => 'panels_colors_style_region_settings',

    // Provide a template to be used by Pane and/or Region. (optional)    
    'hook theme' => array(
        'panels_colors_box' => array(
            'variables' => array(
                'content' => NULL
            ),
            'path' => path_to_theme('plugins/styles/colors'),
            'template' => 'panels-colors-box'
        )
    )

);


/**
 * Settings form for the pane.
 *
 * Any form will do here. The settings will come through to the theme
 * function in $pane->style['settings'].
 * Use form API to construct the form: http://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7
 *
 * @param $style_settings
 *   The $style_settings if they've already been set.
 * @return
 *   The form.
 */


function panels_colors_style_pane_settings($style_settings) {
    $form['color_default'] = array(
        '#type' => 'select',
        '#title' => t('Select a Colour'),
        '#options' => array(
            '000000' => t('Black'),
            'ffffff' => t('White'),
            'custom' => t('custom')
        ),
        '#default_value' => (isset($form['color_default'])) ? $form['color_default'] : '000000',
        '#description' => t('The Colour you want to use')
    );




    $form['color_custom'] = array(
        '#type' => 'textfield',
        '#title' => t('background color for pane'),
        '#states' => array(
            'visible' => array(
                ':input[name="settings[color_default]"]' => array(
                    'value' => t('custom')
                )

            )
        ),
        '#default_value' => (isset($form['color_custom'])) ? $form['color_custom'] : '',
        '#description' => t('The Colour you want to use')
    );

    $form['color_location'] = array(
        '#type' => 'select',
        '#title' => t('Box around'),
        '#options' => array(
            'pane' => t('Each pane'),
            'region' => t('Each region')
        ),
        '#default_value' => (isset($form['color_location'])) ? $form['color_location'] : 'pane',
        '#description' => t('Choose whether to include the box around each pane (piece of content) or region (each column or region)')
    );



    return $form;
}


/**
 * Settings form for the region.
 *
 * Any form will do here. The settings will come through to the theme
 * function in $pane->style['settings'].
 * Use form API to construct the form: http://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7
 *
 * @param $style_settings
 *   The $style_settings if they've already been set.
 * @return
 *   The form.
 */

function panels_colors_style_region_settings($style_settings) {
    $form['color_default'] = array(
        '#type' => 'select',
        '#title' => t('Select a Colour'),
        '#options' => array(
            '000000' => t('Black'),
            'ffffff' => t('White'),
            'custom' => t('custom')
        ),
        '#default_value' => (isset($form['color_default'])) ? $form['color_default'] : '000000',
        '#description' => t('The Colour you want to use')
    );




    $form['color_custom'] = array(
        '#type' => 'textfield',
        '#title' => t('background color for pane'),
        '#states' => array(
            'visible' => array(
                ':input[name="settings[color_default]"]' => array(
                    'value' => t('custom')
                )

            )
        ),
        '#default_value' => (isset($form['color_custom'])) ? $form['color_custom'] : '',
        '#description' => t('The Colour you want to use')
    );

    $form['color_location'] = array(
        '#type' => 'select',
        '#title' => t('Box around'),
        '#options' => array(
            'pane' => t('Each pane'),
            'region' => t('Each region')
        ),
        '#default_value' => (isset($form['color_location'])) ? $form['color_location'] : 'pane',
        '#description' => t('Choose whether to include the box around each pane (piece of content) or region (each column or region)')
    );

    return $form;

}

/**
 * Render the pane content.
 *
 * The name of this function is referenced in hook_default_panels_styles(), and
 * it's free-form, but of course be careful to namespace it.
 * But the name is just theme_<render pane> where "<render pane>" is what you
 * put into the array above.
 *
 * This is optional, but shows how a plugin can render a pane.
 *
 * Please remember that you have to rebuild the theme registry after
 * introducing this function or changing its name.
 *
 * @param $content
 *   The content of the block to be rendered. It has a title and a content.
 * @param $pane
 * @param $display
 * @return
 *   rendered content
 // */
function theme_panels_colors_style_pane($vars) {
    //kpr($vars);
    $display  = $vars['display'];
    $content  = $vars['content'];
    $pane     = $vars['pane'];
    $settings = $pane->style['settings'];
    $color    = $style_settings['color'];
    $output   = "";
    if (!empty($content->title)) {
        $output .= "<h3>$content->title</h3>";
    }


    $color_default = $settings['color_default'];
    $color_custom  = $settings['color_custom'];

    if ($color_default != 'custom') {
        $color = $color_default;
    } else {
        $color = $color_custom;
    }




    // For this simple example, wrap the content in a div with style.
    // We could have loaded extra css, etc.
    //    drupal_add_css(drupal_get_path('theme', 'legendary') . '/plugins/styles/colors/yellow.css', 'theme');
    $output .= "<div style='text-decoration: underline; background-color: #$color; overflow:hidden;'>";

    $output .= theme('panels_pane', array(
        'content' => $content,
        'pane' => $pane,
        'display' => $display
    ));
    //   $output = theme('panels_colors_box', array('content' => $output));

    $output .= $color;

    $output .= "</div>";

    return $output;
}





/**
 * The function which will render the panel or region with this style.
 *
 * This is optional, but shows how the plugin can be used to change the
 * rendering of a panel or region.
 *
 * @param $display
 * @param $panel_id
 * @param $panes
 * @param $settings
 * @return
 *   Rendered output for the panel.
 */
function theme_panels_colors_style_region($vars) {
    $display   = $vars['display'];
    $region_id = $vars['region_id'];
    $panes     = $vars['panes'];
    $settings  = $vars['settings'];
    $output    = '';

    $color_default = $settings['color_default'];
    $color_custom  = $settings['color_custom'];

    if ($color_default != 'custom') {
        $color = $color_default;
    } else {
        $color = $color_custom;
    }

    $output = "<div style='text-decoration: underline; background-color: #$color;'>";

    $where = empty($settings['color_location']) ? 'pane' : $settings['color_location'];

    foreach ($panes as $pane_id => $pane) {
        $display->cssregionstyle[] = $color;
        $settings[]           = $color;
        if ($where == 'pane') {
            // If you are NOT using a tpl.php file (see top of this document), uncomment the following file:
            //    $output .= $pane;

            //If you ARE using a Tpl.php file (see top of this document), uncomment the following file:        
            $output .= theme('panels_colors_box', array(
                'content' => $pane
            ));
        }

        else {
            //Loop throught to gather each pane and put them into $allpanes          
            $allpanes .= $pane;
            $print_separator = TRUE;
        }
    }

    if ($where == 'region') {
        // If you are NOT using a tpl.php file (see top of this document), uncomment the following file:
        $output .= $allpanes;

        // If you are using a tpl.php file (see top of this document), uncomment the following file:
        //  $output .= theme('panels_colors_box', array(
        //    'content' => $allpanes
        // ));

    }

    $output .= "</div>";
    return $output;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.