| 1 |
<?php |
| 2 |
/** |
| 3 |
* PCH Editor Sidebar class |
| 4 |
* |
| 5 |
* @package Parsely |
| 6 |
* @since 3.5.0 |
| 7 |
*/ |
| 8 |
|
| 9 |
declare(strict_types=1); |
| 10 |
|
| 11 |
namespace Parsely\Content_Helper; |
| 12 |
|
| 13 |
use Parsely\Content_Helper\Editor_Sidebar\Editor_Sidebar_Feature; |
| 14 |
use Parsely\Content_Helper\Editor_Sidebar\Smart_Linking; |
| 15 |
use Parsely\Dashboard_Link; |
| 16 |
use Parsely\Parsely; |
| 17 |
use Parsely\REST_API\Settings\Endpoint_Editor_Sidebar_Settings; |
| 18 |
use Parsely\Utils\Utils; |
| 19 |
use WP_Post; |
| 20 |
|
| 21 |
use const Parsely\PARSELY_FILE; |
| 22 |
|
| 23 |
/** |
| 24 |
* Class that generates and manages the PCH Editor Sidebar. |
| 25 |
* |
| 26 |
* @since 3.5.0 |
| 27 |
* @since 3.9.0 Renamed FQCN from `Parsely\Content_Helper` to `Parsely\Content_Helper\Editor_Sidebar`. |
| 28 |
*/ |
| 29 |
class Editor_Sidebar extends Content_Helper_Feature { |
| 30 |
/** |
| 31 |
* Instance of Parsely class. |
| 32 |
* |
| 33 |
* @since 3.16.0 |
| 34 |
* |
| 35 |
* @var array<Editor_Sidebar_Feature> |
| 36 |
*/ |
| 37 |
protected $features; |
| 38 |
|
| 39 |
/** |
| 40 |
* Constructor. |
| 41 |
* |
| 42 |
* @since 3.9.0 |
| 43 |
* |
| 44 |
* @param Parsely $parsely Instance of Parsely class. |
| 45 |
*/ |
| 46 |
public function __construct( Parsely $parsely ) { |
| 47 |
$this->parsely = $parsely; |
| 48 |
|
| 49 |
// Instantiate the features. |
| 50 |
$this->features = array( |
| 51 |
'Smart_Linking' => new Smart_Linking( $this ), |
| 52 |
'Excerpt_Generator' => new Excerpt_Suggestions( $this ), |
| 53 |
); |
| 54 |
} |
| 55 |
|
| 56 |
/** |
| 57 |
* Returns the feature's filter name. |
| 58 |
* |
| 59 |
* @since 3.9.0 |
| 60 |
* |
| 61 |
* @return string The filter name. |
| 62 |
*/ |
| 63 |
public static function get_feature_filter_name(): string { |
| 64 |
return self::get_global_filter_name() . '_editor_sidebar'; |
| 65 |
} |
| 66 |
|
| 67 |
/** |
| 68 |
* Returns the feature's script ID. |
| 69 |
* |
| 70 |
* @since 3.9.0 |
| 71 |
* |
| 72 |
* @return string The script ID. |
| 73 |
*/ |
| 74 |
public static function get_script_id(): string { |
| 75 |
return 'wp-parsely-block-content-helper'; |
| 76 |
} |
| 77 |
|
| 78 |
/** |
| 79 |
* Returns the feature's style ID. |
| 80 |
* |
| 81 |
* @since 3.9.0 |
| 82 |
* |
| 83 |
* @return string The style ID. |
| 84 |
*/ |
| 85 |
public static function get_style_id(): string { |
| 86 |
return static::get_script_id(); |
| 87 |
} |
| 88 |
|
| 89 |
/** |
| 90 |
* Returns the Parse.ly post dashboard URL for the current post. |
| 91 |
* |
| 92 |
* @since 3.14.0 |
| 93 |
* @since 3.16.1 Added the $show_utm_params parameter. |
| 94 |
* |
| 95 |
* @param int|null|WP_Post $post_id The post ID or post object. Default is the current post. |
| 96 |
* @param bool $add_utm_params Whether to add UTM parameters in the URL. |
| 97 |
* @return string|null The Parse.ly post dashboard URL, or false if the post ID is invalid. |
| 98 |
*/ |
| 99 |
private function get_parsely_post_url( $post_id = null, bool $add_utm_params = true ): ?string { |
| 100 |
// Get permalink for the post. |
| 101 |
$post_id = $post_id ?? get_the_ID(); |
| 102 |
if ( false === $post_id ) { |
| 103 |
return null; |
| 104 |
} |
| 105 |
|
| 106 |
/** |
| 107 |
* The post object. |
| 108 |
* |
| 109 |
* @var WP_Post|null $post |
| 110 |
*/ |
| 111 |
$post = get_post( $post_id ); |
| 112 |
|
| 113 |
if ( null === $post || ! Dashboard_Link::can_show_link( $post, $this->parsely ) ) { |
| 114 |
return null; |
| 115 |
} |
| 116 |
|
| 117 |
if ( ! $add_utm_params ) { |
| 118 |
return Dashboard_Link::generate_url( $post, $this->parsely->get_site_id() ); |
| 119 |
} |
| 120 |
|
| 121 |
return Dashboard_Link::generate_url( $post, $this->parsely->get_site_id(), 'wp-page-single', 'editor-sidebar' ); |
| 122 |
} |
| 123 |
|
| 124 |
/** |
| 125 |
* Initializes the features. |
| 126 |
* |
| 127 |
* @since 3.16.0 |
| 128 |
*/ |
| 129 |
public function init_features(): void { |
| 130 |
if ( ! $this->can_enable_feature() ) { |
| 131 |
return; |
| 132 |
} |
| 133 |
|
| 134 |
// Initialize the features. |
| 135 |
foreach ( $this->features as $feature ) { |
| 136 |
$feature->run(); |
| 137 |
} |
| 138 |
} |
| 139 |
|
| 140 |
/** |
| 141 |
* Inserts the PCH Editor Sidebar assets. |
| 142 |
* |
| 143 |
* @since 3.5.0 |
| 144 |
*/ |
| 145 |
public function run(): void { |
| 146 |
if ( ! $this->can_enable_feature() ) { |
| 147 |
return; |
| 148 |
} |
| 149 |
|
| 150 |
$asset_php = Utils::get_asset_info( 'build/content-helper/editor-sidebar.asset.php' ); |
| 151 |
$built_assets_url = plugin_dir_url( PARSELY_FILE ) . 'build/content-helper/'; |
| 152 |
|
| 153 |
wp_enqueue_script( |
| 154 |
static::get_script_id(), |
| 155 |
$built_assets_url . 'editor-sidebar.js', |
| 156 |
$asset_php['dependencies'], |
| 157 |
$asset_php['version'], |
| 158 |
true |
| 159 |
); |
| 160 |
|
| 161 |
$this->inject_inline_scripts( Endpoint_Editor_Sidebar_Settings::get_endpoint_name() ); |
| 162 |
|
| 163 |
// Inject inline variables for the editor sidebar, without UTM parameters. |
| 164 |
$parsely_post_url = $this->get_parsely_post_url( null, false ); |
| 165 |
if ( null !== $parsely_post_url ) { |
| 166 |
wp_add_inline_script( |
| 167 |
static::get_script_id(), |
| 168 |
'window.wpParselyPostUrl = ' . wp_json_encode( $parsely_post_url ) . ';', |
| 169 |
'before' |
| 170 |
); |
| 171 |
} |
| 172 |
|
| 173 |
// Inject the admin URL for generating admin page links. |
| 174 |
wp_add_inline_script( |
| 175 |
static::get_script_id(), |
| 176 |
'window.wpParselyAdminUrl = ' . wp_json_encode( admin_url() ) . ';', |
| 177 |
'before' |
| 178 |
); |
| 179 |
|
| 180 |
// Inject the trackable statuses. |
| 181 |
$trackable_statuses = Parsely::get_trackable_statuses(); |
| 182 |
wp_add_inline_script( |
| 183 |
static::get_script_id(), |
| 184 |
'window.wpParselyTrackableStatuses = ' . wp_json_encode( $trackable_statuses ) . ';', |
| 185 |
'before' |
| 186 |
); |
| 187 |
|
| 188 |
// Inject the tones and personas, so that PHP stays their single source |
| 189 |
// and the settings page can offer the same choices as the editor. |
| 190 |
wp_add_inline_script( |
| 191 |
static::get_script_id(), |
| 192 |
'window.wpParselyContentHelperTones = ' . |
| 193 |
wp_json_encode( Suggestion_Defaults::get_tones() ) . ';' . |
| 194 |
'window.wpParselyContentHelperPersonas = ' . |
| 195 |
wp_json_encode( Suggestion_Defaults::get_personas() ) . ';', |
| 196 |
'before' |
| 197 |
); |
| 198 |
|
| 199 |
// Inject the site-wide tone and persona. The stored settings carry them |
| 200 |
// already, but not once a user's own value is the custom sentinel, |
| 201 |
// which is exactly when the editor needs them. The desired length has |
| 202 |
// no sentinel, so it is not needed here. |
| 203 |
$excerpt_options = Suggestion_Defaults::get_feature_options( $this->parsely, 'excerpt_suggestions' ); |
| 204 |
$title_options = Suggestion_Defaults::get_feature_options( $this->parsely, 'title_suggestions' ); |
| 205 |
|
| 206 |
wp_add_inline_script( |
| 207 |
static::get_script_id(), |
| 208 |
'window.wpParselyContentHelperDefaults = ' . wp_json_encode( |
| 209 |
array( |
| 210 |
'excerptSuggestions' => array( |
| 211 |
'persona' => Suggestion_Defaults::get_default_persona( $excerpt_options ), |
| 212 |
'tone' => Suggestion_Defaults::get_default_tone( $excerpt_options ), |
| 213 |
), |
| 214 |
'titleSuggestions' => array( |
| 215 |
'persona' => Suggestion_Defaults::get_default_persona( $title_options ), |
| 216 |
'tone' => Suggestion_Defaults::get_default_tone( $title_options ), |
| 217 |
), |
| 218 |
) |
| 219 |
) . ';', |
| 220 |
'before' |
| 221 |
); |
| 222 |
|
| 223 |
$use_category_slugs_in_searches = apply_filters( 'wp_parsely_use_category_slugs_in_searches', false ); |
| 224 |
wp_add_inline_script( |
| 225 |
static::get_script_id(), |
| 226 |
'window.wpParselyUseCategorySlugsInSearches = ' . wp_json_encode( $use_category_slugs_in_searches ) . ';', |
| 227 |
'before' |
| 228 |
); |
| 229 |
|
| 230 |
wp_enqueue_style( |
| 231 |
static::get_style_id(), |
| 232 |
$built_assets_url . 'editor-sidebar.css', |
| 233 |
array(), |
| 234 |
$asset_php['version'] |
| 235 |
); |
| 236 |
} |
| 237 |
|
| 238 |
/** |
| 239 |
* Inserts the styles that need to be loaded inside the Editor canvas. |
| 240 |
* |
| 241 |
* Runs on `enqueue_block_assets`, which is the only hook that reaches the |
| 242 |
* iframed Editor canvas. `enqueue_block_editor_assets` only loads assets in |
| 243 |
* the admin document. |
| 244 |
* |
| 245 |
* @since 3.23.6 |
| 246 |
*/ |
| 247 |
public function run_canvas_styles(): void { |
| 248 |
if ( ! is_admin() || ! $this->can_enable_feature() ) { |
| 249 |
return; |
| 250 |
} |
| 251 |
|
| 252 |
$asset_php = Utils::get_asset_info( 'build/content-helper/block-overlay.asset.php' ); |
| 253 |
|
| 254 |
wp_enqueue_style( |
| 255 |
static::get_style_id() . '-canvas', |
| 256 |
plugin_dir_url( PARSELY_FILE ) . 'build/content-helper/block-overlay.css', |
| 257 |
array(), |
| 258 |
$asset_php['version'] |
| 259 |
); |
| 260 |
} |
| 261 |
} |
| 262 |
|