Plugin Directory

Changeset 3243842


Ignore:
Timestamp:
02/20/2025 11:59:47 AM (12 months ago)
Author:
progressplanner
Message:

Update to version 1.1.0 from GitHub

Location:
progress-planner
Files:
62 added
24 deleted
58 edited
1 copied

Legend:

Unmodified
Added
Removed
  • progress-planner/tags/1.1.0/CHANGELOG.md

    r3238385 r3243842  
     1= 1.0.5 =
     2
     3Under the hood:
     4
     5* Improved suggested tasks completion conditions.
     6* Improved checks for suggested 'review post' tasks.
     7
     8We've added the following Recommendations from Ravi:
     9
     10* [Setting the permalink structure](TBD).
     11* [Update PHP version](TBD).
     12* [Disable comments on your site](TBD).
     13* [Remove inactive plugins](TBD).
     14* [Search engine visibility](TBD).
     15
    116= 1.0.4 =
    217
  • progress-planner/tags/1.1.0/assets/css/admin.css

    r3226821 r3243842  
    346346
    347347/*------------------------------------*\
     348    Input fields.
     349\*------------------------------------*/
     350
     351.prpl-wrap input[type="text"],
     352.prpl-wrap input[type="email"],
     353.prpl-wrap input[type="number"],
     354.prpl-wrap input[type="url"],
     355.prpl-wrap input[type="tel"],
     356.prpl-wrap input[type="search"] {
     357    height: 40px;
     358    box-shadow: 1px 2px 4px 0 rgba(0, 0, 0, 0.25);
     359}
     360
     361/*------------------------------------*\
    348362    Popovers generic styles.
    349363\*------------------------------------*/
  • progress-planner/tags/1.1.0/assets/css/welcome.css

    r3217671 r3243842  
    2525
    2626    .welcome-header {
    27         background: var(--prpl-color-accent-orange);
     27        background: var(--prpl-color-400-orange);
    2828        display: flex;
    2929        justify-content: space-between;
    3030        align-items: center;
     31        border-top-left-radius: var(--prpl-border-radius);
     32        border-top-right-radius: var(--prpl-border-radius);
     33        overflow: hidden;
    3134
    3235        h1 {
     
    3740
    3841        .welcome-header-icon {
    39             background: var(--prpl-background-orange);
    40             background: linear-gradient(105deg, var(--prpl-color-accent-orange) 25%, var(--prpl-background-orange) 25%);
     42            background: var(--prpl-color-400-orange);
     43            background: linear-gradient(105deg, var(--prpl-color-400-orange) 25%, var(--prpl-background-orange) 25%);
    4144            padding: var(--prpl-padding);
    4245            padding-left: 100px;
     
    4952    }
    5053
     54    .prpl-form-notice-title {
     55        font-size: var(--prpl-font-size-lg);
     56    }
     57
    5158    ul {
    5259        list-style: disc;
     
    5663    .prpl-onboard-form-radio-select {
    5764        margin-top: 0.75rem;
     65
     66        label {
     67            margin-top: 0.5rem;
     68
     69            &:first-child {
     70                margin-top: 0;
     71            }
     72        }
    5873    }
    5974
  • progress-planner/tags/1.1.0/assets/js/ajax-request.js

    r3099196 r3243842  
    3535            }
    3636        }
    37         if ( http.readyState === 4 && http.status === 200 ) {
    38             return successAction
    39                 ? successAction( response )
     37
     38        if ( http.readyState === 4 ) {
     39            if ( http.status === 200 ) {
     40                return successAction
     41                    ? successAction( response )
     42                    : defaultCallback( response );
     43            }
     44
     45            // Request is completed, but the status is not 200.
     46            return failAction
     47                ? failAction( response )
    4048                : defaultCallback( response );
    4149        }
    42         return failAction
    43             ? failAction( response )
    44             : defaultCallback( response );
    4550    };
    4651
  • progress-planner/tags/1.1.0/assets/js/grid-masonry.js

    r3210975 r3243842  
    11/* global prplDocumentReady */
    2 
    3 /**
    4  * Custom script to allow a grid to behave like a masonry layout.
     2/*
     3 * Grid Masonry
    54 *
     5 * A script to allow a grid to behave like a masonry layout.
    66 * Inspired by https://medium.com/@andybarefoot/a-masonry-style-layout-using-css-grid-8c663d355ebb
     7 *
     8 * Dependencies: progress-planner-document-ready
    79 */
    810
  • progress-planner/tags/1.1.0/assets/js/onboard.js

    r3217671 r3243842  
    1 /* global progressPlanner, progressPlannerAjaxRequest, progressPlannerTriggerScan */
     1/* global progressPlanner, progressPlannerAjaxRequest, progressPlannerTriggerScan, prplOnboardTasks */
     2/*
     3 * Onboard
     4 *
     5 * A script to handle the onboarding process.
     6 *
     7 * Dependencies: progress-planner-ajax-request, progress-planner-scan-posts, progress-planner-upgrade-tasks
     8 */
    29
    310/**
     
    4552            // Start scanning posts.
    4653            progressPlannerTriggerScan();
     54
     55            // Start the tasks.
     56            prplOnboardTasks();
    4757        },
    4858        failAction: ( response ) => {
  • progress-planner/tags/1.1.0/assets/js/scan-posts.js

    r3156816 r3243842  
    1 /* global progressPlanner, progressPlannerAjaxRequest */
     1/* global progressPlanner, progressPlannerAjaxRequest, prplOnboardRedirect */
     2/*
     3 * Scan Posts
     4 *
     5 * A script to scan posts for the Progress Planner.
     6 *
     7 * Dependencies: progress-planner-ajax-request, progress-planner-upgrade-tasks
     8 */
    29
    310// eslint-disable-next-line no-unused-vars
     
    2936        // Refresh the page when scan has finished.
    3037        if ( response.data.progress >= 100 ) {
    31             document.getElementById(
     38            const scanProgressElement = document.getElementById(
    3239                'progress-planner-scan-progress'
    33             ).style.display = 'none';
     40            );
    3441
    35             window.location.href =
    36                 window.location.href
    37                     .replace( '&content-scan-finished=true', '' )
    38                     .replace( '&content-scan', '' ) +
    39                 '&content-scan-finished=true';
     42            scanProgressElement.style.display = 'none';
     43            scanProgressElement.setAttribute(
     44                'data-onboarding-finished',
     45                'true'
     46            );
     47
     48            // Redirect if scanning is finished.
     49            prplOnboardRedirect( 'scanPosts' );
    4050
    4151            return;
  • progress-planner/tags/1.1.0/assets/js/settings-page.js

    r3226821 r3243842  
    11/* global alert, prplDocumentReady */
    2 
     2/*
     3 * Settings Page
     4 *
     5 * A script to handle the settings page.
     6 *
     7 * Dependencies: progress-planner-document-ready, wp-util
     8 */
    39const prplTogglePageSelectorSettingVisibility = function ( page, value ) {
    410    const itemRadiosWrapperEl = document.querySelector(
  • progress-planner/tags/1.1.0/assets/js/settings.js

    r3198155 r3243842  
    11/* global progressPlanner, progressPlannerAjaxRequest, progressPlannerSaveLicenseKey */
     2/*
     3 * Settings
     4 *
     5 * A script to handle the settings page.
     6 *
     7 * Dependencies: progress-planner-ajax-request, wp-util
     8 */
    29document
    310    .getElementById( 'prpl-settings-form' )
  • progress-planner/tags/1.1.0/assets/js/tour.js

    r3210975 r3243842  
    11/* global progressPlannerTour */
     2/*
     3 * Tour
     4 *
     5 * A tour for the Progress Planner.
     6 *
     7 * Dependencies: driver
     8 */
    29const prplDriver = window.driver.js.driver;
    310
     
    119126            .replace( '&content-scan-finished=true', '' )
    120127            .replace( 'content-scan-finished=true', '' )
     128            .replace( '&delay-tour=true', '' )
     129            .replace( 'delay-tour=true', '' )
    121130    );
    122131}
     
    124133// Start the tour if the URL contains the query parameter.
    125134if ( window.location.href.includes( 'content-scan-finished=true' ) ) {
    126     prplStartTour();
     135    // If there are pending celebration tasks, delay the tour until celebration is done.
     136    const delay = window.location.href.includes( 'delay-tour=true' ) ? 5000 : 0;
     137
     138    setTimeout( () => {
     139        prplStartTour();
     140    }, delay );
    127141}
  • progress-planner/tags/1.1.0/assets/js/web-components/prpl-badge.js

    r3238385 r3243842  
    1919                        progressPlannerBadge.remoteServerRootUrl
    2020                    }/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=${ badgeId }"
    21                     alt="Badge"
     21                    alt="${ progressPlannerBadge.l10n.badge }"
    2222                    ${ false === complete ? 'style="filter: grayscale(1);opacity: 0.25;"' : '' }
    2323                    onerror="this.onerror=null;this.src='${
  • progress-planner/tags/1.1.0/assets/js/web-components/prpl-gauge.js

    r3217671 r3243842  
    11/* global customElements, HTMLElement */
     2/*
     3 * Web Component: prpl-gauge
     4 *
     5 * A web component that displays a gauge.
     6 *
     7 * Dependencies: progress-planner-web-components-prpl-badge
     8 */
    29
    310/**
  • progress-planner/tags/1.1.0/assets/js/widgets/suggested-tasks.js

    r3238385 r3243842  
    3636    // Remove completed and snoozed items.
    3737    const tasks = progressPlannerSuggestedTasks.tasks;
    38     const items = tasks.details[ type ];
     38    let items = tasks.details[ type ];
    3939    const completed = tasks.completed;
    4040    const snoozed = tasks.snoozed;
     
    4848        } );
    4949
    50     items.forEach( function ( item ) {
    51         if (
    52             completed.includes( item.task_id.toString() ) ||
    53             inList.includes( item.task_id.toString() )
    54         ) {
    55             items.splice( items.indexOf( item ), 1 );
    56         }
    57         snoozed.forEach( ( snoozedItem ) => {
    58             if ( item.task_id.toString() === snoozedItem.id ) {
    59                 items.splice( items.indexOf( item ), 1 );
     50    // Remove items which are completed or already in the list.
     51    items = items.filter( function ( item ) {
     52        return (
     53            ! completed.includes( item.task_id.toString() ) &&
     54            ! inList.includes( item.task_id.toString() )
     55        );
     56    } );
     57
     58    // Remove items which are snoozed.
     59    items = items.filter( function ( item ) {
     60        for ( let i = 0; i < snoozed.length; i++ ) {
     61            if ( item.task_id.toString() === snoozed[ i ].id.toString() ) {
     62                return false;
    6063            }
    61         } );
     64        }
     65        return true;
    6266    } );
     67
     68    // Do nothing if there are no items left.
     69    if ( 0 === items.length ) {
     70        return null;
     71    }
    6372
    6473    // Get items with a priority set to `high`.
     
    275284const prplPendingCelebration =
    276285    progressPlannerSuggestedTasks.tasks.pending_celebration;
    277 if ( prplPendingCelebration && prplPendingCelebration.length ) {
     286if (
     287    ! progressPlannerSuggestedTasks.delayCelebration &&
     288    prplPendingCelebration &&
     289    prplPendingCelebration.length
     290) {
    278291    setTimeout( () => {
    279292        // Trigger the celebration event.
  • progress-planner/tags/1.1.0/classes/admin/class-page.php

    r3238385 r3243842  
    108108     */
    109109    public function enqueue_assets( $hook ) {
     110        $this->maybe_enqueue_focus_el_script( $hook );
    110111        if ( 'toplevel_page_progress-planner' !== $hook && 'progress-planner_page_progress-planner-settings' !== $hook ) {
    111112            return;
     
    139140                \wp_enqueue_script( 'progress-planner-settings' );
    140141                \wp_enqueue_script( 'progress-planner-grid-masonry' );
     142                \wp_enqueue_script( 'progress-planner-upgrade-tasks' );
    141143            } else {
    142144                \wp_enqueue_script( 'progress-planner-onboard' );
     
    147149            \wp_enqueue_script( 'progress-planner-settings-page' );
    148150        }
     151    }
     152
     153    /**
     154     * Enqueue the focus element script.
     155     *
     156     * @param string $hook The current admin page.
     157     *
     158     * @return void
     159     */
     160    public function maybe_enqueue_focus_el_script( $hook ) {
     161        $suggested_tasks       = \progress_planner()->get_suggested_tasks();
     162        $local_tasks_providers = $suggested_tasks->get_local()->get_task_providers();
     163        $tasks_details         = [];
     164        $total_points          = 0;
     165        $completed_points      = 0;
     166        foreach ( $local_tasks_providers as $provider ) {
     167            if ( 'configuration' !== $provider->get_provider_type() ) {
     168                continue;
     169            }
     170            $details = $provider->get_task_details();
     171            if ( ! isset( $details['link_setting']['hook'] ) ||
     172                $hook !== $details['link_setting']['hook']
     173            ) {
     174                continue;
     175            }
     176            $details['is_complete'] = $provider->is_task_completed();
     177            $tasks_details[]        = $details;
     178            $total_points          += $details['points'];
     179            if ( $details['is_complete'] ) {
     180                $completed_points += $details['points'];
     181            }
     182        }
     183
     184        if ( empty( $tasks_details ) ) {
     185            return;
     186        }
     187
     188        // Register the scripts.
     189        \progress_planner()->get_admin__scripts()->register_scripts();
     190
     191        \wp_enqueue_script( 'progress-planner-focus-element' );
     192        \wp_localize_script(
     193            'progress-planner-focus-element',
     194            'progressPlannerFocusElement',
     195            [
     196                'tasks'           => $tasks_details,
     197                'totalPoints'     => $total_points,
     198                'completedPoints' => $completed_points,
     199                'base_url'        => PROGRESS_PLANNER_URL,
     200                'l10n'            => [
     201                    /* translators: %d: The number of points. */
     202                    'fixThisIssue' => \esc_html__( 'Fix this issue to get %d point(s) in Progress Planner', 'progress-planner' ),
     203                ],
     204            ]
     205        );
     206        \wp_enqueue_style(
     207            'progress-planner-focus-element',
     208            PROGRESS_PLANNER_URL . '/assets/css/focus-element.css',
     209            [],
     210            \progress_planner()->get_file_version( PROGRESS_PLANNER_DIR . '/assets/css/focus-element.css' )
     211        );
    149212    }
    150213
     
    173236                [],
    174237                \progress_planner()->get_file_version( PROGRESS_PLANNER_DIR . '/assets/css/settings-page.css' )
     238            );
     239        }
     240
     241        if ( 'toplevel_page_progress-planner' === $current_screen->id ) {
     242            // Enqueue ugprading (onboarding) tasks styles, these are needed both when privacy policy is accepted and when it is not.
     243            \wp_enqueue_style(
     244                'progress-planner-upgrade-tasks',
     245                PROGRESS_PLANNER_URL . '/assets/css/upgrade-tasks.css',
     246                [],
     247                \progress_planner()->get_file_version( PROGRESS_PLANNER_DIR . '/assets/css/upgrade-tasks.css' )
    175248            );
    176249        }
  • progress-planner/tags/1.1.0/classes/admin/class-scripts.php

    r3226821 r3243842  
    6262     */
    6363    public function get_dependencies( $file ) {
    64         switch ( $file ) {
    65             case 'web-components/prpl-gauge':
    66                 return [ 'progress-planner-web-components-prpl-badge' ];
    67 
    68             case 'tour':
    69                 return [ 'driver' ];
    70 
    71             case 'grid-masonry':
    72                 return [ 'progress-planner-document-ready' ];
    73 
    74             case 'scan-posts':
    75                 return [ 'progress-planner-ajax-request' ];
    76 
    77             case 'onboard':
    78                 return [ 'progress-planner-ajax-request', 'progress-planner-scan-posts' ];
    79 
    80             case 'settings':
    81                 return [ 'progress-planner-ajax-request', 'wp-util' ];
    82 
    83             case 'settings-page':
    84                 return [ 'wp-util', 'progress-planner-document-ready' ];
    85 
    86             default:
    87                 return [];
    88         }
     64        $path    = PROGRESS_PLANNER_DIR . '/assets/js/' . $file . '.js';
     65        $headers = \get_file_data(
     66            $path,
     67            [
     68                'dependencies' => 'Dependencies',
     69            ]
     70        );
     71        if ( ! isset( $headers['dependencies'] ) ) {
     72            return [];
     73        }
     74
     75        return \array_filter( \array_map( 'trim', \explode( ',', $headers['dependencies'] ) ) );
    8976    }
    9077
     
    10491                        'remoteServerRootUrl' => \progress_planner()->get_remote_server_root_url(),
    10592                        'placeholderImageUrl' => \progress_planner()->get_placeholder_svg(),
     93                        'l10n'                => [
     94                            'badge' => \esc_html__( 'Badge', 'progress-planner' ),
     95                        ],
    10696                    ]
    10797                );
  • progress-planner/tags/1.1.0/classes/class-badges.php

    r3226821 r3243842  
    8484     */
    8585    public function get_badges( $context ) {
    86         if ( ! isset( $this->$context ) ) {
    87             return [];
    88         }
    89 
    90         return $this->$context;
     86        return isset( $this->$context ) ? $this->$context : [];
    9187    }
    9288
     
    156152
    157153            // If the badge is already complete, skip it.
    158             if ( 100 === $badge->progress_callback()['progress'] ) {
     154            if ( 100 <= $badge->progress_callback()['progress'] ) {
    159155                continue;
    160156            }
  • progress-planner/tags/1.1.0/classes/class-base.php

    r3238385 r3243842  
    1717use Progress_Planner\Actions\Maintenance as Actions_Maintenance;
    1818use Progress_Planner\Admin\Page_Settings as Admin_Page_Settings;
     19use Progress_Planner\Plugin_Upgrade_Handler;
     20use Progress_Planner\Debug_Tools;
    1921/**
    2022 * Main plugin class.
     
    103105
    104106            new Plugin_Deactivation();
     107        }
     108
     109        $this->cached['plugin_upgrade_handler'] = new Plugin_Upgrade_Handler();
     110
     111        // Debug tools.
     112        if ( ( defined( 'PRPL_DEBUG' ) && PRPL_DEBUG ) || \get_option( 'prpl_debug' ) ) {
     113            new Debug_Tools();
    105114        }
    106115
     
    197206     */
    198207    public function add_action_links( $actions ) {
    199         $action_link = [ '<a href="' . admin_url( 'admin.php?page=progress-planner' ) . '">' . __( 'Dashboard', 'progress-planner' ), '</a>' ];
    200         $actions     = array_merge( $action_link, $actions );
    201         return $actions;
     208        return array_merge(
     209            [
     210                sprintf(
     211                    '<a href="%1$s">%2$s</a>',
     212                    admin_url( 'admin.php?page=progress-planner' ),
     213                    __( 'Dashboard', 'progress-planner' )
     214                ),
     215            ],
     216            $actions
     217        );
    202218    }
    203219
  • progress-planner/tags/1.1.0/classes/class-lessons.php

    r3210975 r3243842  
    5555        }
    5656
    57         $response = \wp_remote_get(
    58             $url
    59         );
     57        $response = \wp_remote_get( $url );
    6058
    6159        if ( \is_wp_error( $response ) ) {
  • progress-planner/tags/1.1.0/classes/class-page-types.php

    r3226821 r3243842  
    397397            return;
    398398        }
     399
    399400        $terms = \get_the_terms( $post_id, self::TAXONOMY_NAME );
    400401        if ( ! \is_array( $terms ) || ! isset( $terms[0] ) ) {
  • progress-planner/tags/1.1.0/classes/class-playground.php

    r3238385 r3243842  
    1717     */
    1818    public function __construct() {
    19         \add_action( 'init', [ $this, 'register_hooks' ] );
     19        \add_action( 'init', [ $this, 'register_hooks' ], 9 );
     20
     21        \add_action( 'plugins_loaded', [ $this, 'enable_debug_tools' ], 1 );
    2022    }
    2123
     
    5153
    5254    /**
     55     * Enable debug tools.
     56     *
     57     * @return void
     58     */
     59    public function enable_debug_tools() {
     60        \update_option( 'prpl_debug', true );
     61    }
     62
     63    /**
    5364     * Toggle the onboarding visibility in the Playground environment.
    5465     *
  • progress-planner/tags/1.1.0/classes/class-popover.php

    r3198155 r3243842  
    4141     */
    4242    public function render_button( $icon, $content ) {
    43         ?>
    44         <!-- The triggering button. -->
    45         <button
    46             class="prpl-info-icon"
    47             popovertarget="prpl-popover-<?php echo \esc_attr( $this->id ); ?>"
    48             id="prpl-popover-<?php echo \esc_attr( $this->id ); ?>-trigger"
    49         >
    50             <?php if ( '' !== $icon ) : ?>
    51                 <span class="dashicons dashicons-<?php echo \esc_attr( $icon ); ?>"></span>
    52             <?php endif; ?>
    53             <?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
    54         </button>
    55         <?php
     43        \progress_planner()->the_view(
     44            'popovers/parts/icon.php',
     45            [
     46                'prpl_popover_id'              => $this->id,
     47                'prpl_popover_trigger_icon'    => $icon,
     48                'prpl_popover_trigger_content' => $content,
     49            ]
     50        );
    5651    }
    5752
     
    6257     */
    6358    public function render() {
    64         ?>
    65         <div id="prpl-popover-<?php echo \esc_attr( $this->id ); ?>" class="prpl-popover" popover>
    66             <!-- The content. -->
    67             <?php \progress_planner()->the_view( 'popovers/' . $this->id . '.php' ); ?>
    68 
    69             <!-- The close button. -->
    70             <button
    71                 class="prpl-popover-close"
    72                 popovertarget="prpl-popover-<?php echo \esc_attr( $this->id ); ?>"
    73                 popovertargetaction="hide"
    74             >
    75                 <span class="dashicons dashicons-no-alt"></span>
    76                 <span class="screen-reader-text"><?php \esc_html_e( 'Close', 'progress-planner' ); ?>
    77             </button>
    78 
    79         </div>
    80         <?php
     59        \progress_planner()->the_view(
     60            'popovers/popover.php',
     61            [
     62                'prpl_popover_id' => $this->id,
     63            ]
     64        );
    8165    }
    8266}
  • progress-planner/tags/1.1.0/classes/class-suggested-tasks.php

    r3238385 r3243842  
    245245     */
    246246    public function mark_task_as_pending_celebration( $task_id ) {
     247        // Don't mark the task as pending celebration if it's already completed.
     248        if ( $this->was_task_completed( $task_id ) ) {
     249            return false;
     250        }
     251
    247252        return $this->mark_task_as( 'pending_celebration', $task_id );
    248253    }
     
    372377     */
    373378    public function get_snoozed_tasks() {
    374         $option  = \get_option( self::OPTION_NAME, [] );
    375         $snoozed = $option['snoozed'] ?? [];
    376 
    377         return $snoozed;
     379        $option = \get_option( self::OPTION_NAME, [] );
     380        return $option['snoozed'] ?? [];
    378381    }
    379382
     
    384387     */
    385388    public function get_completed_tasks() {
    386         $option    = \get_option( self::OPTION_NAME, [] );
    387         $completed = $option['completed'] ?? [];
    388 
    389         return $completed;
     389        $option = \get_option( self::OPTION_NAME, [] );
     390        return $option['completed'] ?? [];
    390391    }
    391392
     
    473474        );
    474475
    475         if ( 'completed' === $parsed_condition['type'] ) {
    476             $completed_tasks = $this->get_completed_tasks();
    477 
    478             if ( \in_array( $parsed_condition['task_id'], $completed_tasks, true ) ) {
    479                 return true;
    480             }
    481         }
    482 
    483         if ( 'snoozed' === $parsed_condition['type'] ) {
    484             $snoozed_tasks = $this->get_snoozed_tasks();
    485 
    486             if ( \in_array( $parsed_condition['task_id'], $snoozed_tasks, true ) ) {
    487                 return true;
    488             }
    489         }
    490 
    491         if ( 'snoozed-post-length' === $parsed_condition['type'] && isset( $parsed_condition['post_lengths'] ) ) {
    492             if ( ! \is_array( $parsed_condition['post_lengths'] ) ) {
    493                 $parsed_condition['post_lengths'] = [ $parsed_condition['post_lengths'] ];
    494             }
    495 
    496             $snoozed_tasks        = $this->get_snoozed_tasks();
    497             $snoozed_post_lengths = [];
    498 
    499             // Get the post lengths of the snoozed tasks.
    500             foreach ( $snoozed_tasks as $task ) {
    501                 $data = $this->local->get_data_from_task_id( $task['id'] ); // @phpstan-ignore-line method.nonObject
    502                 if ( isset( $data['type'] ) && 'create-post' === $data['type'] ) {
    503                     $key = true === $data['long'] ? 'long' : 'short';
    504                     if ( ! isset( $snoozed_post_lengths[ $key ] ) ) {
    505                         $snoozed_post_lengths[ $key ] = true;
     476        switch ( $parsed_condition['type'] ) {
     477            case 'completed':
     478                if ( \in_array( $parsed_condition['task_id'], $this->get_completed_tasks(), true ) ) {
     479                    return true;
     480                }
     481                break;
     482
     483            case 'pending_celebration':
     484                if ( \in_array( $parsed_condition['task_id'], $this->get_pending_celebration(), true ) ) {
     485                    return true;
     486                }
     487                break;
     488
     489            case 'snoozed':
     490                if ( \in_array( $parsed_condition['task_id'], $this->get_snoozed_tasks(), true ) ) {
     491                    return true;
     492                }
     493                break;
     494
     495            case 'snoozed-post-length':
     496                if ( isset( $parsed_condition['post_lengths'] ) ) {
     497                    if ( ! \is_array( $parsed_condition['post_lengths'] ) ) {
     498                        $parsed_condition['post_lengths'] = [ $parsed_condition['post_lengths'] ];
    506499                    }
    507                 }
    508             }
    509 
    510             // Check if the snoozed post lengths match the condition.
    511             foreach ( $parsed_condition['post_lengths'] as $post_length ) {
    512                 if ( ! isset( $snoozed_post_lengths[ $post_length ] ) ) {
    513                     return false;
    514                 }
    515             }
    516 
    517             return true;
    518         }
    519 
    520         // If no condition is met, return false.
     500
     501                    $snoozed_tasks        = $this->get_snoozed_tasks();
     502                    $snoozed_post_lengths = [];
     503
     504                    // Get the post lengths of the snoozed tasks.
     505                    foreach ( $snoozed_tasks as $task ) {
     506                        $data = $this->local->get_data_from_task_id( $task['id'] ); // @phpstan-ignore-line method.nonObject
     507                        if ( isset( $data['type'] ) && 'create-post' === $data['type'] ) {
     508                            $key = true === $data['long'] ? 'long' : 'short';
     509                            if ( ! isset( $snoozed_post_lengths[ $key ] ) ) {
     510                                $snoozed_post_lengths[ $key ] = true;
     511                            }
     512                        }
     513                    }
     514
     515                    // Check if the snoozed post lengths match the condition.
     516                    foreach ( $parsed_condition['post_lengths'] as $post_length ) {
     517                        if ( ! isset( $snoozed_post_lengths[ $post_length ] ) ) {
     518                            return false;
     519                        }
     520                    }
     521
     522                    return true;
     523                }
     524                break;
     525        }
     526
    521527        return false;
    522528    }
    523529
    524530    /**
    525      * Check if a task was completed.
     531     * Check if a task was completed. Task is considered completed if it was completed or pending celebration.
    526532     *
    527533     * @param string $task_id The task ID.
     
    530536     */
    531537    public function was_task_completed( $task_id ) {
    532         return true === $this->check_task_condition(
    533             [
    534                 'type'    => 'completed',
    535                 'task_id' => $task_id,
    536             ]
     538
     539        return (
     540            // Check if the task was pending celebration.
     541            true === $this->check_task_condition(
     542                [
     543                    'type'    => 'pending_celebration',
     544                    'task_id' => $task_id,
     545                ]
     546            )
     547            ||
     548            // Check if the task was completed.
     549            true === $this->check_task_condition(
     550                [
     551                    'type'    => 'completed',
     552                    'task_id' => $task_id,
     553                ]
     554            )
    537555        );
    538556    }
  • progress-planner/tags/1.1.0/classes/suggested-tasks/class-local-tasks-manager.php

    r3238385 r3243842  
    99
    1010use Progress_Planner\Suggested_Tasks\Local_Tasks\Local_Task_Factory;
    11 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Content_Create;
    12 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Content_Review;
    13 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Core_Update;
    14 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Core_Blogdescription;
    15 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Settings_Saved;
    16 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Debug_Display;
    17 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Sample_Page;
    18 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Hello_World;
    19 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Core_Siteicon;
     11// Repetitive tasks.
     12use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Repetitive\Core_Update;
     13// Content tasks.
     14use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Content\Create as Content_Create;
     15use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Content\Review as Content_Review;
     16// One-time tasks.
     17use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Blog_Description;
     18use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Settings_Saved;
     19use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Debug_Display;
     20use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Disable_Comments;
     21use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Sample_Page;
     22use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Hello_World;
     23use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Remove_Inactive_Plugins;
     24use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Site_Icon;
     25use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Rename_Uncategorized_Category;
     26use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Permalink_Structure;
     27use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Php_Version;
     28use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Search_Engine_Visibility;
    2029
    2130/**
     
    5160            new Content_Review(),
    5261            new Core_Update(),
    53             new Core_Blogdescription(),
     62            new Blog_Description(),
    5463            new Settings_Saved(),
    5564            new Debug_Display(),
     65            new Disable_Comments(),
    5666            new Sample_Page(),
    5767            new Hello_World(),
    58             new Core_Siteicon(),
     68            new Remove_Inactive_Plugins(),
     69            new Site_Icon(),
     70            new Rename_Uncategorized_Category(),
     71            new Permalink_Structure(),
     72            new Php_Version(),
     73            new Search_Engine_Visibility(),
    5974        ];
    6075
     
    6479        // Add the cleanup action.
    6580        \add_action( 'admin_init', [ $this, 'cleanup_pending_tasks' ] );
     81
     82        // Add the onboarding task providers.
     83        \add_filter( 'prpl_onboarding_task_providers', [ $this, 'add_onboarding_task_providers' ] );
    6684    }
    6785
     
    7391    public function add_plugin_integration() {
    7492        // Add the plugin integration here.
     93    }
     94
     95    /**
     96     * Add the onboarding task providers.
     97     *
     98     * @param array $task_providers The task providers.
     99     *
     100     * @return array
     101     */
     102    public function add_onboarding_task_providers( $task_providers ) {
     103
     104        foreach ( $this->task_providers as $task_provider ) {
     105
     106            if ( $task_provider->is_onboarding_task() ) {
     107                $task_providers[] = $task_provider->get_provider_id();
     108            }
     109        }
     110
     111        return $task_providers;
    75112    }
    76113
     
    95132
    96133    /**
     134     * Get the task providers.
     135     *
     136     * @return array
     137     */
     138    public function get_task_providers() {
     139        return $this->task_providers;
     140    }
     141
     142    /**
    97143     * Get a task provider by its type.
    98144     *
     
    119165     */
    120166    public function inject_tasks( $tasks ) {
     167        $provider_tasks  = [];
    121168        $tasks_to_inject = [];
    122169
    123170        // Loop through all registered task providers and inject their tasks.
    124171        foreach ( $this->task_providers as $provider_instance ) {
    125             $tasks_to_inject = \array_merge( $tasks_to_inject, $provider_instance->get_tasks_to_inject() );
     172            $provider_tasks = \array_merge( $provider_tasks, $provider_instance->get_tasks_to_inject() );
    126173        }
    127174
    128175        // Add the tasks to the pending tasks option, it will not add duplicates.
    129         foreach ( $tasks_to_inject as $task ) {
     176        foreach ( $provider_tasks as $task ) {
     177
     178            // Skip the task if it was completed.
     179            if ( true === \progress_planner()->get_suggested_tasks()->was_task_completed( $task['task_id'] ) ) {
     180                continue;
     181            }
     182
     183            $tasks_to_inject[] = $task;
    130184            $this->add_pending_task( $task['task_id'] );
    131185        }
  • progress-planner/tags/1.1.0/classes/suggested-tasks/local-tasks/providers/class-local-tasks-abstract.php

    r3238385 r3243842  
    3838
    3939    /**
     40     * Whether the task is an onboarding task.
     41     *
     42     * @var bool
     43     */
     44    protected $is_onboarding_task = false;
     45
     46    /**
    4047     * Get the provider type.
    4148     *
     
    6471            ? \current_user_can( $this->capability )
    6572            : true;
     73    }
     74
     75    /**
     76     * Check if the task is an onboarding task.
     77     *
     78     * @return bool
     79     */
     80    public function is_onboarding_task() {
     81        return $this->is_onboarding_task;
    6682    }
    6783
  • progress-planner/tags/1.1.0/classes/widgets/class-suggested-tasks.php

    r3238385 r3243842  
    6969        ];
    7070
     71        // Check if need to load confetti for the local tasks.
     72        $load_confetti = ! empty( $pending_celebration );
     73
     74        foreach ( $pending_tasks as $type => $tasks ) {
     75            foreach ( $tasks as $task ) {
     76                if ( isset( $task['dismissable'] ) && $task['dismissable'] ) {
     77                    $load_confetti = true;
     78                    break 2; // Break out of the foreach loops.
     79                }
     80            }
     81        }
     82
    7183        // Check if need to load confetti.
    72         if ( isset( $pending_tasks['content-update'] ) || ! empty( $pending_celebration ) ) {
     84        if ( $load_confetti ) {
    7385            $deps[] = 'particles-confetti';
    7486        } else {
     
    106118        $tasks['details'] = $this->get_pending_tasks();
    107119
    108         // Insert the pending celebration tasks as high priority tasks, so they are shown always.
    109         foreach ( $tasks['pending_celebration'] as $task_id ) {
    110 
    111             $task_object   = ( new Local_Task_Factory( $task_id ) )->get_task();
    112             $task_provider = \progress_planner()->get_suggested_tasks()->get_local()->get_task_provider( $task_object->get_provider_id() );
    113 
    114             if ( $task_provider && $task_provider->capability_required() ) {
    115                 $task_details = \progress_planner()->get_suggested_tasks()->get_local()->get_task_details( $task_id );
    116 
    117                 if ( $task_details ) {
    118                     $task_details['priority'] = 'high'; // Celebrate tasks are always on top.
    119                     $task_details['action']   = 'celebrate';
    120                     $task_details['type']     = 'pending_celebration';
    121 
    122                     if ( ! isset( $tasks['details']['pending_celebration'] ) ) {
    123                         $tasks['details']['pending_celebration'] = [];
     120        // If there are newly added task providers, delay the celebration in order not to get confetti behind the popover.
     121        $delay_celebration = \progress_planner()->get_plugin_upgrade_handler()->get_newly_added_task_providers() ? true : false;
     122
     123        if ( ! $delay_celebration ) {
     124            // Insert the pending celebration tasks as high priority tasks, so they are shown always.
     125            foreach ( $tasks['pending_celebration'] as $task_id ) {
     126
     127                $task_object   = ( new Local_Task_Factory( $task_id ) )->get_task();
     128                $task_provider = \progress_planner()->get_suggested_tasks()->get_local()->get_task_provider( $task_object->get_provider_id() );
     129
     130                if ( $task_provider && $task_provider->capability_required() ) {
     131                    $task_details = \progress_planner()->get_suggested_tasks()->get_local()->get_task_details( $task_id );
     132
     133                    if ( $task_details ) {
     134                        $task_details['priority'] = 'high'; // Celebrate tasks are always on top.
     135                        $task_details['action']   = 'celebrate';
     136                        $task_details['type']     = 'pending_celebration';
     137
     138                        if ( ! isset( $tasks['details']['pending_celebration'] ) ) {
     139                            $tasks['details']['pending_celebration'] = [];
     140                        }
     141
     142                        $tasks['details']['pending_celebration'][] = $task_details;
    124143                    }
    125144
    126                     $tasks['details']['pending_celebration'][] = $task_details;
     145                    // Mark the pending celebration tasks as completed.
     146                    \progress_planner()->get_suggested_tasks()->transition_task_status( $task_id, 'pending_celebration', 'completed' );
    127147                }
    128 
    129                 // Mark the pending celebration tasks as completed.
    130                 \progress_planner()->get_suggested_tasks()->transition_task_status( $task_id, 'pending_celebration', 'completed' );
    131148            }
    132149        }
     
    173190            'progressPlannerSuggestedTasks',
    174191            [
    175                 'ajaxUrl'         => \admin_url( 'admin-ajax.php' ),
    176                 'nonce'           => \wp_create_nonce( 'progress_planner' ),
    177                 'tasks'           => $tasks,
    178                 'maxItemsPerType' => apply_filters( 'progress_planner_suggested_tasks_max_items_per_type', $max_items_per_type ),
    179                 'confettiOptions' => $confetti_options,
     192                'ajaxUrl'          => \admin_url( 'admin-ajax.php' ),
     193                'nonce'            => \wp_create_nonce( 'progress_planner' ),
     194                'tasks'            => $tasks,
     195                'maxItemsPerType'  => apply_filters( 'progress_planner_suggested_tasks_max_items_per_type', $max_items_per_type ),
     196                'confettiOptions'  => $confetti_options,
     197                'delayCelebration' => $delay_celebration,
    180198            ]
    181199        );
  • progress-planner/tags/1.1.0/progress-planner.php

    r3238385 r3243842  
    1010 * Requires at least: 6.3
    1111 * Requires PHP:      7.4
    12  * Version:           1.0.4
     12 * Version:           1.1.0
    1313 * Author:            Team Emilia Projects
    1414 * Author URI:        https://prpl.fyi/about
  • progress-planner/tags/1.1.0/readme.txt

    r3238385 r3243842  
    55Tested up to: 6.7
    66Requires PHP: 7.4
    7 Stable tag: 1.0.4
     7Stable tag: 1.1.0
    88License: GPL3+
    99License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
     
    1313== Description ==
    1414
    15 Welcome to Progress Planner! This transformative WordPress plugin will empower website owners to keep up the good work on their site. Progress Planner introduces an exciting, interactive approach to website management with badges and achievements to collect. Our mission is to tackle the all-too-common challenge of procrastination. With Progress Planner, the upkeep of your website is a rewarding experience! We’ll encourage you to contribute to the success of your site consistently.
    16 
    17 === Problem We Solve ===
    18 We understand many website owners' dilemma — knowing the necessity of regular updates, content creation, and maintenance, yet often postponing these tasks —. Progress Planner seeks to address this procrastination head-on. A successful website demands regular attention, whether writing engaging content, adding internal links, updating plugins, resolving 404 errors, or optimizing site speed. These tasks are pivotal for a website to rank well and convert visitors effectively. Progress Planner ensures you stay on track, providing the tools and motivation to maintain and enhance your site's success.
    19 
    20 === Features ===
    21 
    22 * **Activity Tracking**: Monitor your actions on your website, from publishing posts to updating pages, and see how they contribute to your overall site health.
    23 * **Gamification**: Unlock achievements, earn badges, and track your progress in a fun and motivating way.
    24 * **Progress Reports**: Receive detailed reports on your website's performance and progress.
    25 * **To-do list**: Keep all those content and maintenance tasks in one place.
    26 * **More to come**: We are creating a Pro version and extra features for the Free version of Progress Planner. Stay tuned for updates!
    27 
    28 === Getting Started ===
    29 * **Install Progress Planner**: Download and activate the plugin from the WordPress plugin repository on your WordPress site.
    30 * **Define your goals**: Set specific, realistic goals for your website's improvement and growth.
    31 * **Engage in daily tasks**: Regularly update your website, with Progress Planner tracking each step and providing motivational feedback.
    32 * **Earn and celebrate**: Achieve your milestones and celebrate your success with rewards and recognitions from Progress Planner.
    33 * **Strive for continuous Improvement**: Utilize our guides and analytics to refine your site perpetually, ensuring its ongoing success.
     15A website isn’t something you set up once and forget about. Over time, small issues pile up — broken links, outdated content, slow load times — and suddenly, your site isn’t performing as well as it should. But staying on top of maintenance and optimization takes time and effort. Where do you even start?
     16
     17Progress Planner makes website upkeep easy. Built by the founders of Yoast, this plugin helps you keep your site optimized with clear, actionable recommendations, a smart to-do list and guided challenges that help you improve your site step by step. No more guesswork — just the right tasks at the right time.
     18
     19### 🔑 Key features
     20
     21#### Get personalized recommendations with Ravi’s Recommendations
     22Keeping up with all the little tasks that make a website run smoothly can be overwhelming. That’s why we’ve curated an interactive list of important but often-overlooked improvements for you. With Ravi’s Recommendations, you don’t have to figure out what needs attention — we do that for you.
     23
     24From setting your site’s tagline and icon to reviewing your permalink structure or removing default WordPress content, we surface the tasks that help keep your site professional, optimized and secure. Each recommendation comes with clear instructions, so all you have to do is put them into practice — no guesswork required.
     25
     26#### Stay organized with an in-context to-do list
     27Managing website tasks can be messy, but Progress Planner keeps everything in one place. Your to-do list isn’t just another checklist — it’s right where you need it. Add your own website tasks and keep them in context, so you have them on hand while working on your site. No more forgetting what needs to be done!
     28
     29#### Track your website activity over time
     30A well-maintained website isn’t built in a day — it’s improved with regular updates. Your website activity score reflects the maintenance work you’ve done over the past 30 days, helping you stay on track and keep your site in top shape.
     31
     32#### Earn badges and streaks for your progress
     33Motivation matters! Stay engaged with Progress Planner’s built-in gamification. Earn badges and track your streaks as you complete tasks and keep your website in great shape.
     34
     35#### Everything in one place: Your dashboard
     36Your dashboard gives you a clear overview of your website’s progress. See your recommendations, to-do list and achievements at a glance — so you can jump right into the most important tasks.
     37
     38### 🆘 Want expert guidance? Get Progress Planner Pro
     39
     40If you’re ready to take things further, [Progress Planner Pro](https://progressplanner.com/pro/) gives you access to in-depth guidance and structured challenges that walk you through key website improvements step by step.
     41
     42#### Get results with guided challenges
     43Maintaining a website can feel overwhelming — but you don’t have to do it alone. With Progress Planner Pro, you get access to expert-led challenges that guide you through key website improvements step by step.
     44
     45Each challenge is interactive and tailored to help you make real progress. You can expect:
     46
     47* Live **webinars & workshops** with experts sharing insights and strategies
     48* Actionable **reports & exercises** to apply what you’ve learned to your own site
     49* Personal **feedback & support**, like having your copywriting reviewed
     50* A **structured plan**, so you always know what to do next
     51
     52It’s not just advice — it’s a hands-on, practical experience that helps you take real action and see results.
     53
     54#### Learn with practical mini courses
     55
     56Want to sharpen your skills while improving your site? [Progress Planner Pro](https://progressplanner.com/pro/) includes mini courses that give you the knowledge you need — without the fluff.
     57
     58#### Get support when you need it
     59Sometimes you just need a little extra help. With Pro, you get access to our support team, ready to answer your questions and guide you through website improvements.
     60
     61### 🧹 Ready to make website maintenance easier?
     62Progress Planner takes the frustration out of keeping your website in top shape. Whether you’re tackling quick fixes or diving into bigger improvements, you’ll always know what to do next.
     63
     64Download Progress Planner for free and start optimizing your site today!
     65
    3466
    3567== Frequently Asked Questions ==
     
    4577= Is there a Pro version of Progress Planner? =
    4678
    47 We are currently creating a Pro version of Progress Planner. The Pro version will include guided tutorials, goal settings, and reminders.
     79Yes! You can [find it right here](https://progressplanner.com/pro/).
    4880
    4981= Where do I file bugs? =
     
    78110
    79111== Changelog ==
     112
     113= 1.1.0 =
     114
     115In this release, we've added more recommendations from Ravi on how to improve your site. We've also made these recommendations more visible on your WordPress
     116settings pages, by showing on settings pages exactly which things we think you should change. Also, if you're just now starting to use Progress Planner,
     117we've made the onboarding experience a lot more fun: we show you immediately which of Ravi's recommended tasks you've already completed and we give
     118you points for those!
     119
     120Added these recommendations from Ravi:
     121
     122* Properly set your [permalink structure](https://progressplanner.com/recommendations/change-default-permalink-structure/).
     123* Fix it if your site is [set to not be shown in search engines](https://progressplanner.com/recommendations/blog-indexing-settings/).
     124* Rename and change the slug of your [Uncategorized category](https://progressplanner.com/recommendations/rename-uncategorized-category/).
     125* Remove [inactive plugins](https://progressplanner.com/recommendations/remove-inactive-plugins/).
     126* [Upgrade your PHP version](https://progressplanner.com/recommendations/update-php-version/) if needed.
     127* [Fully disable comments](https://progressplanner.com/recommendations/disable-comments/) if they're not needed on your site.
     128
     129Bugs we fixed:
     130
     131* If you had `WP_DEBUG` set to false, the plugin would still tell you to disable `WP_DEBUG_DISPLAY`. We think Ravi was a bit overzealous in his recommendation, so we've fixed that.
     132
     133Under the hood:
     134
     135* We've added our set of debug tools straight into the plugin. If you define `PRPL_DEBUG` as `true` in your `wp-config.php` file, you'll get a PRPL Debug admin bar menu item.
     136* Improved suggested tasks completion conditions so they don't trigger at the wrong moment.
    80137
    81138= 1.0.4 =
  • progress-planner/tags/1.1.0/views/admin-page.php

    r3217671 r3243842  
    2828            <?php endforeach; ?>
    2929        </div>
     30
     31        <?php // Display the upgrade tasks popover if needed. ?>
     32        <?php if ( \progress_planner()->get_plugin_upgrade_handler()->get_newly_added_task_providers() ) : ?>
     33            <?php \progress_planner()->get_popover()->the_popover( 'upgrade-tasks' )->render(); ?>
     34        <?php endif; ?>
    3035    <?php else : ?>
    3136        <?php \progress_planner()->the_view( 'welcome.php' ); ?>
  • progress-planner/tags/1.1.0/views/welcome.php

    r3217671 r3243842  
    3131    [],
    3232    \progress_planner()->get_file_version( PROGRESS_PLANNER_DIR . '/assets/css/onboard.css' )
     33);
     34
     35// Enqueue upgrade styles.
     36\wp_enqueue_style(
     37    'progress-planner-upgrade-tasks',
     38    PROGRESS_PLANNER_URL . '/assets/css/upgrade-tasks.css',
     39    [],
     40    \progress_planner()->get_file_version( PROGRESS_PLANNER_DIR . '/assets/css/upgrade-tasks.css' )
    3341);
    3442
     
    4755            <form id="prpl-onboarding-form">
    4856                <div class="prpl-form-notice">
    49                     <strong><?php \esc_html_e( 'Stay on track with weekly updates', 'progress-planner' ); ?></strong>
     57                    <strong class="prpl-form-notice-title"><?php \esc_html_e( 'Stay on track with weekly updates', 'progress-planner' ); ?></strong>
    5058                    <ul>
    5159                        <li>
     
    184192                    ?>
    185193                </p>
     194
     195                <?php \progress_planner()->the_view( 'popovers/parts/upgrade-tasks.php', [ 'context' => 'onboarding' ] ); ?>
     196
    186197                <div id="progress-planner-scan-progress" style="display:none;">
    187198                    <progress value="0" max="100"></progress>
  • progress-planner/trunk/CHANGELOG.md

    r3238385 r3243842  
     1= 1.0.5 =
     2
     3Under the hood:
     4
     5* Improved suggested tasks completion conditions.
     6* Improved checks for suggested 'review post' tasks.
     7
     8We've added the following Recommendations from Ravi:
     9
     10* [Setting the permalink structure](TBD).
     11* [Update PHP version](TBD).
     12* [Disable comments on your site](TBD).
     13* [Remove inactive plugins](TBD).
     14* [Search engine visibility](TBD).
     15
    116= 1.0.4 =
    217
  • progress-planner/trunk/assets/css/admin.css

    r3226821 r3243842  
    346346
    347347/*------------------------------------*\
     348    Input fields.
     349\*------------------------------------*/
     350
     351.prpl-wrap input[type="text"],
     352.prpl-wrap input[type="email"],
     353.prpl-wrap input[type="number"],
     354.prpl-wrap input[type="url"],
     355.prpl-wrap input[type="tel"],
     356.prpl-wrap input[type="search"] {
     357    height: 40px;
     358    box-shadow: 1px 2px 4px 0 rgba(0, 0, 0, 0.25);
     359}
     360
     361/*------------------------------------*\
    348362    Popovers generic styles.
    349363\*------------------------------------*/
  • progress-planner/trunk/assets/css/welcome.css

    r3217671 r3243842  
    2525
    2626    .welcome-header {
    27         background: var(--prpl-color-accent-orange);
     27        background: var(--prpl-color-400-orange);
    2828        display: flex;
    2929        justify-content: space-between;
    3030        align-items: center;
     31        border-top-left-radius: var(--prpl-border-radius);
     32        border-top-right-radius: var(--prpl-border-radius);
     33        overflow: hidden;
    3134
    3235        h1 {
     
    3740
    3841        .welcome-header-icon {
    39             background: var(--prpl-background-orange);
    40             background: linear-gradient(105deg, var(--prpl-color-accent-orange) 25%, var(--prpl-background-orange) 25%);
     42            background: var(--prpl-color-400-orange);
     43            background: linear-gradient(105deg, var(--prpl-color-400-orange) 25%, var(--prpl-background-orange) 25%);
    4144            padding: var(--prpl-padding);
    4245            padding-left: 100px;
     
    4952    }
    5053
     54    .prpl-form-notice-title {
     55        font-size: var(--prpl-font-size-lg);
     56    }
     57
    5158    ul {
    5259        list-style: disc;
     
    5663    .prpl-onboard-form-radio-select {
    5764        margin-top: 0.75rem;
     65
     66        label {
     67            margin-top: 0.5rem;
     68
     69            &:first-child {
     70                margin-top: 0;
     71            }
     72        }
    5873    }
    5974
  • progress-planner/trunk/assets/js/ajax-request.js

    r3099196 r3243842  
    3535            }
    3636        }
    37         if ( http.readyState === 4 && http.status === 200 ) {
    38             return successAction
    39                 ? successAction( response )
     37
     38        if ( http.readyState === 4 ) {
     39            if ( http.status === 200 ) {
     40                return successAction
     41                    ? successAction( response )
     42                    : defaultCallback( response );
     43            }
     44
     45            // Request is completed, but the status is not 200.
     46            return failAction
     47                ? failAction( response )
    4048                : defaultCallback( response );
    4149        }
    42         return failAction
    43             ? failAction( response )
    44             : defaultCallback( response );
    4550    };
    4651
  • progress-planner/trunk/assets/js/grid-masonry.js

    r3210975 r3243842  
    11/* global prplDocumentReady */
    2 
    3 /**
    4  * Custom script to allow a grid to behave like a masonry layout.
     2/*
     3 * Grid Masonry
    54 *
     5 * A script to allow a grid to behave like a masonry layout.
    66 * Inspired by https://medium.com/@andybarefoot/a-masonry-style-layout-using-css-grid-8c663d355ebb
     7 *
     8 * Dependencies: progress-planner-document-ready
    79 */
    810
  • progress-planner/trunk/assets/js/onboard.js

    r3217671 r3243842  
    1 /* global progressPlanner, progressPlannerAjaxRequest, progressPlannerTriggerScan */
     1/* global progressPlanner, progressPlannerAjaxRequest, progressPlannerTriggerScan, prplOnboardTasks */
     2/*
     3 * Onboard
     4 *
     5 * A script to handle the onboarding process.
     6 *
     7 * Dependencies: progress-planner-ajax-request, progress-planner-scan-posts, progress-planner-upgrade-tasks
     8 */
    29
    310/**
     
    4552            // Start scanning posts.
    4653            progressPlannerTriggerScan();
     54
     55            // Start the tasks.
     56            prplOnboardTasks();
    4757        },
    4858        failAction: ( response ) => {
  • progress-planner/trunk/assets/js/scan-posts.js

    r3156816 r3243842  
    1 /* global progressPlanner, progressPlannerAjaxRequest */
     1/* global progressPlanner, progressPlannerAjaxRequest, prplOnboardRedirect */
     2/*
     3 * Scan Posts
     4 *
     5 * A script to scan posts for the Progress Planner.
     6 *
     7 * Dependencies: progress-planner-ajax-request, progress-planner-upgrade-tasks
     8 */
    29
    310// eslint-disable-next-line no-unused-vars
     
    2936        // Refresh the page when scan has finished.
    3037        if ( response.data.progress >= 100 ) {
    31             document.getElementById(
     38            const scanProgressElement = document.getElementById(
    3239                'progress-planner-scan-progress'
    33             ).style.display = 'none';
     40            );
    3441
    35             window.location.href =
    36                 window.location.href
    37                     .replace( '&content-scan-finished=true', '' )
    38                     .replace( '&content-scan', '' ) +
    39                 '&content-scan-finished=true';
     42            scanProgressElement.style.display = 'none';
     43            scanProgressElement.setAttribute(
     44                'data-onboarding-finished',
     45                'true'
     46            );
     47
     48            // Redirect if scanning is finished.
     49            prplOnboardRedirect( 'scanPosts' );
    4050
    4151            return;
  • progress-planner/trunk/assets/js/settings-page.js

    r3226821 r3243842  
    11/* global alert, prplDocumentReady */
    2 
     2/*
     3 * Settings Page
     4 *
     5 * A script to handle the settings page.
     6 *
     7 * Dependencies: progress-planner-document-ready, wp-util
     8 */
    39const prplTogglePageSelectorSettingVisibility = function ( page, value ) {
    410    const itemRadiosWrapperEl = document.querySelector(
  • progress-planner/trunk/assets/js/settings.js

    r3198155 r3243842  
    11/* global progressPlanner, progressPlannerAjaxRequest, progressPlannerSaveLicenseKey */
     2/*
     3 * Settings
     4 *
     5 * A script to handle the settings page.
     6 *
     7 * Dependencies: progress-planner-ajax-request, wp-util
     8 */
    29document
    310    .getElementById( 'prpl-settings-form' )
  • progress-planner/trunk/assets/js/tour.js

    r3210975 r3243842  
    11/* global progressPlannerTour */
     2/*
     3 * Tour
     4 *
     5 * A tour for the Progress Planner.
     6 *
     7 * Dependencies: driver
     8 */
    29const prplDriver = window.driver.js.driver;
    310
     
    119126            .replace( '&content-scan-finished=true', '' )
    120127            .replace( 'content-scan-finished=true', '' )
     128            .replace( '&delay-tour=true', '' )
     129            .replace( 'delay-tour=true', '' )
    121130    );
    122131}
     
    124133// Start the tour if the URL contains the query parameter.
    125134if ( window.location.href.includes( 'content-scan-finished=true' ) ) {
    126     prplStartTour();
     135    // If there are pending celebration tasks, delay the tour until celebration is done.
     136    const delay = window.location.href.includes( 'delay-tour=true' ) ? 5000 : 0;
     137
     138    setTimeout( () => {
     139        prplStartTour();
     140    }, delay );
    127141}
  • progress-planner/trunk/assets/js/web-components/prpl-badge.js

    r3238385 r3243842  
    1919                        progressPlannerBadge.remoteServerRootUrl
    2020                    }/wp-json/progress-planner-saas/v1/badge-svg/?badge_id=${ badgeId }"
    21                     alt="Badge"
     21                    alt="${ progressPlannerBadge.l10n.badge }"
    2222                    ${ false === complete ? 'style="filter: grayscale(1);opacity: 0.25;"' : '' }
    2323                    onerror="this.onerror=null;this.src='${
  • progress-planner/trunk/assets/js/web-components/prpl-gauge.js

    r3217671 r3243842  
    11/* global customElements, HTMLElement */
     2/*
     3 * Web Component: prpl-gauge
     4 *
     5 * A web component that displays a gauge.
     6 *
     7 * Dependencies: progress-planner-web-components-prpl-badge
     8 */
    29
    310/**
  • progress-planner/trunk/assets/js/widgets/suggested-tasks.js

    r3238385 r3243842  
    3636    // Remove completed and snoozed items.
    3737    const tasks = progressPlannerSuggestedTasks.tasks;
    38     const items = tasks.details[ type ];
     38    let items = tasks.details[ type ];
    3939    const completed = tasks.completed;
    4040    const snoozed = tasks.snoozed;
     
    4848        } );
    4949
    50     items.forEach( function ( item ) {
    51         if (
    52             completed.includes( item.task_id.toString() ) ||
    53             inList.includes( item.task_id.toString() )
    54         ) {
    55             items.splice( items.indexOf( item ), 1 );
    56         }
    57         snoozed.forEach( ( snoozedItem ) => {
    58             if ( item.task_id.toString() === snoozedItem.id ) {
    59                 items.splice( items.indexOf( item ), 1 );
     50    // Remove items which are completed or already in the list.
     51    items = items.filter( function ( item ) {
     52        return (
     53            ! completed.includes( item.task_id.toString() ) &&
     54            ! inList.includes( item.task_id.toString() )
     55        );
     56    } );
     57
     58    // Remove items which are snoozed.
     59    items = items.filter( function ( item ) {
     60        for ( let i = 0; i < snoozed.length; i++ ) {
     61            if ( item.task_id.toString() === snoozed[ i ].id.toString() ) {
     62                return false;
    6063            }
    61         } );
     64        }
     65        return true;
    6266    } );
     67
     68    // Do nothing if there are no items left.
     69    if ( 0 === items.length ) {
     70        return null;
     71    }
    6372
    6473    // Get items with a priority set to `high`.
     
    275284const prplPendingCelebration =
    276285    progressPlannerSuggestedTasks.tasks.pending_celebration;
    277 if ( prplPendingCelebration && prplPendingCelebration.length ) {
     286if (
     287    ! progressPlannerSuggestedTasks.delayCelebration &&
     288    prplPendingCelebration &&
     289    prplPendingCelebration.length
     290) {
    278291    setTimeout( () => {
    279292        // Trigger the celebration event.
  • progress-planner/trunk/classes/admin/class-page.php

    r3238385 r3243842  
    108108     */
    109109    public function enqueue_assets( $hook ) {
     110        $this->maybe_enqueue_focus_el_script( $hook );
    110111        if ( 'toplevel_page_progress-planner' !== $hook && 'progress-planner_page_progress-planner-settings' !== $hook ) {
    111112            return;
     
    139140                \wp_enqueue_script( 'progress-planner-settings' );
    140141                \wp_enqueue_script( 'progress-planner-grid-masonry' );
     142                \wp_enqueue_script( 'progress-planner-upgrade-tasks' );
    141143            } else {
    142144                \wp_enqueue_script( 'progress-planner-onboard' );
     
    147149            \wp_enqueue_script( 'progress-planner-settings-page' );
    148150        }
     151    }
     152
     153    /**
     154     * Enqueue the focus element script.
     155     *
     156     * @param string $hook The current admin page.
     157     *
     158     * @return void
     159     */
     160    public function maybe_enqueue_focus_el_script( $hook ) {
     161        $suggested_tasks       = \progress_planner()->get_suggested_tasks();
     162        $local_tasks_providers = $suggested_tasks->get_local()->get_task_providers();
     163        $tasks_details         = [];
     164        $total_points          = 0;
     165        $completed_points      = 0;
     166        foreach ( $local_tasks_providers as $provider ) {
     167            if ( 'configuration' !== $provider->get_provider_type() ) {
     168                continue;
     169            }
     170            $details = $provider->get_task_details();
     171            if ( ! isset( $details['link_setting']['hook'] ) ||
     172                $hook !== $details['link_setting']['hook']
     173            ) {
     174                continue;
     175            }
     176            $details['is_complete'] = $provider->is_task_completed();
     177            $tasks_details[]        = $details;
     178            $total_points          += $details['points'];
     179            if ( $details['is_complete'] ) {
     180                $completed_points += $details['points'];
     181            }
     182        }
     183
     184        if ( empty( $tasks_details ) ) {
     185            return;
     186        }
     187
     188        // Register the scripts.
     189        \progress_planner()->get_admin__scripts()->register_scripts();
     190
     191        \wp_enqueue_script( 'progress-planner-focus-element' );
     192        \wp_localize_script(
     193            'progress-planner-focus-element',
     194            'progressPlannerFocusElement',
     195            [
     196                'tasks'           => $tasks_details,
     197                'totalPoints'     => $total_points,
     198                'completedPoints' => $completed_points,
     199                'base_url'        => PROGRESS_PLANNER_URL,
     200                'l10n'            => [
     201                    /* translators: %d: The number of points. */
     202                    'fixThisIssue' => \esc_html__( 'Fix this issue to get %d point(s) in Progress Planner', 'progress-planner' ),
     203                ],
     204            ]
     205        );
     206        \wp_enqueue_style(
     207            'progress-planner-focus-element',
     208            PROGRESS_PLANNER_URL . '/assets/css/focus-element.css',
     209            [],
     210            \progress_planner()->get_file_version( PROGRESS_PLANNER_DIR . '/assets/css/focus-element.css' )
     211        );
    149212    }
    150213
     
    173236                [],
    174237                \progress_planner()->get_file_version( PROGRESS_PLANNER_DIR . '/assets/css/settings-page.css' )
     238            );
     239        }
     240
     241        if ( 'toplevel_page_progress-planner' === $current_screen->id ) {
     242            // Enqueue ugprading (onboarding) tasks styles, these are needed both when privacy policy is accepted and when it is not.
     243            \wp_enqueue_style(
     244                'progress-planner-upgrade-tasks',
     245                PROGRESS_PLANNER_URL . '/assets/css/upgrade-tasks.css',
     246                [],
     247                \progress_planner()->get_file_version( PROGRESS_PLANNER_DIR . '/assets/css/upgrade-tasks.css' )
    175248            );
    176249        }
  • progress-planner/trunk/classes/admin/class-scripts.php

    r3226821 r3243842  
    6262     */
    6363    public function get_dependencies( $file ) {
    64         switch ( $file ) {
    65             case 'web-components/prpl-gauge':
    66                 return [ 'progress-planner-web-components-prpl-badge' ];
    67 
    68             case 'tour':
    69                 return [ 'driver' ];
    70 
    71             case 'grid-masonry':
    72                 return [ 'progress-planner-document-ready' ];
    73 
    74             case 'scan-posts':
    75                 return [ 'progress-planner-ajax-request' ];
    76 
    77             case 'onboard':
    78                 return [ 'progress-planner-ajax-request', 'progress-planner-scan-posts' ];
    79 
    80             case 'settings':
    81                 return [ 'progress-planner-ajax-request', 'wp-util' ];
    82 
    83             case 'settings-page':
    84                 return [ 'wp-util', 'progress-planner-document-ready' ];
    85 
    86             default:
    87                 return [];
    88         }
     64        $path    = PROGRESS_PLANNER_DIR . '/assets/js/' . $file . '.js';
     65        $headers = \get_file_data(
     66            $path,
     67            [
     68                'dependencies' => 'Dependencies',
     69            ]
     70        );
     71        if ( ! isset( $headers['dependencies'] ) ) {
     72            return [];
     73        }
     74
     75        return \array_filter( \array_map( 'trim', \explode( ',', $headers['dependencies'] ) ) );
    8976    }
    9077
     
    10491                        'remoteServerRootUrl' => \progress_planner()->get_remote_server_root_url(),
    10592                        'placeholderImageUrl' => \progress_planner()->get_placeholder_svg(),
     93                        'l10n'                => [
     94                            'badge' => \esc_html__( 'Badge', 'progress-planner' ),
     95                        ],
    10696                    ]
    10797                );
  • progress-planner/trunk/classes/class-badges.php

    r3226821 r3243842  
    8484     */
    8585    public function get_badges( $context ) {
    86         if ( ! isset( $this->$context ) ) {
    87             return [];
    88         }
    89 
    90         return $this->$context;
     86        return isset( $this->$context ) ? $this->$context : [];
    9187    }
    9288
     
    156152
    157153            // If the badge is already complete, skip it.
    158             if ( 100 === $badge->progress_callback()['progress'] ) {
     154            if ( 100 <= $badge->progress_callback()['progress'] ) {
    159155                continue;
    160156            }
  • progress-planner/trunk/classes/class-base.php

    r3238385 r3243842  
    1717use Progress_Planner\Actions\Maintenance as Actions_Maintenance;
    1818use Progress_Planner\Admin\Page_Settings as Admin_Page_Settings;
     19use Progress_Planner\Plugin_Upgrade_Handler;
     20use Progress_Planner\Debug_Tools;
    1921/**
    2022 * Main plugin class.
     
    103105
    104106            new Plugin_Deactivation();
     107        }
     108
     109        $this->cached['plugin_upgrade_handler'] = new Plugin_Upgrade_Handler();
     110
     111        // Debug tools.
     112        if ( ( defined( 'PRPL_DEBUG' ) && PRPL_DEBUG ) || \get_option( 'prpl_debug' ) ) {
     113            new Debug_Tools();
    105114        }
    106115
     
    197206     */
    198207    public function add_action_links( $actions ) {
    199         $action_link = [ '<a href="' . admin_url( 'admin.php?page=progress-planner' ) . '">' . __( 'Dashboard', 'progress-planner' ), '</a>' ];
    200         $actions     = array_merge( $action_link, $actions );
    201         return $actions;
     208        return array_merge(
     209            [
     210                sprintf(
     211                    '<a href="%1$s">%2$s</a>',
     212                    admin_url( 'admin.php?page=progress-planner' ),
     213                    __( 'Dashboard', 'progress-planner' )
     214                ),
     215            ],
     216            $actions
     217        );
    202218    }
    203219
  • progress-planner/trunk/classes/class-lessons.php

    r3210975 r3243842  
    5555        }
    5656
    57         $response = \wp_remote_get(
    58             $url
    59         );
     57        $response = \wp_remote_get( $url );
    6058
    6159        if ( \is_wp_error( $response ) ) {
  • progress-planner/trunk/classes/class-page-types.php

    r3226821 r3243842  
    397397            return;
    398398        }
     399
    399400        $terms = \get_the_terms( $post_id, self::TAXONOMY_NAME );
    400401        if ( ! \is_array( $terms ) || ! isset( $terms[0] ) ) {
  • progress-planner/trunk/classes/class-playground.php

    r3238385 r3243842  
    1717     */
    1818    public function __construct() {
    19         \add_action( 'init', [ $this, 'register_hooks' ] );
     19        \add_action( 'init', [ $this, 'register_hooks' ], 9 );
     20
     21        \add_action( 'plugins_loaded', [ $this, 'enable_debug_tools' ], 1 );
    2022    }
    2123
     
    5153
    5254    /**
     55     * Enable debug tools.
     56     *
     57     * @return void
     58     */
     59    public function enable_debug_tools() {
     60        \update_option( 'prpl_debug', true );
     61    }
     62
     63    /**
    5364     * Toggle the onboarding visibility in the Playground environment.
    5465     *
  • progress-planner/trunk/classes/class-popover.php

    r3198155 r3243842  
    4141     */
    4242    public function render_button( $icon, $content ) {
    43         ?>
    44         <!-- The triggering button. -->
    45         <button
    46             class="prpl-info-icon"
    47             popovertarget="prpl-popover-<?php echo \esc_attr( $this->id ); ?>"
    48             id="prpl-popover-<?php echo \esc_attr( $this->id ); ?>-trigger"
    49         >
    50             <?php if ( '' !== $icon ) : ?>
    51                 <span class="dashicons dashicons-<?php echo \esc_attr( $icon ); ?>"></span>
    52             <?php endif; ?>
    53             <?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
    54         </button>
    55         <?php
     43        \progress_planner()->the_view(
     44            'popovers/parts/icon.php',
     45            [
     46                'prpl_popover_id'              => $this->id,
     47                'prpl_popover_trigger_icon'    => $icon,
     48                'prpl_popover_trigger_content' => $content,
     49            ]
     50        );
    5651    }
    5752
     
    6257     */
    6358    public function render() {
    64         ?>
    65         <div id="prpl-popover-<?php echo \esc_attr( $this->id ); ?>" class="prpl-popover" popover>
    66             <!-- The content. -->
    67             <?php \progress_planner()->the_view( 'popovers/' . $this->id . '.php' ); ?>
    68 
    69             <!-- The close button. -->
    70             <button
    71                 class="prpl-popover-close"
    72                 popovertarget="prpl-popover-<?php echo \esc_attr( $this->id ); ?>"
    73                 popovertargetaction="hide"
    74             >
    75                 <span class="dashicons dashicons-no-alt"></span>
    76                 <span class="screen-reader-text"><?php \esc_html_e( 'Close', 'progress-planner' ); ?>
    77             </button>
    78 
    79         </div>
    80         <?php
     59        \progress_planner()->the_view(
     60            'popovers/popover.php',
     61            [
     62                'prpl_popover_id' => $this->id,
     63            ]
     64        );
    8165    }
    8266}
  • progress-planner/trunk/classes/class-suggested-tasks.php

    r3238385 r3243842  
    245245     */
    246246    public function mark_task_as_pending_celebration( $task_id ) {
     247        // Don't mark the task as pending celebration if it's already completed.
     248        if ( $this->was_task_completed( $task_id ) ) {
     249            return false;
     250        }
     251
    247252        return $this->mark_task_as( 'pending_celebration', $task_id );
    248253    }
     
    372377     */
    373378    public function get_snoozed_tasks() {
    374         $option  = \get_option( self::OPTION_NAME, [] );
    375         $snoozed = $option['snoozed'] ?? [];
    376 
    377         return $snoozed;
     379        $option = \get_option( self::OPTION_NAME, [] );
     380        return $option['snoozed'] ?? [];
    378381    }
    379382
     
    384387     */
    385388    public function get_completed_tasks() {
    386         $option    = \get_option( self::OPTION_NAME, [] );
    387         $completed = $option['completed'] ?? [];
    388 
    389         return $completed;
     389        $option = \get_option( self::OPTION_NAME, [] );
     390        return $option['completed'] ?? [];
    390391    }
    391392
     
    473474        );
    474475
    475         if ( 'completed' === $parsed_condition['type'] ) {
    476             $completed_tasks = $this->get_completed_tasks();
    477 
    478             if ( \in_array( $parsed_condition['task_id'], $completed_tasks, true ) ) {
    479                 return true;
    480             }
    481         }
    482 
    483         if ( 'snoozed' === $parsed_condition['type'] ) {
    484             $snoozed_tasks = $this->get_snoozed_tasks();
    485 
    486             if ( \in_array( $parsed_condition['task_id'], $snoozed_tasks, true ) ) {
    487                 return true;
    488             }
    489         }
    490 
    491         if ( 'snoozed-post-length' === $parsed_condition['type'] && isset( $parsed_condition['post_lengths'] ) ) {
    492             if ( ! \is_array( $parsed_condition['post_lengths'] ) ) {
    493                 $parsed_condition['post_lengths'] = [ $parsed_condition['post_lengths'] ];
    494             }
    495 
    496             $snoozed_tasks        = $this->get_snoozed_tasks();
    497             $snoozed_post_lengths = [];
    498 
    499             // Get the post lengths of the snoozed tasks.
    500             foreach ( $snoozed_tasks as $task ) {
    501                 $data = $this->local->get_data_from_task_id( $task['id'] ); // @phpstan-ignore-line method.nonObject
    502                 if ( isset( $data['type'] ) && 'create-post' === $data['type'] ) {
    503                     $key = true === $data['long'] ? 'long' : 'short';
    504                     if ( ! isset( $snoozed_post_lengths[ $key ] ) ) {
    505                         $snoozed_post_lengths[ $key ] = true;
     476        switch ( $parsed_condition['type'] ) {
     477            case 'completed':
     478                if ( \in_array( $parsed_condition['task_id'], $this->get_completed_tasks(), true ) ) {
     479                    return true;
     480                }
     481                break;
     482
     483            case 'pending_celebration':
     484                if ( \in_array( $parsed_condition['task_id'], $this->get_pending_celebration(), true ) ) {
     485                    return true;
     486                }
     487                break;
     488
     489            case 'snoozed':
     490                if ( \in_array( $parsed_condition['task_id'], $this->get_snoozed_tasks(), true ) ) {
     491                    return true;
     492                }
     493                break;
     494
     495            case 'snoozed-post-length':
     496                if ( isset( $parsed_condition['post_lengths'] ) ) {
     497                    if ( ! \is_array( $parsed_condition['post_lengths'] ) ) {
     498                        $parsed_condition['post_lengths'] = [ $parsed_condition['post_lengths'] ];
    506499                    }
    507                 }
    508             }
    509 
    510             // Check if the snoozed post lengths match the condition.
    511             foreach ( $parsed_condition['post_lengths'] as $post_length ) {
    512                 if ( ! isset( $snoozed_post_lengths[ $post_length ] ) ) {
    513                     return false;
    514                 }
    515             }
    516 
    517             return true;
    518         }
    519 
    520         // If no condition is met, return false.
     500
     501                    $snoozed_tasks        = $this->get_snoozed_tasks();
     502                    $snoozed_post_lengths = [];
     503
     504                    // Get the post lengths of the snoozed tasks.
     505                    foreach ( $snoozed_tasks as $task ) {
     506                        $data = $this->local->get_data_from_task_id( $task['id'] ); // @phpstan-ignore-line method.nonObject
     507                        if ( isset( $data['type'] ) && 'create-post' === $data['type'] ) {
     508                            $key = true === $data['long'] ? 'long' : 'short';
     509                            if ( ! isset( $snoozed_post_lengths[ $key ] ) ) {
     510                                $snoozed_post_lengths[ $key ] = true;
     511                            }
     512                        }
     513                    }
     514
     515                    // Check if the snoozed post lengths match the condition.
     516                    foreach ( $parsed_condition['post_lengths'] as $post_length ) {
     517                        if ( ! isset( $snoozed_post_lengths[ $post_length ] ) ) {
     518                            return false;
     519                        }
     520                    }
     521
     522                    return true;
     523                }
     524                break;
     525        }
     526
    521527        return false;
    522528    }
    523529
    524530    /**
    525      * Check if a task was completed.
     531     * Check if a task was completed. Task is considered completed if it was completed or pending celebration.
    526532     *
    527533     * @param string $task_id The task ID.
     
    530536     */
    531537    public function was_task_completed( $task_id ) {
    532         return true === $this->check_task_condition(
    533             [
    534                 'type'    => 'completed',
    535                 'task_id' => $task_id,
    536             ]
     538
     539        return (
     540            // Check if the task was pending celebration.
     541            true === $this->check_task_condition(
     542                [
     543                    'type'    => 'pending_celebration',
     544                    'task_id' => $task_id,
     545                ]
     546            )
     547            ||
     548            // Check if the task was completed.
     549            true === $this->check_task_condition(
     550                [
     551                    'type'    => 'completed',
     552                    'task_id' => $task_id,
     553                ]
     554            )
    537555        );
    538556    }
  • progress-planner/trunk/classes/suggested-tasks/class-local-tasks-manager.php

    r3238385 r3243842  
    99
    1010use Progress_Planner\Suggested_Tasks\Local_Tasks\Local_Task_Factory;
    11 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Content_Create;
    12 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Content_Review;
    13 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Core_Update;
    14 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Core_Blogdescription;
    15 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Settings_Saved;
    16 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Debug_Display;
    17 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Sample_Page;
    18 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Hello_World;
    19 use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Core_Siteicon;
     11// Repetitive tasks.
     12use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Repetitive\Core_Update;
     13// Content tasks.
     14use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Content\Create as Content_Create;
     15use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\Content\Review as Content_Review;
     16// One-time tasks.
     17use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Blog_Description;
     18use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Settings_Saved;
     19use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Debug_Display;
     20use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Disable_Comments;
     21use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Sample_Page;
     22use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Hello_World;
     23use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Remove_Inactive_Plugins;
     24use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Site_Icon;
     25use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Rename_Uncategorized_Category;
     26use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Permalink_Structure;
     27use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Php_Version;
     28use Progress_Planner\Suggested_Tasks\Local_Tasks\Providers\One_Time\Search_Engine_Visibility;
    2029
    2130/**
     
    5160            new Content_Review(),
    5261            new Core_Update(),
    53             new Core_Blogdescription(),
     62            new Blog_Description(),
    5463            new Settings_Saved(),
    5564            new Debug_Display(),
     65            new Disable_Comments(),
    5666            new Sample_Page(),
    5767            new Hello_World(),
    58             new Core_Siteicon(),
     68            new Remove_Inactive_Plugins(),
     69            new Site_Icon(),
     70            new Rename_Uncategorized_Category(),
     71            new Permalink_Structure(),
     72            new Php_Version(),
     73            new Search_Engine_Visibility(),
    5974        ];
    6075
     
    6479        // Add the cleanup action.
    6580        \add_action( 'admin_init', [ $this, 'cleanup_pending_tasks' ] );
     81
     82        // Add the onboarding task providers.
     83        \add_filter( 'prpl_onboarding_task_providers', [ $this, 'add_onboarding_task_providers' ] );
    6684    }
    6785
     
    7391    public function add_plugin_integration() {
    7492        // Add the plugin integration here.
     93    }
     94
     95    /**
     96     * Add the onboarding task providers.
     97     *
     98     * @param array $task_providers The task providers.
     99     *
     100     * @return array
     101     */
     102    public function add_onboarding_task_providers( $task_providers ) {
     103
     104        foreach ( $this->task_providers as $task_provider ) {
     105
     106            if ( $task_provider->is_onboarding_task() ) {
     107                $task_providers[] = $task_provider->get_provider_id();
     108            }
     109        }
     110
     111        return $task_providers;
    75112    }
    76113
     
    95132
    96133    /**
     134     * Get the task providers.
     135     *
     136     * @return array
     137     */
     138    public function get_task_providers() {
     139        return $this->task_providers;
     140    }
     141
     142    /**
    97143     * Get a task provider by its type.
    98144     *
     
    119165     */
    120166    public function inject_tasks( $tasks ) {
     167        $provider_tasks  = [];
    121168        $tasks_to_inject = [];
    122169
    123170        // Loop through all registered task providers and inject their tasks.
    124171        foreach ( $this->task_providers as $provider_instance ) {
    125             $tasks_to_inject = \array_merge( $tasks_to_inject, $provider_instance->get_tasks_to_inject() );
     172            $provider_tasks = \array_merge( $provider_tasks, $provider_instance->get_tasks_to_inject() );
    126173        }
    127174
    128175        // Add the tasks to the pending tasks option, it will not add duplicates.
    129         foreach ( $tasks_to_inject as $task ) {
     176        foreach ( $provider_tasks as $task ) {
     177
     178            // Skip the task if it was completed.
     179            if ( true === \progress_planner()->get_suggested_tasks()->was_task_completed( $task['task_id'] ) ) {
     180                continue;
     181            }
     182
     183            $tasks_to_inject[] = $task;
    130184            $this->add_pending_task( $task['task_id'] );
    131185        }
  • progress-planner/trunk/classes/suggested-tasks/local-tasks/providers/class-local-tasks-abstract.php

    r3238385 r3243842  
    3838
    3939    /**
     40     * Whether the task is an onboarding task.
     41     *
     42     * @var bool
     43     */
     44    protected $is_onboarding_task = false;
     45
     46    /**
    4047     * Get the provider type.
    4148     *
     
    6471            ? \current_user_can( $this->capability )
    6572            : true;
     73    }
     74
     75    /**
     76     * Check if the task is an onboarding task.
     77     *
     78     * @return bool
     79     */
     80    public function is_onboarding_task() {
     81        return $this->is_onboarding_task;
    6682    }
    6783
  • progress-planner/trunk/classes/widgets/class-suggested-tasks.php

    r3238385 r3243842  
    6969        ];
    7070
     71        // Check if need to load confetti for the local tasks.
     72        $load_confetti = ! empty( $pending_celebration );
     73
     74        foreach ( $pending_tasks as $type => $tasks ) {
     75            foreach ( $tasks as $task ) {
     76                if ( isset( $task['dismissable'] ) && $task['dismissable'] ) {
     77                    $load_confetti = true;
     78                    break 2; // Break out of the foreach loops.
     79                }
     80            }
     81        }
     82
    7183        // Check if need to load confetti.
    72         if ( isset( $pending_tasks['content-update'] ) || ! empty( $pending_celebration ) ) {
     84        if ( $load_confetti ) {
    7385            $deps[] = 'particles-confetti';
    7486        } else {
     
    106118        $tasks['details'] = $this->get_pending_tasks();
    107119
    108         // Insert the pending celebration tasks as high priority tasks, so they are shown always.
    109         foreach ( $tasks['pending_celebration'] as $task_id ) {
    110 
    111             $task_object   = ( new Local_Task_Factory( $task_id ) )->get_task();
    112             $task_provider = \progress_planner()->get_suggested_tasks()->get_local()->get_task_provider( $task_object->get_provider_id() );
    113 
    114             if ( $task_provider && $task_provider->capability_required() ) {
    115                 $task_details = \progress_planner()->get_suggested_tasks()->get_local()->get_task_details( $task_id );
    116 
    117                 if ( $task_details ) {
    118                     $task_details['priority'] = 'high'; // Celebrate tasks are always on top.
    119                     $task_details['action']   = 'celebrate';
    120                     $task_details['type']     = 'pending_celebration';
    121 
    122                     if ( ! isset( $tasks['details']['pending_celebration'] ) ) {
    123                         $tasks['details']['pending_celebration'] = [];
     120        // If there are newly added task providers, delay the celebration in order not to get confetti behind the popover.
     121        $delay_celebration = \progress_planner()->get_plugin_upgrade_handler()->get_newly_added_task_providers() ? true : false;
     122
     123        if ( ! $delay_celebration ) {
     124            // Insert the pending celebration tasks as high priority tasks, so they are shown always.
     125            foreach ( $tasks['pending_celebration'] as $task_id ) {
     126
     127                $task_object   = ( new Local_Task_Factory( $task_id ) )->get_task();
     128                $task_provider = \progress_planner()->get_suggested_tasks()->get_local()->get_task_provider( $task_object->get_provider_id() );
     129
     130                if ( $task_provider && $task_provider->capability_required() ) {
     131                    $task_details = \progress_planner()->get_suggested_tasks()->get_local()->get_task_details( $task_id );
     132
     133                    if ( $task_details ) {
     134                        $task_details['priority'] = 'high'; // Celebrate tasks are always on top.
     135                        $task_details['action']   = 'celebrate';
     136                        $task_details['type']     = 'pending_celebration';
     137
     138                        if ( ! isset( $tasks['details']['pending_celebration'] ) ) {
     139                            $tasks['details']['pending_celebration'] = [];
     140                        }
     141
     142                        $tasks['details']['pending_celebration'][] = $task_details;
    124143                    }
    125144
    126                     $tasks['details']['pending_celebration'][] = $task_details;
     145                    // Mark the pending celebration tasks as completed.
     146                    \progress_planner()->get_suggested_tasks()->transition_task_status( $task_id, 'pending_celebration', 'completed' );
    127147                }
    128 
    129                 // Mark the pending celebration tasks as completed.
    130                 \progress_planner()->get_suggested_tasks()->transition_task_status( $task_id, 'pending_celebration', 'completed' );
    131148            }
    132149        }
     
    173190            'progressPlannerSuggestedTasks',
    174191            [
    175                 'ajaxUrl'         => \admin_url( 'admin-ajax.php' ),
    176                 'nonce'           => \wp_create_nonce( 'progress_planner' ),
    177                 'tasks'           => $tasks,
    178                 'maxItemsPerType' => apply_filters( 'progress_planner_suggested_tasks_max_items_per_type', $max_items_per_type ),
    179                 'confettiOptions' => $confetti_options,
     192                'ajaxUrl'          => \admin_url( 'admin-ajax.php' ),
     193                'nonce'            => \wp_create_nonce( 'progress_planner' ),
     194                'tasks'            => $tasks,
     195                'maxItemsPerType'  => apply_filters( 'progress_planner_suggested_tasks_max_items_per_type', $max_items_per_type ),
     196                'confettiOptions'  => $confetti_options,
     197                'delayCelebration' => $delay_celebration,
    180198            ]
    181199        );
  • progress-planner/trunk/progress-planner.php

    r3238385 r3243842  
    1010 * Requires at least: 6.3
    1111 * Requires PHP:      7.4
    12  * Version:           1.0.4
     12 * Version:           1.1.0
    1313 * Author:            Team Emilia Projects
    1414 * Author URI:        https://prpl.fyi/about
  • progress-planner/trunk/readme.txt

    r3238385 r3243842  
    55Tested up to: 6.7
    66Requires PHP: 7.4
    7 Stable tag: 1.0.4
     7Stable tag: 1.1.0
    88License: GPL3+
    99License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
     
    1313== Description ==
    1414
    15 Welcome to Progress Planner! This transformative WordPress plugin will empower website owners to keep up the good work on their site. Progress Planner introduces an exciting, interactive approach to website management with badges and achievements to collect. Our mission is to tackle the all-too-common challenge of procrastination. With Progress Planner, the upkeep of your website is a rewarding experience! We’ll encourage you to contribute to the success of your site consistently.
    16 
    17 === Problem We Solve ===
    18 We understand many website owners' dilemma — knowing the necessity of regular updates, content creation, and maintenance, yet often postponing these tasks —. Progress Planner seeks to address this procrastination head-on. A successful website demands regular attention, whether writing engaging content, adding internal links, updating plugins, resolving 404 errors, or optimizing site speed. These tasks are pivotal for a website to rank well and convert visitors effectively. Progress Planner ensures you stay on track, providing the tools and motivation to maintain and enhance your site's success.
    19 
    20 === Features ===
    21 
    22 * **Activity Tracking**: Monitor your actions on your website, from publishing posts to updating pages, and see how they contribute to your overall site health.
    23 * **Gamification**: Unlock achievements, earn badges, and track your progress in a fun and motivating way.
    24 * **Progress Reports**: Receive detailed reports on your website's performance and progress.
    25 * **To-do list**: Keep all those content and maintenance tasks in one place.
    26 * **More to come**: We are creating a Pro version and extra features for the Free version of Progress Planner. Stay tuned for updates!
    27 
    28 === Getting Started ===
    29 * **Install Progress Planner**: Download and activate the plugin from the WordPress plugin repository on your WordPress site.
    30 * **Define your goals**: Set specific, realistic goals for your website's improvement and growth.
    31 * **Engage in daily tasks**: Regularly update your website, with Progress Planner tracking each step and providing motivational feedback.
    32 * **Earn and celebrate**: Achieve your milestones and celebrate your success with rewards and recognitions from Progress Planner.
    33 * **Strive for continuous Improvement**: Utilize our guides and analytics to refine your site perpetually, ensuring its ongoing success.
     15A website isn’t something you set up once and forget about. Over time, small issues pile up — broken links, outdated content, slow load times — and suddenly, your site isn’t performing as well as it should. But staying on top of maintenance and optimization takes time and effort. Where do you even start?
     16
     17Progress Planner makes website upkeep easy. Built by the founders of Yoast, this plugin helps you keep your site optimized with clear, actionable recommendations, a smart to-do list and guided challenges that help you improve your site step by step. No more guesswork — just the right tasks at the right time.
     18
     19### 🔑 Key features
     20
     21#### Get personalized recommendations with Ravi’s Recommendations
     22Keeping up with all the little tasks that make a website run smoothly can be overwhelming. That’s why we’ve curated an interactive list of important but often-overlooked improvements for you. With Ravi’s Recommendations, you don’t have to figure out what needs attention — we do that for you.
     23
     24From setting your site’s tagline and icon to reviewing your permalink structure or removing default WordPress content, we surface the tasks that help keep your site professional, optimized and secure. Each recommendation comes with clear instructions, so all you have to do is put them into practice — no guesswork required.
     25
     26#### Stay organized with an in-context to-do list
     27Managing website tasks can be messy, but Progress Planner keeps everything in one place. Your to-do list isn’t just another checklist — it’s right where you need it. Add your own website tasks and keep them in context, so you have them on hand while working on your site. No more forgetting what needs to be done!
     28
     29#### Track your website activity over time
     30A well-maintained website isn’t built in a day — it’s improved with regular updates. Your website activity score reflects the maintenance work you’ve done over the past 30 days, helping you stay on track and keep your site in top shape.
     31
     32#### Earn badges and streaks for your progress
     33Motivation matters! Stay engaged with Progress Planner’s built-in gamification. Earn badges and track your streaks as you complete tasks and keep your website in great shape.
     34
     35#### Everything in one place: Your dashboard
     36Your dashboard gives you a clear overview of your website’s progress. See your recommendations, to-do list and achievements at a glance — so you can jump right into the most important tasks.
     37
     38### 🆘 Want expert guidance? Get Progress Planner Pro
     39
     40If you’re ready to take things further, [Progress Planner Pro](https://progressplanner.com/pro/) gives you access to in-depth guidance and structured challenges that walk you through key website improvements step by step.
     41
     42#### Get results with guided challenges
     43Maintaining a website can feel overwhelming — but you don’t have to do it alone. With Progress Planner Pro, you get access to expert-led challenges that guide you through key website improvements step by step.
     44
     45Each challenge is interactive and tailored to help you make real progress. You can expect:
     46
     47* Live **webinars & workshops** with experts sharing insights and strategies
     48* Actionable **reports & exercises** to apply what you’ve learned to your own site
     49* Personal **feedback & support**, like having your copywriting reviewed
     50* A **structured plan**, so you always know what to do next
     51
     52It’s not just advice — it’s a hands-on, practical experience that helps you take real action and see results.
     53
     54#### Learn with practical mini courses
     55
     56Want to sharpen your skills while improving your site? [Progress Planner Pro](https://progressplanner.com/pro/) includes mini courses that give you the knowledge you need — without the fluff.
     57
     58#### Get support when you need it
     59Sometimes you just need a little extra help. With Pro, you get access to our support team, ready to answer your questions and guide you through website improvements.
     60
     61### 🧹 Ready to make website maintenance easier?
     62Progress Planner takes the frustration out of keeping your website in top shape. Whether you’re tackling quick fixes or diving into bigger improvements, you’ll always know what to do next.
     63
     64Download Progress Planner for free and start optimizing your site today!
     65
    3466
    3567== Frequently Asked Questions ==
     
    4577= Is there a Pro version of Progress Planner? =
    4678
    47 We are currently creating a Pro version of Progress Planner. The Pro version will include guided tutorials, goal settings, and reminders.
     79Yes! You can [find it right here](https://progressplanner.com/pro/).
    4880
    4981= Where do I file bugs? =
     
    78110
    79111== Changelog ==
     112
     113= 1.1.0 =
     114
     115In this release, we've added more recommendations from Ravi on how to improve your site. We've also made these recommendations more visible on your WordPress
     116settings pages, by showing on settings pages exactly which things we think you should change. Also, if you're just now starting to use Progress Planner,
     117we've made the onboarding experience a lot more fun: we show you immediately which of Ravi's recommended tasks you've already completed and we give
     118you points for those!
     119
     120Added these recommendations from Ravi:
     121
     122* Properly set your [permalink structure](https://progressplanner.com/recommendations/change-default-permalink-structure/).
     123* Fix it if your site is [set to not be shown in search engines](https://progressplanner.com/recommendations/blog-indexing-settings/).
     124* Rename and change the slug of your [Uncategorized category](https://progressplanner.com/recommendations/rename-uncategorized-category/).
     125* Remove [inactive plugins](https://progressplanner.com/recommendations/remove-inactive-plugins/).
     126* [Upgrade your PHP version](https://progressplanner.com/recommendations/update-php-version/) if needed.
     127* [Fully disable comments](https://progressplanner.com/recommendations/disable-comments/) if they're not needed on your site.
     128
     129Bugs we fixed:
     130
     131* If you had `WP_DEBUG` set to false, the plugin would still tell you to disable `WP_DEBUG_DISPLAY`. We think Ravi was a bit overzealous in his recommendation, so we've fixed that.
     132
     133Under the hood:
     134
     135* We've added our set of debug tools straight into the plugin. If you define `PRPL_DEBUG` as `true` in your `wp-config.php` file, you'll get a PRPL Debug admin bar menu item.
     136* Improved suggested tasks completion conditions so they don't trigger at the wrong moment.
    80137
    81138= 1.0.4 =
  • progress-planner/trunk/views/admin-page.php

    r3217671 r3243842  
    2828            <?php endforeach; ?>
    2929        </div>
     30
     31        <?php // Display the upgrade tasks popover if needed. ?>
     32        <?php if ( \progress_planner()->get_plugin_upgrade_handler()->get_newly_added_task_providers() ) : ?>
     33            <?php \progress_planner()->get_popover()->the_popover( 'upgrade-tasks' )->render(); ?>
     34        <?php endif; ?>
    3035    <?php else : ?>
    3136        <?php \progress_planner()->the_view( 'welcome.php' ); ?>
  • progress-planner/trunk/views/welcome.php

    r3217671 r3243842  
    3131    [],
    3232    \progress_planner()->get_file_version( PROGRESS_PLANNER_DIR . '/assets/css/onboard.css' )
     33);
     34
     35// Enqueue upgrade styles.
     36\wp_enqueue_style(
     37    'progress-planner-upgrade-tasks',
     38    PROGRESS_PLANNER_URL . '/assets/css/upgrade-tasks.css',
     39    [],
     40    \progress_planner()->get_file_version( PROGRESS_PLANNER_DIR . '/assets/css/upgrade-tasks.css' )
    3341);
    3442
     
    4755            <form id="prpl-onboarding-form">
    4856                <div class="prpl-form-notice">
    49                     <strong><?php \esc_html_e( 'Stay on track with weekly updates', 'progress-planner' ); ?></strong>
     57                    <strong class="prpl-form-notice-title"><?php \esc_html_e( 'Stay on track with weekly updates', 'progress-planner' ); ?></strong>
    5058                    <ul>
    5159                        <li>
     
    184192                    ?>
    185193                </p>
     194
     195                <?php \progress_planner()->the_view( 'popovers/parts/upgrade-tasks.php', [ 'context' => 'onboarding' ] ); ?>
     196
    186197                <div id="progress-planner-scan-progress" style="display:none;">
    187198                    <progress value="0" max="100"></progress>
Note: See TracChangeset for help on using the changeset viewer.