There are 4 problems a small one, a security problem, a misunderstanding, and a big problem.
The Small Problem
Because you used []
notation in the name
you’ve indicated that there are multiple category_meta_
values:
category_meta_[<?php echo $cat->term_id ?>]
Which means $_POST['category_meta_']
will always be an array.
It would be much easier to append the term ID, or remove it entirely than it would be to wrap it in []
characters.
The Security Problem
This is not good:
esc_attr_e( $category_meta[ $cat->term_id ] )
I can give you points for escaping, but this code is the same as:
echo esc_attr( __( $category_meta[ $cat->term_id ] ) );
Which commits a major mistake of passing dynamic data into a static string localisation API. Never pass dynamic strings into __(
type functions, be it directly or indirectly. echo esc_attr
should have been used.
The Misunderstanding
This:
if ( ... && !update_option(...) )
add_option(...);
Works the same as this:
if ( ! ... ) {
return;
}
update_option(...)
update_
type functions will add the option/meta/etc if it doesn’t exist
The Biggest Problem
You’ve reinvented term meta. There’s already an API for this!!!!!
get_term_meta
add_term_meta
update_term_meta
delete_term_meta
This code is much more reliable and avoids several problems you didn’t realise:
add_action( 'category_edit_form_fields', 'display_category_title_field' );
add_action( 'edit_category', 'save_category_title_field' );
function display_category_title_field( \WP_Term $cat ) : void {
$title = get_term_meta( $cat->term_id, 'title', true );
?>
<tr class="form-field">
<th scope="row" valign="top">
<label for="category-title"><?php esc_html_e( 'Title' ); ?></label>
</th>
<td>
<input id="category-title" name="category-title"
value="<?php echo esc_attr( $title ); ?>" />
</td>
</tr>
<?php
}
function save_category_title_field( int $term_id ) : void {
if ( ! isset( $_POST['category-title'] ) ) {
return;
}
$title = sanitize_text_field( $_POST['category-title'] );
update_term_meta( $term_id, 'title', $title );
}
- when the category is deleted you aren’t left with phantom options, term meta gets cleaned up
- We’re now sanitising our inputs
- no more arrays and serialised data, it stores a plain string
- when WP fetches a term it grabs all the term meta at the same time saving on queries
- if you’d used this system with enough terms you would have made every page load very slow from auto-loading all those options
- grabbing the value is much easier now
get_term_meta( $cat_id, 'title', true );
- The data is now accessible via WP CLI
wp term meta
commands - If you register the meta it can even show up in REST API requests for use with AJAX/JS
A final note, terms already have a title/name, and you’ve chosen super generic name for your fields/functions/etc. Prefix your values so they’re unique to you, e.g. gurky_title
instead of title
. And maybe name them term titles rather than category titles? That way if you decide to use them for tags etc you don’t have to rewrite half your code