*
* @package org.cocur.slugify
* @author Florian Eckerstorfer <florian@eckerstorfer.co>
* @author Marchenko Alexandr
* @copyright 2012-2014 Florian Eckerstorfer
* @license http://www.opensource.org/licenses/MIT The MIT License
*/
interface SlugifyInterface
{
/**
* Return a URL safe version of a string.
*
* @param string $string
* @param string|array|null $options
*
* @return string
*
* @api
*/
public function slugify(string $string, array|string|null $options = null): string;
}
"syntax error, unexpected '|', expecting variable (T_VARIABLE) (View: /home/forge/dev.tfs.staging.poundandgrain.ca/releases/20241113033749/web/app/themes/tfs/resources/views/single.blade.php)"
*
* @param string $__path
* @param array $__data
* @return string
*/
protected function evaluatePath($__path, $__data)
{
$obLevel = ob_get_level();
ob_start();
extract($__data, EXTR_SKIP);
// We'll evaluate the contents of the view inside a try/catch block so we can
// flush out any stray output that might get out before an error occurs or
// an exception is thrown. This prevents any partial views from leaking.
try {
include $__path;
} catch (Throwable $e) {
$this->handleViewException($e, $obLevel);
}
return ltrim(ob_get_clean());
}
/**
* Handle a view exception.
*
* @param \Throwable $e
* @param int $obLevel
* @return void
*
* @throws \Throwable
*/
protected function handleViewException(Throwable $e, $obLevel)
{
while (ob_get_level() > $obLevel) {
ob_end_clean();
}
*
* @package org.cocur.slugify
* @author Florian Eckerstorfer <florian@eckerstorfer.co>
* @author Marchenko Alexandr
* @copyright 2012-2014 Florian Eckerstorfer
* @license http://www.opensource.org/licenses/MIT The MIT License
*/
interface SlugifyInterface
{
/**
* Return a URL safe version of a string.
*
* @param string $string
* @param string|array|null $options
*
* @return string
*
* @api
*/
public function slugify(string $string, array|string|null $options = null): string;
}
"syntax error, unexpected '|', expecting variable (T_VARIABLE)"
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
*
* For the full copyright and license information, please view the LICENSE.md
* file that was distributed with this source code.
*
* ------------------------------------------------------------------
*/
declare(strict_types=1);
namespace TOC;
use Cocur\Slugify\Slugify;
use Cocur\Slugify\SlugifyInterface;
/**
* UniqueSlugify creates slugs from text without repeating the same slug twice per instance
*
* @author Casey McLaughlin <caseyamcl@gmail.com>
*/
class UniqueSlugify implements SlugifyInterface
{
/**
* @var SlugifyInterface
*/
private $slugify;
/**
* @var array
*/
private $used;
/**
* Constructor
*
* @param SlugifyInterface|null $slugify
*/
public function __construct(?SlugifyInterface $slugify = null)
{
$this->used = array();
$this->slugify = $slugify ?: new Slugify();
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}
"/home/forge/dev.tfs.staging.poundandgrain.ca/releases/20241113033749/vendor/caseyamcl/toc/src/UniqueSlugify.php"
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
/**
* @var HTML5
*/
private $htmlParser;
/**
* @var SlugifyInterface
*/
private $slugifier;
/**
* Constructor
*
* @param HTML5|null $htmlParser
* @param SlugifyInterface|null $slugify
*/
public function __construct(?HTML5 $htmlParser = null, ?SlugifyInterface $slugify = null)
{
$this->htmlParser = $htmlParser ?? new HTML5();
$this->slugifier = $slugify ?? new UniqueSlugify();
}
/**
* Fix markup
*
* @param string $markup
* @param int $topLevel
* @param int $depth
* @return string Markup with added IDs
* @throws RuntimeException
*/
public function fix(string $markup, int $topLevel = 1, int $depth = 6): string
{
if (! $this->isFullHtmlDocument($markup)) {
$partialID = uniqid('toc_generator_');
$markup = sprintf("<body id='%s'>%s</body>", $partialID, $markup);
}
$domDocument = $this->htmlParser->loadHTML($markup);
$domDocument->preserveWhiteSpace = true; // do not clobber whitespace
<?php
namespace App\View\Composers;
use DOMDocument;
use Roots\Acorn\View\Composer;
class BlogPost extends Composer
{
protected static $views = [
'partials.content-single',
];
public function override()
{
$fields = get_fields();
$htmlContent = apply_filters( 'the_content', get_the_content() );
$markupFixer = new \TOC\MarkupFixer();
$tocGenerator = new \TOC\TocGenerator();
$htmlContent = $markupFixer->fix($htmlContent);
$fields['toc'] = $tocGenerator->getOrderedHtmlMenu($htmlContent);
$fields['the_content'] = $htmlContent;
$fields['the_category'] = $this->getCategory();
return $fields;
}
public function getCategory() {
$category = null;
if(get_the_terms(get_the_id(), 'category')) {
foreach(get_the_terms(get_the_id(), 'category') as $term) {
if($term->name !== "Blog" && $term->name !== "Events" && $term->name !== "News") {
$category = $term;
return $category;
}
}
}
*/
public function compose(View $view)
{
$this->view = $view;
$this->data = new Fluent($view->getData());
$view->with($this->merge());
}
/**
* Data to be merged and passed to the view before rendering.
*
* @return array
*/
protected function merge()
{
return array_merge(
$this->with(),
$this->view->getData(),
$this->override()
);
}
/**
* Data to be passed to view before rendering
*
* @return array
*/
protected function with()
{
return [];
}
/**
* Data to be passed to view before rendering
*
* @return array
*/
protected function override()
{
return static::$views;
}
$view = array_slice(explode('\\', static::class), 3);
$view = array_map([Str::class, 'snake'], $view, array_fill(0, count($view), '-'));
return implode('/', $view);
}
/**
* Compose the view before rendering.
*
* @param \Illuminate\View\View $view
* @return void
*/
public function compose(View $view)
{
$this->view = $view;
$this->data = new Fluent($view->getData());
$view->with($this->merge());
}
/**
* Data to be merged and passed to the view before rendering.
*
* @return array
*/
protected function merge()
{
return array_merge(
$this->with(),
$this->view->getData(),
$this->override()
);
}
/**
* Data to be passed to view before rendering
*
* @return array
return $callback;
}
/**
* Build a class based container callback Closure.
*
* @param string $class
* @param string $prefix
* @return \Closure
*/
protected function buildClassEventCallback($class, $prefix)
{
[$class, $method] = $this->parseClassEvent($class, $prefix);
// Once we have the class and method name, we can build the Closure to resolve
// the instance out of the IoC container and call the method on it with the
// given arguments that are passed to the Closure as the composer's data.
return function () use ($class, $method) {
return $this->container->make($class)->{$method}(...func_get_args());
};
}
/**
* Parse a class based composer name.
*
* @param string $class
* @param string $prefix
* @return array
*/
protected function parseClassEvent($class, $prefix)
{
return Str::parseCallback($class, $this->classEventMethodForPrefix($prefix));
}
/**
* Determine the class event method based on the given prefix.
*
* @param string $prefix
* @return string
* @param \Closure|string $listener
* @param bool $wildcard
* @return \Closure
*/
public function makeListener($listener, $wildcard = false)
{
if (is_string($listener)) {
return $this->createClassListener($listener, $wildcard);
}
if (is_array($listener) && isset($listener[0]) && is_string($listener[0])) {
return $this->createClassListener($listener, $wildcard);
}
return function ($event, $payload) use ($listener, $wildcard) {
if ($wildcard) {
return $listener($event, $payload);
}
return $listener(...array_values($payload));
};
}
/**
* Create a class based listener using the IoC container.
*
* @param string $listener
* @param bool $wildcard
* @return \Closure
*/
public function createClassListener($listener, $wildcard = false)
{
return function ($event, $payload) use ($listener, $wildcard) {
if ($wildcard) {
return call_user_func($this->createClassCallable($listener), $event, $payload);
}
$callable = $this->createClassCallable($listener);
return $callable(...array_values($payload));
* @param bool $halt
* @return array|null
*/
public function dispatch($event, $payload = [], $halt = false)
{
// When the given "event" is actually an object we will assume it is an event
// object and use the class as the event name and this event itself as the
// payload to the handler, which makes object based events quite simple.
[$event, $payload] = $this->parseEventAndPayload(
$event, $payload
);
if ($this->shouldBroadcast($payload)) {
$this->broadcastEvent($payload[0]);
}
$responses = [];
foreach ($this->getListeners($event) as $listener) {
$response = $listener($event, $payload);
// If a response is returned from the listener and event halting is enabled
// we will just return this response, and not call the rest of the event
// listeners. Otherwise we will add the response on the response list.
if ($halt && ! is_null($response)) {
return $response;
}
// If a boolean false is returned from a listener, we will stop propagating
// the event to any further listeners down in the chain, else we keep on
// looping through the listeners and firing every one in our sequence.
if ($response === false) {
break;
}
$responses[] = $response;
}
return $halt ? null : $responses;
}
protected function addEventListener($name, $callback)
{
if (Str::contains($name, '*')) {
$callback = function ($name, array $data) use ($callback) {
return $callback($data[0]);
};
}
$this->events->listen($name, $callback);
}
/**
* Call the composer for a given view.
*
* @param \Illuminate\Contracts\View\View $view
* @return void
*/
public function callComposer(ViewContract $view)
{
$this->events->dispatch('composing: '.$view->name(), [$view]);
}
/**
* Call the creator for a given view.
*
* @param \Illuminate\Contracts\View\View $view
* @return void
*/
public function callCreator(ViewContract $view)
{
$this->events->dispatch('creating: '.$view->name(), [$view]);
}
}
} catch (Throwable $e) {
$this->factory->flushState();
throw $e;
}
}
/**
* Get the contents of the view instance.
*
* @return string
*/
protected function renderContents()
{
// We will keep track of the amount of views being rendered so we can flush
// the section after the complete rendering operation is done. This will
// clear out the sections for any separate views that may be rendered.
$this->factory->incrementRender();
$this->factory->callComposer($this);
$contents = $this->getContents();
// Once we've finished rendering the view, we'll decrement the render count
// so that each sections get flushed out next time a view is created and
// no old sections are staying around in the memory of an environment.
$this->factory->decrementRender();
return $contents;
}
/**
* Get the evaluated contents of the view.
*
* @return string
*/
protected function getContents()
{
return $this->engine->get($this->path, $this->gatherData());
}
$this->view = $view;
$this->path = $path;
$this->engine = $engine;
$this->factory = $factory;
$this->data = $data instanceof Arrayable ? $data->toArray() : (array) $data;
}
/**
* Get the string contents of the view.
*
* @param callable|null $callback
* @return array|string
*
* @throws \Throwable
*/
public function render(callable $callback = null)
{
try {
$contents = $this->renderContents();
$response = isset($callback) ? $callback($this, $contents) : null;
// Once we have the contents of the view, we will flush the sections if we are
// done rendering all views so that there is nothing left hanging over when
// another view gets rendered in the future by the application developer.
$this->factory->flushStateIfDoneRendering();
return ! is_null($response) ? $response : $contents;
} catch (Throwable $e) {
$this->factory->flushState();
throw $e;
}
}
/**
* Get the contents of the view instance.
*
* @return string
<?php $__env->startSection('content'); ?>
<?php while(have_posts()): ?> <?php (the_post()); ?>
<?php echo $__env->first(['partials.content-single-' . get_post_type(), 'partials.content-single'], \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?>
<?php endwhile; ?>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layouts.app', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?><?php /**PATH /home/forge/dev.tfs.staging.poundandgrain.ca/releases/20241113033749/web/app/themes/tfs/resources/views/single.blade.php ENDPATH**/ ?>
/**
* Get the evaluated contents of the view at the given path.
*
* @param string $__path
* @param array $__data
* @return string
*/
protected function evaluatePath($__path, $__data)
{
$obLevel = ob_get_level();
ob_start();
extract($__data, EXTR_SKIP);
// We'll evaluate the contents of the view inside a try/catch block so we can
// flush out any stray output that might get out before an error occurs or
// an exception is thrown. This prevents any partial views from leaking.
try {
include $__path;
} catch (Throwable $e) {
$this->handleViewException($e, $obLevel);
}
return ltrim(ob_get_clean());
}
/**
* Handle a view exception.
*
* @param \Throwable $e
* @param int $obLevel
* @return void
*
* @throws \Throwable
*/
protected function handleViewException(Throwable $e, $obLevel)
{
while (ob_get_level() > $obLevel) {
ob_end_clean();
"/home/forge/dev.tfs.staging.poundandgrain.ca/releases/20241113033749/web/app/themes/tfs/storage/framework/views/eb422c8beb3d93cfa2fe08ce3b438f23bc0fae21.php"
*
* @param string $path
* @param array $data
* @return string
*/
public function get($path, array $data = [])
{
$this->lastCompiled[] = $path;
// If this given view has expired, which means it has simply been edited since
// it was last compiled, we will re-compile the views so we can evaluate a
// fresh copy of the view. We'll pass the compiler the path of the view.
if ($this->compiler->isExpired($path)) {
$this->compiler->compile($path);
}
// Once we have the path to the compiled file, we will evaluate the paths with
// typical PHP just like any other templates. We also keep a stack of views
// which have been rendered for right exception messages to be generated.
$results = $this->evaluatePath($this->compiler->getCompiledPath($path), $data);
array_pop($this->lastCompiled);
return $results;
}
/**
* Handle a view exception.
*
* @param \Throwable $e
* @param int $obLevel
* @return void
*
* @throws \Throwable
*/
protected function handleViewException(Throwable $e, $obLevel)
{
$e = new ViewException($this->getMessage($e), 0, 1, $e->getFile(), $e->getLine(), $e);
parent::handleViewException($e, $obLevel);
$this->factory->callComposer($this);
$contents = $this->getContents();
// Once we've finished rendering the view, we'll decrement the render count
// so that each sections get flushed out next time a view is created and
// no old sections are staying around in the memory of an environment.
$this->factory->decrementRender();
return $contents;
}
/**
* Get the evaluated contents of the view.
*
* @return string
*/
protected function getContents()
{
return $this->engine->get($this->path, $this->gatherData());
}
/**
* Get the data bound to the view instance.
*
* @return array
*/
public function gatherData()
{
$data = array_merge($this->factory->getShared(), $this->data);
foreach ($data as $key => $value) {
if ($value instanceof Renderable) {
$data[$key] = $value->render();
}
}
return $data;
}
throw $e;
}
}
/**
* Get the contents of the view instance.
*
* @return string
*/
protected function renderContents()
{
// We will keep track of the amount of views being rendered so we can flush
// the section after the complete rendering operation is done. This will
// clear out the sections for any separate views that may be rendered.
$this->factory->incrementRender();
$this->factory->callComposer($this);
$contents = $this->getContents();
// Once we've finished rendering the view, we'll decrement the render count
// so that each sections get flushed out next time a view is created and
// no old sections are staying around in the memory of an environment.
$this->factory->decrementRender();
return $contents;
}
/**
* Get the evaluated contents of the view.
*
* @return string
*/
protected function getContents()
{
return $this->engine->get($this->path, $this->gatherData());
}
/**
$this->view = $view;
$this->path = $path;
$this->engine = $engine;
$this->factory = $factory;
$this->data = $data instanceof Arrayable ? $data->toArray() : (array) $data;
}
/**
* Get the string contents of the view.
*
* @param callable|null $callback
* @return array|string
*
* @throws \Throwable
*/
public function render(callable $callback = null)
{
try {
$contents = $this->renderContents();
$response = isset($callback) ? $callback($this, $contents) : null;
// Once we have the contents of the view, we will flush the sections if we are
// done rendering all views so that there is nothing left hanging over when
// another view gets rendered in the future by the application developer.
$this->factory->flushStateIfDoneRendering();
return ! is_null($response) ? $response : $contents;
} catch (Throwable $e) {
$this->factory->flushState();
throw $e;
}
}
/**
* Get the contents of the view instance.
*
* @return string
<!doctype html>
<html <?php language_attributes(); ?>>
<?php echo \Roots\view(\Roots\app('sage.view'), \Roots\app('sage.data'))->render(); ?>
</html>
}
break;
}
}
if ( ! $template ) {
$template = get_index_template();
}
/**
* Filters the path of the current template before including it.
*
* @since 3.0.0
*
* @param string $template The path of the template to include.
*/
$template = apply_filters( 'template_include', $template );
if ( $template ) {
include $template;
} elseif ( current_user_can( 'switch_themes' ) ) {
$theme = wp_get_theme();
if ( $theme->errors() ) {
wp_die( $theme->errors() );
}
}
return;
}
"/home/forge/dev.tfs.staging.poundandgrain.ca/releases/20241113033749/web/app/themes/tfs/index.php"
<?php
/**
* Loads the WordPress environment and template.
*
* @package WordPress
*/
if ( ! isset( $wp_did_header ) ) {
$wp_did_header = true;
// Load the WordPress library.
require_once __DIR__ . '/wp-load.php';
// Set up the WordPress query.
wp();
// Load the theme template.
require_once ABSPATH . WPINC . '/template-loader.php';
}
"/home/forge/dev.tfs.staging.poundandgrain.ca/releases/20241113033749/web/wp/wp-includes/template-loader.php"
<?php
/**
* WordPress View Bootstrapper
*/
define('WP_USE_THEMES', true);
require __DIR__ . '/wp/wp-blog-header.php';
"/home/forge/dev.tfs.staging.poundandgrain.ca/releases/20241113033749/web/wp/wp-blog-header.php"
Key | Value |
query_vars | array:3 [ "page" => "" "name" => "best-software-for-screenwriters" "category_name" => "blog" ] |
query_string | "name=best-software-for-screenwriters&category_name=blog"
|
request | "blog/best-software-for-screenwriters"
|
matched_rule | "(.+?)/([^/]+)(?:/([0-9]+))?/?$"
|
matched_query | "category_name=blog&name=best-software-for-screenwriters&page="
|
did_permalink | true
|
Key | Value |
query | array:3 [ "page" => "" "name" => "best-software-for-screenwriters" "category_name" => "blog" ] |
query_vars | array:66 [ "page" => 0 "name" => "best-software-for-screenwriters" "category_name" => "blog" "error" => "" "m" => "" "p" => 0 "post_parent" => "" "subpost" => "" "subpost_id" => "" "attachment" => "" "attachment_id" => 0 "pagename" => "" "page_id" => 0 "second" => "" "minute" => "" "hour" => "" "day" => 0 "monthnum" => 0 "year" => 0 "w" => 0 "tag" => "" "cat" => "" "tag_id" => "" "author" => "" "author_name" => "" "feed" => "" "tb" => "" "paged" => 0 "meta_key" => "" "meta_value" => "" "preview" => "" "s" => "" "sentence" => "" "title" => "" "fields" => "" "menu_order" => "" "embed" => "" "category__in" => [] "category__not_in" => [] "category__and" => [] "post__in" => [] "post__not_in" => [] "post_name__in" => [] "tag__in" => [] "tag__not_in" => [] "tag__and" => [] "tag_slug__in" => [] "tag_slug__and" => [] "post_parent__in" => [] "post_parent__not_in" => [] "author__in" => [] "author__not_in" => [] "search_columns" => [] "ignore_sticky_posts" => false "suppress_filters" => false "cache_results" => true "update_post_term_cache" => true "update_menu_item_cache" => false "lazy_load_term_meta" => true "update_post_meta_cache" => true "post_type" => "" "posts_per_page" => 10 "nopaging" => false "comments_per_page" => "50" "no_found_rows" => false "order" => "DESC" ] |
meta_query | WP_Meta_Query {#2559} |
queried_object | WP_Post {#2560} |
queried_object_id | 29449
|
request | """ SELECT wp_posts.*\n \t\t\t\t\t FROM wp_posts \n \t\t\t\t\t WHERE 1=1 AND wp_posts.post_name = 'best-software-for-screenwriters' AND wp_posts.post_type = 'post'\n \t\t\t\t\t \n \t\t\t\t\t ORDER BY wp_posts.post_date DESC\n \t\t\t\t\t """ |
post_count | 1
|
in_the_loop | true
|
current_comment | -1
|
found_posts | 1
|
is_single | true
|
is_singular | true
|
Key | Value |
ID | 29449
|
post_author | "2"
|
post_date | "2023-02-13 00:00:00"
|
post_date_gmt | "2023-02-13 00:00:00"
|
post_content | """ <img src="https://dev.tfs.staging.poundandgrain.ca/app/uploads/2023/03/9V2A3370-scaled.jpg" alt="Software for Screenwriters" width="670" height="447" class="alignnone size-medium wp-image-27724" />\n \n </br>\n \n For the first 70 years of movie-making history, screenwriters relied on a mechanical typewriter to get the job done. Writing had a straightforward and highly intentional quality. Typos could take minutes to correct, not milliseconds. \n \n Nowadays, screenwriting is synonymous with software, and the market for high-tech programs is booming.\n \n If you’re reading this blog post, chances are you're a screenwriter. Or at least an aspiring one. It’s also likely that you're feeling overwhelmed by software options and that you’re struggling to pick the perfect program for you. \n \n Whether you should go with Final Draft, Celtx, Trelby or some other program will depend on a few main things. Your specific writing needs. Your level of experience. And, of course, your budget. \n \n To get started, check out our list of the five best screenwriting software programs in 2023 – we've included an option suitable for every kind of writer. \n \n \n \n \n <h1>The 5 Top Software Programs for Screenwriters</h1>\n </br>\n <img src="https://dev.tfs.staging.poundandgrain.ca/app/uploads/2023/03/final-draft-logo.png" alt="final draft software" width="607" height="301" class="alignnone size-full wp-image-27733" />\n </br>\n <strong>Final Draft</strong>\n \n Founded in 1991 as a Mac-Only product, Final Draft was one the first all-in-one screenwriting programs to hit the market. Flash forward to 2023 – the program is now in its 12th iteration and remains a true juggernaut in the screenwriting space. When people ask “what script writing software is industry standard?”, Final Draft tends to be the most common answer. \n \n Final Draft boasts a sleek, user-friendly design and makes formatting a total breeze thanks to its implementation of AI tools. It's versatile, sophisticated, and can be used by writers of all kinds. For example, it offers hyper-specific templates not just for film and TV writers, but also playwrights and novelists. \n \n <em>Who is Final Draft for?</em>\n \n Final Draft is geared towards professionals. That being said, it’s a good option for beginners who want to learn industry-standard software right from the get-go. \n \n <u>Pros</u>\n \t<p style="padding-left:25px">• <strong>AI-Enabled Formatting (SmartType)</strong> – as you write your scenes Final Draft will offer you specific formatting suggestions and auto-fill your characters’ names.</p>\n \n \t<p style="padding-left:25px">• <strong>Great Templates</strong> – Final Draft offers an impressive library of screenplay templates, ranging from specific production house styles (e.g. Warner Brothers Template) to unique theatre formats (e.g. Dramatist Guild Musical Template). </p>\n \n \t<p style="padding-left:25px">• <strong>Built-in PDF Converter</strong> – Final Draft is one of the only programs available that lets you import and convert PDF scripts into an editable format. </p>\n </br>\n \n <u>Cons</u>\n \t<p style="padding-left:25px">• <strong>It's Expensive</strong> – priced at CA$270.00, Final Draft is one of the most expensive screenwriting programs on the market.</p>\n \n \t<p style="padding-left:25px">• <strong>Limited Creative Collaboration</strong> – although multiple users can collaborate on a single Final Draft document, they can’t do so simultaneously. In addition, non-Final Draft owners will not be able to edit your documents at all.</p>\n \n </br>\n \n <u>Price</u>\n \n \t<p style="padding-left:25px">• CAD$270.00 for (Final Draft 12)</p>\n \n </br>\n <img src="https://dev.tfs.staging.poundandgrain.ca/app/uploads/2023/03/Screen-Shot-2023-02-13-at-11.45.06-AM.png" alt="celtx software" width="607" height="301" class="alignnone size-full wp-image-27735" />\n </br>\n <strong>Celtx</strong>\n \n For many years Celtx was the free alternative to Final Draft. Founded in 2001, the program was initially an open-source product. It quickly garnered a loyal group of customers, none of whom were particularly picky about UX design. \n \n These days, the company has abandoned its open-source roots and the platform is closer in look and feel to one of Google’s slick cloud-based products. \n \n Similar to Final Draft, Celtx offers a well-designed script editor and two-column audio/video formats. It also allows users to create comprehensive production plans based on your screenplays. \n \n \n <em>Who is Celtx for?</em>\n \n Celtx is a great option for film students. And that’s because it's budget-friendly and flexible. Unlike other screenwriting software, Celtx implements a monthly subscription model. This means you can opt in and out of paying for the program depending on your workflow. What’s more, the basic “Writer” plan is offered at a fair price of CAD 13.49. \n \n <u>Pros</u>\n \t<p style="padding-left:25px">• <strong>Cloud-Based</strong> – Celtx is a cloud-based program, meaning you can access and edit your documents across multiple devices. You can also rely on the software’s autosaving feature to back up all your words to the cloud, and do so in real time as you type. </p>\n \n \t<p style="padding-left:25px">• <strong>Progress Reports</strong> – Celtx offers a unique “progress report” feature that allows you to loop in your agent or manager, allowing them to see your script as you write. </p>\n \n \t<p style="padding-left:25px">• <strong>Affordable</strong> – Celtx’s basic “Writer” plan is offered at a very reasonable price of CAD 13.49.</p>\n </br>\n \n <u>Cons</u>\n \t<p style="padding-left:25px">• <strong>Minimal Export Options</strong> – Celtx only lets you export documents in a handful of file types.</p>\n \n \t<p style="padding-left:25px">• <strong>Limited Formatting Styles</strong> – Celtx won’t offer you much control when it comes to changing fonts, font sizes, line spacing, document colours and the like. </p>\n \n </br>\n \n <u>Price</u>\n \n \t<p style="padding-left:25px">• (Writer) CAD$13.49/mo // (Writer Pro) CAD$22.49/mo // (Team) CAD$53.99/mo</p>\n \n </br>\n <img src="https://dev.tfs.staging.poundandgrain.ca/app/uploads/2023/03/Screen-Shot-2023-02-13-at-11.46.28-AM.png" alt="writer duet software" width="607" height="301" class="alignnone size-full wp-image-27737" />\n </br>\n \n <strong>Writer Duet</strong>\n \n Released in 2013, Writer Duet is one of the newest screenwriting programs included on this list, and it's also one of the most specialised. \n \n Writer Duet is a completely cloud-based platform designed specifically for collaborative writing projects. Using this program, you will be able to co-write with multiple other users in real-time.\n \n \n <em>Who is Writer Duet for?</em>\n \n As its name suggests, Writer Duet is targeted toward screenwriting duos – or, more accurately, full-fledged writing teams. \n \n <u>Pros</u>\n \t<p style="padding-left:25px">• <strong>Cloud-Based</strong> – Writer Duet is one of the only screenwriting programs to offer a cloud-based co-creation experience where multiple users can enter and edit a document at the same time. This also makes it one of the only programs comparable to Google Docs. </p>\n \n \t<p style="padding-left:25px">• <strong>Strong Free Plan</strong> – Writer Duet offers one of the best free trials going. Sign up with an email and you’ll be able to write your first three scripts for free. No limits on time, pages, or exports </p>\n \n \t<p style="padding-left:25px">• <strong>Top-Notch Reviewing & Editing Features</strong> – Writer Duet features revision tracking, allowing you to monitor changes made to a script as well as accept and reject other users' suggestions.</p>\n </br>\n \n <u>Cons</u>\n \t<p style="padding-left:25px">• <strong>Slightly Less Sophisticated</strong> – Writer Duet abandons some of the advanced features found in programs like Final Draft; namely, AI-enabled formatting.</p>\n \n \t<p style="padding-left:25px">• <strong>Limited Writing Template Options</strong> – WriterDuet has significantly fewer writing templates than its leading competitors</p>\n \n </br>\n \n <u>Price</u>\n \n \t<p style="padding-left:25px">• (Free) // (Plus) CAD$13.36 // (Pro) CAD$16.00 // (Premium) CAD$18.70</p>\n \n </br>\n <img src="https://dev.tfs.staging.poundandgrain.ca/app/uploads/2023/03/arc-studio.png" alt="arc studio software" width="670" height="352" class="alignnone size-medium wp-image-27738" />\n </br>\n <strong>Arc Studio</strong>\n \n Released in 2019, Arc Studio is very much the new kid on the block when it comes to screenwriting software. It’s also the most modern-feeling program on this list. It boasts a sleek interface, intuitive drag-and-drop tools, and a more stripped-down aesthetic that prioritizes user experience. \n \n In addition, it's another cloud-based offering, which means you’ll be able to write and edit your documents across multiple devices, automatically back up your files to the cloud, and collaborate on screenplays with multiple users.\n \n \n <em>Who is Arc Studio For?</em>\n \n Arc Studio is perfect for the up-and-coming generation of screenwriters. Its intuitive design will feel familiar to users who are already comfortable navigating newer productivity apps, such as Notion and Asana. \n \n <u>Pros</u>\n \t<p style="padding-left:25px">• <strong>Open Collaboration</strong> – Arc Studio allows you to share and collaborate on documents with non-subscribers</p>\n \n \t<p style="padding-left:25px">• <strong>Plot Boards</strong> – Arc Studio offers a unique feature that allows you to quickly build story outlines by plotting events on preset “beat templates”</p>\n \n \t<p style="padding-left:25px">• <strong>Offline Capabilities</strong> – Arc Studio can be used entirely offline, meaning you can write scripts without wifi or data, and have them autosave to the cloud the next time you connect to the Internet. </p>\n </br>\n \n <u>Cons</u>\n \t<p style="padding-left:25px">• <strong>Not Available on Android</strong> – Arc Studio is currently only available on iOS devices and Windows 10 or 11</p>\n \n \t<p style="padding-left:25px">• <strong>Not yet an “industry standard”</strong> – Arc studio is very new. Because of this, it won’t be recognized by agents, managers, or industry execs the same way Final Draft of MovieMagic would.</p>\n \n </br>\n \n <u>Price</u>\n \n \t<p style="padding-left:25px">• (Free) // CAD$92.25</p>\n \n </br>\n <img src="https://dev.tfs.staging.poundandgrain.ca/app/uploads/2023/03/Screen-Shot-2023-02-13-at-11.51.03-AM.png" alt="trelby software" width="590" height="221" class="alignnone size-full wp-image-27739" />\n </br>\n <strong>Trelby</strong>\n \n In 2012 screenwriting platform Blyte rebranded and launched as Trelby, a completely free open-source program offered on GitHub. In terms of zero-cost alternatives, Trelby is by far your best bet. And thanks to being open-source, you can modify nearly every aspect of the software’s code, enabling you to create a highly customized screenwriting experience. \n \n \n <em>Who is Trelby For?</em>\n \n Trelby is a great option for two groups. Those looking to spend zero dollars on screenwriting programs. And tech-savvy developer types who prefer the freedom of an open-source product. \n \n <u>Pros</u>\n \t<p style="padding-left:25px">• <strong>Open-Source </strong> – Trelby is one of the only open-source screenwriting programs on the market. So it's the perfect choice if you're interested in editing the software’s code to fit your specific needs.</p>\n \n \t<p style="padding-left:25px">• <strong>Flexible Imports and Exports</strong> – Trelby lets you import and export work in a variety of formats including HTML, PDF, and RTF</p>\n \n \t<p style="padding-left:25px">• <strong>Script Compare</strong> – Trelby offers a unique Script Compare feature that allows comparing multiple versions of a script you are working, on including the individual differences in edits. </p>\n </br>\n \n <u>Cons</u>\n \t<p style="padding-left:25px">• <strong>Not Compatible with Macs</strong> – Trelby is only offered on Linux and Windows</p>\n \n \t<p style="padding-left:25px">• <strong>Less Intuitive</strong> – Trelby’s coder-friendly interface may feel complicated for first-time users, especially in comparison to a program like Arc Studio. </p>\n \n </br>\n \n <u>Price</u>\n \n \t<p style="padding-left:25px">• (Free)</p>\n \n <h1>Now take your pick and get writing!</h1>\n \n Ultimately, choosing the perfect screenwriting software depends on a writer's individual needs and preferences. Do AI-enabled tools appeal to you? Or are you looking for a more stripped-down writing experience? \n \n What about collaboration? WriterDuet is a great option if you're working in remote teams and need to co-write your projects. Alternatively, if you prefer a more feature-rich tool, we’d say go with Final Draft.\n \n Regardless, the most important thing when it comes to choosing a screenwriting program is that you pick one! That way you can back to the important stuff – writing!\n \n <strong>Oh, and before you go</strong> —if you found this article useful, you should consider <a href="https://create.torontofilmschool.ca/newsletter/" rel="noopener" target="_blank">signing up for Toronto Film School’s industry-focused newsletter Insider Advantage</a>. Packed with exclusive content and useful industry insights, Insider Advantage is essential reading for anyone looking to make their mark in the world of film and television. """ |
post_title | "The 5 Best Software Programs for Screenwriters"
|
post_excerpt | "" |
post_status | "publish"
|
comment_status | "closed"
|
ping_status | "open"
|
post_password | "" |
post_name | "best-software-for-screenwriters"
|
to_ping | "" |
pinged | "" |
post_modified | "2023-03-27 21:06:47"
|
post_modified_gmt | "2023-03-27 21:06:47"
|
post_content_filtered | "" |
post_parent | 0
|
guid | "https://dev.tfs.staging.poundandgrain.ca/best-software-for-screenwriters/"
|
menu_order | 0
|
post_type | "post"
|
post_mime_type | "" |
comment_count | "0"
|
filter | "raw"
|
Key | Value |
SERVER_SOFTWARE | "nginx/1.22.1"
|
REQUEST_URI | "/blog/best-software-for-screenwriters/"
|
USER | "forge"
|
HOME | "/home/forge"
|
HTTP_REFERER | "https://dev.tfs.staging.poundandgrain.ca/blog/best-software-for-screenwriters"
|
HTTP_ACCEPT_ENCODING | "gzip, br, zstd, deflate"
|
HTTP_USER_AGENT | "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)"
|
HTTP_ACCEPT | "*/*"
|
HTTP_HOST | "dev.tfs.staging.poundandgrain.ca"
|
REDIRECT_STATUS | "200"
|
HTTPS | "on"
|
SERVER_NAME | "dev.tfs.staging.poundandgrain.ca"
|
SERVER_PORT | "443"
|
SERVER_ADDR | "10.0.1.187"
|
REMOTE_PORT | "37684"
|
REMOTE_ADDR | "3.149.234.102"
|
GATEWAY_INTERFACE | "CGI/1.1"
|
SERVER_PROTOCOL | "HTTP/2.0"
|
DOCUMENT_ROOT | "/home/forge/dev.tfs.staging.poundandgrain.ca/releases/20241113033749/web"
|
DOCUMENT_URI | "/index.php"
|
SCRIPT_NAME | "/index.php"
|
SCRIPT_FILENAME | "/home/forge/dev.tfs.staging.poundandgrain.ca/releases/20241113033749/web/index.php"
|
CONTENT_LENGTH | "" |
CONTENT_TYPE | "" |
REQUEST_METHOD | "GET"
|
QUERY_STRING | "" |
FCGI_ROLE | "RESPONDER"
|
PHP_SELF | "/index.php"
|
REQUEST_TIME_FLOAT | 1731839334.1943
|
REQUEST_TIME | 1731839334
|
DB_NAME | "tfs_dev"
|
DB_USER | "***"
|
DB_PASSWORD | "************"
|
WP_ENV | "development"
|
WP_HOME | "https://dev.tfs.staging.poundandgrain.ca"
|
WP_SITEURL | "https://dev.tfs.staging.poundandgrain.ca/wp"
|
WP_DEBUG_LOG | "/path/to/debug.log"
|
AUTH_KEY | "****************************************************************"
|
SECURE_AUTH_KEY | "****************************************************************"
|
LOGGED_IN_KEY | "****************************************************************"
|
NONCE_KEY | "****************************************************************"
|
AUTH_SALT | "****************************************************************"
|
SECURE_AUTH_SALT | "****************************************************************"
|
LOGGED_IN_SALT | "****************************************************************"
|
NONCE_SALT | "****************************************************************"
|
ACF_PRO_KEY | "b3JkZXJfaWQ9NDQxMjV8dHlwZT1kZXZlbG9wZXJ8ZGF0ZT0yMDE0LTExLTEyIDA2OjA0OjE3"
|
Key | Value |
DB_NAME | "tfs_dev"
|
DB_USER | "***"
|
DB_PASSWORD | "************"
|
WP_ENV | "development"
|
WP_HOME | "https://dev.tfs.staging.poundandgrain.ca"
|
WP_SITEURL | "https://dev.tfs.staging.poundandgrain.ca/wp"
|
WP_DEBUG_LOG | "/path/to/debug.log"
|
AUTH_KEY | "****************************************************************"
|
SECURE_AUTH_KEY | "****************************************************************"
|
LOGGED_IN_KEY | "****************************************************************"
|
NONCE_KEY | "****************************************************************"
|
AUTH_SALT | "****************************************************************"
|
SECURE_AUTH_SALT | "****************************************************************"
|
LOGGED_IN_SALT | "****************************************************************"
|
NONCE_SALT | "****************************************************************"
|
ACF_PRO_KEY | "b3JkZXJfaWQ9NDQxMjV8dHlwZT1kZXZlbG9wZXJ8ZGF0ZT0yMDE0LTExLTEyIDA2OjA0OjE3"
|