array( __( 'Smaller images. Same originals.', 'affstackdev-image-manager' ), __( 'Prepare optimized copies, review the results, and choose how your site delivers them.', 'affstackdev-image-manager' ) ), 'library' => array( __( 'Your media, organized.', 'affstackdev-image-manager' ), __( 'Browse, organize, and edit your media from one familiar workspace.', 'affstackdev-image-manager' ) ), 'backups' => array( __( 'Backups you control.', 'affstackdev-image-manager' ), __( 'Create portable media backups and manage your connected storage.', 'affstackdev-image-manager' ) ), 'settings' => array( __( 'Set your image workflow.', 'affstackdev-image-manager' ), __( 'Choose your quality, discovery, and delivery settings.', 'affstackdev-image-manager' ) ), 'tools' => array( __( 'Image Manager tools', 'affstackdev-image-manager' ), __( 'Review system status, encoder support, and background processing.', 'affstackdev-image-manager' ) ), 'ai' => array( __( 'AI assistants', 'affstackdev-image-manager' ), __( 'Let an AI app read Image Manager and propose changes you approve.', 'affstackdev-image-manager' ) ), ); $extra = Hooks::sections(); foreach ( $extra as $key => $tab ) { $copy[ $key ] = array_values( $tab['heading'] ); } $section = isset( $copy[ $section ] ) ? $section : 'optimize'; $library_url = $library_url ?: Admin::url( 'images', array( 'im_media_view' => 'library' ) ); $links = array( 'library' => array( __( 'Library', 'affstackdev-image-manager' ), $library_url ), 'optimize' => array( __( 'Optimize', 'affstackdev-image-manager' ), Admin::url( 'optimize' ) ), 'backups' => array( __( 'Backups', 'affstackdev-image-manager' ), Admin::url( 'backups' ) ), 'settings' => array( __( 'Settings', 'affstackdev-image-manager' ), Admin::url( 'settings' ) ), 'tools' => array( __( 'Tools', 'affstackdev-image-manager' ), Admin::url( 'tools' ) ), 'ai' => array( __( 'AI assistants', 'affstackdev-image-manager' ), Admin::url( 'ai' ) ), ); foreach ( $extra as $key => $tab ) { $links[ $key ] = array( $tab['label'], Admin::url( $key ) ); } $plain = array_merge( array( 'ai' ), array_keys( $extra ) ); // Tabs that load as a whole page. $action_url = 'library' === $section ? Admin::url( 'optimize' ) : $library_url; $action_label = 'library' === $section ? __( 'Optimize images', 'affstackdev-image-manager' ) : __( 'Open library', 'affstackdev-image-manager' ); if ( $embedded ) { // D-214 (F-SUITE-03): inside the Suite its own heading card names the product, its description and version, so // Image Manager prints only its header button there, in its own look; on its own page it keeps the full header. echo '
'; self::action_button( $section, $action_url, $action_label ); echo '
'; } else { echo '

' . esc_html__( 'AFFSTACKDEV / IMAGE MANAGER', 'affstackdev-image-manager' ) . '

' . esc_html( $copy[ $section ][0] ) . '

' . esc_html( $copy[ $section ][1] ) . '

'; echo '
' . esc_html( 'v' . RELEASE_LABEL ) . ''; self::action_button( $section, $action_url, $action_label ); echo '
'; } echo '
' . esc_html__( 'Sections', 'affstackdev-image-manager' ) . '' . esc_html( $links[ $section ][0] ) . '
'; if ( isset( $extra[ $section ]['intro'] ) && is_callable( $extra[ $section ]['intro'] ) ) { call_user_func( $extra[ $section ]['intro'] ); } } /** * Print the header's button: the library from the other tabs, Optimize from the library. * * @param string $section The tab being shown. * @param string $url The button's address. * @param string $label The button's text. */ private static function action_button( string $section, string $url, string $label ): void { echo '' . esc_html( $label ) . ''; } /** * Print the tab links, the active tab marked. * * @param array $links Tab key => array( label, address ). * @param string $active The active tab's key. * @param array $plain The tabs that load as a whole page (no data-im-nav). */ private static function links( array $links, string $active, array $plain ): void { foreach ( $links as $key => $link ) { echo '' . esc_html( $link[0] ) . ''; } } /** * The tags and attributes Image Manager's screens print, for wp_kses() where HTML a helper built (escaping each * value as it went) is printed. Every element keeps its classes, IDs, data-* and ARIA attributes. * * @return array Tag => its allowed attributes. */ public static function allowed_html(): array { static $allowed = null; if ( null !== $allowed ) { return $allowed; } $global = array_fill_keys( array( 'class', 'id', 'title', 'role', 'hidden', 'tabindex', 'style', 'lang', 'dir', 'data-*', 'aria-atomic', 'aria-busy', 'aria-checked', 'aria-controls', 'aria-current', 'aria-describedby', 'aria-disabled', 'aria-expanded', 'aria-haspopup', 'aria-hidden', 'aria-invalid', 'aria-label', 'aria-labelledby', 'aria-live', 'aria-modal', 'aria-pressed', 'aria-relevant', 'aria-required', 'aria-selected', 'aria-sort', 'aria-valuemax', 'aria-valuemin', 'aria-valuenow', 'aria-valuetext', ), true ); $tags = array( 'a' => array( 'href', 'target', 'rel', 'download', 'hreflang', 'type', ), 'abbr' => array(), 'article' => array(), 'aside' => array(), 'b' => array(), 'br' => array(), 'button' => array( 'type', 'name', 'value', 'disabled', 'form', 'formaction', 'formmethod', 'formenctype', 'formtarget', 'autofocus', ), 'caption' => array(), 'code' => array(), 'dd' => array(), 'del' => array( 'datetime', 'cite', ), 'details' => array( 'open', ), 'div' => array(), 'dl' => array(), 'dt' => array(), 'em' => array(), 'fieldset' => array( 'disabled', 'form', 'name', ), 'figcaption' => array(), 'figure' => array(), 'footer' => array(), 'form' => array( 'action', 'method', 'enctype', 'target', 'novalidate', 'accept-charset', 'autocomplete', 'name', ), 'h1' => array(), 'h2' => array(), 'h3' => array(), 'h4' => array(), 'header' => array(), 'hr' => array(), 'i' => array(), 'img' => array( 'src', 'srcset', 'sizes', 'width', 'height', 'alt', 'loading', 'decoding', 'fetchpriority', ), 'input' => array( 'type', 'name', 'value', 'checked', 'disabled', 'readonly', 'required', 'min', 'max', 'step', 'maxlength', 'minlength', 'size', 'placeholder', 'pattern', 'multiple', 'accept', 'autocomplete', 'autofocus', 'form', 'list', 'inputmode', 'webkitdirectory', 'directory', 'spellcheck', ), 'ins' => array( 'datetime', 'cite', ), 'kbd' => array(), 'label' => array( 'for', 'form', ), 'legend' => array(), 'li' => array( 'value', ), 'mark' => array(), 'meter' => array( 'value', 'min', 'max', 'low', 'high', 'optimum', ), 'nav' => array(), 'ol' => array( 'start', 'reversed', 'type', ), 'optgroup' => array( 'label', 'disabled', ), 'option' => array( 'value', 'selected', 'disabled', 'label', ), 'output' => array( 'for', 'form', 'name', ), 'p' => array(), 'picture' => array(), 'pre' => array(), 'progress' => array( 'value', 'max', ), 'q' => array( 'cite', ), 's' => array(), 'section' => array(), 'select' => array( 'name', 'multiple', 'required', 'disabled', 'size', 'form', 'autocomplete', ), 'small' => array(), 'source' => array( 'src', 'srcset', 'sizes', 'type', 'media', 'width', 'height', ), 'span' => array(), 'strong' => array(), 'sub' => array(), 'summary' => array(), 'sup' => array(), 'table' => array(), 'tbody' => array(), 'td' => array( 'colspan', 'rowspan', 'headers', ), 'textarea' => array( 'name', 'rows', 'cols', 'maxlength', 'minlength', 'placeholder', 'required', 'readonly', 'disabled', 'form', 'autocomplete', 'wrap', 'spellcheck', ), 'tfoot' => array(), 'th' => array( 'colspan', 'rowspan', 'headers', 'scope', 'abbr', ), 'thead' => array(), 'time' => array( 'datetime', ), 'tr' => array(), 'u' => array(), 'ul' => array(), ); $allowed = array(); foreach ( $tags as $tag => $own ) { $allowed[ $tag ] = $global + array_fill_keys( $own, true ); } return $allowed; } }