Paginar Página de Tipo de Entrada Personalizada
Creé una página para mis tipos de entradas personalizadas. El código se puede ver en Snippi: http://snippi.com/s/e8852rx
Estoy tratando de insertar paginate_links, pero por alguna razón simplemente no se muestra. Aquí está el código de paginate_links (este código funciona en archivos archive.php normales):
<?php
global $wp_query;
$big = 999999999; // necesitamos un número entero improbable
echo paginate_links( array(
'base' => str_replace( $big, '%#%', get_pagenum_link( $big ) ),
'format' => '?paged=%#%',
'current' => max( 1, get_query_var('paged') ),
'total' => $wp_query->max_num_pages
) );
?>

Lo siguiente funciona para mí (he eliminado todo el formato/metadatos de posts personalizados).
Agregaría que no está claro por qué necesitas usar una página con una plantilla personalizada, en lugar de crear una plantilla llamada archive-portfolio.php
que se usa para las páginas de archivo de tipos de posts personalizados (ver jerarquía de plantillas)
<?php
/*
Plantilla: Portafolio
*/
?>
<?php get_header(); ?>
<div id="container">
<div id="portfolio_content">
<div id="portfolio_wrap">
<?php $loop = new WP_Query(array('post_type' => 'portfolio', 'posts_per_page' => get_option('to_count_portfolio'), 'paged' => get_query_var('paged') ? get_query_var('paged') : 1 )
); ?>
<?php while ( $loop->have_posts() ) : $loop->the_post(); ?>
<span class="title"><?php the_title(); ?></span></br>
<?php endwhile; ?>
<?php
$big = 999999999; // necesitamos un entero improbable
echo paginate_links( array(
'base' => str_replace( $big, '%#%', get_pagenum_link( $big ) ),
'format' => '?paged=%#%',
'current' => max( 1, get_query_var('paged') ),
'total' => $loop->max_num_pages
) );
?>
</div>
</div>
</div>
</div>
<?php get_footer(); ?>

En lugar de usar el enfoque "$loop->have_posts()", como mencionó Stephen Harris, también puedes intentar recorrer las publicaciones de esta manera:
<?php foreach ($loop->get_posts() as $post) { ?>
<span class="title"><?php echo $post->post_title; ?></span></br>
<?php } ?>

¿Has probado a utilizar la página de archivo raíz del tipo de entrada portfolio?
Si trasladas la mayor parte de tu código a un archivo archive-portfolio.php, entonces el bucle debería configurarse correctamente y la paginación debería funcionar sin necesidad de funciones extrañas, trucos o soluciones improvisadas, al igual que ocurre en los archivos de entradas normales.
Esto también significa que no necesitas usar tu propia consulta personalizada, simplemente utiliza el bucle principal, lo que hará que la página cargue más rápido.

Totalmente. Y si el tipo de contenido personalizado está configurado correctamente, la página de archivo tomará el slug del tipo de post sin necesidad de ajustes adicionales: ej, www.misitio/portafolio

Cuando lo cambio a archive-portfolio.php, el código original de paginate_links no funciona. ¿Estoy pasando por alto algo?

Estás haciendo referencia a la consulta principal, por lo que es probable que esté intentando mostrar solo 'posts', en lugar de tu tipo de publicación personalizado.
No estoy seguro de cuál es tu formato exacto, pero reharía la consulta así:
$args = Array( // Arreglo de argumentos para query_posts()
'numberposts' => -1,
'posts_per_page' => get_option('posts_per_page'),
'paged' => $paged,
'post_type' => array('slug-de-tu-tipo-de-publicacion', 'otro-slug-de-tipo-de-publicacion-si-lo-deseas')
);
query_posts($args);
Esto significa que tu código se convertiría en:
<?php
global $wp_query; // No necesitas esto si no estás en una función, por lo que probablemente se pueda eliminar.
$args = Array( // Arreglo de argumentos para query_posts()
'numberposts' => -1,
'posts_per_page' => get_option('posts_per_page'),
'paged' => $paged,
'post_type' => array('slug-de-tu-tipo-de-publicacion', 'otro-slug-de-tipo-de-publicacion-si-lo-deseas')
);
query_posts($args);
$big = 999999999; // necesitamos un entero improbable
echo paginate_links( array(
'base' => str_replace( $big, '%#%', get_pagenum_link( $big ) ),
'format' => '?paged=%#%',
'current' => max( 1, get_query_var('paged') ),
'total' => $wp_query->max_num_pages )
);
?>

Este es un problema con el que he luchado en muchas ocasiones.
Esto es lo que me ha funcionado en esta situación (WP 3.1.1):
<?php
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = array( 'post_type' => 'custom_post_type', 'posts_per_page' => 5, 'paged' => $paged);
$loop = new WP_Query( $args );
if($loop->have_posts()):
while ( $loop->have_posts() ) : $loop->the_post();
//cualquier salida que necesites, como por ejemplo:
the_excerpt();
endwhile;
endif;
?>
Luego, para los controles de paginación:
<?php
echo custom_paginate_links(
array(
'format' => '?paged=%#%',
'current' => max( 1, get_query_var( 'paged' ) ),
'total' => $loop->max_num_pages
) );
?>

Sería mejor crear una función dentro de tu archivo functions.php que maneje la paginación y pueda ser utilizada en todo tu tema, tanto para tipos de post estándar como personalizados.
Con la siguiente función, al agregar get_pagination()
en tu tema, obtendrás navegación donde la necesites. Escribí un post al respecto aquí: http://deadlyhifi.com/2011/06/non-bloated-pagination-for-your-wordpress-functions-php-file/ (y el código está basado originalmente en http://robertbasic.com/blog/wordpress-paging-navigation/)
/**
* Una función de paginación
* @param integer $range: El rango del slider, funciona mejor con números pares
* Funciones de WP utilizadas:
* get_pagenum_link($i) - crea el enlace, ej. http://site.com/page/4
* previous_posts_link(' ‚ '); - retorna el enlace de la página Anterior
* next_posts_link(' é '); - retorna el enlace de la página Siguiente
* http://robertbasic.com/blog/wordpress-paging-navigation/
* modificado por tdB ...
*/
function get_pagination($range = 4) {
global $paged, $wp_query;
// ¿Cuántas páginas tenemos?
if ( !$max_page ) {
$max_page = $wp_query->max_num_pages;
}
// Necesitamos la paginación solo si hay más de 1 página
if ( $max_page > 1 ) {
if ( !$paged ) $paged = 1;
echo '<div class="postpagination">';
// A la página anterior
previous_posts_link('Anterior');
if ( $paged >= $range ) echo '<a href="' . get_pagenum_link(1) . '">1</a>';
if ( $paged >= ($range + 1) ) echo '<span class="page-numbers">…</span>';
// Necesitamos el efecto deslizante solo si hay más páginas que el rango del slider
if ( $max_page > $range ) {
// Cuando estamos más cerca del inicio
if ( $paged < $range ) {
for ( $i = 1; $i <= ($range + 1); $i++ ) {
echo ( $i != $paged ) ? '<a href="' . get_pagenum_link($i) .'">'.$i.'</a>' : '<span class="this-page">'.$i.'</span>';
}
// Cuando estamos más cerca del final
} elseif ( $paged >= ($max_page - ceil(($range/2))) ) {
for ( $i = $max_page - $range; $i <= $max_page; $i++ ) {
echo ( $i != $paged ) ? '<a href="' . get_pagenum_link($i) .'">'.$i.'</a>' : '<span class="this-page">'.$i.'</span>';
}
// En algún punto intermedio
} elseif ( $paged >= $range && $paged < ($max_page - ceil(($range/2))) ) {
for ( $i = ($paged - ceil($range/2)); $i <= ($paged + ceil(($range/2))); $i++ ) {
echo ($i != $paged) ? '<a href="' . get_pagenum_link($i) .'">'.$i.'</a>' : '<span class="this-page">'.$i.'</span>';
}
}
// Menos páginas que el rango, no se necesita efecto deslizante
} else {
for ( $i = 1; $i <= $max_page; $i++ ) {
echo ($i != $paged) ? '<a href="' . get_pagenum_link($i) .'">'.$i.'</a>' : '<span class="this-page">'.$i.'</span>';
}
}
// En la última página, no mostramos el enlace a la última página
if ( $paged <= $max_page - ($range - 1) ) echo '<span class="page-numbers">…</span><a href="' . get_pagenum_link($max_page) . '">' . $max_page . '</a>';
// Página siguiente
next_posts_link('Siguiente');
echo '</div><!-- postpagination -->';
}
}

Nunca he tenido problemas al usar paginación en un archivo personalizado.
En lugar de crear una página y luego escribir mi propia consulta, simplemente copio/pego archive.php
y lo renombro para que coincida con mi tipo de entrada personalizada, por ejemplo archive-videos.php
.
Si realmente deseas usar una plantilla de página personalizada, agrega esto justo antes de tu consulta:
query_posts( array( 'post_type' => 'videos', 'paged' => get_query_var('page') ) )
Más información: http://scribu.net/wordpress/wp-pagenavi/right-way-to-use-query_posts.html
