Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions src/Controller/Controller_Font_Downloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@
namespace GFPDF\Controller;

use GFPDF\Helper\Helper_Abstract_Controller;
use GFPDF\Helper\Helper_Data;
use GFPDF\Helper\Helper_Interface_Actions;
use GFPDF\Model\Model_Font_Downloader;
use GFPDF\Model\Model_Required_Fonts;
use GPDFAPI;
use WP_Error;
use WP_REST_Request;
use WP_REST_Server;

/**
* @package Gravity PDF
Expand Down Expand Up @@ -61,6 +66,79 @@ public function __construct( Model_Font_Downloader $model, Model_Required_Fonts
*/
public function init() {
$this->add_actions();

add_action( 'rest_api_init', [ $this, 'register_endpoints' ] );
}

/**
* The Font Manager's downloaded fonts list and delete, beside the custom font routes
*
* @since 6.19.0
*/
public function register_endpoints(): void {
register_rest_route(
Helper_Data::REST_API_BASENAME . 'v1',
'/fonts/downloaded',
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_downloaded_fonts' ],
'permission_callback' => [ $this, 'can_view_fonts' ],
]
);

register_rest_route(
Helper_Data::REST_API_BASENAME . 'v1',
'/fonts/downloaded/(?P<key>[a-z0-9_\-]+)',
[
'methods' => WP_REST_Server::DELETABLE,
'callback' => [ $this, 'delete_downloaded_font' ],
'permission_callback' => [ $this, 'can_delete_fonts' ],
]
);
}

/**
* @return array{fonts: array, can_delete: bool}
*
* @since 6.19.0
*/
public function get_downloaded_fonts(): array {
return [
'fonts' => $this->model->get_downloaded_fonts(),
'can_delete' => $this->can_delete_fonts(),
];
}

/**
* @return array|WP_Error
*
* @since 6.19.0
*/
public function delete_downloaded_font( WP_REST_Request $request ) {
return $this->model->delete_downloaded_font( (string) $request->get_param( 'key' ) );
}

/**
* The custom font routes' capability
*
* @since 6.19.0
*/
public function can_view_fonts(): bool {
$allowed = GPDFAPI::get_form_class()->has_capability( 'gravityforms_edit_forms' );
if ( ! $allowed ) {
GPDFAPI::get_log_class()->warning( 'Permission denied: user does not have "gravityforms_edit_forms" capabilities' );
}

return $allowed;
}

/**
* Super admins only on Multisite, as the fonts folder is shared by the network
*
* @since 6.19.0
*/
public function can_delete_fonts(): bool {
return $this->can_view_fonts() && ( ! is_multisite() || is_super_admin() );
}

/**
Expand All @@ -72,9 +150,11 @@ public function init() {
*/
public function add_actions() {
add_action( Model_Font_Downloader::SYNC_EVENT, [ $this->model, 'sync' ] );
add_action( Model_Font_Downloader::CLEANUP_EVENT, [ $this->model, 'cleanup' ] );

add_action( 'gfpdf_plugin_installed', [ $this->model, 'schedule_sync' ] );
add_action( 'gfpdf_version_changed', [ $this->model, 'schedule_sync' ] );
add_action( 'gfpdf_font_sources_changed', [ $this->model, 'schedule_sync' ] );
add_action( 'upgrader_process_complete', [ $this, 'maybe_sync_translations' ], 10, 2 );

/* Both hooks pass the saved settings second */
Expand Down
3 changes: 3 additions & 0 deletions src/Controller/Controller_Font_Sources.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ public function init(): void {
public function add_actions(): void {
/* A language pack may change the language fonts */
add_action( 'upgrader_process_complete', [ $this->model, 'flush' ], 10, 0 );

/* Any admin request, so a plugin activated or updated by any route adds its source */
add_action( 'admin_init', [ $this->model, 'check_added_sources' ] );
}

/**
Expand Down
29 changes: 15 additions & 14 deletions src/Controller/Controller_Upgrade_Routines.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
*/
class Controller_Upgrade_Routines {

/**
* The default font of a site upgraded from before 6.19 with none saved
*
* @since 6.19.0
*/
const PRE_6_19_DEFAULT_FONT = 'dejavusanscondensed';

/**
* @var Helper_Abstract_Options
*/
Expand Down Expand Up @@ -102,11 +109,10 @@ public function maybe_run_upgrade( $old_version, $current_version ): void {

/* A site upgraded from before Arimo was the default keeps DejaVu Sans Condensed, even if it never saved one */
if ( $old_version !== '' && version_compare( $old_version, '6.19.0', '<' ) ) {
$this->save_unset_default_font( 'dejavusanscondensed' );
$this->save_unset_default_font( self::PRE_6_19_DEFAULT_FONT );
$this->adopt_font_source_records();

/* After the default font save, so the font it saves is kept */
$this->remove_unneeded_core_fonts();
$this->schedule_core_font_cleanup();
}

if ( version_compare( $current_version, '7.0.0-beta1', '>=' ) && version_compare( $old_version, '7.0.0-beta1', '<' ) ) {
Expand Down Expand Up @@ -180,22 +186,17 @@ protected function adopt_font_source_records(): void {
}

/**
* Delete the core fonts a new install wouldn't have; any still needed download again on use. A network shares one
* fonts folder, so a Multisite prunes it once, for the site whose request runs the upgrade.
* Queue the removal of the core fonts a new install wouldn't have. It keeps the fonts every site needs and runs in
* the background, as every site on every network shares the fonts folder.
*
* @since 6.19.0
*/
protected function remove_unneeded_core_fonts(): void {
protected function schedule_core_font_cleanup(): void {
$downloader = \GPDFAPI::get_mvc_class( 'Model_Font_Downloader' );
if ( ! $downloader instanceof Model_Font_Downloader ) {
return;
if ( $downloader instanceof Model_Font_Downloader ) {
/* Sites yet to upgrade will save DejaVu Sans Condensed as their default when they do */
$downloader->schedule_cleanup( self::PRE_6_19_DEFAULT_FONT );
}

if ( is_multisite() && ! add_site_option( Model_Font_Downloader::PRUNED, true ) ) {
return;
}

$downloader->prune();
}

/**
Expand Down
18 changes: 18 additions & 0 deletions src/Helper/Helper_Data.php
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,24 @@ public function get_localised_script_data( Helper_Abstract_Options $options, Hel
'fontManagerUpdateFontAriaLabel' => esc_html__( 'Update font', 'gravity-pdf' ),
'fontManagerSelectFontAriaLabel' => esc_html__( 'Select font', 'gravity-pdf' ),
'fontManagerDeleteFontAriaLabel' => esc_html__( 'Delete font', 'gravity-pdf' ),
'fontManagerDownloadedTitle' => esc_html__( 'Downloaded Fonts', 'gravity-pdf' ),
'fontManagerDownloadedDesc' => esc_html__( 'Core fonts downloaded when a PDF, setting or site language needed them. A deleted font downloads again when a PDF needs it.', 'gravity-pdf' ),
'fontManagerDownloadedEmpty' => esc_html__( 'No fonts have been downloaded.', 'gravity-pdf' ),
'fontManagerDownloadedReadOnly' => esc_html__( 'Only a network administrator can delete downloaded fonts, as every site in the network shares them.', 'gravity-pdf' ),
'fontManagerDownloadedFont' => esc_html__( 'Font', 'gravity-pdf' ),
'fontManagerDownloadedStyles' => esc_html__( 'Styles', 'gravity-pdf' ),
'fontManagerDownloadedSize' => esc_html__( 'Size', 'gravity-pdf' ),
'fontManagerDownloadedStatus' => esc_html__( 'In use', 'gravity-pdf' ),
'fontManagerDownloadedUnused' => esc_html__( 'Not in use', 'gravity-pdf' ),
'fontManagerDownloadedDelete' => esc_html__( 'Delete', 'gravity-pdf' ),
/* translators: %s: the font name */
'fontManagerDownloadedDeleteAriaLabel' => esc_html__( 'Delete %s', 'gravity-pdf' ),
/* translators: %s: the font name */
'fontManagerDownloadedConfirm' => esc_html__( 'Delete %s? It downloads again when a PDF needs it.', 'gravity-pdf' ),
/* translators: %s: the font name */
'fontManagerDownloadedConfirmOffline' => esc_html__( 'Delete %s? Font downloads are turned off, so it won\'t come back on its own: copy its files into the fonts folder again to restore it.', 'gravity-pdf' ),
/* translators: %s: the font name */
'fontManagerDownloadedDeleted' => esc_html__( '%s deleted.', 'gravity-pdf' ),

/* Font Manager API response */
'fontListEmpty' => esc_html__( 'Font list empty.', 'gravity-pdf' ),
Expand Down
48 changes: 36 additions & 12 deletions src/Helper/Mpdf/On_Demand_Font_File_Finder.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,25 +80,49 @@ public function findFontFile( $name ) {
throw new MpdfException( esc_html( sprintf( 'Cannot find TTF TrueType font file "%s" in configured font directories.', is_scalar( $name ) ? (string) $name : gettype( $name ) ) ) );
}

$found = '';
$error = null;

try {
return parent::findFontFile( $name );
$found = parent::findFontFile( $name );
} catch ( MpdfException $e ) {
if ( ! $this->downloader->is_core_font_file( $name ) ) {
throw $e;
}
$error = $e;
}

/* The downloader's fonts folder, as mPDF's AddFontDirectory() replaces the search directories */
if ( $this->downloader->download( $name ) ) {
return $this->downloader->get_font_path( $name );
}
/* Bundled fonts and those in other directories aren't on the manifest */
if ( $error === null && ! $this->downloader->is_in_fonts_folder( $found ) ) {
return $found;
}

$fallback = $this->fallback ? $this->get_fallback_file() : '';
if ( $fallback === '' ) {
throw $e;
if ( ! $this->downloader->is_core_font_file( $name ) ) {
if ( $error !== null ) {
throw $error;
}

return $fallback;
return $found;
}

/* A Font Manager record's file belongs to the record. The core font of that name has a hashed name. */
if ( $error === null && $this->downloader->is_record_file( $name ) ) {
return $found;
}

/* The downloader's fonts folder, as mPDF's AddFontDirectory() replaces the search directories. Stat calls only. */
if ( $this->downloader->download( $name ) ) {
return $this->downloader->get_font_path( $name );
}

/* The file at the name stays in use if its replacement can't be saved */
if ( $error === null ) {
return $found;
}

$fallback = $this->fallback ? $this->get_fallback_file() : '';
if ( $fallback === '' ) {
throw $error;
}

return $fallback;
}

/**
Expand Down
33 changes: 4 additions & 29 deletions src/Model/Model_Actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,6 @@ protected static function get_removed_methods(): array {
*/
const UNWRITABLE_FOLDER_DISMISSAL = 'unwritable_folder_';

/**
* The prefix each failed core font's dismissal is recorded under in `action_dismissal`
*
* @since 6.19.0
*/
const FAILED_CORE_FONT_DISMISSAL = 'failed_core_font_';

/**
* How long dismissing the unwritable folders notice hides a folder that keeps failing
*
Expand Down Expand Up @@ -296,22 +289,13 @@ protected function get_unwritable_folder_dismissal( string $dir ): string {
}

/**
* The core fonts that failed to download after their retry, less the ones dismissed since
* The core fonts that failed to download after their retry, less the ones dismissed
*
* @return string[]
* @since 6.19.0
*/
public function get_undismissed_failed_core_fonts(): array {
$files = [];

/* A dismissal covers only the failure it followed */
foreach ( $this->get_downloader()->get_failed_files() as $file => $gave_up ) {
if ( ! $this->is_notice_already_dismissed( $this->get_failed_core_font_dismissal( $file ), $gave_up ) ) {
$files[] = $file;
}
}

return $files;
return $this->get_downloader()->get_undismissed_failed_files();
}

/**
Expand All @@ -324,12 +308,12 @@ public function has_failed_core_fonts(): bool {
}

/**
* Dismiss each listed font; one that fails later raises the notice again
* Dismiss the listed fonts for every site, as they share the fonts folder; one that fails later raises it again
*
* @since 6.19.0
*/
public function dismiss_failed_core_fonts(): void {
$this->dismiss_notices( array_map( [ $this, 'get_failed_core_font_dismissal' ], $this->get_undismissed_failed_core_fonts() ) );
$this->get_downloader()->dismiss_failed_files();
}

/**
Expand All @@ -341,15 +325,6 @@ protected function get_downloader(): Model_Font_Downloader {
return $this->downloader ?? GPDFAPI::get_mvc_class( 'Model_Font_Downloader' );
}

/**
* The ID a failed core font's dismissal is recorded under in `action_dismissal`
*
* @since 6.19.0
*/
protected function get_failed_core_font_dismissal( string $file ): string {
return static::FAILED_CORE_FONT_DISMISSAL . md5( $file );
}

/**
* Send the user to the system report, which lists every detection behind the notice
*
Expand Down
Loading