@prefix sioc: <http://rdfs.org/sioc/ns#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix content: <http://purl.org/rss/1.0/modules/content/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<https://lhero.org/?post_type=lh-portfolio-doc&#038;p=152641>
  a sioc:Post ;
  dc:title "Changelog" ;
  dcterms:identifier 152641 ;
  dc:modified "2026-10-27T12:48:12Z"^^xsd:dateTime ;
  dc:created "2026-10-27T12:42:49Z"^^xsd:dateTime ;
  sioc:link <https://lhero.org/portfolio/lh-private-uploads/changelog/> ;
  sioc:has_creator <https://lhero.org/author/1/#account> ;
  sioc:has_container <https://lhero.org/#posts> ;
  content:encoded "<ul class=\"lh_portfolio-meta\"><li><strong>Part of:</strong> <a href=\"https://lhero.org/portfolio/lh-private-uploads/\">LH Private Uploads</a></li></ul><ul class=\"lh_portfolio-changelog\"><li><strong>1.6.1:</strong> Private media can now be made from plain-text files (CSV, TSV, TXT, Markdown, JSON, iCalendar and vCard) even where the network&#039;s upload file types leave them out, as lhero.org&#039;s do (lh-tasks #153091). Only LH_Private_Uploads_Importer, and so lh-private-uploads/create-private-media, accepts them, only as private items gated by their required capability, and only when the file really is text (no NUL bytes); public uploads still follow the network setting. The list is filterable with lh_private_uploads_private_text_types; every other type is still checked as the uploader checks it.</li><li><strong>1.6.0:</strong> Private media for agents, with a per-file capability floor and an audit trail (lh-tasks #153091). New MCP ability lh-private-uploads/create-private-media copies any LH MCP File Abilities source (a sandbox file, a copied IMAP attachment, an existing attachment) into a site&#039;s private directory as a private media item, written straight there rather than into public uploads, with its type checked as the uploader does; it is site scoped, so site_id picks the site, and a sandbox source works whichever site is named. Requires upload_files and edit_others_posts. Files it makes carry a required capability (edit_others_posts by default, filter lh_private_uploads_default_required_capability) which the access check now applies as a floor after every other rule, so only users with it and super admins can open them, and the password form is never offered for them. They are also logged in LH Audit Trail: private_upload.added, private_upload.viewed (each proxy download, and each MCP read reported through the new lh_private_uploads_file_accessed action) and private_upload.removed, readable with manage_options. Other plugins can make such files with LH_Private_Uploads_Importer::import_file() and listen for lh_private_uploads_file_imported. Fix: deleting a private attachment now deletes its files from the private directory. Core only deletes files inside uploads, so they used to be left on disk. Each file is checked to lie in the site&#039;s own private directory before it is removed.</li><li><strong>1.5.2:</strong> Protected-files requests are no longer treated as not found. The 1.5.1 change set a 200 status just before streaming, but files were still answered with 404, so the plugin now stops WordPress marking these requests as 404 in the first place: a pre_handle_404 filter skips WordPress&#039;s 404 handling whenever the request is for a protected file, the standard way to serve a virtual URL. Errors raised by the proxy itself (403, 404, the password form) are unchanged.</li><li><strong>1.5.1:</strong> Protected files are now served with a 200 OK status. WordPress treats a protected-files URL as a page that does not exist and sets a 404 status before the proxy runs, and the proxy never replaced it, so every file it served (images, PDFs, spreadsheets) went out with the right content but a 404 status. Browsers, apps and caches that act on the status could refuse or discard the file. The proxy now sends 200 OK and clears the not-found state before streaming.</li><li><strong>1.5.0:</strong> Private files are now kept apart per site. On a multisite network each site other than the main site stores its private files in its own sites/ID/ directory in the private directory (ID being the site&#039;s blog ID), mirroring the public uploads layout, and its proxy URLs carry the same sites/ID/ segment. Before this release every site&#039;s private files went into one shared tree, so files from different sites sat side by side. Path mapping now swaps only a leading directory (new private_site_dir() and is_legacy_flat_path()), and path_belongs_to_current_site() really checks the site&#039;s own directory: it previously passed any path in the private tree on every site. The proxy no longer falls back to matching a relative path, which could resolve another site&#039;s private file to one of this site&#039;s public attachments; a file is served only when this site&#039;s own postmeta holds its exact path. Moving a file never overwrites an existing one: the move is refused with a target_exists error, where it previously replaced the file silently, losing another attachment&#039;s file when two sites made a same-named file private in the same month. Subsite files made private before this release stay where they are and keep working until migrated, and once a file has moved into its site&#039;s directory, old protected-files links without the sites/ID/ segment redirect to it. lh-tasks #152634.</li></ul>"^^rdf:XMLLiteral ;
  sioc:content "Part of: LH Private Uploads1.6.1: Private media can now be made from plain-text files (CSV, TSV, TXT, Markdown, JSON, iCalendar and vCard) even where the network&#039;s upload file types leave them out, as lhero.org&#039;s do (lh-tasks #153091). Only LH_Private_Uploads_Importer, and so lh-private-uploads/create-private-media, accepts them, only as private items gated by their required capability, and only when the file really is text (no NUL bytes); public uploads still follow the network setting. The list is filterable with lh_private_uploads_private_text_types; every other type is still checked as the uploader checks it.1.6.0: Private media for agents, with a per-file capability floor and an audit trail (lh-tasks #153091). New MCP ability lh-private-uploads/create-private-media copies any LH MCP File Abilities source (a sandbox file, a copied IMAP attachment, an existing attachment) into a site&#039;s private directory as a private media item, written straight there rather than into public uploads, with its type checked as the uploader does; it is site scoped, so site_id picks the site, and a sandbox source works whichever site is named. Requires upload_files and edit_others_posts. Files it makes carry a required capability (edit_others_posts by default, filter lh_private_uploads_default_required_capability) which the access check now applies as a floor after every other rule, so only users with it and super admins can open them, and the password form is never offered for them. They are also logged in LH Audit Trail: private_upload.added, private_upload.viewed (each proxy download, and each MCP read reported through the new lh_private_uploads_file_accessed action) and private_upload.removed, readable with manage_options. Other plugins can make such files with LH_Private_Uploads_Importer::import_file() and listen for lh_private_uploads_file_imported. Fix: deleting a private attachment now deletes its files from the private directory. Core only deletes files inside uploads, so they used to be left on disk. Each file is checked to lie in the site&#039;s own private directory before it is removed.1.5.2: Protected-files requests are no longer treated as not found. The 1.5.1 change set a 200 status just before streaming, but files were still answered with 404, so the plugin now stops WordPress marking these requests as 404 in the first place: a pre_handle_404 filter skips WordPress&#039;s 404 handling whenever the request is for a protected file, the standard way to serve a virtual URL. Errors raised by the proxy itself (403, 404, the password form) are unchanged.1.5.1: Protected files are now served with a 200 OK status. WordPress treats a protected-files URL as a page that does not exist and sets a 404 status before the proxy runs, and the proxy never replaced it, so every file it served (images, PDFs, spreadsheets) went out with the right content but a 404 status. Browsers, apps and caches that act on the status could refuse or discard the file. The proxy now sends 200 OK and clears the not-found state before streaming.1.5.0: Private files are now kept apart per site. On a multisite network each site other than the main site stores its private files in its own sites/ID/ directory in the private directory (ID being the site&#039;s blog ID), mirroring the public uploads layout, and its proxy URLs carry the same sites/ID/ segment. Before this release every site&#039;s private files went into one shared tree, so files from different sites sat side by side. Path mapping now swaps only a leading directory (new private_site_dir() and is_legacy_flat_path()), and path_belongs_to_current_site() really checks the site&#039;s own directory: it previously passed any path in the private tree on every site. The proxy no longer falls back to matching a relative path, which could resolve another site&#039;s private file to one of this site&#039;s public attachments; a file is served only when this site&#039;s own postmeta holds its exact path. Moving a file never overwrites an existing one: the move is refused with a target_exists error, where it previously replaced the file silently, losing another attachment&#039;s file when two sites made a same-named file private in the same month. Subsite files made private before this release stay where they are and keep working until migrated, and once a file has moved into its site&#039;s directory, old protected-files links without the sites/ID/ segment redirect to it. lh-tasks #152634." ;
  sioc:topic <https://lhero.org/?taxonomy=author&term=cap-1> .

<https://lhero.org/author/1/#account> rdfs:seeAlso <https://lhero.org/author/1/?feed=lhrdf&format=turtle> .
<https://lhero.org/?taxonomy=author&term=cap-1> rdfs:seeAlso <https://lhero.org/?taxonomy=author&term=cap-1&feed=lhrdf&format=turtle> .
