/**
     * Callback to render the "Custom Fields" metabox.
     *
     * @access private
     * @since 0.8
     * @param  cnEntry $entry   An instance of the cnEntry object.
     * @param  array  $metabox The metabox attributes array set in self::register().
     * @return void
     */
    public static function meta($entry, $metabox)
    {
        /** @var wpdb $wpdb */
        global $wpdb;
        $results = $wpdb->get_results($wpdb->prepare("SELECT meta_key, meta_value, meta_id, entry_id\n\t\t\tFROM " . CN_ENTRY_TABLE_META . " WHERE entry_id = %d\n\t\t\tORDER BY meta_key,meta_id", $entry->getId()), ARRAY_A);
        $metabox = $metabox['args'];
        $keys = cnMeta::key('entry');
        $options = array();
        // Toss the meta that is saved as part of a custom field.
        if (!empty($results)) {
            foreach ($results as $metaID => $meta) {
                if (cnMeta::isPrivate($meta['meta_key'])) {
                    unset($results[$metaID]);
                }
            }
        }
        // Build the meta key select drop down options.
        if (!empty($keys)) {
            $options = array_combine(array_map('esc_attr', array_keys($keys)), array_map('esc_html', $keys));
            array_walk($options, create_function('&$key', '$key = "<option value=\\"$key\\">$key</option>";'));
        }
        array_unshift($options, '<option value="-1">&mdash; ' . __('Select', 'connections') . ' &mdash;</option>');
        $options = implode($options, PHP_EOL);
        // echo '<input type="hidden" name="wp_meta_box_nonce" value="', wp_create_nonce( basename(__FILE__) ), '" />';
        echo '<div class="cn-metabox-section" id="meta-fields">';
        ?>

		<table id="list-table" style="<?php 
        echo empty($results) ? 'display: none;' : 'display: table;';
        ?>
">
			<thead>
				<tr>
					<th class="left"><?php 
        _e('Name', 'connections');
        ?>
</th>
					<th><?php 
        _e('Value', 'connections');
        ?>
</th>
				</tr>
			</thead>

			<tbody id="the-list">

			<?php 
        if (!empty($results)) {
            foreach ($results as $metaID => $meta) {
                // Class added to alternate tr rows for CSS styling.
                $alternate = !isset($alternate) || $alternate == '' ? 'alternate' : '';
                ?>

					<tr id="meta-<?php 
                echo $meta['meta_id'];
                ?>
" class="<?php 
                echo $alternate;
                ?>
">

						<td class="left">
							<label class="screen-reader-text" for='meta[<?php 
                echo $meta['meta_id'];
                ?>
][key]'><?php 
                _e('Key', 'connections');
                ?>
</label>
							<input name='meta[<?php 
                echo $meta['meta_id'];
                ?>
][key]' id='meta[<?php 
                echo $meta['meta_id'];
                ?>
][key]' type="text" size="20" value="<?php 
                echo esc_textarea($meta['meta_key']);
                ?>
" />
							<div class="submit">
								<input type="submit" name="deletemeta[<?php 
                echo $meta['meta_id'];
                ?>
]" id="deletemeta[<?php 
                echo $meta['meta_id'];
                ?>
]" class="button deletemeta button-small" value="<?php 
                _e('Delete', 'connections');
                ?>
" />
							</div>
						</td>

						<td>
							<label class="screen-reader-text" for='meta[<?php 
                echo $meta['meta_id'];
                ?>
][value]'><?php 
                _e('Value', 'connections');
                ?>
</label>
							<textarea name='meta[<?php 
                echo $meta['meta_id'];
                ?>
][value]' id='meta[<?php 
                echo $meta['meta_id'];
                ?>
][value]' rows="2" cols="30"><?php 
                echo esc_textarea(cnFormatting::maybeJSONencode($meta['meta_value']));
                ?>
</textarea>
						</td>

					</tr>

					<?php 
            }
            ?>

			<?php 
        }
        ?>

			<!-- This is the row that will be cloned via JS when adding a new Custom Field. -->
			<tr style="display: none;">

				<td class="left">
					<label class="screen-reader-text" for='newmeta[0][key]'><?php 
        _e('Key', 'connections');
        ?>
</label>
					<input name='newmeta[0][key]' id='newmeta[0][key]' type="text" size="20" value=""/>
					<div class="submit">
						<input type="submit" name="deletemeta[0]" id="deletemeta[0]" class="button deletemeta button-small" value="<?php 
        _e('Delete', 'connections');
        ?>
" />
						<!-- <input type="submit" name="newmeta-0-submit" id="newmeta-0-submit" class="button updatemeta button-small" value="Update" /> -->
					</div>
					<!-- <input type="hidden" id="_ajax_nonce" name="_ajax_nonce" value="0db0025bba" /> -->
				</td>
				<td>
					<label class="screen-reader-text" for='newmeta[0][value]'><?php 
        _e('Value', 'connections');
        ?>
</label>
					<textarea name='newmeta[0][value]' id='newmeta[0][value]' rows="2" cols="30"></textarea>
				</td>

			</tr>

			</tbody>
		</table>

		<p><strong><?php 
        _e('Add New Custom Field:', 'connections');
        ?>
</strong></p>

		<table id="newmeta">
			<thead>
				<tr>
					<th class="left"><label for="metakeyselect"><?php 
        _e('Name', 'connections');
        ?>
</label></th>
					<th><label for="metavalue"><?php 
        _e('Value', 'connections');
        ?>
</label></th>
				</tr>
			</thead>
			<tbody>

				<tr>

					<td id="newmetaleft" class="left">
						<select id="metakeyselect" name="metakeyselect">
							<?php 
        echo $options;
        ?>
						</select>
						<input class="hide-if-js" type=text id="metakeyinput" name="newmeta[99][key]" value=""/>
						<a href="#postcustomstuff" class="postcustomstuff hide-if-no-js"> <span id="enternew"><?php 
        _e('Enter New', 'connections');
        ?>
</span> <span id="cancelnew" class="hidden"><?php 
        _e('Cancel', 'connections');
        ?>
</span></a>
					</td>

					<td>
						<textarea id="metavalue" name="newmeta[99][value]" rows="2" cols="25"></textarea>
					</td>

				</tr>



			</tbody>
			<tfoot>
				<td colspan="2">
					<div class="submit">
						<input type="submit" name="addmeta" id="newmeta-submit" class="button" value="<?php 
        _e('Add Custom Field', 'connections');
        ?>
" />
					</div>
					<!-- <input type="hidden" id="_ajax_nonce-add-meta" name="_ajax_nonce-add-meta" value="a7f70d2878" /> -->
				</td>
			</tfoot>
		</table>

		<?php 
        if (isset($metabox['desc']) && !empty($metabox['desc'])) {
            printf('<p>%1$s</p>', esc_html($metabox['desc']));
        }
        echo '</div>';
    }
 /**
  * Update meta by ID.
  *
  * NOTE: This is the Connections equivalent of @see update_metadata_by_mid() in WordPress core ../wp-includes/meta.php
  *
  * @access public
  * @since  8.1.7
  * @static
  *
  * @global wpdb  $wpdb  WordPress database abstraction object.
  *
  * @uses   cnMeta::tableName()
  * @uses   cnMeta::getByID()
  * @uses   sanitize_meta()
  * @uses   cnFormatting::maybeJSONencode()
  * @uses   do_action()
  * @uses   wpdb::update()
  * @uses   wp_cache_delete()
  *
  * @param string $type  Type of object metadata is for (e.g., entry, term).
  * @param int    $id    ID for a specific meta row.
  * @param string $value Metadata value.
  * @param mixed  $key   string|bool Optional, you can provide a meta key to update it.
  *
  * @return bool         TRUE on successful update, FALSE on failure.
  */
 public static function updateByID($type, $id, $value, $key = FALSE)
 {
     /** @var wpdb $wpdb */
     global $wpdb;
     // Make sure everything is valid.
     if (!$type || !is_numeric($id)) {
         return FALSE;
     }
     $id = absint($id);
     if (!$id) {
         return FALSE;
     }
     $table = self::tableName($type);
     $column = sanitize_key($type . '_id');
     $id_column = 'meta_id';
     // Fetch the meta and go on if it's found.
     if ($meta = self::getByID($type, $id)) {
         $original_key = $meta->meta_key;
         $object_id = $meta->{$column};
         // If a new meta_key (last parameter) was specified, change the meta key,
         // otherwise use the original key in the update statement.
         if (FALSE === $key) {
             $key = $original_key;
         } elseif (!is_string($key)) {
             return FALSE;
         }
         // Sanitize the meta
         $_meta_value = $value;
         $value = wp_unslash($value);
         $value = sanitize_meta($key, $value, 'cn_' . $type);
         $value = cnFormatting::maybeJSONencode($value);
         // Format the data query arguments.
         $data = array('meta_key' => $key, 'meta_value' => $value);
         // Format the where query arguments.
         $where = array();
         $where[$id_column] = $id;
         /** This action is documented in includes/class.meta.php */
         do_action("cn_update_{$type}_meta", $id, $object_id, $key, $_meta_value);
         // Run the update query, all fields in $data are %s, $where is a %d.
         $result = $wpdb->update($table, $data, $where, '%s', '%d');
         if (!$result) {
             return FALSE;
         }
         // Clear the caches.
         wp_cache_delete($object_id, 'cn_' . $type . '_meta');
         /** This action is documented in includes/class.meta.php */
         do_action("cn_updated_{$type}_meta", $id, $object_id, $key, $_meta_value);
         return TRUE;
     }
     // And if the meta was not found.
     return FALSE;
 }
 /**
  * Write the CSV rows for the current step.
  *
  * @access public
  * @since  8.5.1
  */
 public function writeRows()
 {
     $results = $this->getData();
     $rows = '';
     if (!empty($results)) {
         // Go through each entry...
         foreach ($results as $entry) {
             $fieldCount = count($this->fields);
             $row = '';
             // ...and go through each cell the user wants to export, and match it with the cell in the entry...
             for ($i = 0; $i < $fieldCount; $i++) {
                 // ...then find out if it's a breakout cell and process it properly...
                 switch ($this->fields[$i]['type']) {
                     case 1:
                         // Export a standard breakout; just list them all in the order requested...
                         $row .= $this->exportBreakoutCell($this->fields[$i], $entry->id);
                         break;
                     case 2:
                         // Process category table and list all categories in a single cell...
                         $terms = array();
                         $results = $this->getTerms($entry->id, 'category');
                         foreach ($results as $term) {
                             $terms[] = $term->name;
                         }
                         $row .= $this->escapeAndQuote(implode(',', $terms)) . ',';
                         break;
                     case 3:
                         $count = $this->getTermCount('category');
                         $terms = array();
                         // Process the category table by breaking them out in separate cells,
                         // Prepare an empty frame of the category cells...
                         for ($j = 0; $j < $count + 1; $j++) {
                             // Make an array filled with empty cells
                             $terms[$j] = '"",';
                         }
                         // Now start filling in the empty cells with data...
                         $row = $this->getTerms($entry->id, 'category');
                         $j = 0;
                         foreach ($row as $result) {
                             $terms[$j] = $this->escapeAndQuote($result->name) . ',';
                             $j++;
                         }
                         $row .= implode('', $terms);
                         break;
                     case 4:
                         // Export breakout data from the serialized option cell.
                         $row .= $this->exportBreakoutOptionsCell($this->fields[$i], $entry);
                         break;
                     case 5:
                         $data = '';
                         $meta = cnMeta::get('entry', $entry->id, $this->fields[$i]['field'], TRUE);
                         if (!empty($meta)) {
                             $data = cnFormatting::maybeJSONencode($meta);
                         }
                         $row .= $this->escapeAndQuote($data) . ',';
                         break;
                     case 6:
                         $terms = array();
                         $parent = $this->fields[$i]['child_of'];
                         $results = $this->getTerms($entry->id, 'category');
                         foreach ($results as $term) {
                             $terms[] = $parent . ':' . $term->term_id;
                             if (cnTerm::isAncestorOf($parent, $term->term_id, 'category')) {
                                 $terms[] = $term->name;
                             }
                         }
                         $row .= $this->escapeAndQuote(implode(',', $terms)) . ',';
                         break;
                     default:
                         // If no breakout type is defined, only display the cell data...
                         $row .= $this->escapeAndQuote($entry->{$this->fields[$i]['field']}) . ',';
                         break;
                 }
             }
             // Trim the trailing comma and space, then add newline.
             $rows .= rtrim($row, ',') . "\r\n";
         }
         // Now write the data...
         $this->write($rows);
         return $rows;
     }
     return FALSE;
 }
 /**
  * Attachments can be supplied as either an array or string. Convert to string if it is an array.
  *
  * @access private
  * @since 8.2.10
  * @static
  *
  * @param array|string $attachments
  *
  * @return mixed
  */
 private static function parseAttachments($attachments)
 {
     return is_array($attachments) ? cnFormatting::maybeJSONencode($attachments) : $attachments;
 }