[]]), ]; } public function sanitizeValue($value, array $field) { // The id of an attachment. Anything else (an id that is gone, text) becomes empty, without a PHP warning. $meta = get_post_meta((int) $value); if (! empty($meta['_wp_attachment_metadata']) || ! empty($meta['_wp_attached_file'])) { return $value; } return ''; } public function usesAssets(): bool { return true; } public function enqueue(array $field): void { wp_enqueue_media(); // Versioned by file date (like ColorPicker), not by the plugin version: a changed script under an // unchanged plugin version would otherwise keep being served from the browser cache. wp_enqueue_script( Plugin::PREFIX . 'file-js', Plugin::assetsUrl() . 'js/' . Plugin::PREFIX . 'file.js', ['wp-i18n'], Enqueue::version('js/' . Plugin::PREFIX . 'file.js'), 'all' ); Enqueue::scriptTranslations(Plugin::PREFIX . 'file-js'); wp_enqueue_style( Plugin::PREFIX . 'file-css', Plugin::assetsUrl() . 'css/' . Plugin::PREFIX . 'file.css', [], Enqueue::version('css/' . Plugin::PREFIX . 'file.css'), 'all' ); } /** * A link to the file with its title as text (`text="..."` for another text); only the URL with `link="0"`. */ public function displayValue($value, array $field, array $args): string { $id = Display::attachmentId($value); $url = $id ? (string) wp_get_attachment_url($id) : ''; if ($url === '') { return ''; } if (in_array($args['link'] ?? '', ['0', 'no', 'false'], true)) { return esc_html($url); } return Display::link($url, ($args['text'] ?? '') !== '' ? (string) $args['text'] : get_the_title($id)); } public function bindingValue($value, array $field, string $attribute): ?string { $id = Display::attachmentId($value); if ($id === 0) { return null; } switch ($attribute) { case 'url': return (string) wp_get_attachment_url($id); case 'title': return get_the_title($id); case 'id': return (string) $id; case 'content': case 'text': return $this->displayValue($value, $field, []); } return null; } public function render(array $field, $value): void { // Like the image field, the name is printed hidden either way (see aop-file.js): the script decides // whether to show it, so there is exactly one place ("is a file chosen?") that makes that call. $filename = $value ? basename((string) get_attached_file((int) $value)) : ''; printf('
', esc_attr(Plugin::PREFIX) . 'file-wrapper'); printf( '
%s
', esc_attr(Plugin::PREFIX) . 'file-preview-wrapper hidden', esc_attr(Plugin::PREFIX) . 'file-preview-name', esc_html($filename) ); printf( '
', esc_attr(Plugin::PREFIX) . 'upload-file', 'button ' . esc_attr(Plugin::PREFIX) . 'upload-file__button', esc_html__('Upload', 'admin-options-pages'), esc_attr($this->mediaTypes($field['extensions'])), // The "Upload files" tab of the media modal does not read `library.type` (that only filters the // "Media Library" tab's query); aop-file.js uses this to restrict it too, via a plupload extension // filter, which matches by file extension rather than by mime type. esc_attr($this->extensionList($field['extensions'])) ); printf( '', esc_attr($field['field_name']), esc_attr($value), esc_attr(Plugin::PREFIX) . 'file-attachment' ); printf( '
%s
', esc_attr(Plugin::PREFIX) . 'delete-file hidden', 'javascript:;', esc_attr(Plugin::PREFIX) . 'delete-file__link', esc_html__('Delete', 'admin-options-pages') ); print('
'); print(wp_kses_post($this->descriptionHtml($field['description'] ?? ''))); } /** * @param array $extensions The stored `extensions` setting: ['types' => ['pdf' => 'on', ...]]. */ private function mediaTypes($extensions): string { $list = Collection::make([ 'pdf' => 'application/pdf', 'doc' => 'application/msword', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'xls' => 'application/vnd.ms-excel', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'csv' => 'text/csv', 'zip' => 'application/zip', 'txt' => 'text/plain' ]); return implode(', ', $list->only($this->selectedExtensions($extensions))->flip()->keys()->all()); } /** * @param array $extensions The stored `extensions` setting: ['types' => ['pdf' => 'on', ...]]. */ private function extensionList($extensions): string { return implode(',', $this->selectedExtensions($extensions)); } /** * @param array $extensions The stored `extensions` setting: ['types' => ['pdf' => 'on', ...]]. * * @return array */ private function selectedExtensions($extensions): array { return Collection::make(Collection::make($extensions)->get('types')) ->keys() ->all(); } }