| @@ -259,8 +259,48 @@ | ||
| 259 | 259 | openstation_desktop_icon_registry( $id, '__unset__' ); |
| 260 | 260 | } |
| 261 | 261 | |
| 262 | 262 | /** |
| 263 | + * One desktop icon entry, as the shell sees it: after the `openstation_icons` | |
| 264 | + * filter, not from the raw registry. | |
| 265 | + * | |
| 266 | + * The payload and the orphan placement both run the filter, so an entry a | |
| 267 | + * plugin injects there gets a placement row minted for it; the shortcut that | |
| 268 | + * row points at has to resolve through the same filter or it serializes as | |
| 269 | + * a missing file and never paints. The same holds the other way: an entry | |
| 270 | + * the filter removes must not keep resolving from the raw store. | |
| 271 | + * | |
| 272 | + * Deliberately uncached here: registrations can change within a request | |
| 273 | + * (tests do it constantly). Each call runs the whole filter chain, so a | |
| 274 | + * caller that asks about one icon several times keeps the answer, as | |
| 275 | + * `OpenStation_Shortcut_File` does for the life of one placement. | |
| 276 | + * | |
| 277 | + * @param string $id Icon id. | |
| 278 | + * @return array|null The entry, or null when no icon has that id. | |
| 279 | + */ | |
| 280 | +function openstation_desktop_icon_entry( $id ) { | |
| 281 | + $id = (string) $id; | |
| 282 | + if ( '' === $id ) { | |
| 283 | + return null; | |
| 284 | + } | |
| 285 | + /** This filter is documented in openstation_build_desktop_icons_payload(). */ | |
| 286 | + $registry = apply_filters( 'openstation_icons', openstation_desktop_icon_registry() ); | |
| 287 | + if ( ! is_array( $registry ) ) { | |
| 288 | + return null; | |
| 289 | + } | |
| 290 | + if ( isset( $registry[ $id ] ) && is_array( $registry[ $id ] ) ) { | |
| 291 | + return $registry[ $id ]; | |
| 292 | + } | |
| 293 | + // A filter may hand back a re-indexed list rather than an id map. | |
| 294 | + foreach ( $registry as $entry ) { | |
| 295 | + if ( is_array( $entry ) && isset( $entry['id'] ) && $id === (string) $entry['id'] ) { | |
| 296 | + return $entry; | |
| 297 | + } | |
| 298 | + } | |
| 299 | + return null; | |
| 300 | +} | |
| 301 | + | |
| 302 | +/** | |
| 263 | 303 | * Build the desktop-icon list for the shell payload. Applies a |
| 264 | 304 | * `openstation_icons` filter so plugins can hide / reorder / rename |
| 265 | 305 | * entries registered by others — mirrors the wallpaper payload |
| 266 | 306 | * builder's filter discipline. |
| @@ -268,10 +308,10 @@ | ||
| 268 | 308 | * @return array[] |
| 269 | 309 | */ |
| 270 | 310 | function openstation_build_desktop_icons_payload() { |
| 271 | 311 | $registry = openstation_desktop_icon_registry(); |
| 272 | - if ( ! is_array( $registry ) || empty( $registry ) ) { | |
| 273 | - return array(); | |
| 312 | + if ( ! is_array( $registry ) ) { | |
| 313 | + $registry = array(); | |
| 274 | 314 | } |
| 275 | 315 | |
| 276 | 316 | /** |
| 277 | 317 | * Filters the full desktop-icon registry before it ships to the |
| @@ -281,9 +321,12 @@ | ||
| 281 | 321 | * |
| 282 | 322 | * @param array[] $registry The registered icon entries. |
| 283 | 323 | */ |
| 284 | 324 | $registry = apply_filters( 'openstation_icons', $registry ); |
| 285 | - if ( ! is_array( $registry ) ) { | |
| 325 | + // Checked after the filter, not before: an empty registry is exactly | |
| 326 | + // where a filter-injected entry is the only icon, and returning early | |
| 327 | + // dropped it. | |
| 328 | + if ( ! is_array( $registry ) || empty( $registry ) ) { | |
| 286 | 329 | return array(); |
| 287 | 330 | } |
| 288 | 331 | |
| 289 | 332 | $out = array(); |