page_layout_aside_meta_box(); $meta_boxes[] = $this->disable_page_card_style_meta_box(); $meta_boxes[] = $this->post_meta_box(); return apply_filters( 'blogsy_metaboxes_settings', $meta_boxes ); } /** * Register metaboxes natively. * * @since 1.0.0 */ public function add_meta_boxes(): void { foreach ( $this->get_meta_boxes() as $metabox ) { if ( empty( $metabox['id'] ) || empty( $metabox['title'] ) || empty( $metabox['pages'] ) ) { continue; } foreach ( (array) $metabox['pages'] as $post_type ) { add_meta_box( $metabox['id'], $metabox['title'], function ( $post ) use ( $metabox ): void { $this->render_meta_box_fields( $metabox, $post ); }, $post_type, $metabox['context'] ?? 'advanced', $metabox['priority'] ?? 'default' ); } } } /** * Render metabox fields. * * @param array $metabox Metabox settings. * @param \WP_Post $post Current post object. * @since 1.0.0 */ public function render_meta_box_fields( array $metabox, \WP_Post $post ): void { wp_nonce_field( 'blogsy_save_metabox_' . $metabox['id'], 'blogsy_metabox_nonce_' . $metabox['id'] ); if ( empty( $metabox['fields'] ) ) { return; } echo '
'; foreach ( $metabox['fields'] as $field ) { $value = get_post_meta( $post->ID, $field['id'], true ); $this->render_field( $field, $value ); } echo '
'; } /** * Render a single field. * * @param array $field Field settings. * @param mixed $value Current value of the field. * @since 1.0.0 * @todo Add more field types and validation. */ public function render_field( array $field, $value ): void { $id = esc_attr( $field['id'] ); $name = esc_attr( $field['id'] ); $label = empty( $field['name'] ) ? '' : $field['name']; $desc = empty( $field['desc'] ) ? '' : '

' . $field['desc'] . '

'; $type = empty( $field['type'] ) ? 'text' : $field['type']; // Add data attributes for conditional display. $data_attrs = ''; if ( ! empty( $field['require'] ) && is_array( $field['require'] ) ) { foreach ( $field['require'] as $cond_key => $cond_val ) { $data_attrs .= ' data-require-' . esc_attr( $cond_key ) . '="' . esc_attr( $cond_val ) . '"'; } } echo '
'; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped if ( 'checkbox' !== $type && 'heading' !== $type && $label ) { echo '
'; } switch ( $type ) { case 'text': default: echo ''; break; case 'textarea': echo ''; break; case 'checkbox': echo ''; break; case 'select': echo ''; break; case 'heading': echo '

' . esc_html( $label ) . '

'; break; case 'image': // Simple image upload (single image). $img = $value ? wp_get_attachment_image( $value, 'thumbnail' ) : ''; echo '
' . wp_kses( $img, [ 'img' => [ 'src' => [] ] ] ) . '
'; echo ''; echo ''; break; case 'gallery': case 'image_advanced': // Multiple images. $ids = is_array( $value ) ? $value : ( $value ? explode( ',', $value ) : [] ); echo ''; echo ''; echo ''; break; } echo wp_kses( $desc, [ 'p' => [ 'class' => [] ] ] ); echo '
'; } /** * Save metabox fields. * * @param int $post_id Post ID. * @since 1.0.0 */ public function save_meta_boxes( int $post_id ): void { // Check autosave, revision, permissions. if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; } if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { return; } if ( wp_is_post_revision( $post_id ) ) { return; } foreach ( $this->get_meta_boxes() as $metabox ) { if ( ! isset( $_POST[ 'blogsy_metabox_nonce_' . $metabox['id'] ] ) ) { continue; } if ( ! wp_verify_nonce( $_POST[ 'blogsy_metabox_nonce_' . $metabox['id'] ], 'blogsy_save_metabox_' . $metabox['id'] ) ) { continue; } if ( empty( $metabox['fields'] ) ) { continue; } foreach ( $metabox['fields'] as $field ) { $field_id = $field['id']; $type = empty( $field['type'] ) ? 'text' : $field['type']; if ( ! isset( $_POST[ $field_id ] ) ) { if ( 'checkbox' === $type ) { update_post_meta( $post_id, $field_id, '0' ); } continue; } $new_value = $_POST[ $field_id ]; if ( 'gallery' === $type || 'image_advanced' === $type ) { // Save as comma separated IDs. $new_value = is_array( $new_value ) ? implode( ',', $new_value ) : sanitize_text_field( $new_value ); } elseif ( 'checkbox' === $type ) { $new_value = '1'; } else { $new_value = sanitize_text_field( $new_value ); } update_post_meta( $post_id, $field_id, $new_value ); } } } /** * Page Layout Aside Meta Box. * * @since 1.0.0 */ public function page_layout_aside_meta_box(): array { return [ 'id' => 'blogsy_page_layout_meta_box', 'title' => esc_html__( 'Page Layout', 'blogsy' ), 'pages' => [ 'post', 'page' ], 'context' => 'side', 'priority' => 'high', 'fields' => [ [ 'name' => esc_html__( 'Page Layout', 'blogsy' ), 'id' => 'blogsy_page_sidebar', 'type' => 'select', 'options' => [ '0' => esc_html__( 'Default', 'blogsy' ), 'left' => esc_html__( 'Left Sidebar', 'blogsy' ), 'right' => esc_html__( 'Right Sidebar', 'blogsy' ), 'none' => esc_html__( 'No Sidebar', 'blogsy' ), 'none-narrow' => esc_html__( 'No Sidebar + Narrow Content', 'blogsy' ), ], ], ], ]; } /** * Disable Page Card Style Meta Box. * * @since 1.0.0 */ public function disable_page_card_style_meta_box(): array { return [ 'id' => 'blogsy_disable_page_card_style_meta_box', 'title' => esc_html__( 'Page Card Style', 'blogsy' ), 'pages' => [ 'page' ], 'context' => 'side', 'priority' => 'high', 'fields' => [ [ 'name' => esc_html__( 'Disable Page Card Style', 'blogsy' ), 'id' => 'blogsy_disable_page_card_style', 'type' => 'checkbox', 'desc' => esc_html__( 'Check to disable the page card style for this page.', 'blogsy' ), ], [ 'name' => esc_html__( 'Disable Page Title', 'blogsy' ), 'id' => 'blogsy_disable_page_title', 'type' => 'checkbox', 'desc' => esc_html__( 'Check to disable the page title for this page.', 'blogsy' ), ], ], ]; } /** * Post Meta Box. * * @since 1.0.0 */ public function post_meta_box(): array { return [ 'id' => 'blogsy_post_meta_box', 'title' => esc_html__( 'Post Hero Section Settings', 'blogsy' ), 'pages' => [ 'post' ], 'context' => 'normal', 'priority' => 'high', 'fields' => [ [ 'name' => esc_html__( 'Standard Post Format:', 'blogsy' ), 'id' => 'blogsy_title_standard_format', 'type' => 'heading', 'desc' => esc_html__( 'Settings for standard post format', 'blogsy' ), 'require' => [ 'post_format' => 'standard' ], ], [ 'name' => esc_html__( 'Post Hero Layout', 'blogsy' ), 'id' => 'blogsy_single_post_layout', 'type' => 'select', 'options' => blogsy_get_single_post_hero_layouts( 2, true ), 'require' => [ 'post_format' => 'standard' ], ], ], ]; } }