'pfbc-select pfbc-post-select');
/**
* The form instance is serialized into a transient at render time and
* restored on submit. The parent OptionElement::__sleep() whitelist would
* drop this element's own properties, so submit-time validation would see
* the defaults (post_type 'page', no extra_args) instead of the configured
* values. Keep them in the serialized representation.
*
* @since 2.2.27
*/
public function __sleep() {
return array('attributes', 'label', 'validation', 'options', 'post_type', 'extra_args', 'ajax_url', 'nonce');
}
/**
* Constructor
*
* @param string $label The field label.
* @param string $name The field name attribute.
* @param string $post_type Post type to query (default: 'page').
* @param string $extra_args Extra query arguments in query string format.
* @param array|null $properties Optional element properties.
*/
public function __construct($label, $name, $post_type = 'page', $extra_args = '', ?array $properties = null) {
// Initialize with empty options - will be loaded via AJAX
parent::__construct($label, $name, array(), $properties);
$this->post_type = $post_type;
$this->extra_args = $extra_args;
$this->ajax_url = admin_url('admin-ajax.php');
$this->nonce = wp_create_nonce('accua_forms_get_posts');
// Add data attributes for JavaScript
$this->attributes['data-post-type'] = $this->post_type;
$this->attributes['data-ajax-url'] = $this->ajax_url;
$this->attributes['data-nonce'] = $this->nonce;
if (!empty($this->extra_args)) {
$this->attributes['data-extra-args'] = $this->extra_args;
}
}
/**
* Render the post select element
*
* Outputs a native select that will be enhanced by JavaScript for search/AJAX.
* Falls back to a working select if JavaScript is disabled (with initial options).
*/
public function render() {
$this->applyAriaAttributes();
// Get current value
$value = '';
if (isset($this->attributes['value'])) {
$value = is_array($this->attributes['value']) ? reset($this->attributes['value']) : $this->attributes['value'];
}
// Store selected value for AJAX to include in first page
if (!empty($value)) {
$this->attributes['data-selected'] = $value;
}
// Generate unique ID for this element (access attributes array directly)
$id = isset($this->attributes['id']) ? $this->attributes['id'] : '';
if (empty($id)) {
$id = 'pfbc-post-select-' . uniqid();
$this->attributes['id'] = $id;
}
// Start rendering
echo '
';
// Native select element (will be hidden when JS enhances it)
echo '';
// Hidden data attributes for JS
echo 'extra_args)) {
echo ' data-extra-args="', esc_attr($this->extra_args), '"';
}
if (!empty($value)) {
echo ' data-selected="', esc_attr($value), '"';
}
echo ' />';
echo '
';
}
/**
* Get the post type for this select
*
* @return string
*/
public function getPostType() {
return $this->post_type;
}
/**
* Get the post type actually queried, honoring the post_type override
* that extra_args may contain (mirrors accua_forms_ajax_get_posts()).
*
* @since 2.2.27
* @return string
*/
public function getEffectivePostType() {
if (!empty($this->extra_args)) {
$extra = array();
wp_parse_str($this->extra_args, $extra);
if (!empty($extra['post_type'])) {
$override = sanitize_text_field($extra['post_type']);
$valid_post_types = get_post_types(array('public' => true));
if (isset($valid_post_types[$override])) {
return $override;
}
}
}
return $this->post_type;
}
/**
* Get the post statuses this field may expose, honoring an explicit
* post_status in extra_args (limited to publish/private).
*
* @since 2.2.27
* @return array
*/
public function getAllowedPostStatuses() {
if (!empty($this->extra_args) && function_exists('accua_forms_filter_field_post_status')) {
$extra = array();
wp_parse_str($this->extra_args, $extra);
if (!empty($extra['post_status'])) {
$statuses = accua_forms_filter_field_post_status($extra['post_status']);
if (!empty($statuses)) {
return $statuses;
}
}
}
return array('publish');
}
/**
* Get the extra query arguments
*
* @return string
*/
public function getExtraArgs() {
return $this->extra_args;
}
}
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped