{
  "schema_version": 1,
  "plugin_id": "plugin:affstackdev-image-manager/affstackdev-image-manager.php",
  "version": "1.9.0",
  "summary": "Complete current Image Manager media organization, optimization, delivery, editing, replacement, portable/cloud recovery, protected updates and native reviewed-action contracts.",
  "features": [
    {
      "id": "inspect",
      "title": "Read Image Manager state",
      "description": "Read current permitted state and readiness. No media, settings or job changes."
    },
    {
      "id": "settings_update",
      "title": "Change image settings",
      "description": "Save the exact changed settings; advance publication generation. Delivery can change newly rendered public output; automatic processing can schedule future work."
    },
    {
      "id": "scan_start",
      "title": "Scan public image sources",
      "description": "Start a bounded public site scan and save progress. Public page HTTP requests and local source indexing follow; scan-only leaves delivery switches unchanged."
    },
    {
      "id": "optimization_start",
      "title": "Start an optimization run",
      "description": "Scan the enabled public sources, freeze the selected images and queue the exact compression/size recipe. Apply mode publishes validated copies; review mode leaves comparisons for later approval. Originals remain unchanged."
    },
    {
      "id": "workflow_pause",
      "title": "Pause image work",
      "description": "Pause before the next image operation and invalidate stale publication; prepared copies remain."
    },
    {
      "id": "workflow_resume",
      "title": "Resume image work",
      "description": "Resume saved image work and scheduling."
    },
    {
      "id": "workflow_cancel",
      "title": "Stop image run",
      "description": "Cancel the saved run and hold queued work; prepared copies and original files remain."
    },
    {
      "id": "workflow_advance",
      "title": "Process image work here",
      "description": "Perform one native bounded batch; local files, indexing and public page checks can advance. Saved work and pause state govern eligibility."
    },
    {
      "id": "background_check",
      "title": "Check background scheduling",
      "description": "Queue an independent native scheduling probe. Queued is distinct from independently executed."
    },
    {
      "id": "codec_check",
      "title": "Check local encoders",
      "description": "Run native local encoder self-checks and save host capability results."
    },
    {
      "id": "comparison_prepare",
      "title": "Queue a compression comparison",
      "description": "Queue comparison files without changing delivery."
    },
    {
      "id": "comparison_apply",
      "title": "Approve prepared compression copies",
      "description": "Publish the exact ready copies after source and output checksum validation; delivery switches remain."
    },
    {
      "id": "comparison_discard",
      "title": "Discard compression comparison",
      "description": "Retire the selected candidate files while retaining approved copies and originals."
    },
    {
      "id": "source_optimize",
      "title": "Queue image optimization",
      "description": "Queue image optimization through the source repository; originals are retained."
    },
    {
      "id": "source_retry",
      "title": "Retry saved image policy",
      "description": "Retry saved image policy through the source repository; originals are retained."
    },
    {
      "id": "source_exclude",
      "title": "Exclude images",
      "description": "Exclude images through the source repository; originals are retained."
    },
    {
      "id": "source_include",
      "title": "Include images again",
      "description": "Include images again through the source repository; originals are retained."
    },
    {
      "id": "source_original",
      "title": "Use original delivery",
      "description": "Disable each selected source delivery switch. Cached pages retain their prior output until cleared."
    },
    {
      "id": "source_optimized",
      "title": "Allow optimized delivery",
      "description": "Enable each source delivery switch; global delivery and public eligibility still govern output."
    },
    {
      "id": "source_cleanup",
      "title": "Remove managed copies",
      "description": "Delete managed alternatives only with global delivery disabled. Clear page/CDN caches before removing files; originals are retained."
    },
    {
      "id": "bulk_run",
      "title": "Run a frozen image bulk selection",
      "description": "Freeze the native selected/page/all-matching source set and queue the chosen operation. The approved selection fingerprint is checked again under the owner lock; later discoveries are not silently added."
    },
    {
      "id": "folder_create",
      "title": "Create a folder",
      "description": "Create a virtual organization label. File paths, URLs and media IDs remain."
    },
    {
      "id": "folder_rename",
      "title": "Rename a folder",
      "description": "Rename a virtual label."
    },
    {
      "id": "folder_delete",
      "title": "Delete a folder",
      "description": "Delete the organization label and its relationships; attachments and files remain. Child folders follow native WordPress term deletion behavior."
    },
    {
      "id": "folder_add",
      "title": "Add media folder membership",
      "description": "Change the exact virtual membership; set replaces the selected taxonomy memberships and an empty set clears them. Paths and attachment IDs remain."
    },
    {
      "id": "folder_remove",
      "title": "Remove media folder membership",
      "description": "Change the exact virtual membership; set replaces the selected taxonomy memberships and an empty set clears them. Paths and attachment IDs remain."
    },
    {
      "id": "folder_set",
      "title": "Set media folder membership",
      "description": "Change the exact virtual membership; set replaces the selected taxonomy memberships and an empty set clears them. Paths and attachment IDs remain."
    },
    {
      "id": "collection_create",
      "title": "Create a collection",
      "description": "Create a virtual organization label. File paths, URLs and media IDs remain."
    },
    {
      "id": "collection_rename",
      "title": "Rename a collection",
      "description": "Rename a virtual label."
    },
    {
      "id": "collection_delete",
      "title": "Delete a collection",
      "description": "Delete the organization label and its relationships; attachments and files remain. Child folders follow native WordPress term deletion behavior."
    },
    {
      "id": "collection_add",
      "title": "Add media collection membership",
      "description": "Change the exact virtual membership; set replaces the selected taxonomy memberships and an empty set clears them. Paths and attachment IDs remain."
    },
    {
      "id": "collection_remove",
      "title": "Remove media collection membership",
      "description": "Change the exact virtual membership; set replaces the selected taxonomy memberships and an empty set clears them. Paths and attachment IDs remain."
    },
    {
      "id": "collection_set",
      "title": "Set media collection membership",
      "description": "Change the exact virtual membership; set replaces the selected taxonomy memberships and an empty set clears them. Paths and attachment IDs remain."
    },
    {
      "id": "metadata_update",
      "title": "Change media metadata",
      "description": "Save supplied title, caption and image alternative text, including explicit empty values. Omitted fields remain. Existing page-specific alternative text is not rewritten; native WordPress hooks run."
    },
    {
      "id": "media_upload",
      "title": "Upload securely staged media",
      "description": "Create WordPress attachments from one to eight human-staged files, generate native metadata and assign the approved folder. Normal upload hooks and enabled future-upload processing may run. Native automatic context-folder hooks run; an explicit reviewed folder choice takes priority."
    },
    {
      "id": "edit_prepare",
      "title": "Prepare a private image edit",
      "description": "Render a private draft using rotation, flip, crop then a resize to the width and height given, larger or smaller (an enlargement at most 16,384 pixels a side and 24 megapixels). Replace the prior draft; the original and public uses remain unchanged."
    },
    {
      "id": "edit_save",
      "title": "Save edited copy",
      "description": "Create a separate attachment with inherited text and organization, native sizes and edit lineage; remove the private draft."
    },
    {
      "id": "edit_discard",
      "title": "Discard image edit",
      "description": "Delete only the selected private edit draft."
    },
    {
      "id": "pdf_prepare",
      "title": "Prepare a PDF page image",
      "description": "Render one selected PDF page locally to a private white-background PNG draft. Host Imagick/PDF policy governs readiness; PDF remains unchanged."
    },
    {
      "id": "pdf_save",
      "title": "Save a converted PDF page",
      "description": "Create one PNG attachment with native sizes and organization from the exact draft; the source PDF remains unchanged."
    },
    {
      "id": "pdf_discard",
      "title": "Discard PDF page preview",
      "description": "Delete the private page conversion preview."
    },
    {
      "id": "pdf_copy_prepare",
      "title": "Prepare a smaller copy of a PDF",
      "description": "1.9.0, where the host's Ghostscript passed its self-test: a private smaller copy of one PDF (quality: pictures kept up to 300 dpi, colours unchanged; small: pictures up to 150 dpi, compressed again), kept only when it is smaller by the minimum saving and has the same pages, text, links, comments and titles, each page drawn at 36 dpi alike (an average difference of at most 10 of 255 per colour, at most one pixel in 5,000 changed by more than half in a colour). A PDF with a password, form fields, a signature, attachments, scripts, layers or multimedia is refused. The PDF remains unchanged."
    },
    {
      "id": "pdf_copy_save",
      "title": "Save a smaller copy of a PDF",
      "description": "Create one new PDF attachment (name-smaller.pdf, the title with “(smaller copy)”) from the exact prepared copy, with the source's caption, description, folders and collections; the source PDF remains unchanged."
    },
    {
      "id": "pdf_copy_discard",
      "title": "Discard a smaller PDF preview",
      "description": "Delete the private smaller PDF preview."
    },
    {
      "id": "replace_prepare",
      "title": "Prepare a replacement preview",
      "description": "Stage the human-supplied same-type image as a private replacement draft after source validation; the live attachment remains unchanged."
    },
    {
      "id": "replace_apply",
      "title": "Apply media replacement",
      "description": "Create a verified recovery ZIP and new native file family, then point the same attachment ID at the new files. New URLs affect attachment-based uses; hardcoded URLs and caches require separate review."
    },
    {
      "id": "replace_undo",
      "title": "Undo media replacement",
      "description": "Restore the latest verified previous file family and metadata. The replacement files are retained; hardcoded content URLs are not rewritten."
    },
    {
      "id": "replace_recover",
      "title": "Recover media replacement",
      "description": "Explicitly recover a partially applied replacement to the verified before family. This is a new reviewed compensating intent; automatic reconciliation never invokes it."
    },
    {
      "id": "replace_discard",
      "title": "Discard media replacement",
      "description": "Delete only the selected private replacement draft; applying drafts cannot be discarded."
    },
    {
      "id": "backup_start",
      "title": "Create a portable media backup",
      "description": "Freeze eligible attachment IDs and package portable media, text, organization and checksums. Published profile includes approved derivative files. Remote destination queues a transfer after verification; retention and local-copy settings can remove older backup copies."
    },
    {
      "id": "backup_pause",
      "title": "Pause local backup",
      "description": "Pause the current backup while retaining saved staging."
    },
    {
      "id": "backup_resume",
      "title": "Resume local backup",
      "description": "Resume the saved backup."
    },
    {
      "id": "backup_cancel",
      "title": "Cancel local backup",
      "description": "Stop the incomplete job and remove its staging; existing media and completed snapshots remain."
    },
    {
      "id": "backup_advance",
      "title": "Advance local backup",
      "description": "Perform one bounded native backup batch and verify completed archive entries; completion may queue the configured remote transfer."
    },
    {
      "id": "backup_delete",
      "title": "Delete a local snapshot",
      "description": "Delete that local archive and sidecars plus its index record; attachments remain."
    },
    {
      "id": "backup_restore",
      "title": "Selectively restore media",
      "description": "Restore the exact verified original, native metadata and organization. New mode allocates a new attachment; same-site in-place creates a safety recovery point before changing the editable existing attachment. Page/product relationships are not rewritten."
    },
    {
      "id": "backup_import",
      "title": "Import a human-staged portable ZIP",
      "description": "Validate archive names, manifest, counts and checksums, then add a private local snapshot for inspection. This action does not restore attachments."
    },
    {
      "id": "remote_settings_update",
      "title": "Change backup destination settings",
      "description": "Preserve omitted settings and credentials; save supplied fields and reschedule. Changing Google app identity invalidates its saved connection; changing S3 identity invalidates its verification. Retention prunes older destination copies after future verified uploads; keep-local false removes completed local copies after verified transfers."
    },
    {
      "id": "remote_google_disconnect",
      "title": "Disconnect Google Drive",
      "description": "Clear the local Drive refresh token, folder identity and connection time; remote files remain."
    },
    {
      "id": "remote_s3_test",
      "title": "Test the S3 destination",
      "description": "PUT a temporary private object, HEAD its size/checksum and attempt its deletion. Record readiness only after the owner check; report incomplete cleanup instead of verified success."
    },
    {
      "id": "remote_upload",
      "title": "Queue a local snapshot transfer",
      "description": "Queue a transfer of the verified local ZIP to the current ready destination. Transfer completion, retention pruning and configured local-copy removal happen through the native worker."
    },
    {
      "id": "remote_pause",
      "title": "Pause remote transfer",
      "description": "Pause saved transfer progress."
    },
    {
      "id": "remote_resume",
      "title": "Resume remote transfer",
      "description": "Resume the saved transfer and schedule."
    },
    {
      "id": "remote_cancel",
      "title": "Cancel remote transfer",
      "description": "Cancel the transfer and attempt S3 multipart abort when relevant; local media and verified remote snapshots remain."
    },
    {
      "id": "remote_advance",
      "title": "Advance remote transfer",
      "description": "Perform the native bounded transfer batch; can upload chunks, verify the remote object, prune retention and delete the local copy when configured."
    },
    {
      "id": "remote_fetch",
      "title": "Fetch remote backup to local recovery",
      "description": "Download and checksum-verify the same destination object before importing it privately for local inspection; no attachment restore."
    },
    {
      "id": "remote_delete",
      "title": "Delete a remote backup",
      "description": "Delete the exact current-destination backup object and remove its native index record after provider acceptance."
    },
    {
      "id": "usage_start",
      "title": "Start media usage check",
      "description": "Check at most 40 saved content items and save the per-actor report. Supported references only, up to 100 findings; native content permissions apply."
    },
    {
      "id": "usage_continue",
      "title": "Continue media usage check",
      "description": "Check at most 40 saved content items and save the per-actor report. Supported references only, up to 100 findings; native content permissions apply."
    },
    {
      "id": "delivery_check",
      "title": "Check saved public-page markup",
      "description": "Fetch mapped public page HTML and record the native signature-bound delivery result. HTML matches do not prove the browser downloaded a derivative."
    },
    {
      "id": "intent_release",
      "title": "Release an uncertain target reservation",
      "description": "Release this exact uncertain operation’s owner reservations after inspecting its native evidence. The prior outcome remains unknown; this never replays, undoes or confirms its business effects. Future changes need a fresh separate approved project. An executing consumer project cannot be released."
    },
    {
      "id": "automatic_organization",
      "title": "Automatic context folders",
      "description": "Native attachment hooks categorize images by owning parent and importer context. Manual folders are preserved. No new AI mutation action."
    },
    {
      "id": "protected_community_library",
      "title": "Protected Community photos",
      "description": "Read-only, current-permission Community >=0.1.0.12 provider. Images remain protected and are never copied to public uploads."
    },
    {
      "id": "lazy_loading",
      "title": "Lazy loading for pictures WordPress does not reach",
      "description": "Settings > Lazy-load pictures that WordPress does not reach (off at the start) adds loading=\"lazy\" on public pages only to pictures WordPress's own loading optimization did not see, after the first wp_omit_loading_attr_threshold() pictures, with a width and height, outside header/noscript, without fetchpriority=high, data-src or skip-lazy. AI: image_manager.settings_update (settings.lazy_loading)."
    },
    {
      "id": "large_pictures",
      "title": "Largest picture to make lighter",
      "description": "Settings > Largest picture to make lighter: up to 2 megapixels (before 1.7.5), up to 2,560 x 2,560 (initial) or up to 8,192 x 8,192 pixels. The per-picture memory check (WordPress image memory) still decides; skipped pictures are tried again only through Retry. AI: image_manager.settings_update (settings.large_pictures)."
    },
    {
      "id": "folder_gallery",
      "title": "Gallery made from a folder",
      "description": "Block affstackdev-image-manager/folder-gallery and shortcode [afsd_im_folder_gallery folder=\"ID\"]: WordPress gallery markup of the folder's pictures, only for folders switched on under Library > Folders and collections > Website galleries (confirmation required). AI: image_manager.folder_gallery_show / folder_gallery_hide, one folder per reviewed proposal."
    },
    {
      "id": "folder_import",
      "title": "Import folders from another plugin",
      "description": "Library > Folders and collections > Import folders from another plugin: FileBird, Real Media Library, HappyFiles, Enhanced Media Library, Folders (Premio). Same tree, files only added, the other plugin's data only read, a second import adds nothing. AI: image_manager.folder_import_start / folder_import_continue (about 8 seconds per approved step); inspect section imports."
    },
    {
      "id": "unused_media",
      "title": "Files with no use found",
      "description": "Library > Files with no use found: one library-wide check of saved content, comments, featured images, product galleries, category pictures, custom-field addresses, site icon/logo/header/background, WooCommerce pictures and widgets; listed files can be put into a collection. Listed does not prove unused; nothing is deleted. AI: image_manager.unused_check_start / unused_check_continue / unused_collect; inspect section unused pages through the list."
    },
    {
      "id": "content_folder_create",
      "title": "Create a folder for an admin list (pages, posts, products ...)",
      "description": "Create a private folder in the folder bar of that admin list (Folders for pages and posts must be on for it), at the top or inside a folder. Nothing changes on the website and no address changes."
    },
    {
      "id": "content_folder_rename",
      "title": "Rename a folder of an admin list",
      "description": "Rename the folder. Its items and sub-folders stay in it."
    },
    {
      "id": "content_folder_nest",
      "title": "Move a folder of an admin list into another folder or to the top",
      "description": "Move the folder, with its items and sub-folders, under another folder (an empty parent: the top level). A folder never goes into itself or one of its own sub-folders."
    },
    {
      "id": "content_folder_delete",
      "title": "Delete a folder of an admin list",
      "description": "Delete the folder only: its items stay as they are, outside any folder, and its sub-folders move up one level. No post, page or product is changed or deleted."
    },
    {
      "id": "content_folder_move",
      "title": "Move items of an admin list into a folder or out of their folder",
      "description": "Put each item (by ID or exact title) into the folder, taking it out of its previous folder; an empty folder takes them out of their folders. Only items you may edit. Nothing changes on the website."
    },
    {
      "id": "fit_sizes",
      "title": "Make the display sizes the measured pages need",
      "description": "Start one run over the measured pictures with your compression defaults: up to six extra display sizes per picture where no existing size is within 20 % above a width the measured pages need, never larger than the original and never cropped. Originals stay unchanged."
    },
    {
      "id": "fit_forget",
      "title": "Forget the page measurements",
      "description": "Delete every saved page measurement and measured width. Pictures go back to the sizes their theme gives them; display sizes already made stay."
    },
    {
      "id": "cdn_check",
      "title": "Check and save your own CDN",
      "description": "Save the CDN address. With deliver on, first write a new small test picture in Image Manager’s folder, ask for it through the CDN address (one request to that address) and switch delivery through the CDN on only when it comes back unchanged; then pictures in the uploads folder on public pages point to the CDN and the check runs daily. With deliver off, pictures come from the site."
    },
    {
      "id": "content_folders",
      "title": "Folders for pages and posts (1.8.0)",
      "description": "Settings > Folders for pages and posts switches private folders on per admin list (Posts, Pages, Products and other types with an admin list; off at the start). The list shows a folder bar (All, Not in a folder, the folder tree with counts; drafts, private and scheduled items count, the trash does not), a Folder column and the bulk actions Move to folder and Take out of its folder; rows can be dragged onto a folder. Manage folders creates, renames, nests and deletes folders (Editors and Administrators: the type’s edit_others right); anyone who may edit an item may move it. An item is in at most one folder; deleting a folder leaves its items outside any folder and moves its sub-folders up. One private taxonomy per type (afsd_im_cf_<type>): not public, no REST, no address; nothing changes on the website."
    },
    {
      "id": "fit_to_page",
      "title": "Pictures sized to fit the page (1.8.0)",
      "description": "Optimize > Sizes for the page measures, in the store owner’s browser, the width each picture takes on Home and the public pages the scan found (filter afsd_im_fit_pages adds more), at every screen width from 320 to 1,920 pixels. Settings > Fit pictures to the page (off at the start; needs the public-images confirmation) then gives a measured picture on a measured page the measured sizes when its sizes is still WordPress’s default (the theme’s own sizes stays; product galleries driven by WooCommerce, art-directed pictures and pictures without srcset are left). Make the sizes these pages need (or the Bulk editor’s Sizes measured on your pages) adds up to six display sizes per picture for the widths phones (2x, 3x), tablets (2x) and computer screens need. Measuring is not an AI action."
    },
    {
      "id": "own_cdn",
      "title": "Delivery through your own CDN (1.8.0)",
      "description": "Settings > Deliver pictures through your CDN: the address of the store owner’s own pull CDN (https, its own host name). Switching on first checks it with a new test picture that must come back unchanged; the check runs daily and a failure switches it off at once. Then, on the public pages Image Manager delivers on, picture addresses in the uploads folder (originals, sizes, Image Manager’s copies) point to the CDN; theme files, scripts, styles, WooCommerce downloads, SVG files and the cart, checkout, account and admin pages keep the site’s address. Refused while Jetpack’s image CDN is active. No AffStackDev service."
    },
    {
      "id": "auto_text",
      "title": "Alt text and titles from file names (1.9.0)",
      "description": "Settings > Fill empty alt text and titles from file names (off at the start): a new image upload whose alt text is empty gets one made from its file name (red-summer_dress-2.jpg gives Red summer dress 2; WordPress's -scaled, -rotated, edit and size suffixes are left out), and the same title when WordPress copied the bare file name into the title. Text a person wrote is never replaced. Names that say nothing give no text: camera names (IMG_1234, DSC_0042, PXL_...), screenshots, numbers only and long hexadecimal names. Tools > Fill empty alt text now fills the empty alt text of images already in the library, 300 per click, oldest first, remembering where it stopped; titles of existing images stay. It skips a picture while another Image Manager change is being written and never holds up an upload. Runs on the site's own server; no AI service."
    },
    {
      "id": "upload_limit",
      "title": "Largest new upload WordPress uses on pages (1.9.0)",
      "description": "Settings > Large pictures > Largest new upload WordPress uses on pages sets WordPress's big-upload threshold (the filter big_image_size_threshold, priority 20): WordPress's own size (the start: 2,560 pixels, or what another plugin sets), 1,920, 2,048, 3,200, 3,840 or 5,120 pixels, or Off. A new upload wider or taller than the size gets a smaller copy named -scaled that WordPress uses on pages; the original stays in the uploads folder. With Off the full picture is the main file (Largest picture to make lighter decides whether Image Manager can make it lighter). Pictures already in the library do not change."
    },
    {
      "id": "dimensions",
      "title": "The missing width and height on measured pages (1.9.0)",
      "description": "Optimize > Sizes for the page also tries, in the store owner's browser, each loaded picture without a width, a height and a srcset: it gets its file's own size for a moment and is kept only when its box stays the same at 360, 768, 1,280 and 1,920 pixels; the server keeps it only when that size is the size of the real file (the uploads folder or the active theme). Settings > Add the missing width and height on measured pages (off at the start; needs the public-images confirmation) then gives those pictures their width and height on the measured pages, so the browser keeps their place while they load. A picture the theme sizes in one direction only, pictures in a picture element and pictures with a srcset stay as they are. Measuring is not an AI action."
    },
    {
      "id": "make_sizes",
      "title": "Make missing sizes (1.9.0)",
      "description": "Tools > Make missing sizes goes through the library's pictures, about eight seconds per step with Continue: WordPress makes the registered sizes a picture does not have yet (wp_update_image_subsizes), and again those whose dimensions no longer match the registered size. Nothing is overwritten or deleted: an out-of-date size's file stays and is kept in the picture's backup sizes. Sizes left out under Settings are not made; sizes no theme or plugin registers now are counted and kept. Native only, not an AI action."
    },
    {
      "id": "picture_folders",
      "title": "Pictures outside the Media Library (1.9.0)",
      "description": "Settings > Other picture folders inside wp-content adds the named folders to the roots of the theme pictures path (Theme::roots): a picture in one of them that a public page shows is indexed when the page is scanned, gets optimized copies and is delivered as the active theme's pictures are. Folders are checked when saved and when used (a real folder inside wp-content, not the uploads folder or inside it, not a link, not Image Manager's own)."
    },
    {
      "id": "gif",
      "title": "GIF pictures (1.9.0)",
      "description": "A still GIF gets a lossless WebP copy (transparency kept), checked pixel for pixel as other copies. An animated GIF that repeats for ever gets an animated lossless WebP copy where Imagick is installed: each frame is decoded again and compared, every visible pixel exact, with the GIF's frame times; one that repeats a set number of times, shows an image for 10 ms or less, or is beyond the animation limits (1,000 images; all its images together twice the large-pictures pixel limit) is kept as it is, as animated PNG and WebP are. A GIF with comments or application data keeps native-only copies, as other formats with metadata do. GIF pictures of the active theme and of the other picture folders are included."
    },
    {
      "id": "watermark",
      "title": "Watermarked copies for public pages (1.9.0)",
      "description": "Settings > Watermark: a still PNG or WebP from the Media Library drawn on copies of the pictures public pages show, at a chosen place, width and opacity, for pictures at least the chosen width. Each Optimize run makes them after the ordinary copies, one file per step; after new watermark settings the earlier ones are no longer offered and the next run makes new ones (the earlier files are kept for pages still cached, as replaced copies are). The copies are checked against the watermarked picture as every copy is checked against its reference; turned photos, colour profiles, GIF pictures and theme pictures are left without a watermark. Original files are never changed. AI: image_manager.settings_update (settings.watermark and its five fields)."
    },
    {
      "id": "svg_uploads",
      "title": "SVG uploads, cleaned before they are saved (1.9.0)",
      "description": "Settings > SVG files (off at the start): the roles chosen there may upload SVG files through WordPress's own upload paths (the Media Library, the block editor, the REST API and media_handle_sideload). Each file is cleaned with svg-sanitizer 1.1.1 before WordPress saves it: only the tags and attributes on its allowlist stay (no scripts, event attributes, script links or embedded web pages), references to other sites are removed, and a file that cannot be read safely, a compressed .svgz or a file over 8 MB is refused. Its width and height go into the attachment's metadata, so WordPress shows it like other pictures; WordPress makes no sizes of it and Image Manager makes no copies of it. While it is on, wp_upload_bits (XML-RPC and importers) refuses SVG files. AI: image_manager.settings_update (settings.svg_uploads and settings.svg_roles)."
    }
  ],
  "settings": [
    {
      "id": "public_policy",
      "title": "Public Policy",
      "description": "Native saved public_policy boolean. Exact defaults, prerequisites, effects and false/omitted behavior are documented in both current manuals.",
      "location": "Settings"
    },
    {
      "id": "delivery",
      "title": "Delivery",
      "description": "Native saved delivery boolean. Exact defaults, prerequisites, effects and false/omitted behavior are documented in both current manuals.",
      "location": "Settings"
    },
    {
      "id": "uploads",
      "title": "Uploads",
      "description": "Native saved uploads boolean. Exact defaults, prerequisites, effects and false/omitted behavior are documented in both current manuals.",
      "location": "Settings"
    },
    {
      "id": "auto_discovery",
      "title": "Auto Discovery",
      "description": "Native saved auto_discovery boolean. Exact defaults, prerequisites, effects and false/omitted behavior are documented in both current manuals.",
      "location": "Settings"
    },
    {
      "id": "local_cdn",
      "title": "Local Cdn",
      "description": "Native saved local_cdn boolean. Exact defaults, prerequisites, effects and false/omitted behavior are documented in both current manuals.",
      "location": "Settings"
    },
    {
      "id": "theme_images",
      "title": "Theme Images",
      "description": "Native saved theme_images boolean. Exact defaults, prerequisites, effects and false/omitted behavior are documented in both current manuals.",
      "location": "Settings"
    },
    {
      "id": "catalog",
      "title": "Catalog",
      "description": "Native saved catalog boolean. Exact defaults, prerequisites, effects and false/omitted behavior are documented in both current manuals.",
      "location": "Settings"
    },
    {
      "id": "comments",
      "title": "Comments",
      "description": "Native saved comments boolean. Exact defaults, prerequisites, effects and false/omitted behavior are documented in both current manuals.",
      "location": "Settings"
    },
    {
      "id": "enhanced_ui",
      "title": "Enhanced Ui",
      "description": "Native saved enhanced_ui boolean. Exact defaults, prerequisites, effects and false/omitted behavior are documented in both current manuals.",
      "location": "Settings"
    },
    {
      "id": "compression_mode",
      "title": "Compression mode",
      "description": "Choices: lossless, high, maximum. Omitted reviewed field preserves current normalized recipe; host capability and fidelity checks apply.",
      "location": "Settings / Optimize / Images comparison / Bulk"
    },
    {
      "id": "compression_content",
      "title": "Compression content",
      "description": "Choices: auto, photo, graphics. Omitted reviewed field preserves current normalized recipe; host capability and fidelity checks apply.",
      "location": "Settings / Optimize / Images comparison / Bulk"
    },
    {
      "id": "compression_effort",
      "title": "Compression effort",
      "description": "Choices: fast, balanced. Omitted reviewed field preserves current normalized recipe; host capability and fidelity checks apply.",
      "location": "Settings / Optimize / Images comparison / Bulk"
    },
    {
      "id": "compression_formats",
      "title": "Compression formats",
      "description": "Choices: auto, native, webp, avif. Omitted reviewed field preserves current normalized recipe; host capability and fidelity checks apply.",
      "location": "Settings / Optimize / Images comparison / Bulk"
    },
    {
      "id": "compression_metadata",
      "title": "Compression metadata",
      "description": "Choices: preserve, remove_gps. Omitted reviewed field preserves current normalized recipe; host capability and fidelity checks apply.",
      "location": "Settings / Optimize / Images comparison / Bulk"
    },
    {
      "id": "remote_provider",
      "title": "Remote provider",
      "description": "Native current remote backup provider control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_schedule",
      "title": "Remote schedule",
      "description": "Native current remote backup schedule control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_profile",
      "title": "Remote profile",
      "description": "Native current remote backup profile control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_scope",
      "title": "Remote scope",
      "description": "Native current remote backup scope control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_retention",
      "title": "Remote retention",
      "description": "Native current remote backup retention control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_keep_local",
      "title": "Remote keep local",
      "description": "Native current remote backup keep_local control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_schedule_encrypt",
      "title": "Remote schedule encrypt",
      "description": "Native current remote backup schedule_encrypt control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_google_client_id",
      "title": "Remote google client id",
      "description": "Native current remote backup google_client_id control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_s3_endpoint",
      "title": "Remote s3 endpoint",
      "description": "Native current remote backup s3_endpoint control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_s3_region",
      "title": "Remote s3 region",
      "description": "Native current remote backup s3_region control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_s3_bucket",
      "title": "Remote s3 bucket",
      "description": "Native current remote backup s3_bucket control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_s3_prefix",
      "title": "Remote s3 prefix",
      "description": "Native current remote backup s3_prefix control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "remote_s3_path_style",
      "title": "Remote s3 path style",
      "description": "Native current remote backup s3_path_style control. Current allowed values, defaults, clear/retention meaning and integrity prerequisites are documented in the remote chapters.",
      "location": "Backups"
    },
    {
      "id": "lazy_loading",
      "title": "Lazy loading",
      "description": "Native saved lazy_loading boolean (1.7.5, off at the start). Saved by the native Settings form or image_manager.settings_update (settings.lazy_loading).",
      "location": "Settings"
    },
    {
      "id": "large_pictures",
      "title": "Largest picture to make lighter",
      "description": "Native saved large_pictures choice: standard, wordpress (initial) or all; sets the compression pixel, byte and memory limits. Saved by the native Settings form or image_manager.settings_update (settings.large_pictures).",
      "location": "Settings"
    },
    {
      "id": "fit",
      "title": "Fit pictures to the page",
      "description": "Native saved fit boolean (1.8.0, off at the start; needs public_policy). Saved by the native Settings form or image_manager.settings_update; uses the saved page measurements.",
      "location": "Settings"
    },
    {
      "id": "content_folders",
      "title": "Folders for pages and posts",
      "description": "Native saved list of post types whose admin lists show folders (1.8.0, empty at the start). Unknown types and Media are refused. Saved by the native Settings form or image_manager.settings_update.",
      "location": "Settings"
    },
    {
      "id": "cdn",
      "title": "Deliver pictures through this CDN",
      "description": "Native saved cdn boolean (1.8.0, off at the start). Only image_manager.cdn_check or the native CDN form changes it, and switching on always runs the CDN check first; the daily check can switch it off.",
      "location": "Settings / Deliver pictures through your CDN"
    },
    {
      "id": "cdn_url",
      "title": "CDN address",
      "description": "Native saved CDN address (https, a host name of its own, optional path; never this site’s host). Saved with the CDN form or image_manager.cdn_check.",
      "location": "Settings / Deliver pictures through your CDN"
    },
    {
      "id": "auto_text",
      "title": "Alt text and titles from file names",
      "description": "Native saved auto_text boolean (1.9.0, off at the start): new uploads with empty alt text get it from their file name, and their title when WordPress copied the bare file name. Saved by the native Settings form or image_manager.settings_update (settings.auto_text). Tools > Fill empty alt text now fills the library's images in batches of 300 (alt text only).",
      "location": "Settings"
    },
    {
      "id": "upload_limit",
      "title": "Largest new upload WordPress uses on pages",
      "description": "Native saved upload_limit (1.9.0): wordpress (the start; WordPress's own big_image_size_threshold, 2,560 pixels or what another plugin sets), off (no -scaled copy; the full picture is the main file), or 1920, 2048, 3200, 3840 or 5120 pixels. Saved by the native Settings form or image_manager.settings_update (settings.upload_limit). Only new uploads change.",
      "location": "Settings / Large pictures"
    },
    {
      "id": "dimensions",
      "title": "Add the missing width and height on measured pages",
      "description": "Native saved dimensions boolean (1.9.0, off at the start; true requires public_policy). Saved by the native Settings form or image_manager.settings_update (settings.dimensions).",
      "location": "Settings"
    },
    {
      "id": "skip_sizes",
      "title": "Sizes WordPress makes for new uploads",
      "description": "Native saved skip_sizes (1.9.0): the registered sizes WordPress does not make for new uploads (none at the start), through the filter intermediate_image_sizes_advanced. Saved by the native Settings form (the ticked sizes are made) or image_manager.settings_update (settings.skip_sizes, at most 40 names). Pictures already in the library keep their sizes.",
      "location": "Settings"
    },
    {
      "id": "picture_folders",
      "title": "Other picture folders inside wp-content",
      "description": "Native saved picture_folders (1.9.0): up to ten folders inside wp-content (relative names) whose pictures are treated like the active theme's: copies and delivery of those shown on public pages, while Include images supplied by the active theme is on. The uploads folder or a folder inside it, Image Manager's own folder, links and .. are refused. Saved by the native Settings form (one per line) or image_manager.settings_update (settings.picture_folders).",
      "location": "Settings"
    },
    {
      "id": "watermark",
      "title": "Show a watermark on pictures on public pages",
      "description": "Native saved watermark boolean (1.9.0, off at the start; needs public_policy and a watermark picture). With it on, each Optimize run gives pictures at least watermark_min pixels wide watermarked copies of every file (the original decoded with the watermark drawn on it, compressed and checked against that picture); public pages then show them, the page's own img src and srcset and WooCommerce's zoom picture included. Original files are never changed; pictures without watermarked copies keep their ordinary copies. Saved by the native Settings form or image_manager.settings_update (settings.watermark).",
      "location": "Settings / Watermark"
    },
    {
      "id": "watermark_image",
      "title": "Watermark picture",
      "description": "Native saved watermark_image (1.9.0): the attachment ID of a still PNG or WebP from the Media Library, at most 2,048 pixels on its longer side and 4 MB; 0 for none. Saved by the native Settings form or image_manager.settings_update (settings.watermark_image).",
      "location": "Settings / Watermark"
    },
    {
      "id": "watermark_place",
      "title": "Watermark place",
      "description": "Native saved watermark_place (1.9.0): top-left, top, top-right, left, center, right, bottom-left, bottom or bottom-right (the start), with a margin of 2 % of the picture's shorter side (at least 4 pixels). Saved by the native Settings form or image_manager.settings_update (settings.watermark_place).",
      "location": "Settings / Watermark"
    },
    {
      "id": "watermark_size",
      "title": "Watermark width",
      "description": "Native saved watermark_size (1.9.0): the watermark's width as a share of each picture's width, 5 to 50 per cent (20 at the start), never more than half the picture's height tall. Saved by the native Settings form or image_manager.settings_update (settings.watermark_size).",
      "location": "Settings / Watermark"
    },
    {
      "id": "watermark_opacity",
      "title": "Watermark opacity",
      "description": "Native saved watermark_opacity (1.9.0): 10 to 100 per cent (60 at the start); the watermark picture's own transparency is kept. Saved by the native Settings form or image_manager.settings_update (settings.watermark_opacity).",
      "location": "Settings / Watermark"
    },
    {
      "id": "watermark_min",
      "title": "Narrowest picture that gets a watermark",
      "description": "Native saved watermark_min (1.9.0): 100 to 4,000 pixels (400 at the start), compared with the picture's widest file. Saved by the native Settings form or image_manager.settings_update (settings.watermark_min).",
      "location": "Settings / Watermark"
    },
    {
      "id": "svg_uploads",
      "title": "Allow SVG uploads, cleaned before they are saved",
      "description": "Native saved svg_uploads boolean (1.9.0, off at the start; needs at least one role in svg_roles and PHP's DOM and XMLReader extensions). Turning it off stops new SVG uploads; SVG files already uploaded stay. Saved by the native Settings form or image_manager.settings_update (settings.svg_uploads).",
      "location": "Settings / SVG files"
    },
    {
      "id": "svg_roles",
      "title": "Roles that may upload SVG files",
      "description": "Native saved svg_roles (1.9.0): role slugs that exist on the site and have the upload_files capability (administrator at the start). Saved by the native Settings form or image_manager.settings_update (settings.svg_roles).",
      "location": "Settings / SVG files"
    }
  ],
  "dependencies": [],
  "integrations": [
    {
      "id": "wordpress",
      "title": "WordPress",
      "description": "Native media, metadata, permissions, image editors, taxonomy, cron and installation owner."
    },
    {
      "id": "woocommerce",
      "title": "WooCommerce",
      "description": "Optional public catalog associations and supported simple/classic variation gallery display; native zoom/lightbox retained."
    },
    {
      "id": "suite",
      "title": "AffStackDev Suite",
      "description": "Optional shared product navigation and global PHP mode."
    },
    {
      "id": "theme",
      "title": "Active theme / rendering owner",
      "description": "Layout ownership and supported observed theme-source/native image integration."
    },
    {
      "id": "jetpack",
      "title": "Jetpack images",
      "description": "Optional exact supported native-size mapping with local-CDN setting."
    },
    {
      "id": "ai",
      "title": "AffStackDev AI",
      "description": "Optional 0.1.0.12 reviewed-action contract, explicit native human approval and exact owner receipt; passive docs never execute."
    },
    {
      "id": "community",
      "title": "AffStackDev Community",
      "description": "Optional 0.1.0.12+ protected entry/profile descriptors, checked through current Community ownership and visibility."
    },
    {
      "id": "cdn",
      "title": "Your own pull CDN",
      "description": "Optional: a CDN with its own host name that fetches from this site (a pull zone). Checked with a new test picture before use and daily; no account, key or AffStackDev service."
    }
  ],
  "limits": [
    "Every registered native reviewed action has a strict bounded schema and needs the current actor/site and exact native human approval.",
    "Nine editable image switches, lazy loading, Fit pictures to the page, Folders for pages and posts, the Largest picture choice and five compression recipe choices; full native field/action coverage included.",
    "Single site WordPress 6.9+ and PHP 8.1+; reviewed owner requires MySQL/MariaDB with InnoDB owner tables.",
    "Library 30 per page, indexed sources 20; reviewed read pages up to 20; shared state and expected-after 32 KiB.",
    "Compression up to 2, 6.55 or 67.1 million pixels and 12, 24 or 64 MiB per file (Largest picture to make lighter; initially 6.55 million / 24 MiB), within the per-picture memory check, edge 8192, 5 percent minimum saving; editor 64 MiB / 24 million pixels / edge 16384.",
    "PDF one page 1–500 with edge 320–2560; Imagick reading PDF through Ghostscript required (self-tested). Smaller PDF copy up to 300 pages and 64 MiB; Ghostscript required (self-tested).",
    "File and secret inputs use native secure form; opaque actor/site reference expires in 24 hours or ten minutes.",
    "Portable recovery namespace affstackdev-image-manager/media version 1; native archive and SHA validation.",
    "Downloads, Google consent and actual browser observation remain explicit authenticated human controls.",
    "Folders for pages and posts: 500 folders per admin list, an item in one folder, 999 items per move (100 per AI action). Page measurements: 100 pages, 120 pictures per page, ten width rules per picture; up to six measured display sizes per picture."
  ],
  "documents": []
}
