Programatically add options to “add new” custom field dropdown

How can I add pre-defined options to the “add new” custom field dropdown?

enter image description here

Read More

Here’s two examples of automatically adding and showing new custom fields:

  1. WordPress: Adding Default Custom Fields on New Posts
  2. Auto create custom field

That’s close to what I want to do; my goal is to add pre-defined options to the “add new” custom filed dropdown, but not have them show as fields until the blogger adds them.

I’d like to know how to do this without using a plugin.

Related posts

4 comments

  1. You cannot do that with pure PHP, because the fields are fetched from existing fields, and there is no hook. But you can use JavaScript, check if the post type supports custom fields and the field does not exist already – and insert it:

    <?php # -*- coding: utf-8 -*-
    /* Plugin Name: Extend custom fields */
    
    add_action( 'admin_footer-post-new.php', 'wpse_98269_script' );
    add_action( 'admin_footer-post.php', 'wpse_98269_script' );
    
    function wpse_98269_script()
    {
        if ( ! isset ( $GLOBALS['post'] ) )
            return;
    
        $post_type = get_post_type( $GLOBALS['post'] );
    
        if ( ! post_type_supports( $post_type, 'custom-fields' ) )
            return;
        ?>
    <script>
        if ( jQuery( "[value='demo_data']" ).length < 1 ) // avoid duplication
            jQuery( "#metakeyselect").append( "<option value='demo_data'>demo_data</option>" );
    </script>
        <?php
    }
    
  2. function add_predefined_custom_field_names( $query ) {
        $predefined = array(
            'www.cyberxoft.com'
        );
    
        global $table_prefix;
    
        $query = preg_replace('/[rnt]/', ' ', $query); //minify by removing all tabs and line breaks
        $query = preg_replace('/s+/', ' ', $query); //minify by replacing spaces, tabs and carriages to single space
    
        //SELECT meta_key FROM wp_postmeta GROUP BY meta_key HAVING meta_key NOT LIKE '\_%' ORDER BY meta_key LIMIT 30
        $pattern = ("/SELECT meta_key FROM ".$table_prefix."postmeta/i");   
    
        if( preg_match($pattern, $query) ) {
            $keys = '';     
    
            foreach($predefined as $key){$keys .= (" UNION SELECT '$key' AS meta_key");}        
    
            $query = preg_replace('/SELECT/i', 'SELECT meta_key FROM (SELECT', $query);
            $query = preg_replace('/FROM wp_postmeta/i', ('FROM wp_postmeta'.$keys), $query);
            $query = preg_replace('/ GROUP BY/i', ')t GROUP BY', $query);
        }
    
        return $query;
    }
    add_filter('query', 'add_predefined_custom_field_names');
    

    Just add the above code anywhere in your themes function.php.
    After you’ve added the above code, it would add ‘www.cyberxoft.com’ to the drop down as one of the option to select.

    If you get to see it, then just replace ‘www.cyberxoft.com’ with your required field name and refresh the admin page and when you see that happened just go ahead and add as many as you like BUT remember that only 30 could be viewed as thats the default limit set for it.

    Enjoy…

  3. Below is a modified version of the awesome script posted by @toscho. I just needed the ability to create the <select> if it didn’t already exist.

    /**
     * Programatically add custom fields.
     *
     * @see http://wordpress.stackexchange.com/questions/98269/programatically-add-options-to-add-new-custom-field-dropdown/
     */
    
    function wpse_98269_script() {
    
        if (isset($GLOBALS['post'])) {
    
            $post_type = get_post_type($GLOBALS['post']);
    
            if (post_type_supports($post_type, 'custom-fields')) {
    
                ?>
    
                    <script>
    
                        // Cache:
                        var $metakeyinput = jQuery('#metakeyinput'),
                            $metakeyselect = jQuery('#metakeyselect');
    
                        // Does the default input field exist and is it visible?
                        if ($metakeyinput.length && ( ! $metakeyinput.hasClass('hide-if-js'))) {
    
                            // Hide it:
                            $metakeyinput.addClass('hide-if-js'); // Using WP admin class.
    
                            // ... and create the select box:
                            $metakeyselect = jQuery('<select id="metakeyselect" name="metakeyselect">').appendTo('#newmetaleft');
    
                            // Add the default select value:
                            $metakeyselect.append('<option value="#NONE#">— Select —</option>');
    
                        }
    
                        // Does "demo_data" already exist?
                        if (jQuery("[value='demo_data']").length < 1) {
    
                            // Add option:
                            $metakeyselect.append("<option value='demo_data'>demo_data</option>");
    
                        }
    
                    </script>
    
                <?php
    
            }
    
        }
    
    }
    
    add_action('admin_footer-post-new.php', 'wpse_98269_script');
    add_action('admin_footer-post.php', 'wpse_98269_script');
    

    I’m sure my JS adaptations could be improved, but it gets the job done. I’ll post updated code back here if I make changes/improvements.

    Thanks again @toscho!!!! I owe you one. 🙂

  4. It works in wordpress v5.8.1

    add_filter( 'postmeta_form_keys', 'filter_function_name_1552', 10, 2 );
    function filter_function_name_1552( $keys, $post ){
        if($post->post_type == 'car') {
            $keys[] = 'regular_price';
        }
        return $keys;
    }
    

Comments are closed.