'POST', 'callback' => array( __CLASS__, 'rest_choice' ), 'permission_callback' => function () { return current_user_can( 'manage_options' ); }, 'args' => array( 'choice' => array( 'type' => 'string', 'enum' => array( 'done', 'later', 'never' ), 'required' => true, ), ), ) ); } /** * Stores "later", "done" or "never" for the current user. * * @param WP_REST_Request $request Request. * @return WP_REST_Response */ public static function rest_choice( $request ) { $state = self::state( get_current_user_id() ); $choice = (string) $request['choice']; if ( 'later' === $choice ) { $state['state'] = 'later'; $state['until'] = time() + self::LATER_DAYS * DAY_IN_SECONDS; } else { $state['state'] = $choice; } ++$state['asked']; update_user_meta( get_current_user_id(), self::META, $state ); return rest_ensure_response( array( 'state' => $state['state'] ) ); } /** * Saved posts (any type, not in the trash, no revisions) that use one of our shortcodes or a table in our style. * Counting stops at 10, the result is kept for a day. * * @return int */ public static function count(): int { $count = get_transient( self::CACHE ); if ( false === $count ) { global $wpdb; // One small query on our own settings page, at most once a day; WP_Query cannot search the content with LIMIT. $ids = $wpdb->get_col( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- cached in a transient right below. $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_status IN ('publish','future','draft','pending','private') AND post_type NOT IN ('revision','nav_menu_item','customize_changeset','wp_global_styles') AND ( post_content LIKE %s OR post_content LIKE %s ) LIMIT %d", '%' . $wpdb->esc_like( '[threece_' ) . '%', '%' . $wpdb->esc_like( 'threece-table' ) . '%', self::MIN_POSTS ) ); $count = count( (array) $ids ); set_transient( self::CACHE, $count, DAY_IN_SECONDS ); } /** * Number of posts with our elements the thank-you card counts. * * @param int $count Saved posts that use our elements, at most 10. */ return (int) apply_filters( 'threece_thanks_count', (int) $count ); } /** * The card for a tab of our settings page, or an empty string. * * @param string $tab Tab. * @return string */ public static function card( string $tab ): string { if ( 'editor' !== $tab || ! current_user_can( 'manage_options' ) ) { return ''; } $installed = (int) get_option( self::INSTALLED, 0 ); if ( $installed < 1 ) { self::activate(); return ''; } if ( time() - $installed < self::WAIT_DAYS * DAY_IN_SECONDS ) { return ''; } $state = self::state( get_current_user_id() ); if ( in_array( $state['state'], array( 'done', 'never' ), true ) || $state['asked'] >= self::MAX_ASKS || ( 'later' === $state['state'] && time() < $state['until'] ) ) { return ''; } $count = self::count(); if ( $count < self::MIN_POSTS ) { return ''; } $html = '
'; $html .= ''; /* translators: %d: number of saved posts that use elements of the plugin, counted up to 10. */ $html .= '

' . esc_html( sprintf( _n( '%d post on this site uses elements from 3task Toolbar. Thank you.', '%d posts on this site use elements from 3task Toolbar. Thank you.', $count, '3task-toolbar-for-classic-editor' ), $count ) ) . '

'; $html .= '

' . esc_html__( 'I am Frank, and I build this editor in the evenings next to my job, without ads and without tracking. Nobody has to pay for it. What keeps it going is hearing from the people who write with it.', '3task-toolbar-for-classic-editor' ) . '

'; $html .= '

' . esc_html__( 'Would you leave a short review on WordPress.org? One honest sentence is enough, good or critical. If something is missing, tell me in the support forum and I will look at it.', '3task-toolbar-for-classic-editor' ) . '

'; $html .= '

'; $html .= '' . esc_html__( 'Write a review on WordPress.org', '3task-toolbar-for-classic-editor' ) . ' '; $html .= '' . esc_html__( 'Something is missing? Tell me', '3task-toolbar-for-classic-editor' ) . ' '; $html .= ' · '; $html .= ''; $html .= '

' . esc_html__( 'This note appears at most twice and only on this page. Nothing changes in the plugin, whatever you choose.', '3task-toolbar-for-classic-editor' ) . '

'; return $html; } /** * Saved choice of a user. * * @param int $user_id User. * @return array{state: string, until: int, asked: int} */ private static function state( int $user_id ): array { $raw = get_user_meta( $user_id, self::META, true ); $raw = is_array( $raw ) ? $raw : array(); return array( 'state' => isset( $raw['state'] ) && in_array( $raw['state'], array( 'done', 'later', 'never' ), true ) ? $raw['state'] : '', 'until' => isset( $raw['until'] ) ? (int) $raw['until'] : 0, 'asked' => isset( $raw['asked'] ) ? max( 0, (int) $raw['asked'] ) : 0, ); } }