Plugin Directory

Changeset 3712148


Ignore:
Timestamp:
09/24/2026 11:06:29 PM (4 weeks ago)
Author:
whoknewio
Message:

Release version 2.1.5

Location:
servantly-ask-qa-spam-protection
Files:
6 added
24 edited
1 copied

Legend:

Unmodified
Added
Removed
  • servantly-ask-qa-spam-protection/tags/2.1.5/admin/views/question-detail.php

    r3641266 r3712148  
    2020$servantly_ask_submitter_name  = get_post_meta( $servantly_ask_question_id, 'servantly_ask_submitter_name', true );
    2121$servantly_ask_submitter_email = get_post_meta( $servantly_ask_question_id, 'servantly_ask_submitter_email', true );
    22 $servantly_ask_answer_text     = get_post_meta( $servantly_ask_question_id, 'servantly_ask_answer_text', true );
    2322$servantly_ask_internal_notes  = get_post_meta( $servantly_ask_question_id, 'servantly_ask_internal_notes', true );
    24 $servantly_ask_is_public       = Servantly_Ask_Archive::is_public( $servantly_ask_question_id );
    25 $servantly_ask_can_publish     = Servantly_Ask_Settings::can_publish_to_archive( $servantly_ask_question_post );
    2623$servantly_ask_terms           = get_the_terms( $servantly_ask_question_id, Servantly_Ask_Post_Type::TAXONOMY );
    2724$servantly_ask_category_label  = ( ! empty( $servantly_ask_terms ) && ! is_wp_error( $servantly_ask_terms ) ) ? implode( ', ', wp_list_pluck( $servantly_ask_terms, 'name' ) ) : '';
    … …  
    122119                        <tr>
    123120                                <th scope="row">
    124                                         <label for="servantly_ask_answer_text"><?php esc_html_e( 'Answer', 'servantly-ask-qa-spam-protection' ); ?></label>
    125                                 </th>
    126                                 <td>
    127                                         <textarea name="servantly_ask_answer_text" id="servantly_ask_answer_text" rows="6" class="large-text"><?php echo esc_textarea( $servantly_ask_answer_text ); ?></textarea>
     121                                        <label for="servantly_ask_short_title"><?php esc_html_e( 'Short title', 'servantly-ask-qa-spam-protection' ); ?></label>
     122                                </th>
     123                                <td>
     124                                        <?php $servantly_ask_short_title = Servantly_Ask_Public_Question::short_title( $servantly_ask_question_id ); ?>
     125                                        <input type="text" class="large-text" name="servantly_ask_short_title" id="servantly_ask_short_title" value="<?php echo esc_attr( $servantly_ask_short_title ); ?>" />
     126                                        <?php if ( Servantly_Ask_Archive::is_public( $servantly_ask_question_id ) ) : ?>
    128127                                        <p class="description">
    129                                                 <?php esc_html_e( 'Shown publicly on the archive underneath this question once published. Leave blank to show the question without an answer.', 'servantly-ask-qa-spam-protection' ); ?>
    130                                         </p>
     128                                                <?php esc_html_e( 'This is the heading. The link stays the same unless you edit the link below.', 'servantly-ask-qa-spam-protection' ); ?>
     129                                        </p>
     130                                                <?php $servantly_ask_page_url = get_permalink( $servantly_ask_question_id ); ?>
     131                                                <p>
     132                                                        <a href="<?php echo esc_url( $servantly_ask_page_url ); ?>"><?php esc_html_e( 'View page', 'servantly-ask-qa-spam-protection' ); ?></a>
     133                                                        <code><?php echo esc_html( $servantly_ask_page_url ); ?></code>
     134                                                </p>
     135                                                <p>
     136                                                        <label for="servantly_ask_link_slug"><?php esc_html_e( 'Edit link', 'servantly-ask-qa-spam-protection' ); ?></label><br />
     137                                                        <input type="text" class="regular-text" name="servantly_ask_link_slug" id="servantly_ask_link_slug" value="<?php echo esc_attr( $servantly_ask_question_post->post_name ); ?>" />
     138                                                </p>
     139                                        <?php else : ?>
     140                                                <p class="description">
     141                                                        <?php esc_html_e( 'The page is created when you set the status to Published to Archive and save.', 'servantly-ask-qa-spam-protection' ); ?>
     142                                                </p>
     143                                        <?php endif; ?>
     144                                </td>
     145                        </tr>
     146                        <tr>
     147                                <th scope="row"><?php esc_html_e( 'Asker name', 'servantly-ask-qa-spam-protection' ); ?></th>
     148                                <td>
     149                                        <label>
     150                                                <input type="checkbox" name="servantly_ask_hide_name" value="1" <?php checked( 'yes', get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_HIDE_NAME, true ) ); ?> />
     151                                                <?php esc_html_e( 'Hide the asker’s name on the public archive and the question page', 'servantly-ask-qa-spam-protection' ); ?>
     152                                        </label>
     153                                </td>
     154                        </tr>
     155                        <tr>
     156                                <th scope="row">
     157                                        <label for="servantly_ask_date_answered"><?php esc_html_e( 'Date answered', 'servantly-ask-qa-spam-protection' ); ?></label>
     158                                </th>
     159                                <td>
     160                                        <input type="date" name="servantly_ask_date_answered" id="servantly_ask_date_answered" value="<?php echo esc_attr( (string) get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_DATE_ANSWERED, true ) ); ?>" />
     161                                </td>
     162                        </tr>
     163                        <tr>
     164                                <th scope="row"><?php esc_html_e( 'Answers', 'servantly-ask-qa-spam-protection' ); ?></th>
     165                                <td>
     166                                        <?php
     167                                        $servantly_ask_answer_rows = Servantly_Ask_Public_Question::get_answers( $servantly_ask_question_id );
     168                                        $servantly_ask_answer_rows[] = array(
     169                                                'pastor' => 'other',
     170                                                'custom' => '',
     171                                                'text'   => '',
     172                                        );
     173                                        ?>
     174                                        <?php foreach ( $servantly_ask_answer_rows as $servantly_ask_answer_row ) : ?>
     175                                                <p>
     176                                                        <select name="servantly_ask_answer_pastor[]">
     177                                                                <?php foreach ( Servantly_Ask_Public_Question::author_names() as $servantly_ask_author_name ) : ?>
     178                                                                        <option value="<?php echo esc_attr( sanitize_key( $servantly_ask_author_name ) ); ?>" <?php selected( $servantly_ask_answer_row['pastor'], sanitize_key( $servantly_ask_author_name ) ); ?>>
     179                                                                                <?php echo esc_html( $servantly_ask_author_name ); ?>
     180                                                                        </option>
     181                                                                <?php endforeach; ?>
     182                                                                <option value="other" <?php selected( $servantly_ask_answer_row['pastor'], 'other' ); ?>><?php esc_html_e( 'Other', 'servantly-ask-qa-spam-protection' ); ?></option>
     183                                                        </select>
     184                                                        <input type="text" name="servantly_ask_answer_custom[]" value="<?php echo esc_attr( $servantly_ask_answer_row['custom'] ); ?>" placeholder="<?php esc_attr_e( 'Name if Other', 'servantly-ask-qa-spam-protection' ); ?>" />
     185                                                </p>
     186                                                <textarea name="servantly_ask_answer_text_row[]" rows="5" class="large-text"><?php echo esc_textarea( $servantly_ask_answer_row['text'] ); ?></textarea>
     187                                        <?php endforeach; ?>
     188                                        <p class="description">
     189                                                <?php esc_html_e( 'One block per pastor, in the order they should appear. The original combined answer is kept in sync from these fields.', 'servantly-ask-qa-spam-protection' ); ?>
     190                                        </p>
     191                                </td>
     192                        </tr>
     193                        <tr>
     194                                <th scope="row"><?php esc_html_e( 'Topics', 'servantly-ask-qa-spam-protection' ); ?></th>
     195                                <td>
     196                                        <?php
     197                                        $servantly_ask_all_topics = get_terms(
     198                                                array(
     199                                                        'taxonomy'   => Servantly_Ask_Public_Question::TAXONOMY,
     200                                                        'hide_empty' => false,
     201                                                )
     202                                        );
     203                                        $servantly_ask_set_topics = wp_get_post_terms( $servantly_ask_question_id, Servantly_Ask_Public_Question::TAXONOMY, array( 'fields' => 'ids' ) );
     204                                        if ( is_wp_error( $servantly_ask_set_topics ) ) {
     205                                                $servantly_ask_set_topics = array();
     206                                        }
     207                                        if ( is_array( $servantly_ask_all_topics ) && $servantly_ask_all_topics ) :
     208                                                foreach ( $servantly_ask_all_topics as $servantly_ask_topic_term ) :
     209                                                        ?>
     210                                                        <label style="display:block;margin:0 0 0.25em;">
     211                                                                <input type="checkbox" name="servantly_ask_topics[]" value="<?php echo esc_attr( (string) $servantly_ask_topic_term->term_id ); ?>" <?php checked( in_array( $servantly_ask_topic_term->term_id, $servantly_ask_set_topics, true ) ); ?> />
     212                                                                <?php echo esc_html( $servantly_ask_topic_term->name ); ?>
     213                                                        </label>
     214                                                        <?php
     215                                                endforeach;
     216                                        else :
     217                                                ?>
     218                                                <p class="description"><?php esc_html_e( 'No topics yet.', 'servantly-ask-qa-spam-protection' ); ?></p>
     219                                                <?php
     220                                        endif;
     221                                        ?>
     222                                        <p>
     223                                                <label for="servantly_ask_new_topic"><?php esc_html_e( 'Add a topic', 'servantly-ask-qa-spam-protection' ); ?></label>
     224                                                <input type="text" name="servantly_ask_new_topic" id="servantly_ask_new_topic" class="regular-text" />
     225                                        </p>
     226                                </td>
     227                        </tr>
     228                        <tr>
     229                                <th scope="row">
     230                                        <label for="servantly_ask_video_url"><?php esc_html_e( 'Video URL', 'servantly-ask-qa-spam-protection' ); ?></label>
     231                                </th>
     232                                <td>
     233                                        <input type="url" class="large-text" name="servantly_ask_video_url" id="servantly_ask_video_url" value="<?php echo esc_attr( (string) get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_VIDEO_URL, true ) ); ?>" />
     234                                        <p>
     235                                                <label for="servantly_ask_video_start"><?php esc_html_e( 'Start time (seconds or mm:ss)', 'servantly-ask-qa-spam-protection' ); ?></label>
     236                                                <input type="text" name="servantly_ask_video_start" id="servantly_ask_video_start" value="<?php echo esc_attr( (string) get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_VIDEO_START, true ) ); ?>" />
     237                                        </p>
     238                                </td>
     239                        </tr>
     240                        <tr>
     241                                <th scope="row">
     242                                        <label for="servantly_ask_scripture"><?php esc_html_e( 'Scripture references', 'servantly-ask-qa-spam-protection' ); ?></label>
     243                                </th>
     244                                <td>
     245                                        <input type="text" class="large-text" name="servantly_ask_scripture" id="servantly_ask_scripture" value="<?php echo esc_attr( (string) get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_SCRIPTURE, true ) ); ?>" placeholder="<?php esc_attr_e( '1 Corinthians 8; Luke 9:23', 'servantly-ask-qa-spam-protection' ); ?>" />
     246                                </td>
     247                        </tr>
     248                        <tr>
     249                                <th scope="row">
     250                                        <label for="servantly_ask_related_sermons"><?php esc_html_e( 'Related sermon IDs', 'servantly-ask-qa-spam-protection' ); ?></label>
     251                                </th>
     252                                <td>
     253                                        <?php
     254                                        $servantly_ask_related_ids = get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_RELATED, true );
     255                                        $servantly_ask_related_ids = is_array( $servantly_ask_related_ids ) ? implode( ', ', $servantly_ask_related_ids ) : '';
     256                                        ?>
     257                                        <input type="text" class="large-text" name="servantly_ask_related_sermons" id="servantly_ask_related_sermons" value="<?php echo esc_attr( $servantly_ask_related_ids ); ?>" />
     258                                </td>
     259                        </tr>
     260                        <tr>
     261                                <th scope="row">
     262                                        <label for="servantly_ask_meta_description"><?php esc_html_e( 'Meta description', 'servantly-ask-qa-spam-protection' ); ?></label>
     263                                </th>
     264                                <td>
     265                                        <textarea name="servantly_ask_meta_description" id="servantly_ask_meta_description" rows="3" class="large-text" maxlength="160"><?php echo esc_textarea( (string) get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_DESCRIPTION, true ) ); ?></textarea>
     266                                        <p class="description"><?php esc_html_e( 'Optional. Leave blank to use the start of the first answer.', 'servantly-ask-qa-spam-protection' ); ?></p>
    131267                                </td>
    132268                        </tr>
    … …  
    140276                        </tr>
    141277                </table>
    142 
    143                 <?php if ( $servantly_ask_is_public ) : ?>
    144                         <p>
    145                                 <strong><?php esc_html_e( 'Public archive:', 'servantly-ask-qa-spam-protection' ); ?></strong>
    146                                 <?php esc_html_e( 'This question is published on the public archive.', 'servantly-ask-qa-spam-protection' ); ?>
    147                         </p>
    148                         <?php submit_button( __( 'Remove from Public Archive', 'servantly-ask-qa-spam-protection' ), 'secondary', 'servantly_ask_unpublish_archive', false ); ?>
    149                 <?php elseif ( $servantly_ask_can_publish ) : ?>
    150                         <?php submit_button( __( 'Publish to Public Archive', 'servantly-ask-qa-spam-protection' ), 'secondary', 'servantly_ask_publish_archive', false ); ?>
    151                 <?php else : ?>
    152                         <p class="description">
    153                                 <?php esc_html_e( 'Approve this question (or clear spam checks in Auto-clear mode) before publishing to the public archive.', 'servantly-ask-qa-spam-protection' ); ?>
    154                         </p>
    155                 <?php endif; ?>
    156278
    157279                <?php submit_button( __( 'Save Question', 'servantly-ask-qa-spam-protection' ), 'primary', 'servantly_ask_save_question' ); ?>
  • servantly-ask-qa-spam-protection/tags/2.1.5/assets/css/servantly-ask-frontend.css

    r3641266 r3712148  
    287287        font-style: italic;
    288288}
     289
     290.servantly-ask-topic-filters,
     291.servantly-ask-archive-card-meta,
     292.servantly-ask-share,
     293.servantly-ask-scripture {
     294        display: flex;
     295        flex-wrap: wrap;
     296        gap: 0.5rem;
     297        align-items: center;
     298}
     299
     300.servantly-ask-topic-filter,
     301.servantly-ask-topic-tag,
     302.servantly-ask-watch,
     303.servantly-ask-share a,
     304.servantly-ask-share button {
     305        display: inline-block;
     306        border: 1px solid var(--servantly-ask-border);
     307        border-radius: 999px;
     308        padding: 0.35em 0.8em;
     309        background: #fff;
     310        color: var(--servantly-ask-text);
     311        text-decoration: none;
     312        font: inherit;
     313        cursor: pointer;
     314}
     315
     316body.servantly-ask-public-page .servantly-ask-share a,
     317body.servantly-ask-public-page .servantly-ask-share button {
     318        border-radius: 999px !important;
     319        box-shadow: none !important;
     320        color: #226053;
     321        line-height: 1.4;
     322}
     323
     324.servantly-ask-topic-filter.is-active,
     325.servantly-ask-watch {
     326        background: var(--servantly-ask-archive-accent, var(--servantly-ask-accent));
     327        border-color: var(--servantly-ask-archive-accent, var(--servantly-ask-accent));
     328        color: #fff;
     329}
     330
     331.servantly-ask-archive-card-title {
     332        margin: 0 0 0.35em;
     333        font-size: 1.25rem;
     334}
     335
     336.servantly-ask-archive-card-title a {
     337        color: inherit;
     338        text-decoration: none;
     339}
     340
     341.servantly-ask-archive-card-excerpt {
     342        margin: 0 0 0.5em;
     343}
     344
     345.servantly-ask-archive-pages {
     346        display: flex;
     347        justify-content: space-between;
     348        gap: 1rem;
     349        margin-top: 1.5rem;
     350}
     351
     352.servantly-ask-archive.is-searching .servantly-ask-archive-pages,
     353.servantly-ask-archive.is-searching .servantly-ask-topic-filters {
     354        display: none;
     355}
     356
     357body.servantly-ask-public-page #ajax-content-wrap > .container-wrap {
     358        background-color: #ffffff !important;
     359}
     360
     361.servantly-ask-single,
     362.servantly-ask-single-wrap {
     363        max-width: 42rem;
     364        margin: 2rem auto;
     365        color: #1a1a1a;
     366}
     367
     368body.servantly-ask-public-page .servantly-ask-single h1,
     369body.servantly-ask-public-page .servantly-ask-single h2,
     370body.servantly-ask-public-page .servantly-ask-single-wrap h1,
     371body.servantly-ask-public-page .servantly-ask-single-wrap h2 {
     372        color: #1a2744;
     373}
     374
     375body.servantly-ask-public-page .servantly-ask-single a,
     376body.servantly-ask-public-page .servantly-ask-single-wrap a {
     377        color: #226053;
     378}
     379
     380.servantly-ask-breadcrumb {
     381        color: var(--servantly-ask-muted);
     382        font-size: 0.95rem;
     383}
     384
     385.servantly-ask-single-question,
     386.servantly-ask-single-answer {
     387        margin: 1.25rem 0;
     388}
     389
     390.servantly-ask-single-cta {
     391        margin-top: 2rem;
     392        font-weight: 700;
     393}
  • servantly-ask-qa-spam-protection/tags/2.1.5/assets/js/servantly-ask-frontend.js

    r3641266 r3712148  
    149149                function restoreOriginalList() {
    150150                        setStatus( '' );
     151                        var archive = list.closest( '.servantly-ask-archive' );
     152                        if ( archive ) {
     153                                archive.classList.remove( 'is-searching' );
     154                        }
    151155                        list.innerHTML = originalHtml;
    152156                        initArchiveVoting( list );
    … …  
    176180                        activeController = controller;
    177181
     182                        var archive = list.closest( '.servantly-ask-archive' );
     183                        if ( archive ) {
     184                                archive.classList.add( 'is-searching' );
     185                        }
    178186                        setStatus( searchI18n( 'searching', 'Searching…' ) );
    179187
    … …  
    237245                        li.setAttribute( 'data-question-id', String( row.id ) );
    238246
     247                        if ( row.url && row.title ) {
     248                                var heading = document.createElement( 'h2' );
     249                                heading.className = 'servantly-ask-archive-card-title';
     250                                var titleLink = document.createElement( 'a' );
     251                                titleLink.href = row.url;
     252                                titleLink.textContent = row.title;
     253                                heading.appendChild( titleLink );
     254                                li.appendChild( heading );
     255
     256                                if ( row.excerpt ) {
     257                                        var excerpt = document.createElement( 'p' );
     258                                        excerpt.className = 'servantly-ask-archive-card-excerpt';
     259                                        appendHighlighted( excerpt, row.excerpt, term );
     260                                        li.appendChild( excerpt );
     261                                }
     262
     263                                var meta = document.createElement( 'p' );
     264                                meta.className = 'servantly-ask-archive-card-meta';
     265                                if ( row.dateLabel ) {
     266                                        var date = document.createElement( 'span' );
     267                                        date.textContent = row.dateLabel;
     268                                        meta.appendChild( date );
     269                                }
     270                                ( row.topics || [] ).forEach( function ( topic ) {
     271                                        var tag = document.createElement( 'a' );
     272                                        tag.className = 'servantly-ask-topic-tag';
     273                                        tag.href = topic.url;
     274                                        tag.textContent = topic.name;
     275                                        meta.appendChild( tag );
     276                                } );
     277                                if ( meta.childNodes.length ) {
     278                                        li.appendChild( meta );
     279                                }
     280
     281                                var more = document.createElement( 'p' );
     282                                more.className = 'servantly-ask-archive-card-more';
     283                                var moreLink = document.createElement( 'a' );
     284                                moreLink.href = row.url;
     285                                moreLink.textContent = searchI18n( 'readMore', 'Read full answer →' );
     286                                more.appendChild( moreLink );
     287                                li.appendChild( more );
     288
     289                                if ( config.voting && config.voting.enabled ) {
     290                                        li.appendChild( buildVoteMarkup( row ) );
     291                                }
     292                                return li;
     293                        }
     294
    239295                        var questionBlock = document.createElement( 'div' );
    240296                        questionBlock.className = 'servantly-ask-archive-block servantly-ask-archive-question-block';
  • servantly-ask-qa-spam-protection/tags/2.1.5/includes/class-servantly-ask-archive.php

    r3641266 r3712148  
    6363         * Publish a question to the public archive (`publish` status per spec).
    6464         *
    65          * @param int $post_id Post ID.
     65         * @param int  $post_id Post ID.
     66         * @param bool $force   When true, publish from whatever status the question
     67         *                      is in. The question detail dropdown uses this so
     68         *                      choosing Published to Archive and saving always
     69         *                      publishes. The separate button still requires an
     70         *                      eligible status.
    6671         * @return bool
    6772         */
    68         public static function publish_to_archive( $post_id ) {
     73        public static function publish_to_archive( $post_id, $force = false ) {
    6974                $post_id = absint( $post_id );
    7075                $post    = get_post( $post_id );
    … …  
    7883                }
    7984
    80                 if ( ! Servantly_Ask_Settings::can_publish_to_archive( $post ) ) {
     85                if ( ! $force && ! Servantly_Ask_Settings::can_publish_to_archive( $post ) ) {
    8186                        return false;
    8287                }
    … …  
    193198         */
    194199        public static function get_public_questions( $search = '' ) {
    195                 $args = array(
     200                $result = self::query_public_questions(
     201                        array(
     202                                'search'         => $search,
     203                                'posts_per_page' => 500,
     204                                'paged'          => 1,
     205                        )
     206                );
     207                return $result['posts'];
     208        }
     209
     210        /**
     211         * Paginated public-archive query. Search matches the question, the
     212         * short title, and the answer text, not only the current page.
     213         *
     214         * @param array<string, mixed> $args search, paged, posts_per_page, topic.
     215         * @return array{posts: WP_Post[], found: int, max_pages: int}
     216         */
     217        public static function query_public_questions( $args = array() ) {
     218                $args = wp_parse_args(
     219                        $args,
     220                        array(
     221                                'search'         => '',
     222                                'paged'          => 1,
     223                                'posts_per_page' => Servantly_Ask_Public_Question::PER_PAGE,
     224                                'topic'          => '',
     225                        )
     226                );
     227
     228                $query_args = array(
    196229                        'post_type'              => Servantly_Ask_Post_Type::POST_TYPE,
    197230                        'post_status'            => 'publish',
    198                         'posts_per_page'         => 100,
     231                        'posts_per_page'         => max( 1, (int) $args['posts_per_page'] ),
     232                        'paged'                  => max( 1, (int) $args['paged'] ),
    199233                        'ignore_sticky_posts'    => true,
    200                         'no_found_rows'          => true,
    201234                        'update_post_meta_cache' => true,
    202235                        'meta_query'             => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
    … …  
    208241                );
    209242
    210                 $search = trim( (string) $search );
     243                $topic = sanitize_title( (string) $args['topic'] );
     244                if ( '' !== $topic ) {
     245                        $query_args['tax_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
     246                                array(
     247                                        'taxonomy' => Servantly_Ask_Public_Question::TAXONOMY,
     248                                        'field'    => 'slug',
     249                                        'terms'    => $topic,
     250                                ),
     251                        );
     252                }
     253
     254                $search = trim( (string) $args['search'] );
    211255                if ( '' !== $search ) {
    212                         $args['s'] = $search;
     256                        $query_args['servantly_ask_archive_search'] = $search;
     257                        add_filter( 'posts_where', array( __CLASS__, 'search_where' ), 10, 2 );
    213258                }
    214259
    215260                if ( Servantly_Ask_Settings::is_voting_enabled() && 'votes' === Servantly_Ask_Settings::get_archive_sort_by() ) {
    216                         $args['meta_key'] = Servantly_Ask_Voting::META_VOTE_COUNT; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
    217                         $args['orderby']  = 'meta_value_num';
    218                         $args['order']    = 'DESC';
     261                        $query_args['meta_key'] = Servantly_Ask_Voting::META_VOTE_COUNT; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
     262                        $query_args['orderby']  = 'meta_value_num';
     263                        $query_args['order']    = 'DESC';
    219264                } else {
    220                         $args['orderby'] = 'date';
    221                         $args['order']   = 'DESC';
    222                 }
    223 
    224                 $query = new WP_Query( $args );
    225                 return $query->posts;
     265                        $query_args['orderby'] = 'date';
     266                        $query_args['order']   = 'DESC';
     267                }
     268
     269                $query = new WP_Query( $query_args );
     270
     271                if ( '' !== $search ) {
     272                        remove_filter( 'posts_where', array( __CLASS__, 'search_where' ), 10 );
     273                }
     274
     275                return array(
     276                        'posts'     => $query->posts,
     277                        'found'     => (int) $query->found_posts,
     278                        'max_pages' => (int) $query->max_num_pages,
     279                );
     280        }
     281
     282        /**
     283         * Match question text, short title, and answer text.
     284         *
     285         * @param string   $where SQL WHERE.
     286         * @param WP_Query $query Query.
     287         * @return string
     288         */
     289        public static function search_where( $where, $query ) {
     290                $term = $query->get( 'servantly_ask_archive_search' );
     291                if ( ! is_string( $term ) || '' === $term ) {
     292                        return $where;
     293                }
     294                global $wpdb;
     295                $like   = '%' . $wpdb->esc_like( $term ) . '%';
     296                $where .= $wpdb->prepare(
     297                        " AND ( {$wpdb->posts}.post_title LIKE %s OR {$wpdb->posts}.post_content LIKE %s OR EXISTS ( SELECT 1 FROM {$wpdb->postmeta} sa_pm WHERE sa_pm.post_id = {$wpdb->posts}.ID AND sa_pm.meta_key IN ('servantly_ask_answer_text','servantly_ask_short_title') AND sa_pm.meta_value LIKE %s ) )",
     298                        $like,
     299                        $like,
     300                        $like
     301                );
     302                return $where;
    226303        }
    227304
    … …  
    234311         */
    235312        private static function format_row_for_json( WP_Post $post ) {
     313                $indexable = Servantly_Ask_Public_Question::is_indexable( $post );
     314                $name      = Servantly_Ask_Public_Question::public_asker_name( $post->ID );
     315                $topics    = array();
     316                $terms     = get_the_terms( $post->ID, Servantly_Ask_Public_Question::TAXONOMY );
     317                if ( is_array( $terms ) ) {
     318                        foreach ( $terms as $term ) {
     319                                $topics[] = array(
     320                                        'name' => $term->name,
     321                                        'url'  => Servantly_Ask_Public_Question::topic_url( $term->slug ),
     322                                );
     323                        }
     324                }
    236325                return array(
    237326                        'id'            => $post->ID,
    238327                        'text'          => wp_strip_all_tags( $post->post_content ),
    239                         'submitterName' => (string) get_post_meta( $post->ID, 'servantly_ask_submitter_name', true ),
     328                        'submitterName' => $name,
    240329                        'answerText'    => wp_strip_all_tags( (string) get_post_meta( $post->ID, 'servantly_ask_answer_text', true ) ),
    241330                        'voteCount'     => Servantly_Ask_Voting::get_vote_count( $post->ID ),
     331                        'indexable'     => $indexable,
     332                        'title'         => $indexable ? Servantly_Ask_Public_Question::short_title( $post->ID ) : '',
     333                        'url'           => $indexable ? get_permalink( $post->ID ) : '',
     334                        'excerpt'       => Servantly_Ask_Public_Question::excerpt_from_first_answer( $post->ID, 180 ),
     335                        'dateLabel'     => Servantly_Ask_Public_Question::answered_label( $post->ID ),
     336                        'topics'        => $topics,
    242337                );
    243338        }
  • servantly-ask-qa-spam-protection/tags/2.1.5/includes/class-servantly-ask-moderation-queue.php

    r3641266 r3712148  
    216216                }
    217217
    218                 self::update_question_status( $post_id, $new_status );
    219 
    220                 $answer_text = isset( $_POST['servantly_ask_answer_text'] )
    221                         ? sanitize_textarea_field( wp_unslash( $_POST['servantly_ask_answer_text'] ) )
    222                         : '';
    223                 update_post_meta( $post_id, 'servantly_ask_answer_text', $answer_text );
     218                self::apply_status_from_detail_save( $post, $new_status );
     219
     220                if ( ! isset( $_POST['servantly_ask_answer_pastor'] ) ) {
     221                        $answer_text = isset( $_POST['servantly_ask_answer_text'] )
     222                                ? sanitize_textarea_field( wp_unslash( $_POST['servantly_ask_answer_text'] ) )
     223                                : '';
     224                        update_post_meta( $post_id, 'servantly_ask_answer_text', $answer_text );
     225                }
    224226
    225227                $internal_notes = isset( $_POST['servantly_ask_internal_notes'] )
    … …  
    228230                update_post_meta( $post_id, 'servantly_ask_internal_notes', $internal_notes );
    229231
     232                if ( class_exists( 'Servantly_Ask_Public_Question' ) ) {
     233                        Servantly_Ask_Public_Question::save_detail_fields( $post_id );
     234                }
     235
    230236                $redirect = Servantly_Ask_Admin_Menu::get_question_detail_url( $post_id );
    231237                $redirect = add_query_arg( 'servantly_ask_saved', '1', $redirect );
    … …  
    233239                wp_safe_redirect( $redirect );
    234240                exit;
     241        }
     242
     243        /**
     244         * Apply the detail-screen status dropdown.
     245         *
     246         * Published to Archive sets the public flag and the status together.
     247         * Any other status takes the question off the public archive. Notes and
     248         * the other fields are saved by the caller either way.
     249         *
     250         * @param WP_Post $post       Question before this save.
     251         * @param string  $new_status Requested status slug.
     252         * @return void
     253         */
     254        private static function apply_status_from_detail_save( WP_Post $post, $new_status ) {
     255                $post_id    = (int) $post->ID;
     256                $was_public = Servantly_Ask_Archive::is_public( $post_id );
     257
     258                if ( 'publish' === $new_status ) {
     259                        if ( ! $was_public ) {
     260                                Servantly_Ask_Archive::publish_to_archive( $post_id, true );
     261                        }
     262                        return;
     263                }
     264
     265                if ( $was_public ) {
     266                        Servantly_Ask_Archive::unpublish_from_archive( $post_id );
     267                }
     268
     269                $current = get_post_status( $post_id );
     270                if ( $current !== $new_status ) {
     271                        self::update_question_status( $post_id, $new_status );
     272                }
    235273        }
    236274
  • servantly-ask-qa-spam-protection/tags/2.1.5/includes/class-servantly-ask-post-type.php

    r3641266 r3712148  
    5252         * Register the `servantly_ask_q` custom post type.
    5353         *
    54          * The post type is intentionally non-public: questions are private
    55          * submissions, never directly browsable/queryable on the front end.
     54         * Questions stay out of the admin UI and out of site search. Published
     55         * archive answers are publicly queryable so each one can have its own
     56         * URL. Anything that is not on the public archive, or whose short title
     57         * is still awaiting review, is 404'd in Servantly_Ask_Public_Question.
    5658         * `show_ui` is false: questions are managed only via the Servantly Ask
    5759         * moderation queue (guest submission is the only intended entry path).
    … …  
    8284                                'description'         => __( 'A question submitted through the Servantly Ask submission form.', 'servantly-ask-qa-spam-protection' ),
    8385                                'public'              => false,
    84                                 'publicly_queryable'  => false,
     86                                'publicly_queryable'  => true,
    8587                                'exclude_from_search' => true,
    8688                                'show_ui'             => false,
    … …  
    8991                                'show_in_admin_bar'   => false,
    9092                                'show_in_rest'        => false,
    91                                 'query_var'           => false,
     93                                'query_var'           => true,
    9294                                'rewrite'             => false,
    9395                                'has_archive'         => false,
  • servantly-ask-qa-spam-protection/tags/2.1.5/includes/class-servantly-ask-script-config.php

    r3641266 r3712148  
    197197                                                'questionBadge' => __( 'Question', 'servantly-ask-qa-spam-protection' ),
    198198                                                'answerBadge'   => __( 'Answer', 'servantly-ask-qa-spam-protection' ),
     199                                                'readMore'      => __( 'Read full answer →', 'servantly-ask-qa-spam-protection' ),
    199200                                        ),
    200201                                );
  • servantly-ask-qa-spam-protection/tags/2.1.5/includes/class-servantly-ask-settings.php

    r3699296 r3712148  
    12381238                }
    12391239
    1240                 return in_array( $post->post_status, array( 'sa_approved', 'sa_displayed', 'sa_answered' ), true );
     1240                if ( in_array( $post->post_status, array( 'sa_approved', 'sa_displayed', 'sa_answered' ), true ) ) {
     1241                        return true;
     1242                }
     1243
     1244                // Status was set to publish without the public flag (dropdown save
     1245                // used to do this). Treat it as not yet on the archive so the
     1246                // publish button and a second save can finish the job.
     1247                return 'publish' === $post->post_status && ! Servantly_Ask_Archive::is_public( $post->ID );
    12411248        }
    12421249
  • servantly-ask-qa-spam-protection/tags/2.1.5/public/class-servantly-ask-shortcodes.php

    r3699296 r3712148  
    185185                self::enqueue_archive_accent_style();
    186186
    187                 $questions = Servantly_Ask_Archive::get_public_questions();
     187                $servantly_ask_topic = isset( $_GET['servantly_ask_topic'] ) ? sanitize_title( wp_unslash( $_GET['servantly_ask_topic'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     188                if ( '' === $servantly_ask_topic ) {
     189                        $queried = get_query_var( 'servantly_ask_topic' );
     190                        $servantly_ask_topic = is_string( $queried ) ? sanitize_title( $queried ) : '';
     191                }
     192                $servantly_ask_paged  = Servantly_Ask_Public_Question::hub_page_number();
     193                $servantly_ask_result = Servantly_Ask_Archive::query_public_questions(
     194                        array(
     195                                'paged' => $servantly_ask_paged,
     196                                'topic' => $servantly_ask_topic,
     197                        )
     198                );
     199                $questions                  = $servantly_ask_result['posts'];
     200                $servantly_ask_found        = $servantly_ask_result['found'];
     201                $servantly_ask_max_pages    = $servantly_ask_result['max_pages'];
     202                $servantly_ask_topic_terms  = get_terms(
     203                        array(
     204                                'taxonomy'   => Servantly_Ask_Public_Question::TAXONOMY,
     205                                'hide_empty' => true,
     206                        )
     207                );
     208                if ( is_wp_error( $servantly_ask_topic_terms ) ) {
     209                        $servantly_ask_topic_terms = array();
     210                }
    188211
    189212                ob_start();
  • servantly-ask-qa-spam-protection/tags/2.1.5/public/views/public-archive.php

    r3641266 r3712148  
    66 *
    77 * @var WP_Post[] $questions Published archive questions.
     8 * @var int       $servantly_ask_found Number of matching questions.
     9 * @var int       $servantly_ask_max_pages Page count.
     10 * @var int       $servantly_ask_paged Current page.
     11 * @var string    $servantly_ask_topic Active topic slug.
     12 * @var WP_Term[] $servantly_ask_topic_terms Topic terms.
    813 */
    914
    … …  
    2126                </p>
    2227        <?php else : ?>
     28                <?php if ( ! empty( $servantly_ask_topic_terms ) ) : ?>
     29                        <nav class="servantly-ask-topic-filters" aria-label="<?php esc_attr_e( 'Topics', 'servantly-ask-qa-spam-protection' ); ?>">
     30                                <a class="servantly-ask-topic-filter<?php echo '' === $servantly_ask_topic ? ' is-active' : ''; ?>" href="<?php echo esc_url( Servantly_Ask_Public_Question::archive_url() ); ?>">
     31                                        <?php esc_html_e( 'All', 'servantly-ask-qa-spam-protection' ); ?>
     32                                </a>
     33                                <?php foreach ( $servantly_ask_topic_terms as $servantly_ask_topic_term ) : ?>
     34                                        <a class="servantly-ask-topic-filter<?php echo $servantly_ask_topic === $servantly_ask_topic_term->slug ? ' is-active' : ''; ?>" href="<?php echo esc_url( Servantly_Ask_Public_Question::topic_url( $servantly_ask_topic_term->slug ) ); ?>">
     35                                                <?php echo esc_html( $servantly_ask_topic_term->name ); ?>
     36                                        </a>
     37                                <?php endforeach; ?>
     38                        </nav>
     39                <?php endif; ?>
    2340                <?php if ( $servantly_ask_search_enabled ) : ?>
    2441                        <div class="servantly-ask-archive-search">
    … …  
    4562                                ?>
    4663                                <li class="servantly-ask-archive-item" data-question-id="<?php echo esc_attr( (string) $servantly_ask_archive_question_id ); ?>">
     64                                        <?php if ( Servantly_Ask_Public_Question::is_indexable( $servantly_ask_question_post ) ) : ?>
     65                                                <?php
     66                                                $servantly_ask_card_url   = get_permalink( $servantly_ask_question_post );
     67                                                $servantly_ask_card_title = Servantly_Ask_Public_Question::short_title( $servantly_ask_archive_question_id );
     68                                                $servantly_ask_card_date  = Servantly_Ask_Public_Question::answered_label( $servantly_ask_archive_question_id );
     69                                                $servantly_ask_card_terms = get_the_terms( $servantly_ask_archive_question_id, Servantly_Ask_Public_Question::TAXONOMY );
     70                                                ?>
     71                                                <h2 class="servantly-ask-archive-card-title">
     72                                                        <a href="<?php echo esc_url( $servantly_ask_card_url ); ?>"><?php echo esc_html( $servantly_ask_card_title ); ?></a>
     73                                                </h2>
     74                                                <p class="servantly-ask-archive-card-excerpt"><?php echo esc_html( Servantly_Ask_Public_Question::excerpt_from_first_answer( $servantly_ask_archive_question_id, 180 ) ); ?></p>
     75                                                <p class="servantly-ask-archive-card-meta">
     76                                                        <?php if ( $servantly_ask_card_date ) : ?>
     77                                                                <span><?php echo esc_html( $servantly_ask_card_date ); ?></span>
     78                                                        <?php endif; ?>
     79                                                        <?php if ( is_array( $servantly_ask_card_terms ) ) : ?>
     80                                                                <?php foreach ( $servantly_ask_card_terms as $servantly_ask_card_term ) : ?>
     81                                                                        <a class="servantly-ask-topic-tag" href="<?php echo esc_url( Servantly_Ask_Public_Question::topic_url( $servantly_ask_card_term->slug ) ); ?>"><?php echo esc_html( $servantly_ask_card_term->name ); ?></a>
     82                                                                <?php endforeach; ?>
     83                                                        <?php endif; ?>
     84                                                </p>
     85                                                <p class="servantly-ask-archive-card-more">
     86                                                        <a href="<?php echo esc_url( $servantly_ask_card_url ); ?>"><?php esc_html_e( 'Read full answer →', 'servantly-ask-qa-spam-protection' ); ?></a>
     87                                                </p>
     88                                        <?php else : ?>
    4789                                        <div class="servantly-ask-archive-block servantly-ask-archive-question-block">
    4890                                                <span class="servantly-ask-archive-badge servantly-ask-archive-badge-question">
    … …  
    5294                                                        <?php echo esc_html( $servantly_ask_question_post->post_content ); ?>
    5395                                                </div>
    54                                                 <?php if ( $servantly_ask_submitter_name ) : ?>
     96                                                <?php if ( $servantly_ask_submitter_name && '' !== Servantly_Ask_Public_Question::public_asker_name( $servantly_ask_archive_question_id ) ) : ?>
    5597                                                        <p class="servantly-ask-archive-meta">
    5698                                                                <?php
    … …  
    76118                                                </div>
    77119                                        <?php endif; ?>
     120                                        <?php endif; ?>
    78121                                        <?php if ( $servantly_ask_voting_enabled ) : ?>
    79122                                                <div class="servantly-ask-vote-wrap">
    … …  
    93136                        <?php endforeach; ?>
    94137                </ul>
     138                <?php if ( $servantly_ask_max_pages > 1 ) : ?>
     139                        <nav class="servantly-ask-archive-pages" aria-label="<?php esc_attr_e( 'Archive pages', 'servantly-ask-qa-spam-protection' ); ?>">
     140                                <?php
     141                                $servantly_ask_page_url = static function ( $page ) use ( $servantly_ask_topic ) {
     142                                        $page = max( 1, (int) $page );
     143                                        if ( '' !== $servantly_ask_topic ) {
     144                                                $base = Servantly_Ask_Public_Question::topic_url( $servantly_ask_topic );
     145                                                return 1 === $page ? $base : trailingslashit( $base ) . 'page/' . $page . '/';
     146                                        }
     147                                        return Servantly_Ask_Public_Question::hub_page_url( $page );
     148                                };
     149                                ?>
     150                                <?php if ( $servantly_ask_paged > 1 ) : ?>
     151                                        <a href="<?php echo esc_url( $servantly_ask_page_url( $servantly_ask_paged - 1 ) ); ?>"><?php esc_html_e( '← Newer', 'servantly-ask-qa-spam-protection' ); ?></a>
     152                                <?php endif; ?>
     153                                <span>
     154                                        <?php
     155                                        echo esc_html(
     156                                                sprintf(
     157                                                        /* translators: 1: current page, 2: total pages */
     158                                                        __( 'Page %1$d of %2$d', 'servantly-ask-qa-spam-protection' ),
     159                                                        $servantly_ask_paged,
     160                                                        $servantly_ask_max_pages
     161                                                )
     162                                        );
     163                                        ?>
     164                                </span>
     165                                <?php if ( $servantly_ask_paged < $servantly_ask_max_pages ) : ?>
     166                                        <a href="<?php echo esc_url( $servantly_ask_page_url( $servantly_ask_paged + 1 ) ); ?>"><?php esc_html_e( 'Older →', 'servantly-ask-qa-spam-protection' ); ?></a>
     167                                <?php endif; ?>
     168                        </nav>
     169                <?php endif; ?>
    95170        <?php endif; ?>
    96171</div>
  • servantly-ask-qa-spam-protection/tags/2.1.5/readme.txt

    r3699296 r3712148  
    55Tested up to: 7.1
    66Requires PHP: 7.4
    7 Stable tag: 2.0.2
     7Stable tag: 2.1.5
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
  • servantly-ask-qa-spam-protection/tags/2.1.5/servantly-ask-qa-spam-protection.php

    r3699296 r3712148  
    44 * Plugin URI:        https://servantly.org/
    55 * Description:       Collect questions from your community through a guest-friendly, spam-resistant submission form, review them in a private moderation queue, and optionally run a live Q&A projector display.
    6  * Version:           2.0.2
     6 * Version:           2.1.5
    77 * Requires at least: 6.0
    88 * Requires PHP:      7.4
    … …  
    2121}
    2222
    23 define( 'SERVANTLY_ASK_VERSION', '2.0.2' );
     23define( 'SERVANTLY_ASK_VERSION', '2.1.5' );
    2424define( 'SERVANTLY_ASK_PLUGIN_FILE', __FILE__ );
    2525define( 'SERVANTLY_ASK_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    … …  
    5050require_once SERVANTLY_ASK_PLUGIN_DIR . 'includes/class-servantly-ask-presenter-kit.php';
    5151require_once SERVANTLY_ASK_PLUGIN_DIR . 'includes/class-servantly-ask-archive.php';
     52require_once SERVANTLY_ASK_PLUGIN_DIR . 'includes/class-servantly-ask-public-question.php';
    5253require_once SERVANTLY_ASK_PLUGIN_DIR . 'includes/class-servantly-ask-voting.php';
    5354require_once SERVANTLY_ASK_PLUGIN_DIR . 'includes/class-servantly-ask-live-display.php';
    … …  
    7778        Servantly_Ask_Script_Config::init();
    7879        Servantly_Ask_Archive::init();
     80        Servantly_Ask_Public_Question::init();
    7981        Servantly_Ask_Voting::init();
    8082        Servantly_Ask_Live_Display::init();
    … …  
    101103        Servantly_Ask_Post_Type::register_post_type();
    102104        Servantly_Ask_Post_Type::register_taxonomy();
     105        Servantly_Ask_Public_Question::register_taxonomy();
     106        Servantly_Ask_Public_Question::register_rewrites();
    103107        Servantly_Ask_Roles::activate();
    104108        Servantly_Ask_Settings::seed_defaults();
  • servantly-ask-qa-spam-protection/trunk/admin/views/question-detail.php

    r3641266 r3712148  
    2020$servantly_ask_submitter_name  = get_post_meta( $servantly_ask_question_id, 'servantly_ask_submitter_name', true );
    2121$servantly_ask_submitter_email = get_post_meta( $servantly_ask_question_id, 'servantly_ask_submitter_email', true );
    22 $servantly_ask_answer_text     = get_post_meta( $servantly_ask_question_id, 'servantly_ask_answer_text', true );
    2322$servantly_ask_internal_notes  = get_post_meta( $servantly_ask_question_id, 'servantly_ask_internal_notes', true );
    24 $servantly_ask_is_public       = Servantly_Ask_Archive::is_public( $servantly_ask_question_id );
    25 $servantly_ask_can_publish     = Servantly_Ask_Settings::can_publish_to_archive( $servantly_ask_question_post );
    2623$servantly_ask_terms           = get_the_terms( $servantly_ask_question_id, Servantly_Ask_Post_Type::TAXONOMY );
    2724$servantly_ask_category_label  = ( ! empty( $servantly_ask_terms ) && ! is_wp_error( $servantly_ask_terms ) ) ? implode( ', ', wp_list_pluck( $servantly_ask_terms, 'name' ) ) : '';
    … …  
    122119                        <tr>
    123120                                <th scope="row">
    124                                         <label for="servantly_ask_answer_text"><?php esc_html_e( 'Answer', 'servantly-ask-qa-spam-protection' ); ?></label>
    125                                 </th>
    126                                 <td>
    127                                         <textarea name="servantly_ask_answer_text" id="servantly_ask_answer_text" rows="6" class="large-text"><?php echo esc_textarea( $servantly_ask_answer_text ); ?></textarea>
     121                                        <label for="servantly_ask_short_title"><?php esc_html_e( 'Short title', 'servantly-ask-qa-spam-protection' ); ?></label>
     122                                </th>
     123                                <td>
     124                                        <?php $servantly_ask_short_title = Servantly_Ask_Public_Question::short_title( $servantly_ask_question_id ); ?>
     125                                        <input type="text" class="large-text" name="servantly_ask_short_title" id="servantly_ask_short_title" value="<?php echo esc_attr( $servantly_ask_short_title ); ?>" />
     126                                        <?php if ( Servantly_Ask_Archive::is_public( $servantly_ask_question_id ) ) : ?>
    128127                                        <p class="description">
    129                                                 <?php esc_html_e( 'Shown publicly on the archive underneath this question once published. Leave blank to show the question without an answer.', 'servantly-ask-qa-spam-protection' ); ?>
    130                                         </p>
     128                                                <?php esc_html_e( 'This is the heading. The link stays the same unless you edit the link below.', 'servantly-ask-qa-spam-protection' ); ?>
     129                                        </p>
     130                                                <?php $servantly_ask_page_url = get_permalink( $servantly_ask_question_id ); ?>
     131                                                <p>
     132                                                        <a href="<?php echo esc_url( $servantly_ask_page_url ); ?>"><?php esc_html_e( 'View page', 'servantly-ask-qa-spam-protection' ); ?></a>
     133                                                        <code><?php echo esc_html( $servantly_ask_page_url ); ?></code>
     134                                                </p>
     135                                                <p>
     136                                                        <label for="servantly_ask_link_slug"><?php esc_html_e( 'Edit link', 'servantly-ask-qa-spam-protection' ); ?></label><br />
     137                                                        <input type="text" class="regular-text" name="servantly_ask_link_slug" id="servantly_ask_link_slug" value="<?php echo esc_attr( $servantly_ask_question_post->post_name ); ?>" />
     138                                                </p>
     139                                        <?php else : ?>
     140                                                <p class="description">
     141                                                        <?php esc_html_e( 'The page is created when you set the status to Published to Archive and save.', 'servantly-ask-qa-spam-protection' ); ?>
     142                                                </p>
     143                                        <?php endif; ?>
     144                                </td>
     145                        </tr>
     146                        <tr>
     147                                <th scope="row"><?php esc_html_e( 'Asker name', 'servantly-ask-qa-spam-protection' ); ?></th>
     148                                <td>
     149                                        <label>
     150                                                <input type="checkbox" name="servantly_ask_hide_name" value="1" <?php checked( 'yes', get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_HIDE_NAME, true ) ); ?> />
     151                                                <?php esc_html_e( 'Hide the asker’s name on the public archive and the question page', 'servantly-ask-qa-spam-protection' ); ?>
     152                                        </label>
     153                                </td>
     154                        </tr>
     155                        <tr>
     156                                <th scope="row">
     157                                        <label for="servantly_ask_date_answered"><?php esc_html_e( 'Date answered', 'servantly-ask-qa-spam-protection' ); ?></label>
     158                                </th>
     159                                <td>
     160                                        <input type="date" name="servantly_ask_date_answered" id="servantly_ask_date_answered" value="<?php echo esc_attr( (string) get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_DATE_ANSWERED, true ) ); ?>" />
     161                                </td>
     162                        </tr>
     163                        <tr>
     164                                <th scope="row"><?php esc_html_e( 'Answers', 'servantly-ask-qa-spam-protection' ); ?></th>
     165                                <td>
     166                                        <?php
     167                                        $servantly_ask_answer_rows = Servantly_Ask_Public_Question::get_answers( $servantly_ask_question_id );
     168                                        $servantly_ask_answer_rows[] = array(
     169                                                'pastor' => 'other',
     170                                                'custom' => '',
     171                                                'text'   => '',
     172                                        );
     173                                        ?>
     174                                        <?php foreach ( $servantly_ask_answer_rows as $servantly_ask_answer_row ) : ?>
     175                                                <p>
     176                                                        <select name="servantly_ask_answer_pastor[]">
     177                                                                <?php foreach ( Servantly_Ask_Public_Question::author_names() as $servantly_ask_author_name ) : ?>
     178                                                                        <option value="<?php echo esc_attr( sanitize_key( $servantly_ask_author_name ) ); ?>" <?php selected( $servantly_ask_answer_row['pastor'], sanitize_key( $servantly_ask_author_name ) ); ?>>
     179                                                                                <?php echo esc_html( $servantly_ask_author_name ); ?>
     180                                                                        </option>
     181                                                                <?php endforeach; ?>
     182                                                                <option value="other" <?php selected( $servantly_ask_answer_row['pastor'], 'other' ); ?>><?php esc_html_e( 'Other', 'servantly-ask-qa-spam-protection' ); ?></option>
     183                                                        </select>
     184                                                        <input type="text" name="servantly_ask_answer_custom[]" value="<?php echo esc_attr( $servantly_ask_answer_row['custom'] ); ?>" placeholder="<?php esc_attr_e( 'Name if Other', 'servantly-ask-qa-spam-protection' ); ?>" />
     185                                                </p>
     186                                                <textarea name="servantly_ask_answer_text_row[]" rows="5" class="large-text"><?php echo esc_textarea( $servantly_ask_answer_row['text'] ); ?></textarea>
     187                                        <?php endforeach; ?>
     188                                        <p class="description">
     189                                                <?php esc_html_e( 'One block per pastor, in the order they should appear. The original combined answer is kept in sync from these fields.', 'servantly-ask-qa-spam-protection' ); ?>
     190                                        </p>
     191                                </td>
     192                        </tr>
     193                        <tr>
     194                                <th scope="row"><?php esc_html_e( 'Topics', 'servantly-ask-qa-spam-protection' ); ?></th>
     195                                <td>
     196                                        <?php
     197                                        $servantly_ask_all_topics = get_terms(
     198                                                array(
     199                                                        'taxonomy'   => Servantly_Ask_Public_Question::TAXONOMY,
     200                                                        'hide_empty' => false,
     201                                                )
     202                                        );
     203                                        $servantly_ask_set_topics = wp_get_post_terms( $servantly_ask_question_id, Servantly_Ask_Public_Question::TAXONOMY, array( 'fields' => 'ids' ) );
     204                                        if ( is_wp_error( $servantly_ask_set_topics ) ) {
     205                                                $servantly_ask_set_topics = array();
     206                                        }
     207                                        if ( is_array( $servantly_ask_all_topics ) && $servantly_ask_all_topics ) :
     208                                                foreach ( $servantly_ask_all_topics as $servantly_ask_topic_term ) :
     209                                                        ?>
     210                                                        <label style="display:block;margin:0 0 0.25em;">
     211                                                                <input type="checkbox" name="servantly_ask_topics[]" value="<?php echo esc_attr( (string) $servantly_ask_topic_term->term_id ); ?>" <?php checked( in_array( $servantly_ask_topic_term->term_id, $servantly_ask_set_topics, true ) ); ?> />
     212                                                                <?php echo esc_html( $servantly_ask_topic_term->name ); ?>
     213                                                        </label>
     214                                                        <?php
     215                                                endforeach;
     216                                        else :
     217                                                ?>
     218                                                <p class="description"><?php esc_html_e( 'No topics yet.', 'servantly-ask-qa-spam-protection' ); ?></p>
     219                                                <?php
     220                                        endif;
     221                                        ?>
     222                                        <p>
     223                                                <label for="servantly_ask_new_topic"><?php esc_html_e( 'Add a topic', 'servantly-ask-qa-spam-protection' ); ?></label>
     224                                                <input type="text" name="servantly_ask_new_topic" id="servantly_ask_new_topic" class="regular-text" />
     225                                        </p>
     226                                </td>
     227                        </tr>
     228                        <tr>
     229                                <th scope="row">
     230                                        <label for="servantly_ask_video_url"><?php esc_html_e( 'Video URL', 'servantly-ask-qa-spam-protection' ); ?></label>
     231                                </th>
     232                                <td>
     233                                        <input type="url" class="large-text" name="servantly_ask_video_url" id="servantly_ask_video_url" value="<?php echo esc_attr( (string) get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_VIDEO_URL, true ) ); ?>" />
     234                                        <p>
     235                                                <label for="servantly_ask_video_start"><?php esc_html_e( 'Start time (seconds or mm:ss)', 'servantly-ask-qa-spam-protection' ); ?></label>
     236                                                <input type="text" name="servantly_ask_video_start" id="servantly_ask_video_start" value="<?php echo esc_attr( (string) get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_VIDEO_START, true ) ); ?>" />
     237                                        </p>
     238                                </td>
     239                        </tr>
     240                        <tr>
     241                                <th scope="row">
     242                                        <label for="servantly_ask_scripture"><?php esc_html_e( 'Scripture references', 'servantly-ask-qa-spam-protection' ); ?></label>
     243                                </th>
     244                                <td>
     245                                        <input type="text" class="large-text" name="servantly_ask_scripture" id="servantly_ask_scripture" value="<?php echo esc_attr( (string) get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_SCRIPTURE, true ) ); ?>" placeholder="<?php esc_attr_e( '1 Corinthians 8; Luke 9:23', 'servantly-ask-qa-spam-protection' ); ?>" />
     246                                </td>
     247                        </tr>
     248                        <tr>
     249                                <th scope="row">
     250                                        <label for="servantly_ask_related_sermons"><?php esc_html_e( 'Related sermon IDs', 'servantly-ask-qa-spam-protection' ); ?></label>
     251                                </th>
     252                                <td>
     253                                        <?php
     254                                        $servantly_ask_related_ids = get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_RELATED, true );
     255                                        $servantly_ask_related_ids = is_array( $servantly_ask_related_ids ) ? implode( ', ', $servantly_ask_related_ids ) : '';
     256                                        ?>
     257                                        <input type="text" class="large-text" name="servantly_ask_related_sermons" id="servantly_ask_related_sermons" value="<?php echo esc_attr( $servantly_ask_related_ids ); ?>" />
     258                                </td>
     259                        </tr>
     260                        <tr>
     261                                <th scope="row">
     262                                        <label for="servantly_ask_meta_description"><?php esc_html_e( 'Meta description', 'servantly-ask-qa-spam-protection' ); ?></label>
     263                                </th>
     264                                <td>
     265                                        <textarea name="servantly_ask_meta_description" id="servantly_ask_meta_description" rows="3" class="large-text" maxlength="160"><?php echo esc_textarea( (string) get_post_meta( $servantly_ask_question_id, Servantly_Ask_Public_Question::META_DESCRIPTION, true ) ); ?></textarea>
     266                                        <p class="description"><?php esc_html_e( 'Optional. Leave blank to use the start of the first answer.', 'servantly-ask-qa-spam-protection' ); ?></p>
    131267                                </td>
    132268                        </tr>
    … …  
    140276                        </tr>
    141277                </table>
    142 
    143                 <?php if ( $servantly_ask_is_public ) : ?>
    144                         <p>
    145                                 <strong><?php esc_html_e( 'Public archive:', 'servantly-ask-qa-spam-protection' ); ?></strong>
    146                                 <?php esc_html_e( 'This question is published on the public archive.', 'servantly-ask-qa-spam-protection' ); ?>
    147                         </p>
    148                         <?php submit_button( __( 'Remove from Public Archive', 'servantly-ask-qa-spam-protection' ), 'secondary', 'servantly_ask_unpublish_archive', false ); ?>
    149                 <?php elseif ( $servantly_ask_can_publish ) : ?>
    150                         <?php submit_button( __( 'Publish to Public Archive', 'servantly-ask-qa-spam-protection' ), 'secondary', 'servantly_ask_publish_archive', false ); ?>
    151                 <?php else : ?>
    152                         <p class="description">
    153                                 <?php esc_html_e( 'Approve this question (or clear spam checks in Auto-clear mode) before publishing to the public archive.', 'servantly-ask-qa-spam-protection' ); ?>
    154                         </p>
    155                 <?php endif; ?>
    156278
    157279                <?php submit_button( __( 'Save Question', 'servantly-ask-qa-spam-protection' ), 'primary', 'servantly_ask_save_question' ); ?>
  • servantly-ask-qa-spam-protection/trunk/assets/css/servantly-ask-frontend.css

    r3641266 r3712148  
    287287        font-style: italic;
    288288}
     289
     290.servantly-ask-topic-filters,
     291.servantly-ask-archive-card-meta,
     292.servantly-ask-share,
     293.servantly-ask-scripture {
     294        display: flex;
     295        flex-wrap: wrap;
     296        gap: 0.5rem;
     297        align-items: center;
     298}
     299
     300.servantly-ask-topic-filter,
     301.servantly-ask-topic-tag,
     302.servantly-ask-watch,
     303.servantly-ask-share a,
     304.servantly-ask-share button {
     305        display: inline-block;
     306        border: 1px solid var(--servantly-ask-border);
     307        border-radius: 999px;
     308        padding: 0.35em 0.8em;
     309        background: #fff;
     310        color: var(--servantly-ask-text);
     311        text-decoration: none;
     312        font: inherit;
     313        cursor: pointer;
     314}
     315
     316body.servantly-ask-public-page .servantly-ask-share a,
     317body.servantly-ask-public-page .servantly-ask-share button {
     318        border-radius: 999px !important;
     319        box-shadow: none !important;
     320        color: #226053;
     321        line-height: 1.4;
     322}
     323
     324.servantly-ask-topic-filter.is-active,
     325.servantly-ask-watch {
     326        background: var(--servantly-ask-archive-accent, var(--servantly-ask-accent));
     327        border-color: var(--servantly-ask-archive-accent, var(--servantly-ask-accent));
     328        color: #fff;
     329}
     330
     331.servantly-ask-archive-card-title {
     332        margin: 0 0 0.35em;
     333        font-size: 1.25rem;
     334}
     335
     336.servantly-ask-archive-card-title a {
     337        color: inherit;
     338        text-decoration: none;
     339}
     340
     341.servantly-ask-archive-card-excerpt {
     342        margin: 0 0 0.5em;
     343}
     344
     345.servantly-ask-archive-pages {
     346        display: flex;
     347        justify-content: space-between;
     348        gap: 1rem;
     349        margin-top: 1.5rem;
     350}
     351
     352.servantly-ask-archive.is-searching .servantly-ask-archive-pages,
     353.servantly-ask-archive.is-searching .servantly-ask-topic-filters {
     354        display: none;
     355}
     356
     357body.servantly-ask-public-page #ajax-content-wrap > .container-wrap {
     358        background-color: #ffffff !important;
     359}
     360
     361.servantly-ask-single,
     362.servantly-ask-single-wrap {
     363        max-width: 42rem;
     364        margin: 2rem auto;
     365        color: #1a1a1a;
     366}
     367
     368body.servantly-ask-public-page .servantly-ask-single h1,
     369body.servantly-ask-public-page .servantly-ask-single h2,
     370body.servantly-ask-public-page .servantly-ask-single-wrap h1,
     371body.servantly-ask-public-page .servantly-ask-single-wrap h2 {
     372        color: #1a2744;
     373}
     374
     375body.servantly-ask-public-page .servantly-ask-single a,
     376body.servantly-ask-public-page .servantly-ask-single-wrap a {
     377        color: #226053;
     378}
     379
     380.servantly-ask-breadcrumb {
     381        color: var(--servantly-ask-muted);
     382        font-size: 0.95rem;
     383}
     384
     385.servantly-ask-single-question,
     386.servantly-ask-single-answer {
     387        margin: 1.25rem 0;
     388}
     389
     390.servantly-ask-single-cta {
     391        margin-top: 2rem;
     392        font-weight: 700;
     393}
  • servantly-ask-qa-spam-protection/trunk/assets/js/servantly-ask-frontend.js

    r3641266 r3712148  
    149149                function restoreOriginalList() {
    150150                        setStatus( '' );
     151                        var archive = list.closest( '.servantly-ask-archive' );
     152                        if ( archive ) {
     153                                archive.classList.remove( 'is-searching' );
     154                        }
    151155                        list.innerHTML = originalHtml;
    152156                        initArchiveVoting( list );
    … …  
    176180                        activeController = controller;
    177181
     182                        var archive = list.closest( '.servantly-ask-archive' );
     183                        if ( archive ) {
     184                                archive.classList.add( 'is-searching' );
     185                        }
    178186                        setStatus( searchI18n( 'searching', 'Searching…' ) );
    179187
    … …  
    237245                        li.setAttribute( 'data-question-id', String( row.id ) );
    238246
     247                        if ( row.url && row.title ) {
     248                                var heading = document.createElement( 'h2' );
     249                                heading.className = 'servantly-ask-archive-card-title';
     250                                var titleLink = document.createElement( 'a' );
     251                                titleLink.href = row.url;
     252                                titleLink.textContent = row.title;
     253                                heading.appendChild( titleLink );
     254                                li.appendChild( heading );
     255
     256                                if ( row.excerpt ) {
     257                                        var excerpt = document.createElement( 'p' );
     258                                        excerpt.className = 'servantly-ask-archive-card-excerpt';
     259                                        appendHighlighted( excerpt, row.excerpt, term );
     260                                        li.appendChild( excerpt );
     261                                }
     262
     263                                var meta = document.createElement( 'p' );
     264                                meta.className = 'servantly-ask-archive-card-meta';
     265                                if ( row.dateLabel ) {
     266                                        var date = document.createElement( 'span' );
     267                                        date.textContent = row.dateLabel;
     268                                        meta.appendChild( date );
     269                                }
     270                                ( row.topics || [] ).forEach( function ( topic ) {
     271                                        var tag = document.createElement( 'a' );
     272                                        tag.className = 'servantly-ask-topic-tag';
     273                                        tag.href = topic.url;
     274                                        tag.textContent = topic.name;
     275                                        meta.appendChild( tag );
     276                                } );
     277                                if ( meta.childNodes.length ) {
     278                                        li.appendChild( meta );
     279                                }
     280
     281                                var more = document.createElement( 'p' );
     282                                more.className = 'servantly-ask-archive-card-more';
     283                                var moreLink = document.createElement( 'a' );
     284                                moreLink.href = row.url;
     285                                moreLink.textContent = searchI18n( 'readMore', 'Read full answer →' );
     286                                more.appendChild( moreLink );
     287                                li.appendChild( more );
     288
     289                                if ( config.voting && config.voting.enabled ) {
     290                                        li.appendChild( buildVoteMarkup( row ) );
     291                                }
     292                                return li;
     293                        }
     294
    239295                        var questionBlock = document.createElement( 'div' );
    240296                        questionBlock.className = 'servantly-ask-archive-block servantly-ask-archive-question-block';
  • servantly-ask-qa-spam-protection/trunk/includes/class-servantly-ask-archive.php

    r3641266 r3712148  
    6363         * Publish a question to the public archive (`publish` status per spec).
    6464         *
    65          * @param int $post_id Post ID.
     65         * @param int  $post_id Post ID.
     66         * @param bool $force   When true, publish from whatever status the question
     67         *                      is in. The question detail dropdown uses this so
     68         *                      choosing Published to Archive and saving always
     69         *                      publishes. The separate button still requires an
     70         *                      eligible status.
    6671         * @return bool
    6772         */
    68         public static function publish_to_archive( $post_id ) {
     73        public static function publish_to_archive( $post_id, $force = false ) {
    6974                $post_id = absint( $post_id );
    7075                $post    = get_post( $post_id );
    … …  
    7883                }
    7984
    80                 if ( ! Servantly_Ask_Settings::can_publish_to_archive( $post ) ) {
     85                if ( ! $force && ! Servantly_Ask_Settings::can_publish_to_archive( $post ) ) {
    8186                        return false;
    8287                }
    … …  
    193198         */
    194199        public static function get_public_questions( $search = '' ) {
    195                 $args = array(
     200                $result = self::query_public_questions(
     201                        array(
     202                                'search'         => $search,
     203                                'posts_per_page' => 500,
     204                                'paged'          => 1,
     205                        )
     206                );
     207                return $result['posts'];
     208        }
     209
     210        /**
     211         * Paginated public-archive query. Search matches the question, the
     212         * short title, and the answer text, not only the current page.
     213         *
     214         * @param array<string, mixed> $args search, paged, posts_per_page, topic.
     215         * @return array{posts: WP_Post[], found: int, max_pages: int}
     216         */
     217        public static function query_public_questions( $args = array() ) {
     218                $args = wp_parse_args(
     219                        $args,
     220                        array(
     221                                'search'         => '',
     222                                'paged'          => 1,
     223                                'posts_per_page' => Servantly_Ask_Public_Question::PER_PAGE,
     224                                'topic'          => '',
     225                        )
     226                );
     227
     228                $query_args = array(
    196229                        'post_type'              => Servantly_Ask_Post_Type::POST_TYPE,
    197230                        'post_status'            => 'publish',
    198                         'posts_per_page'         => 100,
     231                        'posts_per_page'         => max( 1, (int) $args['posts_per_page'] ),
     232                        'paged'                  => max( 1, (int) $args['paged'] ),
    199233                        'ignore_sticky_posts'    => true,
    200                         'no_found_rows'          => true,
    201234                        'update_post_meta_cache' => true,
    202235                        'meta_query'             => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
    … …  
    208241                );
    209242
    210                 $search = trim( (string) $search );
     243                $topic = sanitize_title( (string) $args['topic'] );
     244                if ( '' !== $topic ) {
     245                        $query_args['tax_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
     246                                array(
     247                                        'taxonomy' => Servantly_Ask_Public_Question::TAXONOMY,
     248                                        'field'    => 'slug',
     249                                        'terms'    => $topic,
     250                                ),
     251                        );
     252                }
     253
     254                $search = trim( (string) $args['search'] );
    211255                if ( '' !== $search ) {
    212                         $args['s'] = $search;
     256                        $query_args['servantly_ask_archive_search'] = $search;
     257                        add_filter( 'posts_where', array( __CLASS__, 'search_where' ), 10, 2 );
    213258                }
    214259
    215260                if ( Servantly_Ask_Settings::is_voting_enabled() && 'votes' === Servantly_Ask_Settings::get_archive_sort_by() ) {
    216                         $args['meta_key'] = Servantly_Ask_Voting::META_VOTE_COUNT; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
    217                         $args['orderby']  = 'meta_value_num';
    218                         $args['order']    = 'DESC';
     261                        $query_args['meta_key'] = Servantly_Ask_Voting::META_VOTE_COUNT; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
     262                        $query_args['orderby']  = 'meta_value_num';
     263                        $query_args['order']    = 'DESC';
    219264                } else {
    220                         $args['orderby'] = 'date';
    221                         $args['order']   = 'DESC';
    222                 }
    223 
    224                 $query = new WP_Query( $args );
    225                 return $query->posts;
     265                        $query_args['orderby'] = 'date';
     266                        $query_args['order']   = 'DESC';
     267                }
     268
     269                $query = new WP_Query( $query_args );
     270
     271                if ( '' !== $search ) {
     272                        remove_filter( 'posts_where', array( __CLASS__, 'search_where' ), 10 );
     273                }
     274
     275                return array(
     276                        'posts'     => $query->posts,
     277                        'found'     => (int) $query->found_posts,
     278                        'max_pages' => (int) $query->max_num_pages,
     279                );
     280        }
     281
     282        /**
     283         * Match question text, short title, and answer text.
     284         *
     285         * @param string   $where SQL WHERE.
     286         * @param WP_Query $query Query.
     287         * @return string
     288         */
     289        public static function search_where( $where, $query ) {
     290                $term = $query->get( 'servantly_ask_archive_search' );
     291                if ( ! is_string( $term ) || '' === $term ) {
     292                        return $where;
     293                }
     294                global $wpdb;
     295                $like   = '%' . $wpdb->esc_like( $term ) . '%';
     296                $where .= $wpdb->prepare(
     297                        " AND ( {$wpdb->posts}.post_title LIKE %s OR {$wpdb->posts}.post_content LIKE %s OR EXISTS ( SELECT 1 FROM {$wpdb->postmeta} sa_pm WHERE sa_pm.post_id = {$wpdb->posts}.ID AND sa_pm.meta_key IN ('servantly_ask_answer_text','servantly_ask_short_title') AND sa_pm.meta_value LIKE %s ) )",
     298                        $like,
     299                        $like,
     300                        $like
     301                );
     302                return $where;
    226303        }
    227304
    … …  
    234311         */
    235312        private static function format_row_for_json( WP_Post $post ) {
     313                $indexable = Servantly_Ask_Public_Question::is_indexable( $post );
     314                $name      = Servantly_Ask_Public_Question::public_asker_name( $post->ID );
     315                $topics    = array();
     316                $terms     = get_the_terms( $post->ID, Servantly_Ask_Public_Question::TAXONOMY );
     317                if ( is_array( $terms ) ) {
     318                        foreach ( $terms as $term ) {
     319                                $topics[] = array(
     320                                        'name' => $term->name,
     321                                        'url'  => Servantly_Ask_Public_Question::topic_url( $term->slug ),
     322                                );
     323                        }
     324                }
    236325                return array(
    237326                        'id'            => $post->ID,
    238327                        'text'          => wp_strip_all_tags( $post->post_content ),
    239                         'submitterName' => (string) get_post_meta( $post->ID, 'servantly_ask_submitter_name', true ),
     328                        'submitterName' => $name,
    240329                        'answerText'    => wp_strip_all_tags( (string) get_post_meta( $post->ID, 'servantly_ask_answer_text', true ) ),
    241330                        'voteCount'     => Servantly_Ask_Voting::get_vote_count( $post->ID ),
     331                        'indexable'     => $indexable,
     332                        'title'         => $indexable ? Servantly_Ask_Public_Question::short_title( $post->ID ) : '',
     333                        'url'           => $indexable ? get_permalink( $post->ID ) : '',
     334                        'excerpt'       => Servantly_Ask_Public_Question::excerpt_from_first_answer( $post->ID, 180 ),
     335                        'dateLabel'     => Servantly_Ask_Public_Question::answered_label( $post->ID ),
     336                        'topics'        => $topics,
    242337                );
    243338        }
  • servantly-ask-qa-spam-protection/trunk/includes/class-servantly-ask-moderation-queue.php

    r3641266 r3712148  
    216216                }
    217217
    218                 self::update_question_status( $post_id, $new_status );
    219 
    220                 $answer_text = isset( $_POST['servantly_ask_answer_text'] )
    221                         ? sanitize_textarea_field( wp_unslash( $_POST['servantly_ask_answer_text'] ) )
    222                         : '';
    223                 update_post_meta( $post_id, 'servantly_ask_answer_text', $answer_text );
     218                self::apply_status_from_detail_save( $post, $new_status );
     219
     220                if ( ! isset( $_POST['servantly_ask_answer_pastor'] ) ) {
     221                        $answer_text = isset( $_POST['servantly_ask_answer_text'] )
     222                                ? sanitize_textarea_field( wp_unslash( $_POST['servantly_ask_answer_text'] ) )
     223                                : '';
     224                        update_post_meta( $post_id, 'servantly_ask_answer_text', $answer_text );
     225                }
    224226
    225227                $internal_notes = isset( $_POST['servantly_ask_internal_notes'] )
    … …  
    228230                update_post_meta( $post_id, 'servantly_ask_internal_notes', $internal_notes );
    229231
     232                if ( class_exists( 'Servantly_Ask_Public_Question' ) ) {
     233                        Servantly_Ask_Public_Question::save_detail_fields( $post_id );
     234                }
     235
    230236                $redirect = Servantly_Ask_Admin_Menu::get_question_detail_url( $post_id );
    231237                $redirect = add_query_arg( 'servantly_ask_saved', '1', $redirect );
    … …  
    233239                wp_safe_redirect( $redirect );
    234240                exit;
     241        }
     242
     243        /**
     244         * Apply the detail-screen status dropdown.
     245         *
     246         * Published to Archive sets the public flag and the status together.
     247         * Any other status takes the question off the public archive. Notes and
     248         * the other fields are saved by the caller either way.
     249         *
     250         * @param WP_Post $post       Question before this save.
     251         * @param string  $new_status Requested status slug.
     252         * @return void
     253         */
     254        private static function apply_status_from_detail_save( WP_Post $post, $new_status ) {
     255                $post_id    = (int) $post->ID;
     256                $was_public = Servantly_Ask_Archive::is_public( $post_id );
     257
     258                if ( 'publish' === $new_status ) {
     259                        if ( ! $was_public ) {
     260                                Servantly_Ask_Archive::publish_to_archive( $post_id, true );
     261                        }
     262                        return;
     263                }
     264
     265                if ( $was_public ) {
     266                        Servantly_Ask_Archive::unpublish_from_archive( $post_id );
     267                }
     268
     269                $current = get_post_status( $post_id );
     270                if ( $current !== $new_status ) {
     271                        self::update_question_status( $post_id, $new_status );
     272                }
    235273        }
    236274
  • servantly-ask-qa-spam-protection/trunk/includes/class-servantly-ask-post-type.php

    r3641266 r3712148  
    5252         * Register the `servantly_ask_q` custom post type.
    5353         *
    54          * The post type is intentionally non-public: questions are private
    55          * submissions, never directly browsable/queryable on the front end.
     54         * Questions stay out of the admin UI and out of site search. Published
     55         * archive answers are publicly queryable so each one can have its own
     56         * URL. Anything that is not on the public archive, or whose short title
     57         * is still awaiting review, is 404'd in Servantly_Ask_Public_Question.
    5658         * `show_ui` is false: questions are managed only via the Servantly Ask
    5759         * moderation queue (guest submission is the only intended entry path).
    … …  
    8284                                'description'         => __( 'A question submitted through the Servantly Ask submission form.', 'servantly-ask-qa-spam-protection' ),
    8385                                'public'              => false,
    84                                 'publicly_queryable'  => false,
     86                                'publicly_queryable'  => true,
    8587                                'exclude_from_search' => true,
    8688                                'show_ui'             => false,
    … …  
    8991                                'show_in_admin_bar'   => false,
    9092                                'show_in_rest'        => false,
    91                                 'query_var'           => false,
     93                                'query_var'           => true,
    9294                                'rewrite'             => false,
    9395                                'has_archive'         => false,
  • servantly-ask-qa-spam-protection/trunk/includes/class-servantly-ask-script-config.php

    r3641266 r3712148  
    197197                                                'questionBadge' => __( 'Question', 'servantly-ask-qa-spam-protection' ),
    198198                                                'answerBadge'   => __( 'Answer', 'servantly-ask-qa-spam-protection' ),
     199                                                'readMore'      => __( 'Read full answer →', 'servantly-ask-qa-spam-protection' ),
    199200                                        ),
    200201                                );
  • servantly-ask-qa-spam-protection/trunk/includes/class-servantly-ask-settings.php

    r3699296 r3712148  
    12381238                }
    12391239
    1240                 return in_array( $post->post_status, array( 'sa_approved', 'sa_displayed', 'sa_answered' ), true );
     1240                if ( in_array( $post->post_status, array( 'sa_approved', 'sa_displayed', 'sa_answered' ), true ) ) {
     1241                        return true;
     1242                }
     1243
     1244                // Status was set to publish without the public flag (dropdown save
     1245                // used to do this). Treat it as not yet on the archive so the
     1246                // publish button and a second save can finish the job.
     1247                return 'publish' === $post->post_status && ! Servantly_Ask_Archive::is_public( $post->ID );
    12411248        }
    12421249
  • servantly-ask-qa-spam-protection/trunk/public/class-servantly-ask-shortcodes.php

    r3699296 r3712148  
    185185                self::enqueue_archive_accent_style();
    186186
    187                 $questions = Servantly_Ask_Archive::get_public_questions();
     187                $servantly_ask_topic = isset( $_GET['servantly_ask_topic'] ) ? sanitize_title( wp_unslash( $_GET['servantly_ask_topic'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
     188                if ( '' === $servantly_ask_topic ) {
     189                        $queried = get_query_var( 'servantly_ask_topic' );
     190                        $servantly_ask_topic = is_string( $queried ) ? sanitize_title( $queried ) : '';
     191                }
     192                $servantly_ask_paged  = Servantly_Ask_Public_Question::hub_page_number();
     193                $servantly_ask_result = Servantly_Ask_Archive::query_public_questions(
     194                        array(
     195                                'paged' => $servantly_ask_paged,
     196                                'topic' => $servantly_ask_topic,
     197                        )
     198                );
     199                $questions                  = $servantly_ask_result['posts'];
     200                $servantly_ask_found        = $servantly_ask_result['found'];
     201                $servantly_ask_max_pages    = $servantly_ask_result['max_pages'];
     202                $servantly_ask_topic_terms  = get_terms(
     203                        array(
     204                                'taxonomy'   => Servantly_Ask_Public_Question::TAXONOMY,
     205                                'hide_empty' => true,
     206                        )
     207                );
     208                if ( is_wp_error( $servantly_ask_topic_terms ) ) {
     209                        $servantly_ask_topic_terms = array();
     210                }
    188211
    189212                ob_start();
  • servantly-ask-qa-spam-protection/trunk/public/views/public-archive.php

    r3641266 r3712148  
    66 *
    77 * @var WP_Post[] $questions Published archive questions.
     8 * @var int       $servantly_ask_found Number of matching questions.
     9 * @var int       $servantly_ask_max_pages Page count.
     10 * @var int       $servantly_ask_paged Current page.
     11 * @var string    $servantly_ask_topic Active topic slug.
     12 * @var WP_Term[] $servantly_ask_topic_terms Topic terms.
    813 */
    914
    … …  
    2126                </p>
    2227        <?php else : ?>
     28                <?php if ( ! empty( $servantly_ask_topic_terms ) ) : ?>
     29                        <nav class="servantly-ask-topic-filters" aria-label="<?php esc_attr_e( 'Topics', 'servantly-ask-qa-spam-protection' ); ?>">
     30                                <a class="servantly-ask-topic-filter<?php echo '' === $servantly_ask_topic ? ' is-active' : ''; ?>" href="<?php echo esc_url( Servantly_Ask_Public_Question::archive_url() ); ?>">
     31                                        <?php esc_html_e( 'All', 'servantly-ask-qa-spam-protection' ); ?>
     32                                </a>
     33                                <?php foreach ( $servantly_ask_topic_terms as $servantly_ask_topic_term ) : ?>
     34                                        <a class="servantly-ask-topic-filter<?php echo $servantly_ask_topic === $servantly_ask_topic_term->slug ? ' is-active' : ''; ?>" href="<?php echo esc_url( Servantly_Ask_Public_Question::topic_url( $servantly_ask_topic_term->slug ) ); ?>">
     35                                                <?php echo esc_html( $servantly_ask_topic_term->name ); ?>
     36                                        </a>
     37                                <?php endforeach; ?>
     38                        </nav>
     39                <?php endif; ?>
    2340                <?php if ( $servantly_ask_search_enabled ) : ?>
    2441                        <div class="servantly-ask-archive-search">
    … …  
    4562                                ?>
    4663                                <li class="servantly-ask-archive-item" data-question-id="<?php echo esc_attr( (string) $servantly_ask_archive_question_id ); ?>">
     64                                        <?php if ( Servantly_Ask_Public_Question::is_indexable( $servantly_ask_question_post ) ) : ?>
     65                                                <?php
     66                                                $servantly_ask_card_url   = get_permalink( $servantly_ask_question_post );
     67                                                $servantly_ask_card_title = Servantly_Ask_Public_Question::short_title( $servantly_ask_archive_question_id );
     68                                                $servantly_ask_card_date  = Servantly_Ask_Public_Question::answered_label( $servantly_ask_archive_question_id );
     69                                                $servantly_ask_card_terms = get_the_terms( $servantly_ask_archive_question_id, Servantly_Ask_Public_Question::TAXONOMY );
     70                                                ?>
     71                                                <h2 class="servantly-ask-archive-card-title">
     72                                                        <a href="<?php echo esc_url( $servantly_ask_card_url ); ?>"><?php echo esc_html( $servantly_ask_card_title ); ?></a>
     73                                                </h2>
     74                                                <p class="servantly-ask-archive-card-excerpt"><?php echo esc_html( Servantly_Ask_Public_Question::excerpt_from_first_answer( $servantly_ask_archive_question_id, 180 ) ); ?></p>
     75                                                <p class="servantly-ask-archive-card-meta">
     76                                                        <?php if ( $servantly_ask_card_date ) : ?>
     77                                                                <span><?php echo esc_html( $servantly_ask_card_date ); ?></span>
     78                                                        <?php endif; ?>
     79                                                        <?php if ( is_array( $servantly_ask_card_terms ) ) : ?>
     80                                                                <?php foreach ( $servantly_ask_card_terms as $servantly_ask_card_term ) : ?>
     81                                                                        <a class="servantly-ask-topic-tag" href="<?php echo esc_url( Servantly_Ask_Public_Question::topic_url( $servantly_ask_card_term->slug ) ); ?>"><?php echo esc_html( $servantly_ask_card_term->name ); ?></a>
     82                                                                <?php endforeach; ?>
     83                                                        <?php endif; ?>
     84                                                </p>
     85                                                <p class="servantly-ask-archive-card-more">
     86                                                        <a href="<?php echo esc_url( $servantly_ask_card_url ); ?>"><?php esc_html_e( 'Read full answer →', 'servantly-ask-qa-spam-protection' ); ?></a>
     87                                                </p>
     88                                        <?php else : ?>
    4789                                        <div class="servantly-ask-archive-block servantly-ask-archive-question-block">
    4890                                                <span class="servantly-ask-archive-badge servantly-ask-archive-badge-question">
    … …  
    5294                                                        <?php echo esc_html( $servantly_ask_question_post->post_content ); ?>
    5395                                                </div>
    54                                                 <?php if ( $servantly_ask_submitter_name ) : ?>
     96                                                <?php if ( $servantly_ask_submitter_name && '' !== Servantly_Ask_Public_Question::public_asker_name( $servantly_ask_archive_question_id ) ) : ?>
    5597                                                        <p class="servantly-ask-archive-meta">
    5698                                                                <?php
    … …  
    76118                                                </div>
    77119                                        <?php endif; ?>
     120                                        <?php endif; ?>
    78121                                        <?php if ( $servantly_ask_voting_enabled ) : ?>
    79122                                                <div class="servantly-ask-vote-wrap">
    … …  
    93136                        <?php endforeach; ?>
    94137                </ul>
     138                <?php if ( $servantly_ask_max_pages > 1 ) : ?>
     139                        <nav class="servantly-ask-archive-pages" aria-label="<?php esc_attr_e( 'Archive pages', 'servantly-ask-qa-spam-protection' ); ?>">
     140                                <?php
     141                                $servantly_ask_page_url = static function ( $page ) use ( $servantly_ask_topic ) {
     142                                        $page = max( 1, (int) $page );
     143                                        if ( '' !== $servantly_ask_topic ) {
     144                                                $base = Servantly_Ask_Public_Question::topic_url( $servantly_ask_topic );
     145                                                return 1 === $page ? $base : trailingslashit( $base ) . 'page/' . $page . '/';
     146                                        }
     147                                        return Servantly_Ask_Public_Question::hub_page_url( $page );
     148                                };
     149                                ?>
     150                                <?php if ( $servantly_ask_paged > 1 ) : ?>
     151                                        <a href="<?php echo esc_url( $servantly_ask_page_url( $servantly_ask_paged - 1 ) ); ?>"><?php esc_html_e( '← Newer', 'servantly-ask-qa-spam-protection' ); ?></a>
     152                                <?php endif; ?>
     153                                <span>
     154                                        <?php
     155                                        echo esc_html(
     156                                                sprintf(
     157                                                        /* translators: 1: current page, 2: total pages */
     158                                                        __( 'Page %1$d of %2$d', 'servantly-ask-qa-spam-protection' ),
     159                                                        $servantly_ask_paged,
     160                                                        $servantly_ask_max_pages
     161                                                )
     162                                        );
     163                                        ?>
     164                                </span>
     165                                <?php if ( $servantly_ask_paged < $servantly_ask_max_pages ) : ?>
     166                                        <a href="<?php echo esc_url( $servantly_ask_page_url( $servantly_ask_paged + 1 ) ); ?>"><?php esc_html_e( 'Older →', 'servantly-ask-qa-spam-protection' ); ?></a>
     167                                <?php endif; ?>
     168                        </nav>
     169                <?php endif; ?>
    95170        <?php endif; ?>
    96171</div>
  • servantly-ask-qa-spam-protection/trunk/readme.txt

    r3699296 r3712148  
    55Tested up to: 7.1
    66Requires PHP: 7.4
    7 Stable tag: 2.0.2
     7Stable tag: 2.1.5
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
  • servantly-ask-qa-spam-protection/trunk/servantly-ask-qa-spam-protection.php

    r3699296 r3712148  
    44 * Plugin URI:        https://servantly.org/
    55 * Description:       Collect questions from your community through a guest-friendly, spam-resistant submission form, review them in a private moderation queue, and optionally run a live Q&A projector display.
    6  * Version:           2.0.2
     6 * Version:           2.1.5
    77 * Requires at least: 6.0
    88 * Requires PHP:      7.4
    … …  
    2121}
    2222
    23 define( 'SERVANTLY_ASK_VERSION', '2.0.2' );
     23define( 'SERVANTLY_ASK_VERSION', '2.1.5' );
    2424define( 'SERVANTLY_ASK_PLUGIN_FILE', __FILE__ );
    2525define( 'SERVANTLY_ASK_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    … …  
    5050require_once SERVANTLY_ASK_PLUGIN_DIR . 'includes/class-servantly-ask-presenter-kit.php';
    5151require_once SERVANTLY_ASK_PLUGIN_DIR . 'includes/class-servantly-ask-archive.php';
     52require_once SERVANTLY_ASK_PLUGIN_DIR . 'includes/class-servantly-ask-public-question.php';
    5253require_once SERVANTLY_ASK_PLUGIN_DIR . 'includes/class-servantly-ask-voting.php';
    5354require_once SERVANTLY_ASK_PLUGIN_DIR . 'includes/class-servantly-ask-live-display.php';
    … …  
    7778        Servantly_Ask_Script_Config::init();
    7879        Servantly_Ask_Archive::init();
     80        Servantly_Ask_Public_Question::init();
    7981        Servantly_Ask_Voting::init();
    8082        Servantly_Ask_Live_Display::init();
    … …  
    101103        Servantly_Ask_Post_Type::register_post_type();
    102104        Servantly_Ask_Post_Type::register_taxonomy();
     105        Servantly_Ask_Public_Question::register_taxonomy();
     106        Servantly_Ask_Public_Question::register_rewrites();
    103107        Servantly_Ask_Roles::activate();
    104108        Servantly_Ask_Settings::seed_defaults();
Note: See TracChangeset for help on using the changeset viewer.