Fieldmanager
  • Package
  • Class
  • Tree
  • Todo

Packages

  • Fieldmanager
    • Context
    • Datasource
    • Field
    • Util
  • None

Classes

  • Fieldmanager_Autocomplete
  • Fieldmanager_Checkbox
  • Fieldmanager_Checkboxes
  • Fieldmanager_Colorpicker
  • Fieldmanager_Datepicker
  • Fieldmanager_DraggablePost
  • Fieldmanager_Field
  • Fieldmanager_Grid
  • Fieldmanager_Group
  • Fieldmanager_Hidden
  • Fieldmanager_Link
  • Fieldmanager_Media
  • Fieldmanager_Options
  • Fieldmanager_Password
  • Fieldmanager_Radios
  • Fieldmanager_RichTextArea
  • Fieldmanager_Select
  • Fieldmanager_TextArea
  • Fieldmanager_TextField
  1 <?php
  2 
  3 /**
  4  * Text field that responds to user input with autocomplete suggestions
  5  * (optionally via an ajax request).
  6  *
  7  * This must include a {@link Fieldmanager_Datasource}, which the autocomplete
  8  * uses to search against.
  9  *
 10  * @package Fieldmanager_Field
 11  */
 12 class Fieldmanager_Autocomplete extends Fieldmanager_Field {
 13 
 14     /**
 15      * @var boolean
 16      * Require an exact match; e.g. prevent the user from entering free text
 17      */
 18     public $exact_match = True;
 19 
 20     /**
 21      * @var boolean
 22      */
 23     public $show_edit_link = False;
 24 
 25     /**
 26      * @var string
 27      * Key for reciprocal relationship; if defined will add an entry to postmeta on the mirrored post.
 28      */
 29     public $reciprocal = Null;
 30 
 31     /**
 32      * @var callable
 33      * What function to call to match posts. Initialized to Null here because it will be
 34      * written in __construct to an internal function that calls get_posts, so only
 35      * overwrite it if you do /not/ want to use get_posts.
 36      *
 37      * The function signature should be query_callback( $match, $args );
 38      */
 39     public $query_callback = Null;
 40 
 41     /**
 42      * @var string
 43      * Javascript trigger to handle adding custom args
 44      */
 45     public $custom_args_js_event = Null;
 46 
 47     /**
 48      * @var boolean
 49      * Override save_empty for this element type
 50      */
 51     public $save_empty = False;
 52 
 53     /**
 54      * Add libraries for autocomplete
 55      * @param string $label
 56      * @param array $options
 57      */
 58     public function __construct( $label = '', $options = array() ) {
 59         $this->attributes = array(
 60             'size' => '50',
 61         );
 62         parent::__construct( $label, $options );
 63 
 64         // Enqueue required scripts in the proper context
 65         add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
 66         add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
 67 
 68         fm_add_script( 'fm_autocomplete_js', 'js/fieldmanager-autocomplete.js', array( 'fieldmanager_script' ), '1.0.5', false, 'fm_search', array( 'nonce' => wp_create_nonce( 'fm_search_nonce' ) ) );
 69 
 70         if ( empty( $this->datasource ) ) {
 71             $message = esc_html__( 'You must supply a datasource for the autocomplete field', 'fieldmanager' );
 72             if ( Fieldmanager_Field::$debug ) {
 73                 throw new FM_Developer_Exception( $message );
 74             } else {
 75                 wp_die( $message, esc_html__( 'No Datasource', 'fieldmanager' ) );
 76             }
 77         }
 78         $this->datasource->allow_optgroups = False;
 79     }
 80 
 81     /**
 82      * Handle enqueuing built-in scripts required for autocomplete
 83      * @return void
 84      */
 85     public function enqueue_scripts() {
 86         wp_enqueue_script( 'jquery-ui-autocomplete' );
 87     }
 88 
 89     /**
 90      * Alter values before rendering
 91      * @param array $values
 92      */
 93     public function preload_alter_values( $values ) {
 94         if ( $this->datasource ) return $this->datasource->preload_alter_values( $this, $values );
 95         return $values;
 96     }
 97 
 98     /**
 99      * Render form element
100      * @param mixed $value
101      * @return string HTML
102      */
103     public function form_element( $value = Null ) {
104 
105         if ( $this->exact_match ) {
106             $this->attributes['data-exact-match'] = True;
107         }
108 
109         if ( $this->datasource->use_ajax ) {
110             $this->attributes['data-action'] = $this->datasource->get_ajax_action( $this->name );
111             list ( $context, $subcontext ) = fm_get_context();
112             $this->attributes['data-context'] = $context;
113             $this->attributes['data-subcontext'] = $subcontext;
114         } else {
115             $this->attributes['data-options'] = htmlspecialchars( json_encode( $this->datasource->get_items() ) );
116         }
117 
118         $display_value = $this->datasource->get_value( $value );
119         if ( '' == $display_value && ! $this->exact_match && ! isset( $this->datasource->options[ $value ] ) ) {
120             $display_value = $value;
121         }
122 
123         $element = sprintf(
124             '<input class="fm-autocomplete fm-element fm-incrementable" type="text" id="%s" value="%s"%s %s />',
125             esc_attr( $this->get_element_id() ),
126             esc_attr( $display_value ),
127             ( ! empty( $this->custom_args_js_event ) ) ? ' data-custom-args-js-event="' . esc_attr( $this->custom_args_js_event ) . '"' : '',
128             $this->get_element_attributes()
129         );
130 
131         $element .= sprintf(
132             '<input class="fm-autocomplete-hidden fm-element" type="hidden" name="%s" value="%s" />',
133             esc_attr( $this->get_form_name() ),
134             esc_attr( $value )
135         );
136 
137         if ( isset( $this->show_view_link ) && $this->show_view_link ) {
138             $element .= $this->datasource->get_view_link( $value );
139         }
140 
141         if ( isset( $this->show_edit_link ) && $this->show_edit_link ) {
142             $element .= $this->datasource->get_edit_link( $value );
143         }
144 
145         return $element;
146     }
147 
148     /**
149      * Trigger datasource's presave_alter() event to allow it to handle reciprocal values
150      * @param array $values new post values
151      * @param array $current_values existing post values
152      */
153     public function presave_alter_values( $values, $current_values = array() ) {
154         // return if there is no data id
155         if ( empty( $this->data_id ) ) {
156             return $values;
157         }
158 
159         if ( ! empty( $this->datasource->only_save_to_taxonomy ) ) {
160             $this->skip_save = true;
161         } elseif ( ! empty( $this->datasource->only_save_to_post_parent ) ) {
162             $this->skip_save = true;
163         }
164 
165         return $this->datasource->presave_alter_values( $this, $values, $current_values );
166     }
167 
168     /**
169      * Delegate sanitization and validation to the datasource's presave() method.
170      * @param array $value
171      * @return array $value
172      */
173     public function presave( $value, $current_value = array() ) {
174         return $this->datasource->presave( $this, $value, $current_value );
175     }
176 
177     /**
178      * Helper function to get the list of default meta boxes to remove.
179      * If $remove_default_meta_boxes is true and the datasource is Fieldmanager_Datasource_Term,
180      * this will return a list of all default meta boxes for the specified taxonomies.
181      * We only need to return id and context since the page will be handled by the list of post types provided to add_meta_box.
182      * Otherwise, this will just return an empty array.
183      * @param array current list of meta boxes to remove
184      * @return array list of meta boxes to remove
185      */
186     protected function add_meta_boxes_to_remove( &$meta_boxes_to_remove ) {
187         if ( $this->remove_default_meta_boxes && get_class( $this->datasource ) == 'Fieldmanager_Datasource_Term' ) {
188             // Iterate over the list and build the list of meta boxes
189             $meta_boxes = array();
190             foreach( $this->datasource->get_taxonomies() as $taxonomy ) {
191                 // The ID differs if this is a hierarchical taxonomy or not. Get the taxonomy object.
192                 $taxonomy_obj = get_taxonomy( $taxonomy );
193                 if ( false !== $taxonomy_obj ) {
194                     if ( $taxonomy_obj->hierarchical )
195                         $id = $taxonomy . "div";
196                     else
197                         $id = 'tagsdiv-' . $taxonomy;
198 
199                     $meta_boxes[$id] = array(
200                         'id' => $id,
201                         'context' => 'side'
202                     );
203                 }
204             }
205 
206             // Merge in the new meta boxes to remove
207             $meta_boxes_to_remove = array_merge( $meta_boxes_to_remove, $meta_boxes );
208         }
209     }
210 }
211 
Fieldmanager API documentation generated by ApiGen 2.8.0