토론 포럼 스키마 개선

URL이 차단되어 있더라도 해당 위치에 남겨 두시기 바랍니다. 포럼 사용 사례에 대해 그렇게 하는 것이 합리적인지 여부를 논의해 볼 수 있지만, 크롤링이 차단된 상태에서도 URL은 명료성 확보에 도움이 될 수 있습니다.

이것은 여전히 정중한 요청일 뿐이며, 구글조차도 항상 이를 존중하지는 않습니다. 예를 들어, Gmail 내 링크는 구글봇을 즉시 해당 URL로 보내며, 충분한 방문 횟수는 인덱싱과 검색 결과로 이어집니다.

게다가… 우리(또는 당신)는 미래에 상황이 어떻게 변할지 알 수 없습니다. 지금 해결해 두면 나중에 걱정할 필요가 없습니다. 물론 작업 시간이 필요하지만, 투자와 논의도 마찬가지입니다 :smirking_face:

이제 first page의 DiscussionForumPosting에 대한 속성 datePublished가 page=2+의 datePublished와 다르게 나타납니다!

  • first page:
    2015-07-05T22:02:58Z
  • page=2+:
    2015-07-05T22:02:57Z

Google은 불일치하는 데이터를 신뢰하지 않을 것이며, 이로 인해 두 URL이 서로 다른 DiscussionForumPosting을 포함하고 있어 결합할 수 없다고 판단할 수 있습니다.

first page와 page=2+에서 동일한 데이터 소스를 사용하는 것이 좋습니다.
예를 들어, 항상 토픽의 datePublished를 사용하고 첫 번째 게시글의 것은 사용하지 않는 것 등입니다.

first page에 대한 search.google.com/test/rich-results
datePublished: 2015-07-05T22:02:58Z

page=2에 대한 search.google.com/test/rich-results
datePublished: 2015-07-05T22:02:57Z


PR:

항상 datePublished는 토픽에서 가져오고 first_post에서는 가져오지 않습니다. 이를 통해 first page와 page=2+에서 datePublished가 일관되게 유지됩니다.

page=2+에서 text를 반복할 필요는 없습니다. 특히 text가 요약일 뿐이며 first page의 text와 100% 일치하지 않는 경우 page=2+에 text를 설정하지 마십시오.
Google Search Console에서 의도치 않은 결과가 발생: 후속 페이지 page=2+에서 text 속성을 유지하십시오.

크롤러 보기에서 “x일 전 닫힘” 게시글 숨기기

토픽이 닫히면 해당 토픽에 특수 게시글이 추가됩니다:
예를 들어 Google structured data for forums and profile pages - #14 by techAPJ 참조

물론 이 게시글은 없 text 속성이 비어 있습니다. validator.schema.org for …/t/-/286762 → 마지막 댓글 참조:

Google 검색 콘솔 보고서

결론

따라서 이러한 특수한 시스템/공지 게시글은 크롤러 보기에서 제외되어야 합니다.

PR

특수한 시스템/공지 게시글은 콘텐츠가 없으므로 크롤러 보기에서 제외됩니다.

빈 콘텐츠는 Google 검색 콘솔에서 비치명적 문제인 '필드 “text” 누락 (“comment” 내)'을 유발합니다.

가용한 경우, 저자 이름 메타데이터를 전체 이름 프로필 필드로 설정하는 것이 더 합리적일까요? 적어도 prioritize username in ux가 비활성화된 포럼에서는 그렇습니다(다만, URL 필드가 이미 구분을 해주므로 어느 쪽이든 괜찮다고 생각합니다).

이 문제를 해결할 수 있는 방법이 있나요, 아니면 discourse 팀이 코어를 업데이트해야 하나요?

@rrlevering 이 “후속 페이지에 text 속성이 필요 없음” / IsExternalContent() 검사에 대해:

실제 도메인에서 이 테스트 케이스를 가지고 있습니다:

Discourse는 다음에 DiscussionForumPosting을 구현합니다 …

  • 첫 번째 페이지 - 페이지 URL: https://example.org/t/-/12345
    • 속성 url: https://example.org/t/-/12345
    • 속성 text: 설정됨
    • 속성 author: – 설정됨 –
  • page=2 - 페이지 URL: https://example.org/t/-/12345?page=2
    • 속성 url: https://example.org/t/-/12345
    • 속성 text: 전혀 설정되지 않음
    • 속성 author: – 설정됨 –

결과: Google Search Console (실시간 테스트)

  • 첫 번째 페이지:
    DiscussionForumPosting 유효
  • page=2:
    DiscussionForumPosting 유효하지 않음
    • 중요 문제 1건 – "text", "image", 또는 "video" 중 하나가 지정되어야 함

따라서 여기에는 IsExternalContent()에 대한 검사가 없거나, 검사에서 다음에 대해 페이지 URL이 속성 url과 같다고 가정하고 있습니다:

  • 페이지 URL:
    https://example.org/t/-/12345?page=2
  • 속성 url:
    https://example.org/t/-/12345

따라서 현재로서는 Google Search Console에서 유효한 DiscussionForumPosting을 얻으려면 후속 페이지에 속성 text를 반복해야 합니다.

DiscussionForumPosting에 대한 잘못된 스키마 마크업 - 특정 토픽/게시물 URL에만 해당

영향받는 토픽: 총 게시물이 20개를 초과하는 토픽
영향받는 URL: …/t/-/NNN/7부터 …/t/-/NNN/20까지

‘Google Rich Result Test’ 보고서

URL …/t/-/NNN/11: 총 게시물 수가 다른 다양한 토픽 (클릭하여 열기)

– 모든 예시 토픽은 총 게시물 수가 변하지 않도록 ‘닫힘(closed)’ 상태로 설정되어 있습니다. 이 버그 자체도 ‘열림(open)’ 상태의 토픽에도 영향을 미칩니다! –

URLs …/t/-/16968/1부터 …/t/-/16968/38까지: 현재 38개 게시물이 있는 하나의 토픽 (클릭하여 열기)

유효한 스키마 마크업:
– DiscussionForumPosting 자체에는 여전히 불필요한 속성 position: 1이 있습니다. –

무효한 스키마 마크업: author/datePublished 누락

다시 유효한 스키마 마크업: (여기서: @page > 1은 true임):

기술적 고려 사항

1. `@topic_view.prev_page`는 `author`/`datePublished`를 표시할지 여부를 결정하는 데 최선의 해결책이 아닐 수 있습니다.

app/views/topics/show.html.erb#L53-L60

      <% if @topic_view.prev_page %>
        <meta itemprop='datePublished' content='<%= @topic_view.topic.created_at.to_formatted_s(:iso8601) %>'>
        <span itemprop='author' itemscope itemtype="http://schema.org/Person">
          <meta itemprop='name' content='<%= @topic_view.topic.user.username %>'>
          <link itemprop='url' href='<%= Discourse.base_url %>/u/<%= @topic_view.topic.user.username %>'>
        </span>
        <meta itemprop='text' content='<%= @topic_view.topic.excerpt %>'>
      <% end %>
2. `@topic_view.prev_page`의 구현 자체가 버그가 있을 수 있습니다.

lib/topic_view.rb#L113-L115
lib/topic_view.rb#L128-L130
lib/topic_view.rb#L193-L195

    @post_number = [@post_number.to_i, 1].max
# ---
    @page = @page.to_i > 1 ? @page.to_i : calculate_page
# ---
  def prev_page
    @page > 1 && posts.size > 0 ? @page - 1 : nil
  end

여기에 버그가 있는가?
lib/topic_view.rb#L751-L755

  def calculate_page
    posts_count =
      is_mega_topic? ? @post_number : unfiltered_posts.where("post_number <= ?", @post_number).count
    ((posts_count - 1) / @limit) + 1
  end
  • calculate_page는 현재 @post_number를 사용하며 7~20 값에서 실패할 수 있어 예상치 못한 결과를 줄 수 있습니다.
  • ((posts_count - 1) / @limit) + 1의 결과는 다음과 같습니다:
    ((7 - 1) / 20) + 1 = 1.3 = 1
  • 예상되는 페이지 번호는 얼마인가? 아마도 정수가 아닌 값으로 계산한 후 floor/ceil을 통해 의도대로 반올림하고 정수로 타입 캐스팅해야 할 것입니다:
    (((posts_count - 1.0) / (@limit + 0.0)) + 1.0).floor.to_i
  • 의도대로 post_1부터 모든 게시물을 포함하지 않을 수 있으므로 unfiltered_posts.where("post_number <= ?", @post_number)를 @topic.posts와 비교하여 확인해 보십시오.

lib/topic_view.rb#L53-L55
lib/topic_view.rb#L119-L127
lib/topic_view.rb#L835-L841

  def self.chunk_size
    20
  end
# ---
    @chunk_size =
      case
      when @print
        TopicView.print_chunk_size
      else
        TopicView.chunk_size
      end

    @limit ||= @chunk_size
# ---
  def unfiltered_posts
    result = filter_post_types(@topic.posts)
    result = result.with_deleted if @guardian.can_see_deleted_posts?(@topic.category)
    result = result.where("user_id IS NOT NULL") if @exclude_deleted_users
    result = result.where(hidden: false) if @exclude_hidden
    result
  end

결론

이 경계 케이스에서 …

  • 총 게시물이 20개를 초과하는 토픽
  • …/t/-/NNN/7부터 …/t/-/NNN/20까지

… 첫 번째 게시물이 현재 뷰의 일부가 아니었고, 뷰가 여전히 첫 페이지에 있었기 때문에 @topic_view.prev_page가 트리거되지 않았습니다.

따라서 첫 번째 게시물의 컨텍스트 또는 @topic_view.prev_page == true일 때만 렌더링되던 마이크로데이터 스키마 DiscussionForumPosting의 모든 속성이 누락되었습니다.

PR

마이크로데이터 스키마 DiscussionForumPosting의 일부 속성은 첫 번째 게시물의 컨텍스트에서 렌더링됩니다. 첫 번째 게시물이 현재 뷰의 일부가 아닌 경우에도 이러한 속성이 설정되도록 보장하십시오.

음… 예상치 못한 일이네요. 불편을 드려 죄송합니다. URL 비교 검사에서 쿼리 파라미터가 비교 과정에서 누락되는 것 같습니다. 수정을 바로 배포하겠습니다.

이 수정에 대해 최신 업데이트가 있나요?

이번 주 배포된 수정 사항으로 인해 “이것이 외부 URL인지” 확인 시 쿼리 파라미터를 고려하도록 변경되었습니다. 따라서 쿼리 파라미터를 통해 다른 URL에서 OP를 참조하는 포럼(foo와 foo?page=2)의 경우 GSC에서 오류가 보고되지 않을 것입니다.

이번 주 배포된 수정 사항을 통해, "외부 URL인지"를 확인하는 과정에서 쿼리 파라미터를 고려하도록 변경되었습니다.

@rrlevering 다른 포럼 플랫폼에서는 스레드의 각 게시글에 대해 comment - Schema.org Property 스키마를 중첩(nesting)하는 것을 권장했습니다. Discourse에서는 이렇게 하지 않는 것으로 보입니다. 여전히 이 방식을 권장하시나요?

Discourse는 스레드의 각 게시물에 대해 Comment 스키마를 중첩(nest)합니다. Schema Markup Validator 확인하고 DiscussionForumPosting 객체를 열어 중첩된 댓글을 살펴보세요.

감사합니다! DiscussionForumPosting 안에 중첩되어 있어서 놓쳤습니다.