Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add amp-live-list comments #909

Merged
merged 27 commits into from Jan 31, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bf03e0f
add amp comment walker
DavidCramer Jan 26, 2018
9a9b1c3
add amp comment walker to autoloader
DavidCramer Jan 26, 2018
5f004e8
add comments sanitiser
DavidCramer Jan 26, 2018
82162c3
add comment walker
DavidCramer Jan 26, 2018
04eebf6
add comment and form sanitizers
DavidCramer Jan 26, 2018
80feeed
correct ID's and max items limit
DavidCramer Jan 26, 2018
396aa91
fix new line issue
DavidCramer Jan 26, 2018
1d8728a
Add form posting handler
DavidCramer Jan 26, 2018
b2577c2
rename some methods and add walker depth.
DavidCramer Jan 26, 2018
87c46b6
alternate way to get timestamp
DavidCramer Jan 26, 2018
0822a34
Merge branch 'develop' of https://github.com/Automattic/amp-wp into a…
westonruter Jan 26, 2018
dffb7ca
wip - walker changes.
DavidCramer Jan 30, 2018
98fee1b
Rework submission handling
DavidCramer Jan 30, 2018
014807d
Remove uneeded function
DavidCramer Jan 30, 2018
ae13421
merge develop
DavidCramer Jan 30, 2018
646debb
remove duplicate form sanitizer entry.
DavidCramer Jan 30, 2018
4b38a5b
remove amp markup from walker
DavidCramer Jan 30, 2018
63d83d0
Lockdown sort direction and admin notice stating unsupported.
DavidCramer Jan 30, 2018
310a74a
Opt to inline the descending-ordering comment logic since temporary
westonruter Jan 30, 2018
5ee1709
Fix script tag generation for amp-mustache as custom-template
westonruter Jan 30, 2018
8f1b37c
Implement form reset after comment submission via amp-bind and amp-state
westonruter Jan 30, 2018
82e5218
Disable comment input fields during submission
westonruter Jan 31, 2018
91b0c8d
Fix construction of attributes in comment wrapper elements
westonruter Jan 31, 2018
77dc127
Power comment replies with amp-state
westonruter Jan 31, 2018
ef0e4c3
Show who the commenter is replying to
westonruter Jan 31, 2018
28d760c
Fix setting initial replyToName state
westonruter Jan 31, 2018
8b2232f
Move function with closures out of amp.php for sake of PHP 5.2 check
westonruter Jan 31, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
92 changes: 90 additions & 2 deletions includes/class-amp-theme-support.php
Expand Up @@ -191,8 +191,9 @@ public static function register_hooks() {
add_action( 'template_redirect', array( __CLASS__, 'start_output_buffering' ), 0 );

add_filter( 'wp_list_comments_args', array( __CLASS__, 'amp_set_comments_walker' ), PHP_INT_MAX );

add_action( 'comment_form', array( __CLASS__, 'add_amp_comment_form_templates' ), PHP_INT_MAX );
add_filter( 'comment_reply_link', array( __CLASS__, 'filter_comment_reply_link' ), 10, 4 );
add_filter( 'cancel_comment_reply_link', array( __CLASS__, 'filter_cancel_comment_reply_link' ), 10, 3 );
add_action( 'comment_form', array( __CLASS__, 'add_amp_comment_form_templates' ), 100 );

// @todo Add character conversion.
}
Expand Down Expand Up @@ -532,6 +533,93 @@ public static function add_canonical_link() {
}
}

/**
* Get the ID for the amp-state.
*
* @since 0.7
*
* @param int $post_id Post ID.
* @return string ID for amp-state.
*/
public static function get_comment_form_state_id( $post_id ) {
return sprintf( 'commentform_post_%d', $post_id );
}

/**
* Modify the comment reply link for AMP.
*
* @since 0.7
* @see get_comment_reply_link()
*
* @param string $link The HTML markup for the comment reply link.
* @param array $args An array of arguments overriding the defaults.
* @param WP_Comment $comment The object of the comment being replied.
* @return string Comment reply link.
*/
public static function filter_comment_reply_link( $link, $args, $comment ) {

// Continue to show default link to wp-login when user is not logged-in.
if ( get_option( 'comment_registration' ) && ! is_user_logged_in() ) {
return $link;
}

$state_id = self::get_comment_form_state_id( get_the_ID() );
$tap_state = array(
$state_id => array(
'values' => array(
'comment_parent' => (string) $comment->comment_ID,
),
),
);

// @todo Figure out how to support add_below. Instead of moving the form, what about letting the form get a fixed position?
$link = sprintf(
'<a rel="nofollow" class="comment-reply-link" href="%s" on="%s" aria-label="%s">%s</a>',
esc_attr( '#' . $args['respond_id'] ),
esc_attr( sprintf( 'tap:AMP.setState( %s )', wp_json_encode( $tap_state ) ) ),
esc_attr( sprintf( $args['reply_to_text'], $comment->comment_author ) ),
$args['reply_text']
);
return $link;
}

/**
* Filters the cancel comment reply link HTML.
*
* @since 0.7
* @see get_cancel_comment_reply_link()
*
* @param string $formatted_link The HTML-formatted cancel comment reply link.
* @param string $link Cancel comment reply link URL.
* @param string $text Cancel comment reply link text.
* @return string Cancel reply link.
*/
public function filter_cancel_comment_reply_link( $formatted_link, $link, $text ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@westonruter should be a static function.

unset( $formatted_link, $link );
if ( empty( $text ) ) {
$text = __( 'Click here to cancel reply.', 'default' );
}

$state_id = self::get_comment_form_state_id( get_the_ID() );
$tap_state = array(
$state_id => array(
'values' => array(
'comment_parent' => '0',
),
),
);

$respond_id = 'respond'; // Hard-coded in comment_form() and default value in get_comment_reply_link().
return sprintf(
'<a id="cancel-comment-reply-link" href="%s" %s [hidden]="%s" on="%s">%s</a>',
esc_url( remove_query_arg( 'replytocom' ) . '#' . $respond_id ),
isset( $_GET['replytocom'] ) ? '' : ' hidden', // phpcs:ignore
esc_attr( sprintf( '%s.values.comment_parent == "0"', self::get_comment_form_state_id( get_the_ID() ) ) ),
esc_attr( sprintf( 'tap:AMP.setState( %s )', wp_json_encode( $tap_state ) ) ),
esc_html( $text )
);
}

/**
* Print placeholder for Custom AMP styles.
*
Expand Down
165 changes: 90 additions & 75 deletions includes/sanitizers/class-amp-comments-sanitizer.php
Expand Up @@ -30,101 +30,116 @@ public function sanitize() {
$action = $comment_form->getAttribute( 'action' );
}
$action_path = wp_parse_url( $action, PHP_URL_PATH );
if ( ! preg_match( '#/wp-comments-post\.php$#', $action_path ) ) {
continue;
if ( preg_match( '#/wp-comments-post\.php$#', $action_path ) ) {
$this->process_comment_form( $comment_form );
}
}
}

/**
* Comment form.
*
* @param DOMElement $comment_form Comment form.
*/
protected function process_comment_form( $comment_form ) {
/**
* Element.
*
* @var DOMElement $element
*/

$amp_state = $this->dom->createElement( 'amp-state' );
$state_id = sanitize_key( $comment_form->getAttribute( 'id' ) ) . '_props';
$amp_state->setAttribute( 'id', $state_id );
/**
* Named input elements.
*
* @var DOMElement[][] $form_fields
*/
$form_fields = array();
foreach ( $comment_form->getElementsByTagName( 'input' ) as $element ) {
$name = $element->getAttribute( 'name' );
if ( $name ) {
$form_fields[ $name ][] = $element;
}
}
foreach ( $comment_form->getElementsByTagName( 'textarea' ) as $element ) {
$name = $element->getAttribute( 'name' );
if ( $name ) {
$form_fields[ $name ][] = $element;
}
}

$script = $this->dom->createElement( 'script' );
$script->setAttribute( 'type', 'application/json' );
$amp_state->appendChild( $script );
if ( empty( $form_fields['comment_post_ID'] ) ) {
return;
}
$post_id = (int) $form_fields['comment_post_ID'][0]->getAttribute( 'value' );
$state_id = AMP_Theme_Support::get_comment_form_state_id( $post_id );

$form_state = array(
'values' => array(),
'submitting' => false,
);
$form_state = array(
'values' => array(),
'submitting' => false,
);

$amp_bind_attr_format = AMP_DOM_Utils::get_amp_bind_placeholder_prefix() . '%s';
foreach ( $comment_form->getElementsByTagName( 'input' ) as $input ) {
/**
* Input.
*
* @var DOMElement $input
*/
$name = $input->getAttribute( 'name' );
if ( ! $name ) {
continue;
}
$amp_bind_attr_format = AMP_DOM_Utils::get_amp_bind_placeholder_prefix() . '%s';
foreach ( $form_fields as $name => $form_field ) {
foreach ( $form_field as $element ) {

// @todo Radio and checkbox inputs are not supported yet.
$type = strtolower( $input->getAttribute( 'type' ) );
if ( in_array( $type, array( 'checkbox', 'radio' ), true ) ) {
if ( in_array( strtolower( $element->getAttribute( 'type' ) ), array( 'checkbox', 'radio' ), true ) ) {
continue;
}

$form_state['values'][ $name ] = $input->getAttribute( 'value' );
if ( ! isset( $form_state['values'][ $name ] ) ) {
$form_state['values'][ $name ] = '';
}
$element->setAttribute( sprintf( $amp_bind_attr_format, 'disabled' ), "$state_id.submitting" );

$input->setAttribute( sprintf( $amp_bind_attr_format, 'value' ), "$state_id.values.$name" );
$input->setAttribute( sprintf( $amp_bind_attr_format, 'disabled' ), "$state_id.submitting" );
}
foreach ( $comment_form->getElementsByTagName( 'textarea' ) as $textarea ) {
/**
* Textarea.
*
* @var DOMElement $textarea
*/
$name = $textarea->getAttribute( 'name' );
if ( ! $name ) {
continue;
if ( 'textarea' === strtolower( $element->nodeName ) ) {
$form_state['values'][ $name ] = $element->textContent;
$element->setAttribute( sprintf( $amp_bind_attr_format, 'text' ), "$state_id.values.$name" );
} else {
$form_state['values'][ $name ] = $element->hasAttribute( 'value' ) ? $element->getAttribute( 'value' ) : '';
$element->setAttribute( sprintf( $amp_bind_attr_format, 'value' ), "$state_id.values.$name" );
}
$form_state['values'][ $name ] = $textarea->textContent;

$textarea->setAttribute( sprintf( $amp_bind_attr_format, 'text' ), "$state_id.values.$name" );
$textarea->setAttribute( sprintf( $amp_bind_attr_format, 'disabled' ), "$state_id.submitting" );

// Update the state in response to changing the input.
$textarea->setAttribute( 'on', sprintf(
$element->setAttribute( 'on', sprintf(
'change:AMP.setState( { %s: { values: { %s: event.value } } } )',
$state_id,
wp_json_encode( $name )
) );
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per above, I don't think this for loop will be necessary.


$script->appendChild( $this->dom->createTextNode( wp_json_encode( $form_state ) ) );
$comment_form->insertBefore( $amp_state, $comment_form->firstChild );
// Add amp-state to the document.
$amp_state = $this->dom->createElement( 'amp-state' );
$amp_state->setAttribute( 'id', $state_id );
$script = $this->dom->createElement( 'script' );
$script->setAttribute( 'type', 'application/json' );
$amp_state->appendChild( $script );
$script->appendChild( $this->dom->createTextNode( wp_json_encode( $form_state ) ) );
$comment_form->insertBefore( $amp_state, $comment_form->firstChild );

// Update state when submitting form.
$form_reset_state = $form_state;
unset(
$form_reset_state['values']['author'],
$form_reset_state['values']['email'],
$form_reset_state['values']['url']
);
$on = array(
// Disable the form when submitting.
sprintf(
'submit:AMP.setState( { %s: { submitting: true } } )',
wp_json_encode( $state_id )
),
// Re-enable the form fields when the submission fails.
sprintf(
'submit-error:AMP.setState( { %s: { submitting: false } } )',
wp_json_encode( $state_id )
),
// Reset the form to its initial state (with enabled form fields), except for the author, email, and url.
sprintf(
'submit-success:AMP.setState( { %s: %s } )',
$state_id,
wp_json_encode( $form_reset_state )
),
);
$comment_form->setAttribute( 'on', implode( ';', $on ) );
}
// Update state when submitting form.
$form_reset_state = $form_state;
unset(
$form_reset_state['values']['author'],
$form_reset_state['values']['email'],
$form_reset_state['values']['url']
);
$on = array(
// Disable the form when submitting.
sprintf(
'submit:AMP.setState( { %s: { submitting: true } } )',
wp_json_encode( $state_id )
),
// Re-enable the form fields when the submission fails.
sprintf(
'submit-error:AMP.setState( { %s: { submitting: false } } )',
wp_json_encode( $state_id )
),
// Reset the form to its initial state (with enabled form fields), except for the author, email, and url.
sprintf(
'submit-success:AMP.setState( { %s: %s } )',
$state_id,
wp_json_encode( $form_reset_state )
),
);
$comment_form->setAttribute( 'on', implode( ';', $on ) );
}
}