{"id":15744283,"url":"https://github.com/greg-1-anderson/drupal-core-composer-scaffold","last_synced_at":"2026-05-03T02:43:24.684Z","repository":{"id":62512544,"uuid":"256334343","full_name":"greg-1-anderson/drupal-core-composer-scaffold","owner":"greg-1-anderson","description":"Clone of drupal/core-composer-scaffold + https://www.drupal.org/project/drupal/issues/3126566","archived":false,"fork":false,"pushed_at":"2020-04-17T01:06:41.000Z","size":39,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"8.9.x","last_synced_at":"2025-03-31T05:42:55.447Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/greg-1-anderson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-16T21:31:02.000Z","updated_at":"2020-04-17T01:06:21.000Z","dependencies_parsed_at":"2022-11-02T13:16:41.350Z","dependency_job_id":null,"html_url":"https://github.com/greg-1-anderson/drupal-core-composer-scaffold","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/greg-1-anderson/drupal-core-composer-scaffold","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greg-1-anderson%2Fdrupal-core-composer-scaffold","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greg-1-anderson%2Fdrupal-core-composer-scaffold/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greg-1-anderson%2Fdrupal-core-composer-scaffold/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greg-1-anderson%2Fdrupal-core-composer-scaffold/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/greg-1-anderson","download_url":"https://codeload.github.com/greg-1-anderson/drupal-core-composer-scaffold/tar.gz/refs/heads/8.9.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greg-1-anderson%2Fdrupal-core-composer-scaffold/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32556771,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T00:31:16.350Z","status":"online","status_checked_at":"2026-05-03T02:00:09.297Z","response_time":103,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-04T03:41:51.473Z","updated_at":"2026-05-03T02:43:24.668Z","avatar_url":"https://github.com/greg-1-anderson.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Drupal Composer Scaffold\n\nThis project provides a composer plugin for placing scaffold files (like\n`index.php`, `update.php`, …) from the `drupal/core` project into their desired\nlocation inside the web root. Only individual files may be scaffolded with this\nplugin.\n\nThe purpose of scaffolding files is to allow Drupal sites to be fully managed by\nComposer, and still allow individual asset files to be placed in arbitrary\nlocations. The goal of doing this is to enable a properly configured composer\ntemplate to produce a file layout that exactly matches the file layout of a\nDrupal 8.7.x and earlier tarball distribution. Other file layouts will also be\npossible; for example, a project layout very similar to the current\n[drupal-composer/drupal-project](https://github.com/drupal-composer/drupal-scaffold)\ntemplate will also be provided. When one of these projects is used, the user\nshould be able to use `composer require` and `composer update` on a Drupal site\nimmediately after untarring the downloaded archive.\n\nNote that the dependencies of a Drupal site are only able to scaffold files if\nexplicitly granted that right in the top-level composer.json file. See\n[allowed packages](#allowed-packages), below.\n\n## Usage\n\nDrupal Composer Scaffold is used by requiring `drupal/core-composer-scaffold` in your\nproject, and providing configuration settings in the `extra` section of your\nproject's composer.json file. Additional configuration from the composer.json\nfile of your project's dependencies is also consulted in order to scaffold the\nfiles a project needs. Additional information may be added to the beginning or\nend of scaffold files, as is commonly done to `.htaccess` and `robots.txt`\nfiles. See [altering scaffold files](#altering-scaffold-files) for more\ninformation.\n\nTypically, the scaffold operations run automatically as needed, e.g. after\n`composer install`, so it is usually not necessary to do anything different\nto scaffold a project once the configuration is set up in the project\ncomposer.json file, as described below. To scaffold files directly, run:\n```\ncomposer drupal:scaffold\n```\n\n### Allowed Packages\n\nScaffold files are stored inside of projects that are required from the main\nproject's composer.json file as usual. The scaffolding operation happens after\n`composer install`, and involves copying or symlinking the desired assets to\ntheir destination location. In order to prevent arbitrary dependencies from\ncopying files via the scaffold mechanism, only those projects that are\nspecifically permitted by the top-level project will be used to scaffold files.\n\nExample: Permit scaffolding from the project `drupal/core`\n```\n  \"name\": \"my/project\",\n  ...\n  \"extra\": {\n    \"drupal-scaffold\": {\n      \"allowed-packages\": [\n        \"drupal/core\"\n      ],\n      ...\n    }\n  }\n```\nAllowing a package to scaffold files also permits it to delegate permission to\nscaffold to any project that it requires itself. This allows a package to\norganize its scaffold assets as it sees fit. For example, the project\n`drupal/core` may choose to store its assets in a subproject `drupal/assets`.\n\nIt is possible for a project to obtain scaffold files from multiple projects.\nFor example, a Drupal project using a distribution, and installing on a specific\nweb hosting service provider might take its scaffold files from:\n\n- Drupal core\n- Its distribution\n- A project provided by the hosting provider\n- The project itself\n\nEach project allowed to scaffold by the top-level project will be used in turn,\nwith projects declared later in the `allowed-packages` list taking precedence\nover the projects named before. The top-level composer.json itself is always\nimplicitly allowed to scaffold files, and its scaffold files have highest\npriority.\n\n### Defining Project Locations\n\nThe top-level project in turn must define where the web root is located. It does\nso via the `locations` mapping, as shown below:\n```\n  \"name\": \"my/project\",\n  ...\n  \"extra\": {\n    \"drupal-scaffold\": {\n      \"locations\": {\n        \"web-root\": \"./docroot\"\n      },\n      ...\n    }\n  }\n```\nThis makes it possible to configure a project with different file layouts; for\nexample, either the `drupal/drupal` file layout or the\n`drupal-composer/drupal-project` file layout could be used to set up a project.\n\nIf a web-root is not explicitly defined, then it will default to `./`.\n\n### Altering Scaffold Files\n\nSometimes, a project might wish to use a scaffold file provided by a dependency,\nbut alter it in some way. Two forms of alteration are supported: appending and\npatching.\n\nThe example below shows a project that appends additional entries onto the end\nof the `robots.txt` file provided by `drupal/core`:\n```\n  \"name\": \"my/project\",\n  ...\n  \"extra\": {\n    \"drupal-scaffold\": {\n      \"file-mapping\": {\n        \"[web-root]/robots.txt\": {\n          \"append\": \"assets/my-robots-additions.txt\",\n        }\n      }\n    }\n  }\n```\nIt is also possible to prepend to a scaffold file instead of, or in addition to\nappending by including a \"prepend\" entry that provides the relative path to the\nfile to prepend to the scaffold file.\n\nThe example below demonstrates the use of the `post-drupal-scaffold-cmd` hook\nto patch the `.htaccess` file using a patch.\n```\n  \"name\": \"my/project\",\n  ...\n  \"scripts\": {\n    \"post-drupal-scaffold-cmd\": [\n      \"cd docroot \u0026\u0026 patch -p1 \u003c../patches/htaccess-ssl.patch\"\n    ]\n  }\n```\n\n### Defining Scaffold Files\n\nThe placement of scaffold assets is under the control of the project that\nprovides them, but the location is always relative to some directory defined by\nthe root project -- usually the web root. For example, the scaffold file\n`robots.txt` is copied from its source location, `assets/robots.txt` into the\nweb root in the snippet below.\n```\n{\n  \"name\": \"drupal/assets\",\n  ...\n  \"extra\": {\n    \"drupal-scaffold\": {\n      \"file-mapping\": {\n        \"[web-root]/robots.txt\": \"assets/robots.txt\",\n        ...\n      }\n    }\n  }\n}\n```\n\n### Excluding Scaffold Files\n\nSometimes, a project might prefer to entirely replace a scaffold file provided\nby a dependency, and receive no further updates for it. This can be done by\nsetting the value for the scaffold file to exclude to `false`:\n```\n  \"name\": \"my/project\",\n  ...\n  \"extra\": {\n    \"drupal-scaffold\": {\n      \"file-mapping\": {\n        \"[web-root]/robots.txt\": false\n      }\n    }\n  }\n```\nIf possible, use the `append` and `prepend` directives as explained in [altering\nscaffold files](#altering-scaffold-files), above. Excluding a file means that\nyour project will not get any bug fixes or other updates to files that are\nmodified locally.\n\n### Overwrite\n\nBy default, scaffold files overwrite whatever content exists at the target\nlocation. Sometimes a project may wish to provide the initial contents for a\nfile that will not be changed in subsequent updates. This can be done by setting\nthe `overwrite` flag to `false`, as shown in the example below:\n```\n{\n  \"name\": \"service-provider/d8-scaffold-files\",\n  \"extra\": {\n    \"drupal-scaffold\": {\n      \"file-mapping\": {\n        \"[web-root]/sites/default/settings.php\": {\n          \"mode\": \"replace\",\n          \"path\": \"assets/sites/default/settings.php\",\n          \"overwrite\": false\n        }\n      }\n    }\n  }\n}\n```\nNote that the `overwrite` directive is intended to be used by starter kits,\nservice providers, and so on. Individual Drupal sites should exclude the file\nby setting its value to false instead.\n\n### Autoload File\n\nThe scaffold tool automatically creates the required `autoload.php` file at the\nDrupal root as part of the scaffolding operation. This file should not be\nmodified or customized in any way. If it is committed to the repository, though,\nthen the scaffold tool will stop managing it. If the location of the `vendor`\ndirectory is changed for any reason, and the `autoload.php` file has been\ncommitted to the repository, manually delete it and then run `composer install`\nto update it.\n\n## Specifications\n\nReference section for the configuration directives for the \"drupal-scaffold\"\nsection of the \"extra\" section of a `composer.json` file appear below.\n\n### allowed-packages\n\nThe `allowed-packages` configuration setting contains an ordered list of package\nnames that will be used during the scaffolding phase.\n```\n\"allowed-packages\": [\n  \"drupal/core\",\n],\n```\n### file-mapping\n\nThe `file-mapping` configuration setting consists of a map from the destination\npath of the file to scaffold to a set of properties that control how the file\nshould be scaffolded.\n\nThe available properties are as follows:\n\n- mode: One of \"replace\", \"append\" or \"skip\".\n- path: The path to the source file to write over the destination file.\n- prepend: The path to the source file to prepend to the destination file, which\n  must always be a scaffold file provided by some other project.\n- append: Like `prepend`, but appends content rather than prepends.\n- overwrite: If `false`, prevents a `replace` from happening if the destination\n  already exists.\n\nThe mode may be inferred from the other properties. If the mode is not\nspecified, then the following defaults will be supplied:\n\n- replace: Selected if a `path` property is present, or if the entry's value is\n  a string rather than a property set.\n- append: Selected if a `prepend` or `append` property is present.\n- skip: Selected if the entry's value is a boolean `false`.\n\nExamples:\n```\n\"file-mapping\": {\n  \"[web-root]/sites/default/default.settings.php\": {\n    \"mode\": \"replace\",\n    \"path\": \"assets/sites/default/default.settings.php\",\n    \"overwrite\": true\n  },\n  \"[web-root]/sites/default/settings.php\": {\n    \"mode\": \"replace\",\n    \"path\": \"assets/sites/default/settings.php\",\n    \"overwrite\": false\n  },\n  \"[web-root]/robots.txt\": {\n    \"mode\": \"append\",\n    \"prepend\": \"assets/robots-prequel.txt\",\n    \"append\": \"assets/robots-append.txt\"\n  },\n  \"[web-root]/.htaccess\": {\n    \"mode\": \"skip\",\n  }\n}\n```\nThe short-form of the above example would be:\n```\n\"file-mapping\": {\n  \"[web-root]/sites/default/default.settings.php\": \"assets/sites/default/default.settings.php\",\n  \"[web-root]/sites/default/settings.php\": {\n    \"path\": \"assets/sites/default/settings.php\",\n    \"overwrite\": false\n  },\n  \"[web-root]/robots.txt\": {\n    \"prepend\": \"assets/robots-prequel.txt\",\n    \"append\": \"assets/robots-append.txt\"\n  },\n  \"[web-root]/.htaccess\": false\n}\n```\nNote that there is no distinct \"prepend\" mode; \"append\" mode is used to both\nappend and prepend to scaffold files. The reason for this is that scaffold file\nentries are identified in the file-mapping section keyed by their destination\npath, and it is not possible for multiple entries to have the same key. If\n\"prepend\" were a separate mode, then it would not be possible to both prepend\nand append to the same file.\n\nBy default, append operations may only be applied to files that were scaffolded\nby a previously evaluated project. If the `force-append` attribute is added to\nan `append` operation, though, then the append will be made to non-scaffolded\nfiles if and only if the append text does not already appear in the file. When\nusing this mode, it is also possible to provide default contents to use in the\nevent that the destination file is entirely missing.\n\nThe example below demonstrates scaffolding a settings-custom.php file, and\nincluding it from the existing `settings.php` file.\n\n```\n\"file-mapping\": {\n  \"[web-root]/sites/default/settings-custom.php\": \"assets/settings-custom.php\",\n  \"[web-root]/sites/default/settings.php\": {\n    \"append\": \"assets/include-settings-custom.txt\",\n    \"force-append\": true,\n    \"default\": \"assets/initial-default-settings.txt\"\n  }\n}\n```\n\nNote that the example above still works if used with a project that scaffolds\nthe settings.php file.\n\n### gitignore\n\nThe `gitignore` configuration setting controls whether or not this plugin will\nmanage `.gitignore` files for files written during the scaffold operation.\n\n- true: `.gitignore` files will be updated when scaffold files are written.\n- false: `.gitignore` files will never be modified.\n- Not set: `.gitignore` files will be updated if the target directory is a local\nworking copy of a git repository, and the `vendor` directory is ignored\nin that repository.\n\n### locations\n\nThe `locations` configuration setting contains a list of named locations that\nmay be used in placing scaffold files. The only required location is `web-root`.\nOther locations may also be defined if desired.\n```\n\"locations\": {\n  \"web-root\": \"./docroot\"\n},\n```\n### symlink\n\nThe `symlink` property causes `replace` operations to make a symlink to the\nsource file rather than copying it. This is useful when doing core development,\nas the symlink files themselves should not be edited. Note that `append`\noperations override the `symlink` option, to prevent the original scaffold\nassets from being altered.\n```\n\"symlink\": true,\n```\n## Managing Scaffold Files\n\nScaffold files should be treated the same way that the `vendor` directory is\nhandled. If you need to commit `vendor` (e.g. in order to deploy your site),\nthen you should also commit your scaffold files. You should not commit your\n`vendor` directory or scaffold files unless it is necessary.\n\nIf a dependency provides a scaffold file with `overwrite` set to `false`, that\nfile should be committed to your repository.\n\nBy default, `.gitignore` files will be automatically updated if needed when\nscaffold files are written. See the `gitignore` setting in the Specifications\nsection above.\n\n## Examples\n\nSome full-length examples appear below.\n\nSample composer.json for a project that relies on packages that use composer-scaffold:\n```\n{\n  \"name\": \"my/project\",\n  \"require\": {\n    \"drupal/core-composer-scaffold\": \"*\",\n    \"composer/installers\": \"^1.2\",\n    \"cweagans/composer-patches\": \"^1.6.5\",\n    \"drupal/core\": \"^8.8.x-dev\",\n    \"service-provider/d8-scaffold-files\": \"^1\"\n  },\n  \"config\": {\n    \"optimize-autoloader\": true,\n    \"sort-packages\": true\n  },\n  \"extra\": {\n    \"drupal-scaffold\": {\n      \"allowed-packages\": [\n        \"drupal/core\"\n      ],\n      \"locations\": {\n        \"web-root\": \"./docroot\"\n      },\n      \"symlink\": true,\n      \"overwrite\": true,\n      \"file-mapping\": {\n        \"[web-root]/.htaccess\": false,\n        \"[web-root]/robots.txt\": \"assets/robots-default.txt\"\n      }\n    }\n  }\n}\n```\n\nSample composer.json for drupal/core, with assets placed in a different project:\n\n```\n{\n  \"name\": \"drupal/core\",\n  \"extra\": {\n    \"drupal-scaffold\": {\n      \"allowed-packages\": [\n        \"drupal/assets\",\n      ]\n    }\n  }\n}\n```\n\nSample composer.json for composer-scaffold files in drupal/assets:\n\n```\n{\n  \"name\": \"drupal/assets\",\n  \"extra\": {\n    \"drupal-scaffold\": {\n      \"file-mapping\": {\n        \"[web-root]/.csslintrc\": \"assets/.csslintrc\",\n        \"[web-root]/.editorconfig\": \"assets/.editorconfig\",\n        \"[web-root]/.eslintignore\": \"assets/.eslintignore\",\n        \"[web-root]/.eslintrc.json\": \"assets/.eslintrc.json\",\n        \"[web-root]/.gitattributes\": \"assets/.gitattributes\",\n        \"[web-root]/.ht.router.php\": \"assets/.ht.router.php\",\n        \"[web-root]/.htaccess\": \"assets/.htaccess\",\n        \"[web-root]/sites/default/default.services.yml\": \"assets/default.services.yml\",\n        \"[web-root]/sites/default/default.settings.php\": \"assets/default.settings.php\",\n        \"[web-root]/sites/example.settings.local.php\": \"assets/example.settings.local.php\",\n        \"[web-root]/sites/example.sites.php\": \"assets/example.sites.php\",\n        \"[web-root]/index.php\": \"assets/index.php\",\n        \"[web-root]/robots.txt\": \"assets/robots.txt\",\n        \"[web-root]/update.php\": \"assets/update.php\",\n        \"[web-root]/web.config\": \"assets/web.config\"\n      }\n    }\n  }\n}\n```\n\nSample composer.json for a library that implements composer-scaffold:\n\n```\n{\n  \"name\": \"service-provider/d8-scaffold-files\",\n  \"extra\": {\n    \"drupal-scaffold\": {\n      \"file-mapping\": {\n        \"[web-root]/sites/default/settings.php\": \"assets/sites/default/settings.php\"\n      }\n    }\n  }\n}\n```\n\nAppend to robots.txt:\n\n```\n{\n  \"name\": \"service-provider/d8-scaffold-files\",\n  \"extra\": {\n    \"drupal-scaffold\": {\n      \"file-mapping\": {\n        \"[web-root]/robots.txt\": {\n          \"append\": \"assets/my-robots-additions.txt\",\n        }\n      }\n    }\n  }\n}\n```\n\nPatch a file after it's copied:\n\n```\n\"post-drupal-scaffold-cmd\": [\n  \"cd docroot \u0026\u0026 patch -p1 \u003c../patches/htaccess-ssl.patch\"\n]\n```\n\n## Related Plugins\n\n### drupal-composer/drupal-scaffold\n\nPrevious versions of Drupal Composer Scaffold (see community project,\n[drupal-composer/drupal-scaffold](https://github.com/drupal-composer/drupal-project))\ndownloaded each scaffold file directly from its distribution server (e.g.\n`https://git.drupalcode.org`) to the desired destination directory. This was\nnecessary, because there was no subtree split of the scaffold files available.\nCopying the scaffold assets from projects already downloaded by Composer is more\neffective, as downloading and unpacking archive files is more efficient than\ndownloading each scaffold file individually.\n\n### composer/installers\n\nThe [composer/installers](https://github.com/composer/installers) plugin is\nsimilar to this plugin in that it allows dependencies to be installed in\nlocations other than the `vendor` directory. However, Composer and the\n`composer/installers` plugin have a limitation that one project cannot be moved\ninside of another project. Therefore, if you use `composer/installers` to place\nDrupal modules inside the directory `web/modules/contrib`, then you cannot also\nuse `composer/installers` to place files such as `index.php` and `robots.txt`\ninto the `web` directory. The drupal-scaffold plugin was created to work around\nthis limitation.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreg-1-anderson%2Fdrupal-core-composer-scaffold","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgreg-1-anderson%2Fdrupal-core-composer-scaffold","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreg-1-anderson%2Fdrupal-core-composer-scaffold/lists"}