# Sources

A source is a folder Byte reads snippets from. Every folder inside it that
holds a `snippet.json`, at any depth, is a snippet. Byte shows all sources in
one file tree and runs the snippets of all of them.

## The default source

Without configuration Byte has one source, named `Snippets`, in the uploads
folder:

```text
wp-content/uploads/sleek-byte/
```

On a multisite network each site uses its own uploads folder, so a site's
default snippets live in `wp-content/uploads/sites/<site id>/sleek-byte/`.

Byte creates this folder when it needs it and adds an `index.php` and an
`.htaccess` that refuse every direct web request except for the stylesheets,
scripts, images and fonts a snippet loads, so snippet code and its history
cannot be read by URL on servers that read `.htaccess`.

Every PHP file Byte writes, in any source, also starts with
`defined('ABSPATH') || exit;`, so a PHP file requested by its URL outside
WordPress exits before it runs, whatever the server. The line comes after a
`declare` or `namespace` statement, and a file that starts outside PHP, such as
a template, takes `<?php defined('ABSPATH') || exit; ?>` in front of it; a file
that already starts with an `ABSPATH` check keeps its own. Byte adds the line
again when you save a file without it, and on updating to this release adds it
to the PHP files already in `uploads/sleek-byte` and the preview folder. PHP
files you put into a source another way, such as over SFTP or in a source your
own filter adds, need the line themselves.

Nginx does not read `.htaccess`, so there `snippet.json`, the snippet history
and other files can still be read by URL. Give it the same rule for each Byte
folder in uploads:

```nginx
location ~ ^/wp-content/uploads/(sites/[0-9]+/)?sleek-byte[^/]*/ {
    location ~ \.(css|js|mjs|map|png|jpe?g|gif|svg|webp|avif|ico|woff2?|ttf|otf|eot)$ {
        try_files $uri =404;
    }
    deny all;
}
```

## Adding sources

The `sleekByte/snippets/paths` filter returns the list of sources. Each entry
has three keys:

| Key    | Meaning                                                                                                                                   |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | The name shown as the source's top-level folder in the file tree. It must be unique: the workspace shows only the first source of a name. |
| `path` | The absolute path of the folder.                                                                                                          |
| `sort` | The tree order, lower first. The default source uses 100.                                                                                 |

```php
add_filter('sleekByte/snippets/paths', function ($sources) {
  $sources[] = [
    'name' => 'Theme Snippets',
    'path' => get_stylesheet_directory() . '/snippets',
    'sort' => 50,
  ];

  return $sources;
});
```

Byte creates and protects only its default folder. Create the folder of a
source you add yourself; a source whose path does not exist is skipped.

CSS, SCSS and JavaScript files load by URL, which Byte derives from where the
file sits: in uploads, in `wp-content` or anywhere below it, in the plugins
folder or in the themes folder. Keep a source inside one of those, or its
stylesheets and scripts cannot load. PHP files run from anywhere.

Returning a list without the default entry removes the uploads source, and
returning an empty list stops every saved snippet; the
[preview](/docs/byte/snippets/preview.md) does exactly that while it shows a
draft.

## Where new files go

The workspace creates new snippets, files and folders in the source listed
first in the tree, the one with the lowest `sort`. WP-CLI writes new snippets
and new files into the first source of the list the filter returns, which is
the uploads source unless your filter puts another one first. Files that
already exist are written where they are.

## Examples

Snippets that ship with a theme, and with its child theme when there is one:

```php
add_filter('sleekByte/snippets/paths', function ($sources) {
  $sources[] = [
    'name' => 'Theme Snippets',
    'path' => get_template_directory() . '/snippets',
    'sort' => 10,
  ];

  if (get_template_directory() !== get_stylesheet_directory()) {
    $sources[] = [
      'name' => 'Child Theme Snippets',
      'path' => get_stylesheet_directory() . '/snippets',
      'sort' => 5,
    ];
  }

  return $sources;
});
```

Snippets that exist only in one environment:

```php
add_filter('sleekByte/snippets/paths', function ($sources) {
  if (wp_get_environment_type() === 'development') {
    $uploads = wp_upload_dir();

    $sources[] = [
      'name' => 'Development Tools',
      'path' => $uploads['basedir'] . '/sleek-byte-dev',
      'sort' => 5,
    ];
  }

  return $sources;
});
```

A snippet can also limit itself to environments without a separate source,
through `environments` in its [configuration](/docs/byte/snippets/configuration.md).
