Skip to content

Creating Virtual Files ​

Learn how to create different types of virtual files, configure them properly, and publish them to your WordPress site.

File Creation Process ​

Step 1: Access File Creation ​

  1. Navigate to Virtual Files

    • In WordPress admin, click Virtual Files in left menu
    • Click Add New button
    • Or visit directly: /wp-admin/post-new.php?post_type=idep_virtual_file
  2. File Creation Interface

    • Title: Descriptive name for your reference
    • Filename: Actual filename that will be served (without extension)
    • File Type: Extension and MIME type selection via dropdown
    • Content Editor: Where you add file content (textarea or CodeMirror)
    • Status: Active/Inactive selector in sidebar
    • Enhanced Info Sidebar: Shows MIME type, public URL, and analytics (Pro)
    • Action Buttons: Copy URL, Visit File, Upgrade to Pro

Step 2: Configure File Details ​

Basic Information ​

  • Title: Internal name for organization (e.g., "Main Robots File")
  • Path / File Name: The actual URL path and filename without extension (e.g., robots or .well-known/security)
  • File Type: Choose from supported extensions via dropdown

Using Paths and Folders 🆕 ​

Virtual Files now supports nested folder structures! You can create files in custom directories:

Examples:

  • Root files: robots → yourdomain.com/robots.txt
  • Nested 1 level: .well-known/security → yourdomain.com/.well-known/security.txt
  • Nested 2+ levels: api/v1/users → yourdomain.com/api/v1/users.json
  • Deep nesting: data/company/team/members → yourdomain.com/data/company/team/members.csv

Path Rules:

  • Use forward slashes (/) to separate folder levels
  • No leading or trailing slashes needed (they're automatically normalized)
  • Dots allowed in folder names (e.g., .well-known)
  • Both data/file and /data/file work the same
  • Single-letter folders supported (a/b/c/d/file)

Restricted Paths: The following WordPress core paths are blocked for security:

  • ❌ wp-admin/ - WordPress admin area
  • ❌ wp-includes/ - WordPress core files
  • ❌ wp-content/plugins/ - Plugin directory
  • ❌ wp-content/themes/ - Theme directory
  • ❌ wp-json/ - REST API endpoint
  • ❌ feed, embed, trackback - Reserved WordPress slugs
  • ❌ .htaccess - Server configuration files (blocked by most servers)

Automatic Validation: The Path / File Name field validates automatically when you click away from the field: |- ✅ Checks for restricted paths |- ✅ Prevents duplicate file paths |- ✅ Warns about .htaccess files |- ✅ Ensures proper formatting

File Types and Extensions ​

File TypeExtensionMIME TypeBest For
Text File.txttext/plainDocumentation, logs, simple data
Markdown.mdtext/markdownDocumentation, readme files
JSON.jsonapplication/jsonAPI responses, configuration
XML.xmlapplication/xmlCustom feeds, API data exchange
RSS.rssapplication/rss+xmlNews feeds, updates
CSV.csvtext/csvData export, spreadsheets
YAML.yml, .yamltext/yamlConfiguration files
Log File.logtext/plainDebug logs, access logs

Step 3: Add Content ​

Content Editor Features ​

  • Basic Editor (Free): Simple WordPress text area with monospace font
  • CodeMirror Editor (Pro): Professional code editor with:
    • Syntax highlighting for all supported file types
    • Line numbers and bracket matching
    • Search functionality
    • Dark/light theme options (default/monokai)
    • Auto-indent and code folding
    • Keyboard shortcuts (Ctrl-Space autocomplete, Ctrl-/ toggle comment, F11 fullscreen)

Content Validation ​

  • Real-time Validation: Shows file accessibility status
  • Security Scanning: Automatic content sanitization (PHP tag removal, script/iframe filtering)
  • Size Limits: 1MB maximum content size
  • Uniqueness Check: Prevents duplicate filenames
  • Character Validation: No forbidden characters (<>:"|?*)

File Type Examples ​

Text Files (.txt) ​

.well-known/ Security Files 🆕 ​

The .well-known URI is a standardized location for site metadata and verification files. Virtual Files makes it easy to create these without server access:

security.txt Example (Path: .well-known/security)

text
Contact: mailto:security@yourdomain.com
Contact: https://yourdomain.com/security-contact
Expires: 2027-12-31T23:59:59z
Preferred-Languages: en
Canonical: https://yourdomain.com/.well-known/security.txt
Policy: https://yourdomain.com/security-policy
Hiring: https://yourdomain.com/jobs
Acknowledgments: https://yourdomain.com/security-researchers

OpenAI Plugin Manifest (Path: .well-known/ai-plugin)

json
{
  "schema_version": "v1",
  "name_for_human": "My WordPress Site",
  "name_for_model": "wordpress_site",
  "description_for_human": "Access content from My WordPress Site",
  "description_for_model": "Retrieve blog posts, pages, and other content",
  "auth": {
    "type": "none"
  },
  "api": {
    "type": "openapi",
    "url": "https://yourdomain.com/.well-known/openapi.json"
  },
  "logo_url": "https://yourdomain.com/logo.png",
  "contact_email": "support@yourdomain.com",
  "legal_info_url": "https://yourdomain.com/legal"
}

Apple App Site Association (Path: .well-known/apple-app-site-association)

json
{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "TEAM_ID.com.yourcompany.app",
        "paths": ["/blog/*", "/news/*"]
      }
    ]
  },
  "webcredentials": {
    "apps": ["TEAM_ID.com.yourcompany.app"]
  }
}

robots.txt Example ​

text
User-agent: *
Allow: /
Disallow: /wp-admin/
Disallow: /wp-includes/
Disallow: /wp-content/plugins/
Disallow: /wp-content/themes/
Disallow: /readme.html
Disallow: /license.txt

# Allow specific bots
User-agent: Googlebot
Allow: /

User-agent: Bingbot
Allow: /

# Crawl delay
Crawl-delay: 10

# Crawl delay
Crawl-delay: 1

API Endpoints Example 🆕 ​

Create a virtual API structure with nested paths:

User Endpoint (Path: api/v1/users)

json
{
  "version": "1.0",
  "endpoint": "/api/v1/users",
  "users": [
    {
      "id": 1,
      "name": "John Doe",
      "email": "john@example.com",
      "role": "admin"
    }
  ]
}

Posts Endpoint (Path: api/v1/posts)

json
{
  "version": "1.0",
  "endpoint": "/api/v1/posts",
  "total": 50,
  "posts": [
    {
      "id": 1,
      "title": "Hello World",
      "slug": "hello-world",
      "excerpt": "Welcome to our blog"
    }
  ]
}

Markdown Files (.md) ​

API Documentation Example ​

markdown
# API Documentation

## Overview

This API provides access to website content in JSON format.

## Authentication

All API endpoints require authentication:

```bash
curl -H "Authorization: Bearer YOUR_TOKEN" \
     https://yourdomain.com/api/posts.json
```

Endpoints ​

Posts ​

URL: /api/posts.jsonMethod: GET Description: Retrieve all published posts

Response:

json
{
  "status": "success",
  "data": [
    {
      "id": 1,
      "title": "Sample Post",
      "slug": "sample-post",
      "content": "Post content here",
      "date": "2026-01-01T00:00:00Z",
      "author": "John Doe"
    }
  ],
  "total": 1,
  "pages": 1
}

Pages ​

URL: /api/pages.jsonMethod: GET Description: Retrieve all published pages

Media ​

URL: /api/media.jsonMethod: GET Description: Retrieve media library items

Error Handling ​

401 Unauthorized ​

json
{
  "error": "unauthorized",
  "message": "Invalid or missing authentication token"
}

404 Not Found ​

json
{
  "error": "not_found",
  "message": "Requested resource not found"
}

Rate Limiting ​

  • Requests: 100 per hour per IP
  • Burst: 10 requests per minute
  • Headers: Check X-RateLimit-Limit and X-RateLimit-Remaining

Usage Examples ​

JavaScript ​

javascript
// Fetch posts
fetch("/api/posts.json")
  .then(response => response.json())
  .then(data => {
    console.log("Posts:", data.data);
  })
  .catch(error => {
    console.error("Error:", error);
  });

PHP ​

php
// Fetch posts using WordPress HTTP API
$response = wp_remote_get('https://yourdomain.com/api/posts.json');
if (!is_wp_error($response)) {
  $data = json_decode(wp_remote_retrieve_body($response), true);
  print_r($data);
}

License ​

© 2026 Your Website Name. All rights reserved.


### **JSON Files (.json)**

#### **Configuration File Example**
```json
{
  "application": {
    "name": "My WordPress Site",
    "version": "1.0.0",
    "environment": "production",
    "debug": false
  },
  "api": {
    "version": "v1",
    "base_url": "https://yourdomain.com/api",
    "endpoints": {
      "posts": "/posts.json",
      "pages": "/pages.json",
      "media": "/media.json",
      "users": "/users.json"
    },
    "authentication": {
      "type": "bearer_token",
      "required": true
    },
    "rate_limiting": {
      "requests_per_hour": 100,
      "burst_per_minute": 10
    }
  },
  "features": {
    "caching": {
      "enabled": true,
      "ttl": 3600,
      "invalidation": "auto"
    },
    "cors": {
      "enabled": true,
      "allowed_origins": ["*"],
      "allowed_methods": ["GET", "POST", "PUT", "DELETE"],
      "allowed_headers": ["Content-Type", "Authorization"]
    },
    "analytics": {
      "enabled": true,
      "tracking_level": "detailed"
    }
  },
  "security": {
    "https_required": true,
    "token_expiration": 86400,
    "max_request_size": "10MB"
  },
  "database": {
    "type": "mysql",
    "version": "8.0+",
    "charset": "utf8mb4"
  },
  "wordpress": {
    "version": "6.0+",
    "multisite": false,
    "permalink_structure": "/%postname%/"
  }
}

API Response Example ​

json
{
  "status": "success",
  "message": "Data retrieved successfully",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "posts": [
      {
        "id": 1,
        "title": "Welcome to Our Site",
        "slug": "welcome",
        "content": "Welcome to our amazing website!",
        "excerpt": "Welcome to our amazing website!",
        "author": {
          "id": 1,
          "name": "Admin User",
          "email": "admin@yourdomain.com"
        },
        "categories": [
          {
            "id": 1,
            "name": "Uncategorized",
            "slug": "uncategorized"
          }
        ],
        "tags": ["welcome", "intro"],
        "featured_media": null,
        "status": "published",
        "date_created": "2026-01-01T10:00:00Z",
        "date_modified": "2026-01-01T10:00:00Z",
        "url": "https://yourdomain.com/welcome",
        "meta": {
          "views": 150,
          "likes": 12,
          "shares": 5
        }
      }
    ],
    "pagination": {
      "current_page": 1,
      "total_pages": 5,
      "total_items": 25,
      "items_per_page": 5,
      "has_next": true,
      "has_prev": false
    }
  },
  "performance": {
    "query_time": "0.045s",
    "memory_usage": "12.5MB",
    "cache_hit": true
  }
}

XML Files (.xml) ​

Custom Product Feed Example ​

xml
<?xml version="1.0" encoding="UTF-8"?>
<products>

    <!-- Widget A -->
    <product>
        <id>101</id>
        <name>Super Widget A</name>
        <price>19.99</price>
        <category>Widgets</category>
        <stock>In Stock</stock>
        <url>https://yourdomain.com/product/widget-a</url>
        <image>https://yourdomain.com/wp-content/uploads/2026/01/widget-a.jpg</image>
    </product>

    <!-- Widget B -->
    <product>
        <id>102</id>
        <name>Mega Widget B</name>
        <price>29.99</price>
        <category>Widgets</category>
        <stock>Out of Stock</stock>
        <url>https://yourdomain.com/product/widget-b</url>
        <image>https://yourdomain.com/wp-content/uploads/2026/01/widget-b.jpg</image>
    </product>

    <!-- Accessories -->
    <product>
        <id>201</id>
        <name>Widget Stand</name>
        <price>9.99</price>
        <category>Accessories</category>
        <stock>In Stock</stock>
        <url>https://yourdomain.com/product/widget-stand</url>
    </product>

</products>

RSS Feed Example ​

xml
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:dc="http://purl.org/dc/elements/1.1/">

    <channel>
        <title>My WordPress Site</title>
        <description>Latest news and updates from My WordPress Site</description>
        <link>https://yourdomain.com</link>
        <language>en-US</language>
        <copyright>Copyright 2026 My WordPress Site. All rights reserved.</copyright>
        <managingEditor>editor@yourdomain.com</managingEditor>
        <webMaster>webmaster@yourdomain.com</webMaster>
        <pubDate>Mon, 01 Jan 2026 12:00:00 +0000</pubDate>
        <lastBuildDate>Mon, 01 Jan 2026 12:00:00 +0000</lastBuildDate>
        <generator>WordPress 6.0</generator>
        <docs>https://www.rssboard.org/rss/specification</docs>
        <ttl>60</ttl>
        <image>
            <url>https://yourdomain.com/wp-content/uploads/2026/01/logo.jpg</url>
            <title>My WordPress Site</title>
            <link>https://yourdomain.com</link>
            <width>144</width>
            <height>144</height>
            <description>Site logo</description>
        </image>

        <!-- Posts -->
        <item>
            <title>Sample Post Title</title>
            <link>https://yourdomain.com/sample-post</link>
            <comments>https://yourdomain.com/sample-post#comments</comments>
            <pubDate>Mon, 01 Jan 2026 10:00:00 +0000</pubDate>
            <dc:creator>Admin User</dc:creator>
            <category>Technology</category>
            <category>WordPress</category>
            <guid isPermaLink="true">https://yourdomain.com/sample-post</guid>
            <description>This is a sample post description that appears in RSS feeds.</description>
            <content:encoded><![CDATA[
                <p>This is the full content of the post with <strong>HTML formatting</strong> preserved.</p>
                <img src="https://yourdomain.com/wp-content/uploads/2026/01/post-image.jpg" alt="Post image" />
                <p>Continue reading the post for more information...</p>
            ]]></content:encoded>
            <enclosure url="https://yourdomain.com/wp-content/uploads/2026/01/podcast.mp3"
                     type="audio/mpeg"
                     length="1234567" />
        </item>

        <item>
            <title>Another Post</title>
            <link>https://yourdomain.com/another-post</link>
            <pubDate>Sun, 31 Dec 2023 15:30:00 +0000</pubDate>
            <dc:creator>Guest Author</dc:creator>
            <category>Tutorials</category>
            <description>Another post description for RSS feed.</description>
            <content:encoded><![CDATA[
                <p>Full content with HTML formatting and images.</p>
            ]]></content:encoded>
        </item>

    </channel>

</rss>

CSV Files (.csv) ​

Product Export Example ​

csv
id,title,description,price,category,stock,sku,created_at
1,"WordPress Theme","Premium WordPress theme with modern design",49.99,"Themes",15,"WP-THEME-001","2026-01-01T10:00:00Z"
2,"Plugin Bundle","Collection of essential WordPress plugins",29.99,"Plugins",50,"WP-BUNDLE-001","2026-01-02T14:30:00Z"
3,"Support Package","1 year priority support package",99.99,"Services",100,"WP-SUPPORT-001","2026-01-03T09:15:00Z"
4,"Custom Development","Custom WordPress development service",299.99,"Services",5,"WP-DEV-001","2026-01-04T16:45:00Z"

User Export Example ​

csv
id,username,email,first_name,last_name,role,registered_at,last_login
1,"admin","admin@yourdomain.com","Admin","User","administrator","2026-01-01T10:00:00Z","2026-01-15T14:30:00Z"
2,"editor","editor@yourdomain.com","Editor","User","editor","2026-01-02T11:20:00Z","2026-01-14T09:45:00Z"
3,"author","author@yourdomain.com","Author","User","author","2026-01-03T13:45:00Z","2026-01-13T16:20:00Z"

YAML Files (.yml/.yaml) ​

Docker Configuration Example ​

yaml
# WordPress Docker Configuration
version: "3.8"

services:
  # WordPress Application
  wordpress:
    image: wordpress:6.0-php8.0-apache
    container_name: my-wordpress
    restart: unless-stopped
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: secure_password_here
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_TABLE_PREFIX: wp_
      WORDPRESS_DEBUG: false
    volumes:
      - ./wp-content:/var/www/html/wp-content
      - ./uploads:/var/www/html/wp-content/uploads
    depends_on:
      - db
    networks:
      - wordpress-network

  # MySQL Database
  db:
    image: mysql:8.0
    container_name: my-wordpress-db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: secure_password_here
      MYSQL_ROOT_PASSWORD: root_password_here
    volumes:
      - db_data:/var/lib/mysql
      - ./mysql-backups:/backup
    networks:
      - wordpress-network

  # Redis Cache
  redis:
    image: redis:7-alpine
    container_name: my-wordpress-redis
    restart: unless-stopped
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    networks:
      - wordpress-network

  # Nginx Reverse Proxy
  nginx:
    image: nginx:alpine
    container_name: my-wordpress-nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - wordpress
    networks:
      - wordpress-network

# Volumes
volumes:
  db_data:
    driver: local
  redis_data:
    driver: local

# Networks
networks:
  wordpress-network:
    driver: bridge

CI/CD Pipeline Example ​

yaml
# GitHub Actions Workflow for WordPress
name: WordPress Deployment

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  NODE_VERSION: "18"
  PHP_VERSION: "8.0"

jobs:
  # Test Suite
  test:
    runs-on: ubuntu-latest

    services:
      mysql:
        image: mysql:8.0
        env:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: wordpress_test
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=3
        ports:
          - 3306:3306

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: "npm"

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ env.PHP_VERSION }}
          extensions: mbstring, xml, mysql, curl
          coverage: xdebug

      - name: Install dependencies
        run: |
          npm ci
          composer install --no-progress --no-suggest --optimize-autoloader

      - name: Run tests
        run: |
          npm run test:php
          npm run test:js

      - name: Code coverage
        run: |
          npm run coverage:php
          npm run coverage:js

  # Build and Deploy
  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: ${{ env.NODE_VERSION }}

      - name: Build assets
        run: |
          npm ci
          npm run build

      - name: Deploy to server
        uses: appleboy/ssh-action@v0.1.5
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /var/www/html
            git pull origin main
            npm run build
            wp plugin activate virtual-files
            wp cache flush

Free vs Pro File Limits ​

Free Version ​

  • Maximum 5 active virtual files at a time

  • Create and manage unlimited files, but you can only set up to 5 files to the "Active" status simultaneously.

  • Basic text editor only

  • No file analytics

Pro Version ​

  • Unlimited virtual files
  • All active files are accessible
  • Advanced CodeMirror editor
  • File analytics and tracking
  • All file types supported

Publishing and Testing ​

Publishing Your File ​

  1. Review Content: Double-check your file content for errors
  2. Set Status: Choose "Active" to make file publicly accessible or "Inactive" to keep it private
  3. Save File: Click "Publish" (for new files) or "Update" (for existing files)
  4. Test Access: Verify file is accessible via its URL

Testing Your Virtual File ​

  1. Direct URL: Visit yourdomain.com/your-filename.ext
  2. Headers Check: Verify correct MIME headers are sent
  3. Content Validation: Ensure content displays correctly
  4. Performance: Check load times and caching

Common Testing Methods ​

CURL Testing ​

bash
# Test file with headers
curl -I https://yourdomain.com/robots.txt

# Test file content
curl https://yourdomain.com/api-config.json

# Test with specific headers
curl -H "Accept: application/json" \
     https://yourdomain.com/api-endpoint.json

Browser Testing ​

  • Chrome DevTools: Check Network tab for headers
  • Firefox Developer: Inspect response headers
  • Safari Web Inspector: Verify content delivery

Validation Tools ​

Best Practices ​

File Naming & Paths 🆕 ​

  • Use lowercase for consistency (api/users, not API/Users)
  • Avoid spaces - use hyphens instead (my-file, not my file)
  • Keep paths descriptive but not too long
  • Use standard conventions:
    • .well-known/ for standard metadata files
    • api/ for API endpoints
    • data/ for data files
    • assets/ for static resources
  • Avoid special characters in path names (only letters, numbers, hyphens, dots, slashes)
  • Single-letter folders work but use meaningful names when possible
  • Don't use restricted paths (wp-admin, wp-includes, etc.)
  • Test your URLs before publishing

Content Optimization ​

  • Keep file sizes reasonable
  • Use proper formatting
  • Validate syntax before publishing
  • Test in multiple browsers

Security Considerations ​

  • Don't include sensitive data
  • Validate user input in dynamic content
  • Use HTTPS for sensitive endpoints
  • Regular security audits

Performance Tips ​

  • Enable caching for frequently accessed files (Pro feature)
  • Use appropriate file formats for your use case
  • Monitor file access through WordPress analytics (Pro feature)
  • Consider rewrite rules efficiency

Troubleshooting ​

Common Issues ​

File Not Accessible ​

  1. Check file status is "Active" (for Free users: only 5 most recent active files are accessible)
  2. Verify rewrite rules are flushed (Settings → Permalinks → Save)
  3. Check file doesn't conflict with existing WordPress URLs
  4. For nested paths, ensure all parent folders are in the path (e.g., api/v1/users, not users)
  5. Test with different browsers

Path Validation Errors 🆕 ​

  1. "Cannot use WordPress reserved path"

    • Avoid wp-admin/, wp-includes/, wp-json/, etc.
    • Don't use feed, embed, or trackback as first folder
    • Choose a different path that doesn't conflict with WordPress core
  2. ".htaccess files are blocked"

    • Most web servers block .htaccess files for security
    • Use a different filename or file type
    • Server configuration files cannot be served as virtual files
  3. "Path should not include file extension"

    • Don't add extensions in the Path field (.well-known/security, not .well-known/security.txt)
    • Select the extension from the "File Type" dropdown instead

Incorrect MIME Type ​

  1. Verify file extension matches content
  2. Check MIME type settings
  3. Validate content format
  4. Test with header inspection tools

Content Not Displaying ​

  1. Check for syntax errors
  2. Verify content encoding
  3. Test with validation tools
  4. Check browser console for errors

Getting Help ​

Next Steps ​

Now that you've mastered creating virtual files:

  1. Learn File Management: Advanced organization techniques
  2. Configure Settings: Optimize your plugin configuration
  3. Explore Backup & Restore: Backup and restore capabilities
  4. Check Features: Discover advanced functionality

Virtual Files - Better WordPress SEO Through Smart Virtual File Management