$v) { $out[$k] = $v; if ($k === 'title') { // The shortcode has to be copyable from the list screen — that is the step from the admin to the front // end, and hiding it inside the edit screen costs one more click $out['aumframe_shortcode'] = __('Shortcode', 'aumframe'); $out['aumframe_entries'] = __('Inquiries', 'aumframe'); } } return $out; } public static function column(string $col, int $post_id): void { if ($col === 'aumframe_shortcode') { /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- The format string is a literal; its only replacement is cast by %d, and $post_id is an int in this method's signature. */ printf('[aumframe_form id="%1$d"]', $post_id); } if ($col === 'aumframe_entries') { $n = Inbox::count($post_id); $url = add_query_arg('form', $post_id, EntriesPage::url()); /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Both replacements are escaped: %s is esc_url($url), and %d takes $n from Inbox::count(): int. */ printf('%d', esc_url($url), $n); } } public static function assets(string $hook): void { $screen = get_current_screen(); if (!$screen || $screen->post_type !== Store::POST_TYPE) { return; } $base = AUMFRAME_URL . 'assets/forms/'; $dir = AUMFRAME_DIR . 'assets/forms/'; wp_enqueue_style('aumframe-form-admin', $base . 'form-admin.css', [], @filemtime($dir . 'form-admin.css') ?: null); wp_enqueue_script('aumframe-form-admin', $base . 'form-admin.js', [], @filemtime($dir . 'form-admin.js') ?: null, true); // The source list for dynamic options: whatever is genuinely registered on the site, so nobody has to // type an identifier $sources = ['post_type' => [], 'taxonomy' => []]; foreach (get_post_types(['public' => true], 'objects') as $pt) { if ($pt->name === 'attachment') { continue; } $sources['post_type'][] = ['name' => $pt->name, 'label' => $pt->labels->name ?? $pt->name]; } foreach (get_taxonomies(['public' => true], 'objects') as $tx) { if ($tx->name === 'post_format') { continue; } $sources['taxonomy'][] = ['name' => $tx->name, 'label' => $tx->labels->name ?? $tx->name]; } wp_add_inline_script('aumframe-form-admin', 'window.AUMFRAME_FORM_ADMIN = ' . wp_json_encode([ 'types' => array_map( static fn($k, $v) => ['value' => $k, 'label' => $v['label'], 'options' => !empty($v['options'])], array_keys(Fields::types()), Fields::types() ), 'sources' => $sources, /* * Every piece of the field editor's interface copy is emitted here, with no literals left in the JS. * * Through wp_localize rather than attaching wp-i18n to the theme's script: the theme's translations * are a single .mo, while `wp_set_script_translations` wants a separate per-script JSON — maintaining * a second translation chain for one field editor is not worth it. * Coming from PHP has another benefit: `wp i18n make-pot` scans PHP anyway. */ 'i18n' => [ 'newField' => __('New field', 'aumframe'), 'confirmDel' => __('Delete this field? Inquiries already received are not affected.', 'aumframe'), 'dragSort' => __('Drag to reorder', 'aumframe'), 'fieldName' => __('Field name', 'aumframe'), 'required' => __('Required', 'aumframe'), 'widthFull' => __('Full width', 'aumframe'), 'widthHalf' => __('Half width', 'aumframe'), 'more' => __('More', 'aumframe'), 'remove' => __('Delete', 'aumframe'), 'placeholder' => __('Placeholder', 'aumframe'), 'help' => __('Help text', 'aumframe'), 'slug' => __('Identifier', 'aumframe'), 'slugHint' => __('The name it is submitted under. Changing it affects any email template that already uses it.', 'aumframe'), 'optSource' => __('Options from', 'aumframe'), 'optManual' => __('Typed in by hand', 'aumframe'), 'postTypes' => __('Content types', 'aumframe'), 'taxonomies' => __('Taxonomies', 'aumframe'), 'sourceHint' => __('Pick a content type and the options follow the site’s content automatically.', 'aumframe'), 'optsLabel' => __('Options (one per line)', 'aumframe'), 'defaultVal' => __('Default value', 'aumframe'), ], ]) . ';', 'before'); } public static function meta_boxes(): void { add_meta_box( 'aum-form-fields', __('Fields', 'aumframe'), [self::class, 'render_fields'], Store::POST_TYPE, 'normal', 'high' ); add_meta_box( 'aum-form-settings', __('Submission & notifications', 'aumframe'), [self::class, 'render_settings'], Store::POST_TYPE, 'normal', 'default' ); add_meta_box( 'aum-form-usage', __('How to use it', 'aumframe'), [self::class, 'render_usage'], Store::POST_TYPE, 'side', 'high' ); } public static function render_usage(\WP_Post $post): void { $n = Inbox::count($post->ID); ?>

[aumframe_form id="ID; ?>"]


ID, 'aumframe_form_meta_nonce'); $fields = Store::fields($post->ID); ?>

ID); $admin_email = get_option('admin_email'); $fields = Store::fields($post->ID); ?>

>