Skip to content
16 changes: 10 additions & 6 deletions assets/js/recommendations/core-siteicon.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,16 @@
? attachment.sizes.thumbnail.url
: attachment.url;

this.elements.preview.innerHTML =
'<img src="' +
imageUrl +
'" alt="' +
( attachment.alt || 'Site icon preview' ) +
'" style="max-width: 150px; height: auto; border-radius: 4px; border: 1px solid #ddd;">';
// Build the node instead of interpolating into an HTML string: the
// alt text is free-text set by any upload-capable user, and a value
// like `" onerror="` would otherwise break out of the attribute.
const img = document.createElement( 'img' );
img.src = imageUrl;
img.alt = attachment.alt || 'Site icon preview';
img.style.cssText =
'max-width: 150px; height: auto; border-radius: 4px; border: 1px solid #ddd;';

this.elements.preview.replaceChildren( img );
}

/**
Expand Down
16 changes: 10 additions & 6 deletions assets/js/recommendations/yoast-organization-logo.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,16 @@
? attachment.sizes.thumbnail.url
: attachment.url;

this.elements.preview.innerHTML =
'<img src="' +
imageUrl +
'" alt="' +
( attachment.alt || 'Site icon preview' ) +
'" style="max-width: 150px; height: auto; border-radius: 4px; border: 1px solid #ddd;">';
// Build the node instead of interpolating into an HTML string: the
// alt text is free-text set by any upload-capable user, and a value
// like `" onerror="` would otherwise break out of the attribute.
const img = document.createElement( 'img' );
img.src = imageUrl;
img.alt = attachment.alt || 'Site icon preview';
img.style.cssText =
'max-width: 150px; height: auto; border-radius: 4px; border: 1px solid #ddd;';

this.elements.preview.replaceChildren( img );
}

/**
Expand Down
6 changes: 6 additions & 0 deletions classes/suggested-tasks/providers/class-email-sending.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ protected function get_description( $task_data = [] ) {
* @return void
*/
public function enqueue_scripts( $hook ) {
// Don't enqueue the script if the user lacks the capability required by this task,
// since the localized data contains a nonce.
if ( ! $this->capability_required() ) {
return;
}

// Enqueue the script only on Progress Planner and WP dashboard pages.
if ( 'toplevel_page_progress-planner' !== $hook && 'index.php' !== $hook ) {
return;
Expand Down
2 changes: 1 addition & 1 deletion classes/suggested-tasks/providers/class-hello-world.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ protected function get_description() {
$content .= \sprintf(
/* translators: %s: Link to the post. */
\esc_html__( 'On install, WordPress creates a "Hello World!" post. You can find yours at %s.', 'progress-planner' ),
'<a href="' . \esc_attr( $hello_world_post_url ) . '" target="_self">' . \esc_html( $hello_world_post_url ) . '</a>',
'<a href="' . \esc_url( $hello_world_post_url ) . '" target="_self">' . \esc_html( $hello_world_post_url ) . '</a>',
);
$content .= '</p><p>';
$content .= \esc_html__( 'This post does not add value to your website and solely exists to show what a post can look like. Therefore, "Hello World!" is not needed and should be deleted.', 'progress-planner' );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,25 @@ public function handle_interactive_task_submit() {
\wp_send_json_error( [ 'message' => \esc_html__( 'Term not found.', 'progress-planner' ) ] );
}

// Only public taxonomies are tracked by this task, mirroring the check in
// maybe_remove_irrelevant_tasks().
$taxonomy_object = \get_taxonomy( $taxonomy );
if ( ! $taxonomy_object || ! $taxonomy_object->public ) {
\wp_send_json_error( [ 'message' => \esc_html__( 'You do not have permission to delete terms.', 'progress-planner' ) ] );
}

// Bind the request to a task that actually suggested this term, so this
// handler cannot be repurposed to delete arbitrary terms.
if ( ! $this->has_task_for_term( $term_id, $taxonomy ) ) {
\wp_send_json_error( [ 'message' => \esc_html__( 'You do not have permission to delete terms.', 'progress-planner' ) ] );
}

// Re-check the post count at deletion time: the term may have gained posts
// after the task was created.
if ( $term->count > self::MIN_POSTS ) {
\wp_send_json_error( [ 'message' => \esc_html__( 'This term is not empty and cannot be deleted.', 'progress-planner' ) ] );
}

// Delete the term.
$result = \wp_delete_term( $term_id, $taxonomy );

Expand All @@ -462,4 +481,24 @@ public function handle_interactive_task_submit() {

\wp_send_json_success( [ 'message' => \esc_html__( 'Term deleted successfully.', 'progress-planner' ) ] );
}

/**
* Check whether a task from this provider targets the given term.
*
* @param int $term_id The term ID.
* @param string $taxonomy The taxonomy.
*
* @return bool
*/
protected function has_task_for_term( $term_id, $taxonomy ) {
foreach ( \progress_planner()->get_suggested_tasks_db()->get_tasks_by( [ 'provider_id' => $this->get_provider_id() ] ) as $task ) {
if ( (int) $task->target_term_id === (int) $term_id
&& (string) $task->target_taxonomy === (string) $taxonomy
) {
return true;
}
}

return false;
}
}
2 changes: 1 addition & 1 deletion classes/suggested-tasks/providers/class-sample-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ protected function get_description() {
$content .= \sprintf(
/* translators: %s: Link to the post. */
\esc_html__( 'On install, WordPress creates a "Sample Page" page. You can find yours at %s.', 'progress-planner' ),
'<a href="' . \esc_attr( $sample_page_url ) . '" target="_blank">' . \esc_html( $sample_page_url ) . '</a>',
'<a href="' . \esc_url( $sample_page_url ) . '" target="_blank">' . \esc_html( $sample_page_url ) . '</a>',
);
$content .= '</p><p>';
$content .= \esc_html__( 'This page does not add value to your website and solely exists to show what a page can look like. Therefore, "Sample Page" is not needed and should be deleted.', 'progress-planner' );
Expand Down
2 changes: 1 addition & 1 deletion classes/suggested-tasks/providers/class-tasks.php
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ public function get_task_actions( $data = [] ) {
if ( $this->get_external_link_url() ) {
$actions[] = [
'priority' => 40,
'html' => '<a class="prpl-tooltip-action-text" href="' . \esc_attr( $this->get_external_link_url() ) . '" target="_blank">' . \esc_html__( 'Why is this important?', 'progress-planner' ) . '</a>',
'html' => '<a class="prpl-tooltip-action-text" href="' . \esc_url( $this->get_external_link_url() ) . '" target="_blank">' . \esc_html__( 'Why is this important?', 'progress-planner' ) . '</a>',
];
} elseif ( isset( $data['content']['rendered'] ) && $data['content']['rendered'] !== '' && ! $this instanceof Tasks_Interactive ) {
$actions[] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,18 @@ public function handle_interactive_task_submit() {
\wp_send_json_error( [ 'message' => \esc_html__( 'Term not found.', 'progress-planner' ) ] );
}

// Only public taxonomies are tracked by this task.
$taxonomy_object = \get_taxonomy( $taxonomy );
if ( ! $taxonomy_object || ! $taxonomy_object->public ) {
\wp_send_json_error( [ 'message' => \esc_html__( 'You do not have permission to update terms.', 'progress-planner' ) ] );
}

// Bind the request to a task that actually suggested this term, so this
// handler cannot be repurposed to edit arbitrary terms.
if ( ! $this->has_task_for_term( $term_id, $taxonomy ) ) {
\wp_send_json_error( [ 'message' => \esc_html__( 'You do not have permission to update terms.', 'progress-planner' ) ] );
}

// Update the term description.
$result = \wp_update_term(
$term_id,
Expand All @@ -460,4 +472,24 @@ public function handle_interactive_task_submit() {

\wp_send_json_success( [ 'message' => \esc_html__( 'Term description updated successfully.', 'progress-planner' ) ] );
}

/**
* Check whether a task from this provider targets the given term.
*
* @param int $term_id The term ID.
* @param string $taxonomy The taxonomy.
*
* @return bool
*/
protected function has_task_for_term( $term_id, $taxonomy ) {
foreach ( \progress_planner()->get_suggested_tasks_db()->get_tasks_by( [ 'provider_id' => $this->get_provider_id() ] ) as $task ) {
if ( (int) $task->target_term_id === (int) $term_id
&& (string) $task->target_taxonomy === (string) $taxonomy
) {
return true;
}
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,7 @@ public function print_popover_form_contents() {
* @return void
*/
public function handle_interactive_task_specific_submit() {
$this->verify_aioseo_active_or_fail();
$this->verify_nonce_or_fail();
$this->verify_aioseo_ajax_security();

\aioseo()->options->searchAppearance->archives->author->show = false; // @phpstan-ignore-line

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,7 @@ public function print_popover_form_contents() {
* @return void
*/
public function handle_interactive_task_specific_submit() {
$this->verify_aioseo_active_or_fail();
$this->verify_nonce_or_fail();
$this->verify_aioseo_ajax_security();

\aioseo()->options->searchAppearance->archives->date->show = false; // @phpstan-ignore-line

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,7 @@ public function print_popover_form_contents() {
* @return void
*/
public function handle_interactive_task_specific_submit() {
$this->verify_aioseo_active_or_fail();
$this->verify_nonce_or_fail();
$this->verify_aioseo_ajax_security();

\aioseo()->options->searchAppearance->advanced->crawlCleanup->feeds->authors = false; // @phpstan-ignore-line

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,7 @@ public function print_popover_form_contents() {
* @return void
*/
public function handle_interactive_task_specific_submit() {
$this->verify_aioseo_active_or_fail();
$this->verify_nonce_or_fail();
$this->verify_aioseo_ajax_security();

// Global comment feed.
if ( \aioseo()->options->searchAppearance->advanced->crawlCleanup->feeds->globalComments ) { // @phpstan-ignore-line
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,7 @@ public function print_popover_form_contents() {
* @return void
*/
public function handle_interactive_task_specific_submit() {
$this->verify_aioseo_active_or_fail();
$this->verify_nonce_or_fail();
$this->verify_aioseo_ajax_security();

\aioseo()->dynamicOptions->searchAppearance->postTypes->attachment->redirectAttachmentUrls = 'attachment'; // @phpstan-ignore-line

Expand Down
Loading
Loading