Skip to content

Account for package metadata that doesn't include filename when deriving hashed filename#496

Open
kasparsd wants to merge 6 commits into
fairpm:release_1.4.1from
kasparsd:fix-add-plugins-error
Open

Account for package metadata that doesn't include filename when deriving hashed filename#496
kasparsd wants to merge 6 commits into
fairpm:release_1.4.1from
kasparsd:fix-add-plugins-error

Conversation

@kasparsd
Copy link
Copy Markdown
Contributor

@kasparsd kasparsd commented May 16, 2026

Fixes #492.

Updated get_hashed_filename() method to build a stable, hashed install path for a FAIR package from its metadata.

It works in this order:

  1. It derives a short DID hash from the package ID.
  2. It tries to split filename into two parts: a slug-like directory name and a plugin file name.
  3. If the filename does not provide a slug, it falls back to the metadata slug.
  4. If the filename does not provide a file portion, it assumes the main plugin file should be slug.php.
  5. It appends the DID hash to the slug unless it is already present.
  6. If the package type is wp-plugin, it returns a WordPress-style plugin path in the form slug-didhash/file.php.
  7. For non-plugin types, it returns only the hashed slug.

The intent of this version is:

  • prefer the slug embedded in filename when available
  • gracefully recover when filename is missing or incomplete
  • avoid double-appending the DID hash
  • return plugin paths as directory/file.php
  • return non-plugin paths as just the hashed directory/slug name

Examples for this implementation:

  • plugin with filename = example/example.php returns example-<hash>/example.php
  • plugin with missing filename falls back to example-<hash>/example.php
  • theme with slug example returns example-<hash>

kasparsd added 2 commits May 16, 2026 11:27
Signed-off-by: Kaspars Dambis <hi@kaspars.net>
This sample metadata doesn’t have filename returned, for reference https://github.com/fairpm/fair-plugin/releases/latest/download/fair-metadata.json

Signed-off-by: Kaspars Dambis <hi@kaspars.net>
@github-actions
Copy link
Copy Markdown
Contributor

$type = str_replace( 'wp-', '', $metadata->type );
$did_hash = '-' . get_did_hash( $metadata->id );

list( $slug, $file ) = explode( '/', $filename, 2 );
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When $metadata->filename isn't specified (such as https://github.com/fairpm/fair-plugin/releases/latest/download/fair-metadata.json), the explode() failed with:

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /inc/packages/namespace.php on line 694

and the $file was undefined which caused:

Warning: Undefined array key 1 in /inc/packages/namespace.php on line 694

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the problem is that $metadata->filename is supposed to exist and that the fair-metadata.json was incorrectly created.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the general package spec doesn’t require it so I think it makes sense that we support that scenario as a fallback.

https://github.com/fairpm/fair-protocol/blob/83be5fa21fc1f72d5bcbf2bdd654f9e72274bc39/specification.md?plain=1#L197

Arguably, WP determines the bootstrap file dynamically based on header presence (and themes don’t even need it) so I think should probably refactor this eventually.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We did update the spec and it now requires it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@afragen I think the spec shouldn't require it. None of the WP packages have that concept (at least from the existing WP-org API perspective).

I created #500 to illustrate how WP core resolves the plugin_file dynamically during install and never gets it from the update API. Asking package publishers to include the filename is simply unnecessary.

In #500 I demonstrate how we can resolve all the necessary filename data from the canonical places in WP without having to assume or deal with mismatches on the filesystem (what active_plugins thinks) and what the metadata reports.

function get_default_repo_domain() : string {
if ( defined( 'FAIR_DEFAULT_REPO_DOMAIN' ) ) {
return FAIR_DEFAULT_REPO_DOMAIN;
return (string) \FAIR_DEFAULT_REPO_DOMAIN;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure the output type is always correct and use the constant value from the global namespace since that is what defined( 'FAIR_DEFAULT_REPO_DOMAIN' ) checks for.

Comment thread inc/packages/namespace.php Outdated
Comment thread inc/packages/namespace.php Outdated
kasparsd and others added 3 commits May 16, 2026 22:04
Co-authored-by: Colin Stewart <79332690+costdev@users.noreply.github.com>
Signed-off-by: Kaspars Dambis <hi@kaspars.net>
Signed-off-by: Kaspars Dambis <hi@kaspars.net>
Signed-off-by: Kaspars Dambis <hi@kaspars.net>
Copy link
Copy Markdown
Member

@costdev costdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes @kasparsd! I won't get to test this or do a full review, but hopefully someone has availability and can help determine if any further tests would be good here.

…the DID hash appended

Signed-off-by: Kaspars Dambis <hi@kaspars.net>
@kasparsd
Copy link
Copy Markdown
Contributor Author

All the code review feedback has been addressed. Added a few additional phpunit test cases to account for the edge cases resolved.

@cdils cdils changed the base branch from main to release_1.4.1 May 18, 2026 16:59
@cdils cdils requested a review from costdev May 18, 2026 17:06
@costdev
Copy link
Copy Markdown
Member

costdev commented May 18, 2026

@cdils I won't get to do a full review of this PR. If someone else if available to do a full review, that would be great!

Edit: It looks like @afragen started a review

@costdev costdev dismissed their stale review May 18, 2026 17:33

Changes made

}

return $filename;
return $slug;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, not sure I understand why a function named get_hashed_filename() no longer returns $filename.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It returns the filename only for wp-plugin type and returns the slug in all other cases. That is what this updated approach makes clear with a conditional return for that one edge case for WP plugins.

Feel free to push an update or I can update it if you can advise on the updated logic here.

@cdils
Copy link
Copy Markdown
Contributor

cdils commented May 18, 2026

@costdev sorry–I didn't mean to trigger a review from you as I saw your earlier comment. I was attempting to get rid of resolved conversations pertaining to the previous review. Blame it on my github skillz. :)

@costdev
Copy link
Copy Markdown
Member

costdev commented May 18, 2026

No worries haha!

@afragen
Copy link
Copy Markdown
Contributor

afragen commented May 22, 2026

Is there a test for the current state of the FAIR Connect where fair-plugin/plugin.php doesn’t list a filename in the metadata?

@kasparsd
Copy link
Copy Markdown
Contributor Author

@afragen Yes, this pull request adds those test cases, including this one with the missing filename:

https://github.com/kasparsd/fair-plugin/blob/a29caf53ec45d65666c92c8b78edaf41860228f6/tests/phpunit/tests/Packages/GetHashedFilenameTest.php#L34-L47

My proposal is to remove the filename requirement eventually since they're not really required as WP resolves the plugin file automatically by scanning all root-level PHP files for the Plugin Name header during install/activation. Created #500 to demonstrate that. But that's for a separate discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐞 Bug Report: Add plugins "unexpected error" (FAIR 1.4.0)

4 participants