# Farn Core (`farn/farn-core`)

**Farn Core** is the centralized, shared PHP foundation library used across all internal FarnLabs custom WordPress plugins. It provides essential cross-cutting services such as API-based license validation, unified application logging with an admin viewer, automated plugin updates from custom release servers, and shared UI assets.

By embedding `farn/farn-core` via Composer, all Farn plugins remain DRY (*Don't Repeat Yourself*), maintain consistent architectural patterns, and benefit from shared backend infrastructure updates.

---

## 📋 Table of Contents

- [Overview & Capabilities](#-overview--capabilities)
  - [1. License Management (`Farn\Core\License`)](#1-license-management-farncorelicense)
  - [2. Centralized Logging & Viewer (`Farn\Core\Log` & `Farn\Core\LogViewer`)](#2-centralized-logging--viewer-farncorelog--farncorelogviewer)
  - [3. Remote Updater (`Farn\Core\Update`)](#3-remote-updater-farncoreupdate)
  - [4. Plugin UI Icons (`Farn\Core\PluginIcons`)](#4-plugin-ui-icons-farncorepluginicons)
- [🔐 Setting Up Composer for Private Repositories & Access Tokens](#-setting-up-composer-for-private-repositories--access-tokens)
  - [Step 1: Declare the Private VCS Repository](#step-1-declare-the-private-vcs-repository)
  - [Step 2: Configure Authentication (Access Tokens)](#step-2-configure-authentication-access-tokens)
    - [Option A: Global CLI Configuration (Recommended for Local Dev)](#option-a-global-cli-configuration-recommended-for-local-dev)
    - [Option B: Using `auth.json`](#option-b-using-authjson)
    - [Option C: Using `COMPOSER_AUTH` Environment Variable (Best for CI/CD)](#option-c-using-composer_auth-environment-variable-best-for-cicd)
    - [Option D: Using SSH Keys (Alternative)](#option-d-using-ssh-keys-alternative)
  - [Step 3: Require the Package](#step-3-require-the-package)
- [🚀 Integration & Usage Guide](#-integration--usage-guide)
  - [1. Autoloading](#1-autoloading)
  - [2. Remote Updater Integration](#2-remote-updater-integration)
  - [3. Centralized Logging Integration](#3-centralized-logging-integration)
  - [4. License System Integration](#4-license-system-integration)
  - [5. Enqueuing Shared Admin Icons](#5-enqueuing-shared-admin-icons)
- [👨‍💻 Maintainer & Contribution Guidelines](#-maintainer--contribution-guidelines)

---

## 📦 Overview & Capabilities

### 1. License Management (`Farn\Core\License`)
- Communicates securely with `services.farnlabs.de` to check and validate plugin licenses.
- Automatically handles legacy option migrations (e.g., `farn_license_option_migration_v1`).
- Caches valid status using WordPress Transients (1-hour TTL) to minimize remote HTTP requests and overhead.
- Supports license key saving, retrieval, and deletion routines.

### 2. Centralized Logging & Viewer (`Farn\Core\Log` & `Farn\Core\LogViewer`)
- Logs standardized output directly into `wp-content/farn-logs/farnLog_DD-MM-YY.log`.
- Automatically inspects the debug backtrace to capture the exact originating plugin slug, file path, and line number.
- Supports log severity levels (`logInfo`, `logWarning`, `logError`) and optional debug-only logging.
- Includes a daily WP Cron job to clean logs older than 7 days.
- Renders an admin management screen under **Settings > Farn Core Logs** with tabs for both Farn Core logs and `wp-content/debug.log`.

### 3. Remote Updater (`Farn\Core\Update`)
- Hooks into WordPress transient filters (`pre_set_site_transient_update_plugins` and `plugins_api`).
- Queries `services.farnlabs.de` (supports individual and batch endpoint requests) for plugin update metadata.
- Dynamically appends valid license credentials and site domain parameters to update package download URLs.
- Automatically formats structured multi-language patch notes into WordPress-native HTML changelogs.

### 4. Plugin UI Icons (`Farn\Core\PluginIcons`)
- Enqueues shared admin stylesheet assets (`resources/plugin-icons/menuIcon.css`) to enforce uniform icon styling across Farn plugins.

---

## 🔐 Setting Up Composer for Private Repositories & Access Tokens

Since `farn/farn-core` is hosted in a private Git repository, Composer requires authentication credentials (such as a GitHub/GitLab Personal Access Token) to fetch the source code.

Follow these steps to configure your environment or plugin project.

### Step 1: Declare the Private VCS Repository

In the dependent WordPress plugin's `composer.json`, add the private VCS repository URL:

```json
{
    "name": "farn/my-custom-plugin",
    "type": "wordpress-plugin",
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/farnlabs/farn-core.git"
        }
    ],
    "require": {
        "farn/farn-core": "^0.0.1"
    }
}
```

---

### Step 2: Configure Authentication (Access Tokens)

To authorize Composer to pull from private repositories without embedding secrets in project source code, use one of the following methods.

#### Option A: Global CLI Configuration (Recommended for Local Dev)

Generate a **Personal Access Token (PAT)** on GitHub (with `repo` read scope) or GitLab, then run the CLI command:

* **For GitHub:**
  ```bash
  composer config --global github-oauth.github.com <YOUR_PERSONAL_ACCESS_TOKEN>
  ```

* **For GitLab (if applicable):**
  ```bash
  composer config --global gitlab-token.gitlab.com <YOUR_PERSONAL_ACCESS_TOKEN>
  ```

* **For Custom HTTP Basic Auth / Private Git Host:**
  ```bash
  composer config --global http-basic.git.farnlabs.de token <YOUR_PERSONAL_ACCESS_TOKEN>
  ```

Composer will store credentials in your user-level configuration (`~/.composer/auth.json`), so you only need to run this once per machine.

---

#### Option B: Using `auth.json`

You can create an `auth.json` file in your global Composer folder (`~/.composer/auth.json`) or in your local project root (**be sure to add `auth.json` to `.gitignore`**):

```json
{
    "github-oauth": {
        "github.com": "ghp_yourPersonalAccessTokenHere123456789"
    }
}
```

*For GitLab or HTTP Basic Auth:*
```json
{
    "http-basic": {
        "git.farnlabs.de": {
            "username": "token",
            "password": "your_access_token_here"
        }
    }
}
```

---

#### Option C: Using `COMPOSER_AUTH` Environment Variable (Best for CI/CD)

For automated build scripts, Docker containers, or CI/CD pipelines (e.g. GitHub Actions), pass credentials dynamically using the `COMPOSER_AUTH` environment variable:

```bash
export COMPOSER_AUTH='{"github-oauth": {"github.com": "'"$GITHUB_TOKEN"'"}}'
composer install --no-dev --optimize-autoloader
```

---

#### Option D: Using SSH Keys (Alternative)

If developers have SSH keys configured in GitHub/GitLab, you can specify the SSH repository URL instead of HTTPS in `composer.json`:

```json
"repositories": [
    {
        "type": "vcs",
        "url": "git@github.com:farnlabs/farn-core.git"
    }
]
```
*(No token setup is needed for SSH if your SSH agent has access).*

---

### Step 3: Require the Package

Once authentication is configured, install the package using:

```bash
composer require farn/farn-core
```

---

## 🚀 Integration & Usage Guide

### 1. Autoloading

In your plugin's main entry file (e.g. `my-plugin.php`), load the Composer autoloader:

```php
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
    require_once __DIR__ . '/vendor/autoload.php';
}
```

---

### 2. Remote Updater Integration

To enable automatic updates via Farn's release servers, register the updater during plugin initialization:

```php
use Farn\Core\Update;
use Farn\Core\License;

add_action('plugins_loaded', function() {
    Update::setup(
        pluginSlug: 'my-custom-plugin',
        software: 'my_custom_plugin_identifier',
        path_to_main_plugin_file: __FILE__,
        plugin_base_name: plugin_basename(__FILE__),
        licenceKey: License::getLicenceKey(),
        installation_content: '<p>Installation instructions here.</p>',
        description_content: '<p>Plugin description here.</p>',
        faq_content: '<p>FAQ content here.</p>',
        banner_url_low: 'https://example.com/banner-772x250.jpg',
        banner_url_high: 'https://example.com/banner-1544x500.jpg'
    );
});
```

---

### 3. Centralized Logging Integration

Initialize logging early in your plugin setup:

```php
use Farn\Core\Log;

// Initialize log cleanup CRON and Admin Log Viewer menu
Log::setup();

// Optional: Enable debug-only logs during development
// Log::enableDebugMode();

// Logging entries throughout your code
Log::logInfo('Plugin initialized successfully.');
Log::logWarning('API response slow.', showOnlyInDebug: true);
Log::logError('Failed to execute process for ID: ' . $id);
```

Log entries will be written to `wp-content/farn-logs/farnLog_DD-MM-YY.log` formatted like:
```text
29-07-26 05:15:30[INFO]: [my-custom-plugin]: Plugin initialized successfully. -> Called from: plugins/my-custom-plugin/my-custom-plugin.php on line 42
```

---

### 4. License System Integration

Initialize and check license keys before executing premium features:

```php
use Farn\Core\License;

// Initialize license options for the software slug
License::initLicence('my_custom_plugin_identifier');

// Verify if a valid license is present
if (License::validLicence()) {
    // Proceed with plugin logic
} else {
    // Show license key notice or restriction UI
}

// Programmatically save or remove license keys
License::save_licence_key('YOUR-LICENSE-KEY-1234');
// License::removeLicence();
```

---

### 5. Enqueuing Shared Admin Icons

To load the shared stylesheet for admin icons:

```php
use Farn\Core\PluginIcons;

PluginIcons::setup();
```

---

## 👨‍💻 Maintainer & Contribution Guidelines

When adding functionality to `farn/farn-core`:

1. **PSR-4 Namespacing**: All core files must reside in `src/` under the `Farn\Core` namespace.
2. **Context Safety**: Be mindful that multiple Farn plugins on the same site may load `farn/farn-core`. Avoid global function collisions; use static class methods or unique hooks.
3. **Backward Compatibility**: Preserve existing signatures for `Update::setup`, `Log::logInfo`, `License::validLicence`, etc.
4. **Testing Context**: Note that WordPress environment functions (`get_option`, `add_action`, `wp_remote_get`, etc.) are assumed.
