├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── __init__.py ├── ez_setup.py ├── manage.py ├── requirements.pip ├── settings.py ├── setup.py ├── urls.py └── wp ├── __init__.py ├── admin.py ├── management ├── __init__.py └── commands │ ├── __init__.py │ └── import_to_blogango.py ├── models.py ├── templates └── wp │ ├── recent_comments.html │ └── recent_posts.html ├── templatetags ├── __init__.py └── wordpress_tags.py ├── tests.py └── views.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.log 3 | *.temp 4 | localsettings.py 5 | *secrets.py 6 | *secret.py 7 | *.wpr 8 | *.kpf 9 | *.pydev* 10 | *.project 11 | blogango 12 | taggit 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | install: 5 | - "pip install -r requirements.pip --use-mirrors" 6 | - "pip install coveralls --use-mirrors" 7 | script: coverage run --source=wp manage.py test 8 | after_success: 9 | - coveralls 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2013, Agiliq Solutions 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/agiliq/django-wordpress.png?branch=master)](https://travis-ci.org/agiliq/django-wordpress) 2 | [![Coverage Status](https://coveralls.io/repos/agiliq/django-wordpress/badge.png?branch=master)](https://coveralls.io/r/agiliq/django-wordpress?branch=master) 3 | 4 | 5 | This is a Django App which allows easy 6 | integration between athe Django and Wordpress. 7 | 8 | All the core Wordpress tables are made available as Django models. 9 | 10 | Installation & Usage 11 | -------------------- 12 | * pip install -e git+git@github.com:agiliq/django-wordpress.git#egg=django-wordpress 13 | * Add 'wp' to installed apps. 14 | * Enter the wordpress database name in your database settings. 15 | 16 | Now, you can edit the wordpress database using django admin. And you can use templatetags for showing latest posts etc. 17 | 18 | More details are available at 19 | http://agiliq.com/blog/2010/01/wordpress-and-django-best-buddies/ 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agiliq/django-wordpress/8e67234800d223f764f3c19b99c5d7274b239795/__init__.py -------------------------------------------------------------------------------- /ez_setup.py: -------------------------------------------------------------------------------- 1 | #!python 2 | """Bootstrap setuptools installation 3 | 4 | If you want to use setuptools in your package's setup.py, just include this 5 | file in the same directory with it, and add this to the top of your setup.py:: 6 | 7 | from ez_setup import use_setuptools 8 | use_setuptools() 9 | 10 | If you want to require a specific version of setuptools, set a download 11 | mirror, or use an alternate download directory, you can do so by supplying 12 | the appropriate options to ``use_setuptools()``. 13 | 14 | This file can also be run as a script to install or upgrade setuptools. 15 | """ 16 | import sys 17 | DEFAULT_VERSION = "0.6c11" 18 | DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] 19 | 20 | md5_data = { 21 | 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', 22 | 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', 23 | 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', 24 | 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', 25 | 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', 26 | 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', 27 | 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 28 | 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 29 | 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 30 | 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 31 | 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090', 32 | 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4', 33 | 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7', 34 | 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5', 35 | 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de', 36 | 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b', 37 | 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2', 38 | 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086', 39 | 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 40 | 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 41 | 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 42 | 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 43 | 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 44 | 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 45 | 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 46 | 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 47 | 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 48 | 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 49 | 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', 50 | 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', 51 | 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', 52 | 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', 53 | 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', 54 | 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', 55 | 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', 56 | 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', 57 | 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', 58 | 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', 59 | 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03', 60 | 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a', 61 | 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6', 62 | 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', 63 | } 64 | 65 | import sys, os 66 | try: from hashlib import md5 67 | except ImportError: from md5 import md5 68 | 69 | def _validate_md5(egg_name, data): 70 | if egg_name in md5_data: 71 | digest = md5(data).hexdigest() 72 | if digest != md5_data[egg_name]: 73 | print >>sys.stderr, ( 74 | "md5 validation of %s failed! (Possible download problem?)" 75 | % egg_name 76 | ) 77 | sys.exit(2) 78 | return data 79 | 80 | def use_setuptools( 81 | version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, 82 | download_delay=15 83 | ): 84 | """Automatically find/download setuptools and make it available on sys.path 85 | 86 | `version` should be a valid setuptools version number that is available 87 | as an egg for download under the `download_base` URL (which should end with 88 | a '/'). `to_dir` is the directory where setuptools will be downloaded, if 89 | it is not already available. If `download_delay` is specified, it should 90 | be the number of seconds that will be paused before initiating a download, 91 | should one be required. If an older version of setuptools is installed, 92 | this routine will print a message to ``sys.stderr`` and raise SystemExit in 93 | an attempt to abort the calling script. 94 | """ 95 | was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules 96 | def do_download(): 97 | egg = download_setuptools(version, download_base, to_dir, download_delay) 98 | sys.path.insert(0, egg) 99 | import setuptools; setuptools.bootstrap_install_from = egg 100 | try: 101 | import pkg_resources 102 | except ImportError: 103 | return do_download() 104 | try: 105 | pkg_resources.require("setuptools>="+version); return 106 | except pkg_resources.VersionConflict, e: 107 | if was_imported: 108 | print >>sys.stderr, ( 109 | "The required version of setuptools (>=%s) is not available, and\n" 110 | "can't be installed while this script is running. Please install\n" 111 | " a more recent version first, using 'easy_install -U setuptools'." 112 | "\n\n(Currently using %r)" 113 | ) % (version, e.args[0]) 114 | sys.exit(2) 115 | else: 116 | del pkg_resources, sys.modules['pkg_resources'] # reload ok 117 | return do_download() 118 | except pkg_resources.DistributionNotFound: 119 | return do_download() 120 | 121 | def download_setuptools( 122 | version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, 123 | delay = 15 124 | ): 125 | """Download setuptools from a specified location and return its filename 126 | 127 | `version` should be a valid setuptools version number that is available 128 | as an egg for download under the `download_base` URL (which should end 129 | with a '/'). `to_dir` is the directory where the egg will be downloaded. 130 | `delay` is the number of seconds to pause before an actual download attempt. 131 | """ 132 | import urllib2, shutil 133 | egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) 134 | url = download_base + egg_name 135 | saveto = os.path.join(to_dir, egg_name) 136 | src = dst = None 137 | if not os.path.exists(saveto): # Avoid repeated downloads 138 | try: 139 | from distutils import log 140 | if delay: 141 | log.warn(""" 142 | --------------------------------------------------------------------------- 143 | This script requires setuptools version %s to run (even to display 144 | help). I will attempt to download it for you (from 145 | %s), but 146 | you may need to enable firewall access for this script first. 147 | I will start the download in %d seconds. 148 | 149 | (Note: if this machine does not have network access, please obtain the file 150 | 151 | %s 152 | 153 | and place it in this directory before rerunning this script.) 154 | ---------------------------------------------------------------------------""", 155 | version, download_base, delay, url 156 | ); from time import sleep; sleep(delay) 157 | log.warn("Downloading %s", url) 158 | src = urllib2.urlopen(url) 159 | # Read/write all in one block, so we don't create a corrupt file 160 | # if the download is interrupted. 161 | data = _validate_md5(egg_name, src.read()) 162 | dst = open(saveto,"wb"); dst.write(data) 163 | finally: 164 | if src: src.close() 165 | if dst: dst.close() 166 | return os.path.realpath(saveto) 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | def main(argv, version=DEFAULT_VERSION): 204 | """Install or upgrade setuptools and EasyInstall""" 205 | try: 206 | import setuptools 207 | except ImportError: 208 | egg = None 209 | try: 210 | egg = download_setuptools(version, delay=0) 211 | sys.path.insert(0,egg) 212 | from setuptools.command.easy_install import main 213 | return main(list(argv)+[egg]) # we're done here 214 | finally: 215 | if egg and os.path.exists(egg): 216 | os.unlink(egg) 217 | else: 218 | if setuptools.__version__ == '0.0.1': 219 | print >>sys.stderr, ( 220 | "You have an obsolete version of setuptools installed. Please\n" 221 | "remove it from your system entirely before rerunning this script." 222 | ) 223 | sys.exit(2) 224 | 225 | req = "setuptools>="+version 226 | import pkg_resources 227 | try: 228 | pkg_resources.require(req) 229 | except pkg_resources.VersionConflict: 230 | try: 231 | from setuptools.command.easy_install import main 232 | except ImportError: 233 | from easy_install import main 234 | main(list(argv)+[download_setuptools(delay=0)]) 235 | sys.exit(0) # try to force an exit 236 | else: 237 | if argv: 238 | from setuptools.command.easy_install import main 239 | main(argv) 240 | else: 241 | print "Setuptools version",version,"or greater has been installed." 242 | print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' 243 | 244 | def update_md5(filenames): 245 | """Update our built-in md5 registry""" 246 | 247 | import re 248 | 249 | for name in filenames: 250 | base = os.path.basename(name) 251 | f = open(name,'rb') 252 | md5_data[base] = md5(f.read()).hexdigest() 253 | f.close() 254 | 255 | data = [" %r: %r,\n" % it for it in md5_data.items()] 256 | data.sort() 257 | repl = "".join(data) 258 | 259 | import inspect 260 | srcfile = inspect.getsourcefile(sys.modules[__name__]) 261 | f = open(srcfile, 'rb'); src = f.read(); f.close() 262 | 263 | match = re.search("\nmd5_data = {\n([^}]+)}", src) 264 | if not match: 265 | print >>sys.stderr, "Internal error!" 266 | sys.exit(2) 267 | 268 | src = src[:match.start(1)] + repl + src[match.end(1):] 269 | f = open(srcfile,'w') 270 | f.write(src) 271 | f.close() 272 | 273 | 274 | if __name__=='__main__': 275 | if len(sys.argv)>2 and sys.argv[1]=='--md5update': 276 | update_md5(sys.argv[2:]) 277 | else: 278 | main(sys.argv[1:]) 279 | 280 | 281 | 282 | 283 | 284 | 285 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /requirements.pip: -------------------------------------------------------------------------------- 1 | -e git+https://github.com/django/django.git#egg=django 2 | MySQL-python==1.2.4 3 | coverage==3.6 4 | -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for wp_backport project. 2 | 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | 6 | ADMINS = ( 7 | # ('Your Name', 'your_email@domain.com'), 8 | ) 9 | 10 | MANAGERS = ADMINS 11 | 12 | 13 | # Local time zone for this installation. Choices can be found here: 14 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 15 | # although not all choices may be available on all operating systems. 16 | # If running in a Windows environment this must be set to the same as your 17 | # system time zone. 18 | TIME_ZONE = 'America/Chicago' 19 | 20 | # Language code for this installation. All choices can be found here: 21 | # http://www.i18nguy.com/unicode/language-identifiers.html 22 | LANGUAGE_CODE = 'en-us' 23 | 24 | SITE_ID = 1 25 | 26 | # If you set this to False, Django will make some optimizations so as not 27 | # to load the internationalization machinery. 28 | USE_I18N = True 29 | 30 | # Absolute path to the directory that holds media. 31 | # Example: "/home/media/media.lawrence.com/" 32 | MEDIA_ROOT = '' 33 | 34 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 35 | # trailing slash if there is a path component (optional in other cases). 36 | # Examples: "http://media.lawrence.com", "http://example.com/media/" 37 | MEDIA_URL = '' 38 | STATIC_URL = '/static/' 39 | 40 | 41 | # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a 42 | # trailing slash. 43 | # Examples: "http://foo.com/media/", "/media/". 44 | ADMIN_MEDIA_PREFIX = '/media/' 45 | 46 | # Make this unique, and don't share it with anybody. 47 | SECRET_KEY = '@cu79xj-4n7aenosbs#v0j(bj$$0#)h457=9k+wkm7jkxi**_%' 48 | 49 | # List of callables that know how to import templates from various sources. 50 | TEMPLATE_LOADERS = ( 51 | 'django.template.loaders.filesystem.Loader', 52 | 'django.template.loaders.app_directories.Loader', 53 | # 'django.template.loaders.eggs.load_template_source', 54 | ) 55 | 56 | MIDDLEWARE_CLASSES = ( 57 | "django.contrib.sessions.middleware.SessionMiddleware", 58 | "django.contrib.auth.middleware.AuthenticationMiddleware", 59 | "django.middleware.common.CommonMiddleware", 60 | "django.middleware.csrf.CsrfViewMiddleware", 61 | "django.contrib.messages.middleware.MessageMiddleware", 62 | ) 63 | 64 | #ROOT_URLCONF = 'wp_backport.urls' 65 | ROOT_URLCONF = 'urls' 66 | 67 | TEMPLATE_DIRS = ( 68 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 69 | # Always use forward slashes, even on Windows. 70 | # Don't forget to use absolute paths, not relative paths. 71 | ) 72 | 73 | INSTALLED_APPS = ( 74 | "django.contrib.admin", 75 | "django.contrib.auth", 76 | "django.contrib.contenttypes", 77 | "django.contrib.redirects", 78 | "django.contrib.sessions", 79 | "django.contrib.sites", 80 | "django.contrib.sitemaps", 81 | "django.contrib.staticfiles", 82 | "wp", 83 | ) 84 | 85 | try: 86 | from localsettings import * 87 | except ImportError: 88 | pass 89 | 90 | DATABASES = { 91 | 'default': { 92 | 'ENGINE': 'django.db.backends.sqlite3', 93 | 'HOST': '127.0.0.1', 94 | 'NAME': 'wordpress.db', 95 | 'USER': '', 96 | 'PASSWORD': '', 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import ez_setup 2 | ez_setup.use_setuptools() 3 | from setuptools import setup, find_packages 4 | setup( 5 | name = "django-wordpress", 6 | version = "0.2", 7 | packages = find_packages(), 8 | author = "Agiliq and friends", 9 | author_email ="shabda@agiliq.com", 10 | description = "Django app to easily integrate Wordpress.", 11 | url = "http://github.com/agiliq/django-wordpress", 12 | include_package_data = True 13 | ) 14 | -------------------------------------------------------------------------------- /urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | from django.contrib import admin 5 | admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | # Example: 9 | # (r'^wp_backport/', include('wp_backport.foo.urls')), 10 | 11 | # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 12 | # to INSTALLED_APPS to enable admin documentation: 13 | # (r'^admin/doc/', include('django.contrib.admindocs.urls')), 14 | 15 | # Uncomment the next line to enable the admin: 16 | (r'^admin/', include(admin.site.urls)), 17 | ) 18 | -------------------------------------------------------------------------------- /wp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agiliq/django-wordpress/8e67234800d223f764f3c19b99c5d7274b239795/wp/__init__.py -------------------------------------------------------------------------------- /wp/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from wp.models import Post, PostMeta, WpUser, UserMeta, Term, TermTaxonomy, TermRelationship 3 | from wp.models import Comment, CommentMeta, Link, Option 4 | 5 | 6 | admin.site.register(Post) 7 | admin.site.register(PostMeta) 8 | admin.site.register(WpUser) 9 | admin.site.register(UserMeta) 10 | admin.site.register(Term) 11 | admin.site.register(TermTaxonomy) 12 | admin.site.register(TermRelationship) 13 | 14 | admin.site.register(Comment) 15 | admin.site.register(CommentMeta) 16 | admin.site.register(Link) 17 | admin.site.register(Option) -------------------------------------------------------------------------------- /wp/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agiliq/django-wordpress/8e67234800d223f764f3c19b99c5d7274b239795/wp/management/__init__.py -------------------------------------------------------------------------------- /wp/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agiliq/django-wordpress/8e67234800d223f764f3c19b99c5d7274b239795/wp/management/commands/__init__.py -------------------------------------------------------------------------------- /wp/management/commands/import_to_blogango.py: -------------------------------------------------------------------------------- 1 | 2 | from django.conf import settings 3 | from django.contrib.auth.models import User 4 | from django.core.management.base import BaseCommand, CommandError 5 | from django.template.defaultfilters import slugify 6 | 7 | from wp.models import Post, Comment as WpComment, TermTaxonomy, TermRelationship, Term 8 | from blogango.models import BlogEntry, Comment, Reaction 9 | 10 | def get_auth_user(wp_author): 11 | try: 12 | auth_user = User.objects.get(username='wp_%s' % (wp_author.user_login)) 13 | except User.DoesNotExist: 14 | auth_user = User.objects.create_user(username='wp_%s' % (wp_author.user_login), 15 | email = wp_author.user_email) 16 | auth_user.first_name = wp_author.user_nicename 17 | auth_user.save() 18 | return auth_user 19 | 20 | COMMENT_AGENTS = ['btc_reddit', 'btc_yc', 'btc_twitter', 'btc_friendfeed', 'btc_blog'] 21 | class Command(BaseCommand): 22 | help = 'Import blog posts from wordpress to blogango' 23 | def handle(self, *args, **kwargs): 24 | if 'blogango' not in settings.INSTALLED_APPS: 25 | raise CommandError('Add blogango to installed apps to import posts from wordpress') 26 | 27 | # get the offset id from blogango 28 | blog_entries = BlogEntry.objects.all().order_by('-id') 29 | offset = blog_entries.count() and blog_entries[0].id or 0 30 | wp_posts = Post.objects.filter(id__gt=offset, post_status='publish', post_type='post') 31 | 32 | for wp_post in wp_posts: 33 | # insert into BlogEntry 34 | print wp_post.post_date 35 | 36 | blog_entry = BlogEntry.objects.create(id=wp_post.id, 37 | title=wp_post.post_title, 38 | slug=slugify(wp_post.post_title), 39 | text=wp_post.post_content, 40 | created_by=get_auth_user(wp_post.post_author)) 41 | blog_entry.created_on = wp_post.post_date 42 | blog_entry.save() 43 | 44 | tables = ['wp_term_taxonomy', 'wp_term_relationships'] 45 | where = ['wp_term_relationships.object_id = %s', 46 | 'wp_term_taxonomy.term_taxonomy_id = wp_term_relationships.term_taxonomy_id', 47 | 'wp_term_taxonomy.term_id = wp_terms.term_id', 48 | 'wp_term_taxonomy.taxonomy = %s'] 49 | 50 | # get categories 51 | categories = Term.objects.extra(tables=tables, where=where, params=[wp_post.id, 'category']) 52 | for category in categories:blog_entry.tags.add(category.name) 53 | 54 | # get tags 55 | # tags = Term.objects.extra(tables=tables, where=where, params=[wp_post.id, 'post_tag']) 56 | # for tag in tags:blog_entry.tags.add(tag.name) 57 | 58 | # add comments 59 | wp_comments = WpComment.objects.filter(comment_post_id=wp_post.id, comment_approved=1) 60 | for wp_comment in wp_comments: 61 | if wp_comment.comment_type == 'pingback':continue 62 | if wp_comment.comment_agent in COMMENT_AGENTS: 63 | comment = Reaction.objects.create(text=wp_comment.comment_content, 64 | comment_for=blog_entry, 65 | user_name=wp_comment.comment_author, 66 | user_url=wp_comment.comment_author_url, 67 | source=wp_comment.comment_agent.lstrip('btc_')) 68 | else: 69 | comment = Comment.objects.create(text=wp_comment.comment_content, 70 | comment_for=blog_entry, 71 | user_name=wp_comment.comment_author, 72 | user_url=wp_comment.comment_author_url, 73 | email_id=wp_comment.comment_author_email) 74 | comment.created_on = wp_comment.comment_date 75 | comment.is_public = True 76 | comment.save() 77 | -------------------------------------------------------------------------------- /wp/models.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.db import models 4 | 5 | 6 | class WpUser(models.Model): 7 | """This has been given a wp prefix, as contrib.user is so commonly 8 | imported name, and we do not want to namespace this everywhere.""" 9 | 10 | id = models.BigIntegerField(db_column='ID', primary_key=True) # Field name made lowercase. 11 | user_login = models.CharField(max_length=60) 12 | user_pass = models.CharField(max_length=64) 13 | user_nicename = models.CharField(max_length=50) 14 | user_email = models.CharField(max_length=100) 15 | user_url = models.CharField(max_length=100) 16 | user_registered = models.DateTimeField() 17 | user_activation_key = models.CharField(max_length=60) 18 | user_status = models.IntegerField() 19 | display_name = models.CharField(max_length=250) 20 | 21 | class Meta: 22 | verbose_name = u'User' 23 | verbose_name_plural = u'Users' 24 | db_table = 'wp_users' 25 | 26 | def __unicode__(self): 27 | return self.user_nicename 28 | 29 | class Link(models.Model): 30 | link_id = models.BigIntegerField(primary_key=True) 31 | link_url = models.CharField(max_length=255) 32 | link_name = models.CharField(max_length=255) 33 | link_image = models.CharField(max_length=255) 34 | link_target = models.CharField(max_length=25) 35 | link_description = models.CharField(max_length=255) 36 | link_visible = models.CharField(max_length=20) 37 | link_owner = models.ForeignKey(WpUser, db_column='link_owner') 38 | link_rating = models.IntegerField() 39 | link_updated = models.DateTimeField() 40 | link_rel = models.CharField(max_length=255) 41 | link_notes = models.TextField() 42 | link_rss = models.CharField(max_length=255) 43 | 44 | class Meta: 45 | verbose_name = u'Link' 46 | verbose_name_plural = u'Link' 47 | db_table = u'wp_links' 48 | 49 | def __unicode__(self): 50 | return self.link_name 51 | 52 | class Option(models.Model): 53 | option_id = models.BigIntegerField(primary_key=True) 54 | option_name = models.CharField(unique=True, max_length=64) 55 | option_value = models.TextField() 56 | autoload = models.CharField(max_length=20) 57 | 58 | class Meta: 59 | verbose_name = u'Option' 60 | verbose_name_plural = u'Options' 61 | db_table = u'wp_options' 62 | 63 | def __unicode__(self): 64 | return self.option_name 65 | 66 | class Post(models.Model): 67 | id = models.BigIntegerField(db_column='ID', primary_key=True) # Field name made lowercase. 68 | post_author = models.ForeignKey(WpUser, db_column='post_author') 69 | post_parent = models.ForeignKey('self', db_column='post_parent') 70 | post_date = models.DateTimeField() 71 | post_date_gmt = models.DateTimeField() 72 | post_content = models.TextField() 73 | post_title = models.TextField() 74 | post_excerpt = models.TextField() 75 | post_status = models.CharField(max_length=20) 76 | comment_status = models.CharField(max_length=20) 77 | ping_status = models.CharField(max_length=20) 78 | post_password = models.CharField(max_length=20) 79 | post_name = models.CharField(max_length=200) 80 | to_ping = models.TextField() 81 | pinged = models.TextField() 82 | post_modified = models.DateTimeField() 83 | post_modified_gmt = models.DateTimeField() 84 | post_content_filtered = models.TextField() 85 | 86 | guid = models.CharField(max_length=255) 87 | menu_order = models.IntegerField() 88 | post_type = models.CharField(max_length=20) 89 | post_mime_type = models.CharField(max_length=100) 90 | comment_count = models.BigIntegerField() 91 | 92 | class Meta: 93 | verbose_name = u'Post' 94 | verbose_name_plural = u'Posts' 95 | db_table = u'wp_posts' 96 | 97 | def __unicode__(self): 98 | return self.post_title or str(self.id) 99 | 100 | def get_absolute_url(self): 101 | return self.guid 102 | 103 | class PostMeta(models.Model): 104 | meta_id = models.BigIntegerField(primary_key=True) 105 | post = models.ForeignKey(Post) 106 | meta_key = models.CharField(max_length=255, blank=True) 107 | meta_value = models.TextField(blank=True) 108 | 109 | class Meta: 110 | verbose_name = u'Post Meta' 111 | verbose_name_plural = u'Posts Meta' 112 | db_table = u'wp_postmeta' 113 | 114 | def __unicode__(self): 115 | return self.post.post_title or str(self.post.id) 116 | 117 | class Comment(models.Model): 118 | comment_id = models.BigIntegerField(db_column='comment_ID', primary_key=True) # Field name made lowercase. 119 | comment_post_id = models.ForeignKey(Post, db_column='comment_post_ID') # Field name made lowercase. 120 | comment_author = models.TextField() 121 | comment_author_email = models.CharField(max_length=100) 122 | comment_author_url = models.CharField(max_length=200) 123 | comment_author_ip = models.CharField(db_column='comment_author_IP', max_length=100) # Field name made lowercase. 124 | comment_date = models.DateTimeField() 125 | comment_date_gmt = models.DateTimeField() 126 | comment_content = models.TextField() 127 | comment_karma = models.IntegerField() 128 | comment_approved = models.CharField(max_length=20) 129 | comment_agent = models.CharField(max_length=255) 130 | comment_type = models.CharField(max_length=20) 131 | comment_parent = models.BigIntegerField() 132 | user_id = models.BigIntegerField() 133 | 134 | class Meta: 135 | verbose_name = u'Comment' 136 | verbose_name_plural = u'Comments' 137 | db_table = u'wp_comments' 138 | 139 | def __unicode__(self): 140 | return self.comment_content[:50] 141 | 142 | 143 | class CommentMeta(models.Model): 144 | meta_id = models.BigIntegerField(primary_key=True) 145 | comment_id = models.BigIntegerField() 146 | meta_key = models.CharField(max_length=255, blank=True) 147 | meta_value = models.TextField(blank=True) 148 | 149 | class Meta: 150 | verbose_name = u'Comment Meta' 151 | verbose_name_plural = u'Comments Meta' 152 | db_table = u'wp_commentmeta' 153 | 154 | def __unicode__(self): 155 | return self.meta_key 156 | 157 | class Term(models.Model): 158 | term_id = models.BigIntegerField(primary_key=True) 159 | name = models.CharField(max_length=200) 160 | slug = models.CharField(unique=True, max_length=200) 161 | term_group = models.BigIntegerField() 162 | 163 | class Meta: 164 | verbose_name = u'Term' 165 | verbose_name_plural = u'Terms' 166 | db_table = u'wp_terms' 167 | 168 | def __unicode__(self): 169 | return self.name 170 | 171 | class TermTaxonomy(models.Model): 172 | term_taxonomy_id = models.BigIntegerField(primary_key=True) 173 | term = models.ForeignKey(Term, unique=True) 174 | taxonomy = models.CharField(max_length=32) 175 | description = models.TextField() 176 | parent = models.BigIntegerField() 177 | count = models.BigIntegerField() 178 | 179 | class Meta: 180 | verbose_name = "Term Taxonomy" 181 | verbose_name_plural = "Term Taxonomies" 182 | db_table = u'wp_term_taxonomy' 183 | 184 | def __unicode__(self): 185 | return self.taxonomy 186 | 187 | 188 | class TermRelationship(models.Model): 189 | object_id = models.BigIntegerField(primary_key=True) 190 | term_taxonomy = models.ForeignKey(TermTaxonomy) 191 | term_order = models.IntegerField() 192 | 193 | class Meta: 194 | verbose_name = u'Term Relationship' 195 | verbose_name_plural = u'Term Relationships' 196 | db_table = u'wp_term_relationships' 197 | 198 | class UserMeta(models.Model): 199 | umeta_id = models.BigIntegerField(primary_key=True) 200 | user = models.ForeignKey(WpUser) 201 | meta_key = models.CharField(max_length=255, blank=True) 202 | meta_value = models.TextField(blank=True) 203 | 204 | class Meta: 205 | verbose_name = 'User Meta' 206 | verbose_name_plural = 'Users Meta' 207 | db_table = u'wp_usermeta' 208 | 209 | def __unicode__(self): 210 | return self.user.user_nicename 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /wp/templates/wp/recent_comments.html: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /wp/templates/wp/recent_posts.html: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /wp/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agiliq/django-wordpress/8e67234800d223f764f3c19b99c5d7274b239795/wp/templatetags/__init__.py -------------------------------------------------------------------------------- /wp/templatetags/wordpress_tags.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from wp.models import Post, Comment 3 | 4 | 5 | register = template.Library() 6 | 7 | 8 | @register.inclusion_tag("wp/recent_comments.html") 9 | def show_comments(num_comments): 10 | return {"comments":Comment.objects.order_by("-comment_date")[:num_comments]} 11 | 12 | 13 | @register.inclusion_tag("wp/recent_posts.html") 14 | def show_posts(num_comments): 15 | return {"posts": Post.objects.filter(post_type="post", post_status="publish").order_by("-post_date")[:num_comments]} 16 | 17 | @register.tag 18 | def populate_comments(parser, token): 19 | "Use: {% populate_comments 5 as recent_comments %}" 20 | try: 21 | tag_name, num_comments, as_name, name = token.split_contents() 22 | except ValueError: 23 | raise template.TemplateSyntaxError("populate_comments requires three argument") 24 | return CommentsNode(num_comments, name) 25 | 26 | class CommentsNode(template.Node): 27 | def __init__(self, num_comments, name): 28 | self.num_comments = num_comments 29 | self.name = name 30 | 31 | def render(self, context): 32 | "" 33 | context[self.name] = Comment.objects.order_by("-comment_date")[:self.num_comments] 34 | return "" 35 | 36 | @register.tag 37 | def populate_posts(parser, token): 38 | "Use: {% populate_posts 5 as recent_comments %}" 39 | try: 40 | tag_name, num_posts, as_name, name = token.split_contents() 41 | except ValueError: 42 | raise template.TemplateSyntaxError("populate_posts requires three argument") 43 | return PostsNode(num_posts, name) 44 | 45 | class PostsNode(template.Node): 46 | def __init__(self, num_posts, name): 47 | self.num_posts = num_posts 48 | self.name = name 49 | 50 | def render(self, context): 51 | "" 52 | context[self.name] = Post.objects.filter(post_type="post", post_status="publish").order_by("-post_date")[:self.num_posts] 53 | return "" 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /wp/tests.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file demonstrates two different styles of tests (one doctest and one 3 | unittest). These will both pass when you run "manage.py test". 4 | 5 | Replace these with more appropriate tests for your application. 6 | """ 7 | 8 | from django.test import TestCase 9 | from django.template import Template, Context 10 | 11 | 12 | class SimpleTest(TestCase): 13 | def test_template_tags(self): 14 | template_string = """ 15 | {% load wordpress_tags %} 16 | {% show_comments 5 %} 17 | {% show_posts 5 %} 18 | {% populate_comments 5 as commnts%} 19 | {% populate_posts 10 as posts %} 20 | """ 21 | t = Template(template_string) 22 | c = Context({}) 23 | t.render(c) 24 | -------------------------------------------------------------------------------- /wp/views.py: -------------------------------------------------------------------------------- 1 | # Create your views here. 2 | --------------------------------------------------------------------------------