Skip to content

Conversation

@JanJakes
Copy link
Member

WIP alternative exploration to #142.

Closes #132.

@JanJakes
Copy link
Member Author

Here's a bit of a demo of what this WIP does now:

$ blueprint.php info blueprint.json

ERRORS FOUND:

  themes:
    Invalid path "wp-content/invalid/test.php". Expected to match "wp-content/themes/*".
  plugins:
    Invalid path "wp-content/invalid/test.php". Expected to match "wp-content/plugins/*".
  media:
    Invalid path "wp-content/invalid/image.jpg". Expected to match "wp-content/uploads/*".
  content:
    Invalid path "wp-content/content/invalid/test.xml". Expected to match "wp-content/content/posts/*".
    Invalid path "wp-content/content/invalid/test.xml". Expected to match "wp-content/content/posts/*".

BLUEPRINT:

  version: 2
  siteLanguage: "en_US"
  wordpressVersion: "6.7"
  constants: {"TEST_CONSTANT":"plugins"}
  siteOptions: {"blogname":"Full Featured Test Site"}
  plugins: ["./wp-content/plugins/test.php","./wp-content/invalid/test.php"]
  themes: ["./wp-content/themes/test.php","./wp-content/invalid/test.php"]
  media: ["./wp-content/uploads/image.jpg","./wp-content/invalid/image.jpg"]
  content: [{"type":"posts","source":"./wp-content/content/posts/test.xml"},{"type":"posts","source":"./wp-content/content/invalid/test.xml"},{"type":"posts","source":["./wp-content/content/posts/test.xml","./wp-content/content/invalid/test.xml"]}]
  additionalStepsAfterExecution: []

EXECUTION PLAN:

  [1] defineConstants
        constants: {"TEST_CONSTANT":"plugins"}

  [2] setSiteOptions
        options: {"blogname":"Full Featured Test Site"}

  [3] installTheme
        source: "./wp-content/themes/test.php"
        active: false
        importStarterContent: false

  [4] installTheme
        source: "./wp-content/invalid/test.php"
        active: false
        importStarterContent: false

  [5] installPlugin
        source: "./wp-content/plugins/test.php"

  [6] installPlugin
        source: "./wp-content/invalid/test.php"

  [7] importMedia
        media: ["./wp-content/uploads/image.jpg","./wp-content/invalid/image.jpg"]

  [8] setSiteLanguage
        language: "en_US"

  [9] importContent
        content: [{"type":"posts","source":"./wp-content/content/posts/test.xml"},{"type":"posts","source":"./wp-content/content/invalid/test.xml"},{"type":"posts","source":["./wp-content/content/posts/test.xml","./wp-content/content/invalid/test.xml"]}]

@JanJakes
Copy link
Member Author

@adamziel The validation is not complete yet — some steps have more complex requirements — but I think this architecture could work.

At the moment, the BlueprintParser::parse() method returns a Blueprint instance that exposes the plan via $bluprint->getExecutionPlan(). However, that's just an intermediate array of step names and args that are later converted to the step instances.

I think I could take this further and make the parser (maybe renaming it to BlueprintCompiler) create the plan as step instances directly. This would also enable us to move the validation into the step classes by adding a validate( $args ) method to StepInterface. Not sure whether to do this move or not; it has pros and cons, but it's something we could consider.

@JanJakes JanJakes force-pushed the blueprint-validation branch from a7ba5a8 to 0a823e0 Compare August 14, 2025 11:35
@JanJakes JanJakes force-pushed the blueprint-validation branch 2 times, most recently from 45ea455 to 8114999 Compare August 20, 2025 14:13
@JanJakes JanJakes force-pushed the blueprint-validation branch 2 times, most recently from 48839cd to a9e0e95 Compare August 21, 2025 14:12
@JanJakes JanJakes force-pushed the blueprint-validation branch from a9e0e95 to eb04387 Compare August 21, 2025 14:15
@adamziel
Copy link
Collaborator

I think I could take this further and make the parser (maybe renaming it to BlueprintCompiler) create the plan as step instances directly.

This could be potentially useful in the future but it wouldn't make that much of a difference now. Let's keep this in mind and revisit it when a good use-case comes up.

}

private function is_bundle_source( string $source ): bool {
return ! str_contains( $source, '://' ) && str_contains( $source, '/' );
Copy link
Collaborator

Choose a reason for hiding this comment

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

We'd need to run this against a list of data references and confirm that URLReference, GitPath etc. fail to resolve while the AbsoluteLocalPath resolves successfully, similarly to what DataReference::create() does. We have a bunch of data reference syntaxes with possibly more to come, and not even all of them are strings.

$this->assertSame( [
[
'line' => 5,
'message' => 'Invalid plugin path. The path must start with "wp-content/plugins/": ./wp-content/invalid/invalid-plugin-file.php'
Copy link
Collaborator

Choose a reason for hiding this comment

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

The message slightly confused me at first, as in I went "oh, it's about the ./ prefix. No, wait, it's about the /plugins/ part". I wonder if we could rephrase it somehow to make it clear it's about the parent path, not syntax micronuances.

@adamziel
Copy link
Collaborator

This looks good @JanJakes! I've left a few notes and there's a few failing tests. We're pretty close to merging

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.

[Blueprints v2] Constraint the Blueprint bundle format

3 participants