Hello Thierry,
I'm currently diving in the Beans Fields API. Everything works great and the implementation of custom fields via Beans is really awesome, thanks again for your amazing work.
I've a problem, though, with radio and select fields. I can't retrieve the value of these type of fields in the front-end.
This is what I've added in my plugin:
//* Add Custom Fields for Jobs CPT with Beans
add_action( 'admin_init', 'sps_add_jobs_custom_fields' );
function sps_add_jobs_custom_fields() {
$fields = array(
array(
'id' => 'jobs_contrat',
'label' => 'Type de contrat de travail',
'type' => 'radio',
'default' => array( 'value_1' ),
'options' => array(
'value_1' => 'Bénévolat',
'value_2' => 'Stage non conventionné',
'value_3' => 'Stage conventionné',
'value_4' => 'CDD',
'value_5' => 'CDI',
)
),
);
beans_register_post_meta( $fields, array( 'jobs' ), 'section_id', array( 'title' => 'Informations sur le poste' ) );
}
And this is what I've added in my single-jobs.php template :
// Add Job Description Below Post Content
add_action( 'beans_post_content_after_markup', 'sps_add_job_description' );
function sps_add_job_description() {
?>
<?php if ( $contrat = beans_get_post_meta( 'jobs_contrat' ) ) : ?>
<p><?php echo esc_html( $contrat ); ?></p>
<?php endif; ?>
<?php
}
But all what I have on my website is "value_5" or "value_1", etc. I don't have the value in itself... It works perfectly with text and textarea fields.
What's wrong with my code ? Any idea ?
Mathieu
Hey Mathieu,
Your code are correct and the fact that the values retrieved are value_1
or value_5
is correct too.
In your options
array, the array key defines the radio value (what is save in the db and retrieved in the front end) and the array value defines the radio label (used for the admin radio labels only). If you want to display text in your front end, you will have to echo text based on the value returned.
For info, the default needs to be a string for radio field type, in your case 'default' => 'value_1'
.
Hope that help,
Thanks Thierry,
So, for the record, I've changed my code to :
array(
'id' => 'jobs_contrat',
'label' => 'Type de contrat de travail',
'type' => 'radio',
'default' => 'Bénévolat',
'options' => array(
'Bénévolat' => 'Bénévolat',
'Stage conventionné' => 'Stage conventionné',
'CDD' => 'CDD',
'CDI' => 'CDI',
)
)
And it works. Thanks again !
EDIT : your phrase "If you want to display text in your front end, you will have to echo text based on the value returned." makes me think that, though this code works, it is not at all the better way to do that...
Mathieu
Another option would be to do this. In the plugin :
//* Add Custom Fields for Jobs CPT with Beans
add_action( 'admin_init', 'sps_add_jobs_custom_fields' );
function sps_add_jobs_custom_fields() {
$fields = array(
array(
'id' => 'jobs_contrat',
'label' => 'Field label',
'type' => 'radio',
'default' => 'value_1',
'options' => array(
'value_1' => 'Bénévolat',
'value_2' => 'Stage conventionné',
'value_3' => 'CDD',
'value_4' => 'CDI',
)
),
beans_register_post_meta( $fields, array( 'jobs' ), 'section_id', array( 'title' => 'Informations sur le poste' ) );
}
In the single-jobs.php :
<?php if ( $contrat = beans_get_post_meta( 'jobs_contrat' ) ) :
if ($contrat == "value_1") {
echo "Bénévolat";
}
elseif ($contrat == "value_2") {
echo "Stage conventionné";
}
elseif ($contrat == "value_3") {
echo "CDD";
}
elseif ($contrat == "value_4") {
echo "CDI";
}
?>
I don't know which solution is the best/safer way to work. Maybe it is the same.
Hi Mathieu,
Both solutions above will work but I think we can improve it. I don't think saving the text as a value is a good idea as radio input isn't really meant for that and the format isn't ideal.
Your second code snippet is a better solution but a bit difficult to maintain and we want to avoid repeating code. So here what we want to do is to make the array re-usable so that we can use it when registering the option and when retrieving it in your page template. The obvious solution is to make a function which will contain the array but I would like to take this example to demonstrate another approach using the very often left aside WP Core Cache API. Let's have fun a bit 🙂
// Cache the options value and text.
wp_cache_set( 'jobs_contrat', array(
'value_1' => 'Bénévolat',
'value_2' => 'Stage conventionné',
'value_3' => 'CDD',
'value_4' => 'CDI',
) );
// Add Custom Fields for Jobs CPT with Beans.
add_action( 'admin_init', 'sps_add_jobs_custom_fields' );
function sps_add_jobs_custom_fields() {
$fields = array(
array(
'id' => 'jobs_contrat',
'label' => 'Type de contrat de travail',
'type' => 'radio',
'default' => 'value_1',
'options' => wp_cache_get( 'jobs_contrat' ),
) );
beans_register_post_meta( $fields, array( 'jobs' ), 'section_id', array( 'title' => 'Informations sur le poste' ) );
}
// Add Job Description Below Post Content.
add_action( 'beans_post_content_after_markup', 'sps_add_job_description' );
function sps_add_job_description() {
if ( $contrat = beans_get_post_meta( 'jobs_contrat' ) ) :
?><p><?php echo esc_html( beans_get( $contrat, wp_cache_get( 'jobs_contrat' ) ) ); ?></p><?php
endif;
}
So let's look at the code above. We hold the options using WP object cache, then in the sps_add_jobs_custom_fields()
we use it for the field. In the front end, we use the value retrieved and beans_get
to get the text from our options. It essentially do $options[$value]
but prevents a warning if the array key isn't found.
That is it, pretty clean, pretty fun and easy to maintain.
Hope that helps,
A huge thanks to you, Thierry, this is obviously a far more elegant/shiny solution than mine, no doubt on that ! I learn a lot here. Hopefully, I'll launch my first site created with Beans in a couple of days. 🙂
By the way, I was wondering if a datepicker/timepicker field will be added in Beans 1.4.0 ?
Hey Mathieu,
I am really glad I could help and to here you are learning a lot is fantastic. Datepicker isn't on the roadmap for 1.4.0 but I have added it to the feature request list 🙂
Like the frontend, Beans backend is also flexible and adding your own field types is actually really easy. All your really need to do is add it using the beans_field_{$field_type}
action. The dynamic part of the action is your field type and the callback function arguement ($field
in the example below) provides your with all you need.
For this example, I am going to use UIkit Datepicker but you could use any plugin of your choice. UIkit does not load in the backend by default but we can do it on demand using the beans_uikit_admin_enqueue_scripts
, and load only the UIkit components we need just like on the front end. Here we go!
add_action( 'beans_uikit_admin_enqueue_scripts', 'example_datepicker_field_assets' );
function example_datepicker_field_assets() {
$register_fields = beans_get_fields( 'post_meta', 'section_id' );
// Only load on pages where the datepicker is used.
if ( beans_in_multi_array( 'example_datepicker', (array) $register_fields ) ) {
beans_uikit_enqueue_components( array( 'dropdown', 'icon' ) );
beans_uikit_enqueue_components( array( 'datepicker' ), 'add-ons' );
}
}
add_action( 'beans_field_example_datepicker', 'example_datepicker_field' );
function example_datepicker_field( $field ) {
?><input type="text" name="<?php echo esc_attr( $field['name'] ); ?>" value="<?php echo esc_attr( $field['value'] ); ?>" <?php echo beans_esc_attributes( $field['attributes'] ); ?> data-uk-datepicker="{format:'DD.MM.YYYY'}"><?php
}
A few things to take note in the code above:
- Your custom field type is called
example_datepicker
and you would use it just like any other field type and set the type as such'type' => 'example_datepicker'
. If you want to change your field type to mathieu for example, you would changebeans_field_example_datepicker
tobeans_field_mathieu
. I would advise to prefix your custom field types to avoid conflicts with future Beans Core feilds. - The UIkit admin assets will NOT be flushed with the front end assets as it is not meant to be done by users. If for whatever reason you need to flush it, you will have to do manually by deleting the
wp-content/uploads/beans/admin-compiler/uikit
directory or build a process to do so. - The UIkit assets only load if the field is used so it won't load on other admin pages unnecessarily. In the code above we added the if statement in
example_datepicker_field_assets()
to only load the assets if the field is used because we have to enqueue UIkit components inbeans_uikit_admin_enqueue_scripts
. If you were to enqueue normal assets, you could use thebeans_field_enqueue_scripts_{$field_type}
instead ofbeans_uikit_admin_enqueue_scripts
in which case you would not need to add the if statement in your callback sincebeans_field_enqueue_scripts_{$field_type}
only fires if the field exists.
Let me know if anything isn't clear 🙂
Happy coding,
Edit note: in the example above, beans_esc_attributes()
function is used which was introduced in Beans 1.3.1-rc2
.
This is awesome ! Everything works, and your explanations are very clear. I'm truly impressed !
I'm gonna try to use this to create an event CPT, using this date custom field to query posts. I'll share the result here or on Github, if it works. Thanks again, Thierry. I owe you a lot.
Great Mathieu, I am looking forward to it!
You don't owe me anything, I happy to help 🙂 Beans is free ans will always be but if you really love it and appreciate the support, you may donate (any amount) for its development.
Cheers,
Hi Mathieu,
I thought about another approach for the date picker which I think would be even better. Creating a field works well but the field is the same as the text
field except that we add the data-uk-datepicker
attribute. So what I suggest is to actually use the text
field and add the attribute necessary for the date picker. Here is what your field array would look like:
array(
'id' => 'field_id',
'label' => 'Label',
'type' => 'text',
'attributes' => array( 'data-uk-datepicker' => "{format:'DD.MM.YYYY'}" )
)
Then you can enqueue the UIkit components if the array key data-uk-datepicker
exists instead of checking if the field type example_datepicker
exists. Here is what the code looks like:
add_action( 'beans_uikit_admin_enqueue_scripts', 'example_datepicker_field_assets' );
function example_datepicker_field_assets() {
$register_fields = beans_get_fields( 'post_meta', 'section_id' );
// Only load on pages where the datepicker is used.
if ( beans_multi_array_key_exists( 'data-uk-datepicker', (array) $register_fields ) ) {
beans_uikit_enqueue_components( array( 'dropdown', 'icon' ) );
beans_uikit_enqueue_components( array( 'datepicker' ), 'add-ons' );
}
}
So with that you don't need to add a field type and can remove the example_datepicker_field()
function.
Let me know what you think 🙂
Beautiful ! What can I say more ? Works like a charm. 🙂