Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

This is a pretty lengthy question, so bare with me.

In a plugin I've written that allows users to easily create new meta boxes, I have a function that uses a switch() to return the appropriate HTML for the kind of meta field being added. The function looks like this:

// displays the requested field type
function ecpt_render_field($field, $meta) {

    global $wp_version, $post, $ecpt_options;

    switch($field['type']) :

        case 'text' :
            $field_html = '<input type="text" name="' . $field['id'] . '" id="' . $field['id'] . '" value="' . stripslashes($meta) . '" size="30" style="width:97%" /><br/>' . __(stripslashes($field['desc']));
            break;

            /*****************************************************************
            * lots of case statements here have been removed for this example
            ******************************************************************/

    case 'checkbox' :
        $field_html = '<input type="checkbox" name="' . $field['id'] . '" id="' . $field['id'] . '" ' . checked(!empty($meta), true, false) .'/><div class="ecpt_description">' . __(stripslashes($field['desc'])) . '</div>';
        break;      

    endswitch;  

    if(has_filter('ecpt_fields_html')) {
        // this adds any addon fields (from plugins) to the array
        $field_html = apply_filters('ecpt_fields_html', $field, $field_html, $meta);
    }   

    // return the final field
    return $field_html;
}

$field is an array that contains all of the information for the field (id, type, class, etc). $meta is the value stored in the post meta.

At the end of the function there is a check for the existence of the "ecpt_fields_html" filter. This is a filter I've setup to allow additional meta field types to be registered via other plugins.

An example function that registers additional field types (successfully), looks like this:

// generates the HTML for the additional fields
function ecpt_bonus_fields_html($field, $field_html, $meta) {

    switch($field['type']) :

        case 'taxonomy' :
            // returns the options html for select fields
            $field_options = ecpt_get_field_options($field, $meta);
            $field_html =  '<select name="' . $field['id'] . '" id="' . $field['id'] . '">' . $field_options . '</select><br/>' . $field['desc'];
            break;

        case 'separator' :
            $field_html = '<hr/>';
            break;          

        case 'colorpicker' :
            if (empty($meta)) $meta = '#';
            $field_html = "<input class='ecpt-color' type='text' name='" . $field['id'] . "' id='" . $field['id'] . "' value='" . $meta . "' size='8' />
                    <a href='#' class='ecpt-color-select' rel='" . $field['id'] . "'>" . __('Select a color') . "</a>
                    <a href='#' class='ecpt-color-select' style='display: none;'>" . __('Hide Picker') . "</a>
                    <div style='display:none; position: absolute; background: #f0f0f0; border: 1px solid #ccc; z-index: 100;' class='ecpt-color-picker' rel='" . $field['id'] . "'></div>";
            break;

        default :
            $field_html = $field_html;

    endswitch;

    return $field_html;
}
add_filter('ecpt_fields_html', 'ecpt_bonus_fields_html', 10, 3);

This function to register extra field types works exactly like the first one.

Now, let's say that I have the the function above activated in an add-on plugin (everything works fine), and then I setup a second plugin that has a second function that registers more field types (this new second function is structured exactly like the filter function above). If I do this, both of the filter functions that register new field types fail completely. They don't throw any errors, but the "return $field_html;" statement simply returns nothing at all.

The second filter function looks like this:

// generates the HTML for the additional fields
function ecpt_sample_fields_html($field, $field_html, $meta) {

    switch($field['type']) :

        case 'textblock' :
            $field_html = 'this should be shown in the metabox, but is not';
        break;          

    endswitch;

    return $field_html;
}
add_filter('ecpt_fields_html', 'ecpt_sample_fields_html', 10, 3);

Both filter functions work perfectly when the other is not active, but if both are active, then the *$field_html = apply_filters('ecpt_fields_html', $field, $field_html, $meta);* in the very first function results in nothing, just blank.

Alright, now is where it gets a little stranger. I have an almost identical set of functions / filters setup that display the labels for the field types in the meta box. They work perfectly fine.

In the core plugin, the function that setups the label for each field looks like this:

// run the label through a filter. This allows us to modify/remove the label for any field type
function ecpt_field_label($field) {
    $label = '<label for="' . $field['id'] . '">' . __(stripslashes($field['name'])) . '</label>';
    // the ecpt_field_label_filter allows the field label output to be altered for any field type
    if(has_filter('ecpt_field_label_filter')) {
        $label = apply_filters('ecpt_field_label_filter', $label, $field);
    }
    return $label;
}

And the filter function that allows the label HTML to be changed for fields registered with other plugins looks like this:

// modify the labels for the bonus fields (if needed)
function ecpt_bonus_fields_labels($label, $field) {

    if($field['type'] == 'separator') {
        // removes the label for the separator field
        return;
    }
    if($field['type'] == 'header') {
        return '<h4>' . $label . '</h4>';
    }
    return $label;
}
add_filter('ecpt_field_label_filter', 'ecpt_bonus_fields_labels', 10, 2);

This works perfectly fine, even when I setup a second label filter function (remember, setting up the second function for the field types is what caused it to break). So my second filter function for the labels looks like this:

// modify the labels for the bonus fields (if needed)
function ecpt_sample_field_labels($label, $field) {

    if($field['type'] == 'textblock') {
        return '<strong>' . $label . '</strong>';
    }
    return $label;
}
add_filter('ecpt_field_label_filter', 'ecpt_sample_field_labels', 10, 2);

The only difference (aside from using switch() and i() statements) is that the filter types filter has 3 parameters and the field labels filter has 2. At least that is the only difference I can find.

Below are screenshots that illustrates the issue.

Only the first filter function is active, used to register the Color field

Both filter functions are active. The field labels work, but not the input fields

share|improve this question
    
Have you tried setting the priority of the filters to different numbers? Not sure if that would do anything different but worth a try! –  Jared Jan 24 '12 at 16:03
    
Yep, tried every combination I can think of. Another note that is worth mentioning is that both filter functions for adding new field types work perfect by them selves, the problem only comes in if they are both used. –  Pippin Jan 24 '12 at 16:33
    
When you do apply_filters, shouldn't the value to be modified come first? See the Codex. In your case it would be $field_html rather than $field. –  Stephen Harris Jan 24 '12 at 16:39
    
Brilliant! I never realized that the first var had to be the one that is modified. Works perfectly. Please post this as the answer. –  Pippin Jan 24 '12 at 16:51
    
If I got you right, then you're building a visual interface for creating meta boxes. Maybe you don't want to do all the meta box logic, but instead build an UI for RW Meta Box? Combined forces are most times better than single efforts :) –  kaiser Jan 24 '12 at 20:06
show 1 more comment

1 Answer

up vote 0 down vote accepted

apply_filters requires the

  • first argument to be the name of the hook,
  • the second argument to be the value to be modified
  • (optional) subsequent arguments to be passed to the filters.

See the Codex

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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