insert( $blocks[ $index ]['innerBlocks'], $path, $position, $block ); } $parent = &$blocks[ $index ]; $slots = $this->get_slots( $parent ); if ( null === $slots ) { return false; } if ( empty( $slots ) ) { // Empty HTML has no insertion point. Only split known single-wrapper containers. $html = implode( '', $parent['innerContent'] ); if ( ! in_array( $parent['blockName'], array( 'core/group', 'core/column' ), true ) || 1 !== preg_match( '/\A(\s*]*>\s*)(<\/div>\s*)\z/s', $html, $matches ) ) { return false; } $parent['innerContent'] = array( $matches[1], null, $matches[2] ); } else { $offset = isset( $slots[ $position ] ) ? $slots[ $position ] : end( $slots ) + 1; array_splice( $parent['innerContent'], $offset, 0, array( null ) ); } array_splice( $parent['innerBlocks'], $position, 0, array( $block ) ); return true; } /** * Removes a block and its corresponding parent placeholder. * * @param array $blocks Blocks by reference. * @param int[] $path Block path. * @return bool */ public function remove( &$blocks, $path ) { $index = array_shift( $path ); if ( ! isset( $blocks[ $index ] ) ) { return false; } if ( empty( $path ) ) { array_splice( $blocks, $index, 1 ); return true; } $parent = &$blocks[ $index ]; if ( 1 === count( $path ) ) { $slots = $this->get_slots( $parent ); $child = $path[0]; if ( null === $slots || ! isset( $slots[ $child ], $parent['innerBlocks'][ $child ] ) ) { return false; } array_splice( $parent['innerContent'], $slots[ $child ], 1 ); array_splice( $parent['innerBlocks'], $child, 1 ); return true; } return isset( $parent['innerBlocks'] ) && $this->remove( $parent['innerBlocks'], $path ); } /** * Validates the one-to-one correspondence of children and placeholders. * * @param array $container Parent block. * @return int[]|null */ private function get_slots( $container ) { if ( ! isset( $container['innerContent'], $container['innerBlocks'] ) || ! is_array( $container['innerContent'] ) || ! is_array( $container['innerBlocks'] ) ) { return null; } $slots = array(); foreach ( $container['innerContent'] as $index => $chunk ) { if ( null === $chunk ) { $slots[] = $index; } elseif ( ! is_string( $chunk ) ) { return null; } } return count( $slots ) === count( $container['innerBlocks'] ) ? $slots : null; } }